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)
474 XQueryColor(XtDisplay(w), w->core.colormap, &color);
475 sz = snprintf(buf, sizeof(buf), "#%04x%04x%04x", color.red, color.green, color.blue);
476 assert(sz>=0 && (size_t)sz < sizeof(buf));
477 return build_string(buf);
481 x_get_top_level_position(Display * d, Window w, Position * x, Position * y)
483 Window root, parent = w, *children;
484 unsigned int nchildren;
485 XWindowAttributes xwa;
489 if (!XQueryTree(d, w, &root, &parent, &children, &nchildren)) {
496 while (root != parent);
497 XGetWindowAttributes(d, w, &xwa);
503 static void x_smash_bastardly_shell_position(Widget shell)
505 /* Naturally those bastards who wrote Xt couldn't be bothered
506 to learn about race conditions and such. We can't trust
507 the X and Y values to have any semblance of correctness,
508 so we smash the right values in place. */
510 /* We might be called before we've actually realized the window (if
511 we're checking for the minibuffer resource). This will bomb in
512 that case so we don't bother calling it. */
514 x_get_top_level_position(XtDisplay(shell), XtWindow(shell),
515 &shell->core.x, &shell->core.y);
519 static Lisp_Object x_frame_property(struct frame *f, Lisp_Object property)
521 Widget shell = FRAME_X_SHELL_WIDGET(f);
522 EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
523 Widget gw = (Widget) w;
525 if (EQ(Qleft, property) || EQ(Qtop, property)) {
527 if (!XtWindow(shell))
529 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
531 if (EQ(Qleft, property))
533 if (EQ(Qtop, property))
536 if (EQ(Qborder_width, property))
537 return make_int(w->core.border_width);
538 if (EQ(Qinternal_border_width, property))
539 return make_int(w->emacs_frame.internal_border_width);
540 if (EQ(Qborder_color, property))
541 return color_to_string(gw, w->core.border_pixel);
543 if (EQ(Qtop_toolbar_shadow_color, property))
544 return color_to_string(gw,
545 w->emacs_frame.top_toolbar_shadow_pixel);
546 if (EQ(Qbottom_toolbar_shadow_color, property))
547 return color_to_string(gw,
549 bottom_toolbar_shadow_pixel);
550 if (EQ(Qbackground_toolbar_color, property))
551 return color_to_string(gw,
552 w->emacs_frame.background_toolbar_pixel);
553 if (EQ(Qtoolbar_shadow_thickness, property))
554 return make_int(w->emacs_frame.toolbar_shadow_thickness);
555 #endif /* HAVE_TOOLBARS */
556 if (EQ(Qinter_line_space, property))
557 return make_int(w->emacs_frame.interline);
558 if (EQ(Qwindow_id, property))
559 return Fx_window_id(make_frame(f));
564 static int x_internal_frame_property_p(struct frame *f, Lisp_Object property)
566 return EQ(property, Qleft)
567 || EQ(property, Qtop)
568 || EQ(property, Qborder_width)
569 || EQ(property, Qinternal_border_width)
570 || EQ(property, Qborder_color)
572 || EQ(property, Qtop_toolbar_shadow_color)
573 || EQ(property, Qbottom_toolbar_shadow_color)
574 || EQ(property, Qbackground_toolbar_color)
575 || EQ(property, Qtoolbar_shadow_thickness)
576 #endif /* HAVE_TOOLBARS */
577 || EQ(property, Qinter_line_space)
578 || EQ(property, Qwindow_id)
579 || STRINGP(property);
582 static Lisp_Object x_frame_properties(struct frame *f)
584 Lisp_Object props = Qnil;
585 Widget shell = FRAME_X_SHELL_WIDGET(f);
586 EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
587 Widget gw = (Widget) w;
590 props = cons3(Qwindow_id, Fx_window_id(make_frame(f)), props);
592 cons3(Qinter_line_space, make_int(w->emacs_frame.interline), props);
595 props = cons3(Qtoolbar_shadow_thickness,
596 make_int(w->emacs_frame.toolbar_shadow_thickness), props);
597 props = cons3(Qbackground_toolbar_color,
599 w->emacs_frame.background_toolbar_pixel),
602 cons3(Qbottom_toolbar_shadow_color,
604 w->emacs_frame.bottom_toolbar_shadow_pixel),
607 cons3(Qtop_toolbar_shadow_color,
608 color_to_string(gw, w->emacs_frame.top_toolbar_shadow_pixel),
610 #endif /* HAVE_TOOLBARS */
612 props = cons3(Qborder_color,
613 color_to_string(gw, w->core.border_pixel), props);
614 props = cons3(Qinternal_border_width,
615 make_int(w->emacs_frame.internal_border_width), props);
616 props = cons3(Qborder_width, make_int(w->core.border_width), props);
618 if (!XtWindow(shell))
621 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
624 props = cons3(Qtop, make_int(y), props);
625 props = cons3(Qleft, make_int(x), props);
630 /* Functions called only from `x_set_frame_properties' to set
631 individual properties. */
634 x_set_frame_text_value(struct frame *f, Bufbyte * value,
635 String Xt_resource_name,
636 String Xt_resource_encoding_name)
638 Atom encoding = XA_STRING;
639 String new_XtValue = (String) value;
640 String old_XtValue = NULL;
644 /* Optimize for common ASCII case */
645 for (ptr = value; *ptr; ptr++)
646 if (!BYTE_ASCII_P(*ptr)) {
648 encoding = DEVICE_XATOM_COMPOUND_TEXT(
649 XDEVICE(FRAME_DEVICE(f)));
650 C_STRING_TO_EXTERNAL(value, tmp, Qctext);
651 new_XtValue = (String) tmp;
656 /* #### Caching is device-independent - belongs in update_frame_title. */
657 Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), Xt_resource_name, &old_XtValue);
658 if (!old_XtValue || strcmp(new_XtValue, old_XtValue)) {
660 XtSetArg(al[0], Xt_resource_name, new_XtValue);
661 XtSetArg(al[1], Xt_resource_encoding_name, encoding);
662 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
666 static void x_set_title_from_bufbyte(struct frame *f, Bufbyte * name)
668 x_set_frame_text_value(f, name, XtNtitle, XtNtitleEncoding);
671 static void x_set_icon_name_from_bufbyte(struct frame *f, Bufbyte * name)
673 x_set_frame_text_value(f, name, XtNiconName, XtNiconNameEncoding);
676 /* Set the initial frame size as specified. This function is used
677 when the frame's widgets have not yet been realized. In this
678 case, it is not sufficient just to set the width and height of
679 the EmacsFrame widget, because they will be ignored when the
680 widget is realized (instead, the shell's geometry resource is
684 x_set_initial_frame_size(struct frame *f, int flags, int x, int y,
685 unsigned int w, unsigned int h)
687 char shell_geom[255];
690 char uspos = !!(flags & (XValue | YValue));
691 char ussize = !!(flags & (WidthValue | HeightValue));
695 /* assign the correct size to the EmacsFrame widget ... */
696 EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), w, h);
698 /* and also set the WMShell's geometry */
699 (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign =
701 (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign =
705 sz = snprintf(shell_geom, sizeof(shell_geom),
706 "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign,
709 sz = snprintf(shell_geom, sizeof(shell_geom),
710 "=%c%d%c%d", xsign, xval, ysign, yval);
712 sz = snprintf(shell_geom, sizeof(shell_geom),
714 assert(sz >=0 && (size_t)sz < sizeof(shell_geom));
715 if (uspos || ussize) {
716 temp = xnew_atomic_array(char, 1 + strlen(shell_geom));
717 strcpy(temp, shell_geom);
718 FRAME_X_GEOM_FREE_ME_PLEASE(f) = temp;
722 Xt_SET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNgeometry, temp);
725 /* Report to X that a frame property of frame S is being set or changed.
726 If the property is not specially recognized, do nothing.
729 static void x_set_frame_properties(struct frame *f, Lisp_Object plist)
732 Dimension width = 0, height = 0;
733 Bool width_specified_p = False;
734 Bool height_specified_p = False;
735 Bool x_position_specified_p = False;
736 Bool y_position_specified_p = False;
737 Bool internal_border_width_specified = False;
741 /* We can be called after the X IO error handler has seen a
742 broken pipe on the relevant display. Don't do anything in
744 if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
747 w = FRAME_X_TEXT_WIDGET (f);
749 for (tail = plist; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
750 Lisp_Object prop = Fcar(tail);
751 Lisp_Object val = Fcar(Fcdr(tail));
756 if (XSTRING_LENGTH(prop) == 0)
759 LISP_STRING_TO_EXTERNAL(prop, extprop, Qctext);
761 const Extbyte *extval;
764 TO_EXTERNAL_FORMAT(LISP_STRING, val,
765 ALLOCA, (extval, extvallen),
767 XtVaSetValues(w, XtVaTypedArg, extprop,
768 XtRString, extval, extvallen + 1,
771 XtVaSetValues(w, XtVaTypedArg, extprop, XtRInt,
772 XINT(val), sizeof(int),
774 } else if (SYMBOLP(prop)) {
775 Lisp_Object str = Fget(prop, Qx_resource_name, Qnil);
776 int int_p = !NILP(Fget(prop, Qintegerp, Qnil));
778 if (NILP(prop) || NILP(str)) {
779 /* Kludge to handle the font property. */
780 if (EQ(prop, Qfont)) {
781 /* If the value is not a string we silently ignore it. */
783 Lisp_Object frm, font_spec;
787 Fget(Fget_face(Qdefault),
790 Fadd_spec_to_specifier
791 (font_spec, val, frm, Qnil,
793 update_frame_face_values(f);
802 /* Kludge the width/height so that we interpret them in characters
803 instead of pixels. Yuck yuck yuck. */
804 if (!strcmp((char *)XSTRING_DATA(str), "width")) {
807 width_specified_p = True;
810 if (!strcmp((char *)XSTRING_DATA(str), "height")) {
813 height_specified_p = True;
816 /* Further kludge the x/y. */
817 if (!strcmp((char *)XSTRING_DATA(str), "x")) {
819 x = (Position) XINT(val);
820 x_position_specified_p = True;
823 if (!strcmp((char *)XSTRING_DATA(str), "y")) {
825 y = (Position) XINT(val);
826 y_position_specified_p = True;
829 /* Have you figured out by now that this entire function is
830 one gigantic kludge? */
831 if (!strcmp((char *)XSTRING_DATA(str),
832 "internalBorderWidth")) {
833 internal_border_width_specified = True;
838 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str),
840 } else if (EQ(val, Qt)) {
841 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str), True); /* XtN... */
842 } else if (EQ(val, Qnil)) {
843 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str), False); /* XtN... */
846 XtVaSetValues(w, XtVaTypedArg,
848 (char *)XSTRING_DATA(str),
851 XSTRING_LENGTH(val) + 1,
855 #ifdef HAVE_SCROLLBARS
856 if (!strcmp((char *)XSTRING_DATA(str), "scrollBarWidth")
857 || !strcmp((char *)XSTRING_DATA(str),
858 "scrollBarHeight")) {
859 x_update_frame_scrollbars(f);
861 #endif /* HAVE_SCROLLBARS */
865 /* Kludge kludge kludge. We need to deal with the size and position
868 int size_specified_p = width_specified_p || height_specified_p;
869 int position_specified_p = x_position_specified_p ||
870 y_position_specified_p;
872 if (!width_specified_p)
873 width = FRAME_WIDTH(f);
874 if (!height_specified_p)
875 height = FRAME_HEIGHT(f);
877 /* Kludge kludge kludge kludge. */
878 if (position_specified_p &&
879 (!x_position_specified_p || !y_position_specified_p)) {
881 Widget shell = FRAME_X_SHELL_WIDGET(f);
882 x_get_top_level_position(XtDisplay(shell),
884 (x_position_specified_p ?
886 (y_position_specified_p ?
889 x = (int)(FRAME_X_SHELL_WIDGET(f)->core.x);
890 y = (int)(FRAME_X_SHELL_WIDGET(f)->core.y);
894 if (!f->init_finished) {
896 (size_specified_p ? WidthValue | HeightValue : 0) |
897 (position_specified_p ? XValue | YValue |
898 (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0)
901 || position_specified_p
902 || internal_border_width_specified)
903 x_set_initial_frame_size(f, flags, x, y, width,
906 if (size_specified_p || internal_border_width_specified) {
909 Fset_frame_size(frame, make_int(width),
910 make_int(height), Qnil);
912 if (position_specified_p) {
915 Fset_frame_position(frame, make_int(x),
922 static int frame_title_format_already_set;
924 static void maybe_set_frame_title_format(Widget shell)
927 /* Only do this if this is the first X frame we're creating.
929 If the *title resource (or -title option) was specified, then
930 set frame-title-format to its value.
933 if (!frame_title_format_already_set) {
934 /* No doubt there's a less stupid way to do this. */
936 XtResource resources[2];
937 results[0] = results[1] = 0;
938 resources[0].resource_name = XtNtitle;
939 resources[0].resource_class = XtCTitle;
940 resources[0].resource_type = XtRString;
941 resources[0].resource_size = sizeof(String);
942 resources[0].resource_offset = 0;
943 resources[0].default_type = XtRString;
944 resources[0].default_addr = 0;
945 resources[1].resource_name = XtNiconName;
946 resources[1].resource_class = XtCIconName;
947 resources[1].resource_type = XtRString;
948 resources[1].resource_size = sizeof(String);
949 resources[1].resource_offset = sizeof(char *);
950 resources[1].default_type = XtRString;
951 resources[1].default_addr = 0;
952 XtGetSubresources(XtParent(shell), (XtPointer) results,
954 shell->core.widget_class->core_class.
955 class_name, resources, XtNumber(resources), 0,
958 Vframe_title_format = build_string(results[0]);
960 Vframe_icon_title_format = build_string(results[1]);
963 frame_title_format_already_set = 1;
970 static Widget CurrentDragWidget = NULL;
971 static XtCallbackRec dnd_convert_cb_rec[2];
972 static XtCallbackRec dnd_destroy_cb_rec[2];
973 static int drag_not_done = 0;
976 x_cde_destroy_callback(Widget widget, XtPointer clientData, XtPointer callData)
978 DtDndDragFinishCallbackStruct *dragFinishInfo =
979 (DtDndDragFinishCallbackStruct *) callData;
980 DtDndContext *dragData = dragFinishInfo->dragData;
984 if (callData != NULL && dragData != NULL) {
985 if (dragData->protocol == DtDND_BUFFER_TRANSFER) {
986 for (i = 0; i < dragData->numItems; i++) {
987 XtFree((char *)dragData->data.buffers[i].bp);
988 if (dragData->data.buffers[i].name)
989 XtFree(dragData->data.buffers[i].name);
992 for (i = 0; i < dragData->numItems; i++)
993 XtFree(dragData->data.files[i]);
997 /* free the data string */
1000 CurrentDragWidget = NULL;
1004 x_cde_convert_callback(Widget widget, XtPointer clientData, XtPointer callData)
1006 DtDndConvertCallbackStruct *convertInfo =
1007 (DtDndConvertCallbackStruct *) callData;
1008 char *textdata = (char *)clientData;
1009 char *textptr = NULL;
1012 if (convertInfo == NULL) {
1016 if ((convertInfo->dragData->protocol != DtDND_BUFFER_TRANSFER
1017 && convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER) ||
1018 (convertInfo->reason != DtCR_DND_CONVERT_DATA)) {
1022 for (textptr = textdata, i = 0;
1023 i < convertInfo->dragData->numItems;
1024 textptr += strlen(textptr) + 1, i++) {
1025 if (convertInfo->dragData->protocol == DtDND_BUFFER_TRANSFER) {
1026 convertInfo->dragData->data.buffers[i].bp =
1027 XtNewString(textptr);
1028 convertInfo->dragData->data.buffers[i].size =
1030 convertInfo->dragData->data.buffers[i].name = NULL;
1032 convertInfo->dragData->data.files[i] =
1033 XtNewString(textptr);
1037 convertInfo->status = DtDND_SUCCESS;
1040 static Lisp_Object abort_current_drag(Lisp_Object arg)
1042 if (CurrentDragWidget && drag_not_done) {
1043 XmDragCancel(CurrentDragWidget);
1044 CurrentDragWidget = NULL;
1049 DEFUN("cde-start-drag-internal", Fcde_start_drag_internal, 3, 3, 0, /*
1050 Start a CDE drag from a buffer.
1051 First argument is the event that started the drag (must be a
1052 button-press-event),
1053 second arg defines if the data should be treated as a buffer or
1054 a filename transfer (set to nil for buffer transfer),
1055 and the third argument is a list of data strings.
1056 WARNING: can only handle plain/text and file: transfers!
1058 (event, dragtype, dragdata))
1060 if (EVENTP(event)) {
1061 struct frame *f = decode_x_frame(Fselected_frame(Qnil));
1063 Widget wid = FRAME_X_TEXT_WIDGET(f);
1064 Display *display = XtDisplayOfObject(wid);
1065 struct device *d = get_device_from_display(display);
1066 struct x_device *xd = DEVICE_X_DATA(d);
1067 XWindowAttributes win_attrib;
1068 unsigned int modifier = 0, state = 0;
1070 int numItems = 0, textlen = 0, pos = 0;
1071 Lisp_Event *lisp_event = XEVENT(event);
1072 Lisp_Object item = Qnil;
1073 struct gcpro gcpro1;
1075 /* only drag if this is really a press */
1076 if (EVENT_TYPE(lisp_event) != button_press_event
1077 || !LISTP(dragdata))
1083 * not so cross hack that converts a emacs event back to a XEvent
1086 x_event.xbutton.type = ButtonPress;
1087 x_event.xbutton.send_event = False;
1088 x_event.xbutton.display = XtDisplayOfObject(wid);
1089 x_event.xbutton.window = XtWindowOfObject(wid);
1090 x_event.xbutton.root = XRootWindow(x_event.xbutton.display, 0);
1091 x_event.xbutton.subwindow = 0;
1092 x_event.xbutton.time = lisp_event->timestamp;
1093 x_event.xbutton.x = lisp_event->event.button.x;
1094 x_event.xbutton.y = lisp_event->event.button.y;
1095 if (Success == XGetWindowAttributes(x_event.xbutton.display,
1096 x_event.xbutton.window,
1098 x_event.xbutton.x_root =
1099 win_attrib.x + lisp_event->event.button.x;
1100 x_event.xbutton.y_root =
1101 win_attrib.y + lisp_event->event.button.y;
1103 x_event.xbutton.x_root = lisp_event->event.button.x; /* this is wrong */
1104 x_event.xbutton.y_root = lisp_event->event.button.y;
1106 modifier = lisp_event->event.button.modifiers;
1107 if (modifier & XEMACS_MOD_SHIFT)
1109 if (modifier & XEMACS_MOD_CONTROL)
1110 state |= ControlMask;
1111 if (modifier & XEMACS_MOD_META)
1112 state |= xd->MetaMask;
1113 if (modifier & XEMACS_MOD_SUPER)
1114 state |= xd->SuperMask;
1115 if (modifier & XEMACS_MOD_HYPER)
1116 state |= xd->HyperMask;
1117 if (modifier & XEMACS_MOD_ALT)
1118 state |= xd->AltMask;
1119 state |= Button1Mask << (lisp_event->event.button.button - 1);
1121 x_event.xbutton.state = state;
1122 x_event.xbutton.button = lisp_event->event.button.button;
1123 x_event.xkey.same_screen = True;
1125 /* convert data strings into a big string */
1127 while (!NILP(item)) {
1128 if (!STRINGP(XCAR(item))) {
1132 textlen += XSTRING_LENGTH(XCAR(item)) + 1;
1139 * concatenate all strings given to one large string, with
1140 * \0 as separator. List is ended by \0.
1142 Ctext = (char*)xmalloc_atomic(textlen + 1);
1146 while (!NILP(item)) {
1147 if (!STRINGP(XCAR(item))) {
1154 (const char *)XSTRING_DATA(XCAR(item)));
1155 pos += XSTRING_LENGTH(XCAR(item)) + 1;
1160 dnd_convert_cb_rec[0].callback = x_cde_convert_callback;
1161 dnd_convert_cb_rec[0].closure = (XtPointer) Ctext;
1162 dnd_convert_cb_rec[1].callback = NULL;
1163 dnd_convert_cb_rec[1].closure = NULL;
1165 dnd_destroy_cb_rec[0].callback = x_cde_destroy_callback;
1166 dnd_destroy_cb_rec[0].closure = (XtPointer) Ctext;
1167 dnd_destroy_cb_rec[1].callback = NULL;
1168 dnd_destroy_cb_rec[1].closure = NULL;
1171 DtDndDragStart(wid, &x_event,
1173 DtDND_BUFFER_TRANSFER :
1174 DtDND_FILENAME_TRANSFER), numItems,
1175 XmDROP_COPY, dnd_convert_cb_rec,
1176 dnd_destroy_cb_rec, NULL, 0);
1181 return numItems ? Qt : Qnil;
1188 x_cde_transfer_callback(Widget widget, XtPointer clientData, XtPointer callData)
1190 char *filePath, *hurl;
1191 int ii, enqueue = 1;
1192 Lisp_Object frame = Qnil;
1193 Lisp_Object l_type = Qnil;
1194 Lisp_Object l_data = Qnil;
1195 DtDndTransferCallbackStruct *transferInfo = NULL;
1196 struct gcpro gcpro1, gcpro2, gcpro3;
1199 this needs to be changed to the new protocol:
1200 - we need the button, modifier and pointer states to create a
1201 correct misc_user_event
1202 - the data must be converted to the new format (URL/MIME)
1206 transferInfo = (DtDndTransferCallbackStruct *) callData;
1207 if (transferInfo == NULL)
1210 GCPRO3(frame, l_type, l_data);
1212 frame = make_frame((struct frame *)clientData);
1214 if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER) {
1215 l_type = Qdragdrop_URL;
1217 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
1218 filePath = transferInfo->dropData->data.files[ii];
1219 hurl = dnd_url_hexify_string((char *)filePath, "file:");
1220 /* #### Mule-izing required */
1221 l_data = Fcons(make_string((Bufbyte *) hurl,
1222 strlen(hurl)), l_data);
1225 } else if (transferInfo->dropData->protocol == DtDND_BUFFER_TRANSFER) {
1226 int speccount = specpdl_depth();
1228 /* Problem: all buffers a treated as text/plain!!!
1229 Solution: Also support DtDND_TEXT_TRANSFER
1230 perhaps implementation of the Motif protocol
1231 (which is the base of CDE) will clear this */
1232 l_type = Qdragdrop_MIME;
1233 record_unwind_protect(abort_current_drag, Qnil);
1235 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
1236 /* let us forget this name thing for now... */
1237 /* filePath = transferInfo->dropData->data.buffers[ii].name;
1238 path = (filePath == NULL) ? Qnil
1239 : make_string ((Bufbyte *)filePath, strlen (filePath)); */
1240 /* what, if the data is no text, and how can I tell it? */
1244 (make_string((Bufbyte *) "text/plain", 10)),
1245 make_string((Bufbyte *) "8bit", 4),
1246 make_string((Bufbyte *) transferInfo->
1247 dropData->data.buffers[ii].bp,
1248 transferInfo->dropData->data.
1249 buffers[ii].size)), l_data);
1252 unbind_to(speccount, Qnil);
1253 } else /* the other cases: NOOP_TRANSFER */
1256 /* The Problem: no button and mods from CDE... */
1258 enqueue_misc_user_event_pos(frame, Qdragdrop_drop_dispatch,
1259 Fcons(l_type, l_data),
1260 0 /* this is the button */ ,
1261 0 /* these are the mods */ ,
1262 transferInfo->x, transferInfo->y);
1267 #endif /* HAVE_CDE */
1270 /************************************************************************/
1271 /* widget creation */
1272 /************************************************************************/
1274 /* The widget hierarchy is
1276 argv[0] shell container FRAME-NAME
1277 ApplicationShell EmacsShell EmacsManager EmacsFrame
1279 We accept geometry specs in this order:
1281 *FRAME-NAME.geometry
1282 *EmacsFrame.geometry
1285 Other possibilities for widget hierarchies might be
1287 argv[0] frame container FRAME-NAME
1288 ApplicationShell EmacsShell EmacsManager EmacsFrame
1290 argv[0] FRAME-NAME container FRAME-NAME
1291 ApplicationShell EmacsShell EmacsManager EmacsFrame
1293 argv[0] FRAME-NAME container emacsTextPane
1294 ApplicationShell EmacsShell EmacsManager EmacsFrame
1296 #ifdef EXTERNAL_WIDGET
1297 The ExternalShell widget is simply a replacement for the Shell widget
1298 which is able to deal with using an externally-supplied window instead
1299 of always creating its own.
1304 #ifdef EXTERNAL_WIDGET
1306 static int is_valid_window(Window w, struct device *d)
1308 XWindowAttributes xwa;
1309 Display *dpy = DEVICE_X_DISPLAY(d);
1311 expect_x_error(dpy);
1312 XGetWindowAttributes(dpy, w, &xwa);
1313 return !x_error_occurred_p(dpy);
1316 #endif /* EXTERNAL_WIDGET */
1318 /* This sends a synthetic mouse-motion event to the frame, if the mouse
1319 is over the frame. This ensures that the cursor gets set properly
1320 before the user moves the mouse for the first time. */
1322 static void x_send_synthetic_mouse_event(struct frame *f)
1324 /* #### write this function. */
1327 static int first_x_frame_p(struct frame *f)
1329 Lisp_Object rest = DEVICE_FRAME_LIST(XDEVICE(f->device));
1330 while (!NILP(rest) &&
1331 (f == XFRAME(XCAR(rest)) || !FRAME_X_P(XFRAME(XCAR(rest)))))
1336 /* Figure out what size the EmacsFrame widget should initially be,
1337 and set it. Should be called after the default font has been
1338 determined but before the widget has been realized. */
1340 static void x_initialize_frame_size(struct frame *f)
1342 /* Geometry of the AppShell */
1346 unsigned int app_w = 0;
1347 unsigned int app_h = 0;
1349 /* Geometry of the EmacsFrame */
1350 int frame_flags = 0;
1353 unsigned int frame_w = 0;
1354 unsigned int frame_h = 0;
1356 /* Hairily merged geometry */
1359 unsigned int w = 80;
1360 unsigned int h = 40;
1363 char *geom = 0, *ew_geom = 0;
1364 Boolean iconic_p = False, ew_iconic_p = False;
1366 Widget wmshell = FRAME_X_SHELL_WIDGET(f);
1367 /* #### This may not be an ApplicationShell any more, with the 'popup
1369 Widget app_shell = XtParent(wmshell);
1370 Widget ew = FRAME_X_TEXT_WIDGET(f);
1372 /* set the position of the frame's root window now. When the
1373 frame was created, the position was initialized to (0,0). */
1375 struct window *win = XWINDOW(f->root_window);
1377 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f)
1378 + FRAME_LEFT_GUTTER_BOUNDS(f);
1379 WINDOW_TOP(win) = FRAME_TOP_BORDER_END(f)
1380 + FRAME_TOP_GUTTER_BOUNDS(f);
1382 if (!NILP(f->minibuffer_window)) {
1383 win = XWINDOW(f->minibuffer_window);
1384 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f)
1385 + FRAME_LEFT_GUTTER_BOUNDS(f);
1389 #ifdef EXTERNAL_WIDGET
1390 /* If we're an external widget, then the size of the frame is predetermined
1391 (by the client) and is not our decision to make. */
1392 if (FRAME_X_EXTERNAL_WINDOW_P(f))
1397 /* #### this junk has not been tested; therefore it's
1398 probably wrong. Doesn't really matter at this point because
1399 currently all frames are either top-level or external widgets. */
1401 /* If we're not our own top-level window, then we shouldn't go messing around
1402 with top-level shells or "Emacs.geometry" or any such stuff. Therefore,
1403 we do as follows to determine the size of the frame:
1405 1) If a value for the frame's "geometry" resource was specified, then
1406 use it. (This specifies a size in characters.)
1407 2) Else, if the "width" and "height" resources were specified, then
1408 leave them alone. (This is a value in pixels. Sorry, we can't break
1409 Xt conventions here.)
1410 3) Else, assume a size of 64x12. (This is somewhat arbitrary, but
1411 it's unlikely that a size of 80x40 is desirable because we're probably
1412 inside of a dialog box.)
1414 Set the widget's x, y, height, and width as determined. Don't set the
1415 top-level container widget, because we don't necessarily know what it
1416 is. (Assume it is smart and pays attention to our values.)
1419 if (!FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1420 Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1422 frame_flags = XParseGeometry(ew_geom,
1424 &frame_w, &frame_h);
1425 if (!(frame_flags & (WidthValue | HeightValue))) {
1427 XtSetArg(al[0], XtNwidth, &frame_w);
1428 XtSetArg(al[1], XtNheight, &frame_h);
1429 XtGetValues(ew, al, 2);
1430 if (!frame_w && !frame_h) {
1433 frame_flags |= WidthValue | HeightValue;
1436 if (frame_flags & (WidthValue | HeightValue))
1437 EmacsFrameSetCharSize(ew, frame_w, frame_h);
1438 if (frame_flags & (XValue | YValue)) {
1440 XtSetArg(al[0], XtNwidth, &frame_w);
1441 XtSetArg(al[1], XtNheight, &frame_h);
1442 XtGetValues(ew, al, 2);
1444 if (frame_flags & XNegative)
1446 if (frame_flags & YNegative)
1449 XtSetArg(al[0], XtNx, frame_x);
1450 XtSetArg(al[1], XtNy, frame_y);
1451 XtSetValues(ew, al, 2);
1457 /* OK, we're a top-level shell. */
1459 if (!XtIsWMShell(wmshell))
1462 /* If the EmacsFrame doesn't have a geometry but the shell does,
1463 treat that as the geometry of the frame.
1464 (Is this bogus? I'm not sure.) */
1466 Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1468 Xt_GET_VALUE(wmshell, XtNgeometry, &geom);
1471 Xt_SET_VALUE(ew, XtNgeometry, ew_geom);
1475 /* If the Shell is iconic, then the EmacsFrame is iconic.
1476 (Is this bogus? I'm not sure.) */
1477 Xt_GET_VALUE(ew, XtNiconic, &ew_iconic_p);
1479 Xt_GET_VALUE(wmshell, XtNiconic, &iconic_p);
1481 ew_iconic_p = iconic_p;
1482 Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1486 Xt_GET_VALUE(app_shell, XtNgeometry, &geom);
1489 XParseGeometry(geom, &app_x, &app_y, &app_w, &app_h);
1492 frame_flags = XParseGeometry(ew_geom,
1494 &frame_w, &frame_h);
1496 if (first_x_frame_p(f)) {
1497 /* If this is the first frame created:
1498 ====================================
1500 - Use the ApplicationShell's size/position, if specified.
1501 (This is "Emacs.geometry", or the "-geometry" command line arg.)
1502 - Else use the EmacsFrame's size/position.
1503 (This is "*FRAME-NAME.geometry")
1505 - If the AppShell is iconic, the frame should be iconic.
1507 AppShell comes first so that -geometry always applies to the first
1508 frame created, even if there is an "every frame" entry in the
1511 if (app_flags & (XValue | YValue)) {
1516 (XValue | YValue | XNegative | YNegative));
1517 } else if (frame_flags & (XValue | YValue)) {
1522 (XValue | YValue | XNegative | YNegative));
1525 if (app_flags & (WidthValue | HeightValue)) {
1528 flags |= (app_flags & (WidthValue | HeightValue));
1529 } else if (frame_flags & (WidthValue | HeightValue)) {
1532 flags |= (frame_flags & (WidthValue | HeightValue));
1535 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1537 Xt_GET_VALUE(app_shell, XtNiconic, &iconic_p);
1539 ew_iconic_p = iconic_p;
1540 Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1544 /* If this is not the first frame created:
1545 ========================================
1547 - use the EmacsFrame's size/position if specified
1548 - Otherwise, use the ApplicationShell's size, but not position.
1550 So that means that one can specify the position of the first frame
1551 with "Emacs.geometry" or `-geometry'; but can only specify the
1552 position of subsequent frames with "*FRAME-NAME.geometry".
1554 AppShell comes second so that -geometry does not apply to subsequent
1555 frames when there is an "every frame" entry in the resource db,
1556 but does apply to the first frame.
1558 if (frame_flags & (XValue | YValue)) {
1563 (XValue | YValue | XNegative | YNegative));
1566 if (frame_flags & (WidthValue | HeightValue)) {
1569 flags |= (frame_flags & (WidthValue | HeightValue));
1570 } else if (app_flags & (WidthValue | HeightValue)) {
1573 flags |= (app_flags & (WidthValue | HeightValue));
1577 x_set_initial_frame_size(f, flags, x, y, w, h);
1580 static void x_get_layout_sizes(struct frame *f, Dimension * topbreadth)
1584 /* compute height of all top-area widgets */
1585 for (i = 0, *topbreadth = 0; i < FRAME_X_NUM_TOP_WIDGETS(f); i++) {
1586 Widget wid = FRAME_X_TOP_WIDGETS(f)[i];
1587 if (wid && XtIsManaged(wid))
1589 wid->core.height + 2 * wid->core.border_width;
1594 x_layout_widgets(Widget w, XtPointer client_data, XtPointer call_data)
1596 struct frame *f = (struct frame *)client_data;
1597 EmacsManagerResizeStruct *emst = (EmacsManagerResizeStruct *) call_data;
1598 Dimension width = emst->width;
1599 Dimension height = emst->height;
1600 Widget text = FRAME_X_TEXT_WIDGET(f);
1601 Dimension textbord = text->core.border_width;
1602 Dimension topbreadth;
1603 Position text_x = 0, text_y = 0;
1606 x_get_layout_sizes(f, &topbreadth);
1608 /* first the menubar and psheets ... */
1609 for (i = 0; i < FRAME_X_NUM_TOP_WIDGETS(f); i++) {
1610 Widget wid = FRAME_X_TOP_WIDGETS(f)[i];
1611 if (wid && XtIsManaged(wid)) {
1612 Dimension bord = wid->core.border_width;
1613 XtConfigureWidget(wid, 0, text_y,
1614 width - 2 * bord, wid->core.height,
1616 text_y += wid->core.height + 2 * bord;
1620 #ifdef HAVE_SCROLLBARS
1621 f->scrollbar_y_offset = topbreadth + textbord;
1624 /* finally the text area */
1626 Dimension nw = width - 2 * textbord;
1627 Dimension nh = height - text_y - 2 * textbord;
1629 if (nh != f->pixheight || nw != f->pixwidth)
1630 MARK_FRAME_SIZE_SLIPPED(f);
1631 XtConfigureWidget(text, text_x, text_y, nw, nh, textbord);
1636 x_do_query_geometry(Widget w, XtPointer client_data, XtPointer call_data)
1638 struct frame *f = (struct frame *)client_data;
1639 EmacsManagerQueryGeometryStruct *emst =
1640 (EmacsManagerQueryGeometryStruct *) call_data;
1641 Widget text = FRAME_X_TEXT_WIDGET(f);
1642 Dimension textbord = text->core.border_width;
1643 Dimension topbreadth;
1644 XtWidgetGeometry req, repl;
1645 int mask = emst->request_mode & (CWWidth | CWHeight);
1647 x_get_layout_sizes(f, &topbreadth);
1649 /* Strip away menubar from suggested size, and ask the text widget
1650 what size it wants to be. */
1651 req.request_mode = mask;
1653 req.width = emst->proposed_width - 2 * textbord;
1654 if (mask & CWHeight)
1655 req.height = emst->proposed_height - topbreadth - 2 * textbord;
1656 XtQueryGeometry(text, &req, &repl);
1658 /* Now add the menubar back again */
1659 emst->proposed_width = repl.width + 2 * textbord;
1660 emst->proposed_height = repl.height + topbreadth + 2 * textbord;
1663 /* Creates the widgets for a frame.
1664 lisp_window_id is a Lisp description of an X window or Xt
1666 parent is a frame to use as the parent.
1667 overridep if non-nil says to set the override-redirect setting.
1669 This function does not create or map the windows. (That is
1670 done by x_popup_frame().)
1673 x_create_widgets(struct frame *f, Lisp_Object lisp_window_id,
1674 Lisp_Object parent, Lisp_Object overridep)
1676 struct device *d = XDEVICE(f->device);
1677 Visual *visual = DEVICE_X_VISUAL(d);
1678 int depth = DEVICE_X_DEPTH(d);
1679 Colormap cmap = DEVICE_X_COLORMAP(d);
1680 #ifdef EXTERNAL_WIDGET
1681 Window window_id = 0;
1686 Widget text, container, shell;
1687 Widget parentwid = 0;
1688 #ifdef HAVE_MENUBARS
1689 int menubar_visible;
1693 if (STRINGP(f->name))
1694 LISP_STRING_TO_EXTERNAL(f->name, name, Qctext);
1698 /* The widget hierarchy is
1700 argv[0] shell pane FRAME-NAME
1701 ApplicationShell EmacsShell EmacsManager EmacsFrame
1703 (the type of the shell is ExternalShell if this frame is running
1704 in another client's window)
1706 However the EmacsShell widget has WM_CLASS of FRAME-NAME/Emacs.
1707 Normally such shells have name/class shellname/appclass, which in this
1708 case would be "shell/Emacs" instead of "frame-name/Emacs". We could
1709 also get around this by naming the shell "frame-name", but that would
1710 be confusing because the text area (the EmacsFrame widget inferior of
1711 the shell) is also called that. So we just set the WM_CLASS property.
1714 #ifndef EXTERNAL_WIDGET
1715 if (!NILP(lisp_window_id))
1717 ("support for external widgets was not enabled at compile-time");
1719 if (!NILP(lisp_window_id)) {
1722 CHECK_STRING(lisp_window_id);
1723 string = (char *)XSTRING_DATA(lisp_window_id);
1724 if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
1725 sscanf(string + 2, "%lxu", &window_id);
1727 else if (string[0] == 'w') {
1728 sscanf(string + 1, "%x", &parent_widget);
1730 window_id = XtWindow(parent_widget);
1734 sscanf(string, "%lu", &window_id);
1735 if (!is_valid_window(window_id, d))
1736 error("Invalid window %lu", (unsigned long)window_id);
1737 FRAME_X_EXTERNAL_WINDOW_P(f) = 1;
1739 #endif /* EXTERNAL_WIDGET */
1740 FRAME_X_TOP_LEVEL_FRAME_P(f) = 1;
1743 XtSetArg(al[ac], XtNallowShellResize, True);
1745 #ifdef LWLIB_USES_MOTIF
1746 /* Motif sucks beans. Without this in here, it will delete the window
1747 out from under us when it receives a WM_DESTROY_WINDOW message
1749 XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING);
1753 #ifdef EXTERNAL_WIDGET
1755 XtSetArg(al[ac], XtNwindow, window_id);
1758 #endif /* EXTERNAL_WIDGET */
1760 XtSetArg(al[ac], XtNinput, True);
1762 XtSetArg(al[ac], XtNminWidthCells, 10);
1764 XtSetArg(al[ac], XtNminHeightCells, 1);
1766 XtSetArg(al[ac], XtNvisual, visual);
1768 XtSetArg(al[ac], XtNdepth, depth);
1770 XtSetArg(al[ac], XtNcolormap, cmap);
1774 if (!NILP(overridep)) {
1775 XtSetArg(al[ac], XtNoverrideRedirect, True);
1779 /* #### maybe we should check for FRAMEP instead? */
1780 if (!NILP(parent)) {
1781 parentwid = FRAME_X_SHELL_WIDGET(XFRAME(parent));
1782 XtSetArg(al[ac], XtNtransientFor, parentwid);
1786 shell = XtCreatePopupShell("shell", (
1787 #ifdef EXTERNAL_WIDGET
1789 externalShellWidgetClass :
1792 transientEmacsShellWidgetClass
1794 topLevelEmacsShellWidgetClass),
1795 parentwid ? parentwid :
1796 DEVICE_XT_APP_SHELL(d), al, ac);
1797 FRAME_X_SHELL_WIDGET(f) = shell;
1798 maybe_set_frame_title_format(shell);
1800 /* Create the manager widget */
1802 XtSetArg(al[ac], XtNvisual, visual);
1804 XtSetArg(al[ac], XtNdepth, depth);
1806 XtSetArg(al[ac], XtNcolormap, cmap);
1809 container = XtCreateWidget("container",
1810 emacsManagerWidgetClass, shell, al, ac);
1811 FRAME_X_CONTAINER_WIDGET(f) = container;
1812 XtAddCallback(container, XtNresizeCallback, x_layout_widgets,
1814 XtAddCallback(container, XtNqueryGeometryCallback, x_do_query_geometry,
1817 /* Create the text area */
1819 XtSetArg(al[ac], XtNvisual, visual);
1821 XtSetArg(al[ac], XtNdepth, depth);
1823 XtSetArg(al[ac], XtNcolormap, cmap);
1825 XtSetArg(al[ac], XtNborderWidth, 0);
1826 ac++; /* should this be settable? */
1827 XtSetArg(al[ac], XtNemacsFrame, f);
1829 text = XtCreateWidget(name, emacsFrameClass, container, al, ac);
1830 FRAME_X_TEXT_WIDGET(f) = text;
1832 #ifdef HAVE_MENUBARS
1833 /* Create the initial menubar widget. */
1834 menubar_visible = x_initialize_frame_menubar(f);
1835 FRAME_X_TOP_WIDGETS(f)[0] = menubar = FRAME_X_MENUBAR_WIDGET(f);
1836 FRAME_X_NUM_TOP_WIDGETS(f) = 1;
1838 if (menubar_visible)
1839 XtManageChild(menubar);
1840 #endif /* HAVE_MENUBARS */
1841 XtManageChild(text);
1842 XtManageChild(container);
1845 /* We used to call XtPopup() in x_popup_frame, but that doesn't give
1846 you control over whether the widget is initially mapped or not
1847 because XtPopup() makes an unconditional call to XMapRaised().
1848 Boy, those Xt designers were clever.
1850 When we first removed it we only kept the XtRealizeWidget call in
1851 XtPopup. For everything except HP's that was enough. For HP's,
1852 though, the failure to call the popup callbacks resulted in XEmacs
1853 not accepting any input. Bizarre but true. Stupid but true.
1855 So, in case there are any other gotchas floating out there along
1856 the same lines I've duplicated the majority of XtPopup here. It
1857 assumes no grabs and that the widget is not already popped up, both
1858 valid assumptions for the one place this is called from. */
1859 static void xemacs_XtPopup(Widget widget)
1861 ShellWidget shell_widget = (ShellWidget) widget;
1862 XtGrabKind call_data = XtGrabNone;
1864 XtCallCallbacks(widget, XtNpopupCallback, (XtPointer) & call_data);
1866 shell_widget->shell.popped_up = TRUE;
1867 shell_widget->shell.grab_kind = XtGrabNone;
1868 shell_widget->shell.spring_loaded = False;
1870 if (shell_widget->shell.create_popup_child_proc != NULL)
1871 (*(shell_widget->shell.create_popup_child_proc)) (widget);
1873 /* The XtSetValues below are not in XtPopup menu. We just want to
1874 make absolutely sure... */
1875 Xt_SET_VALUE(widget, XtNmappedWhenManaged, False);
1876 XtRealizeWidget(widget);
1877 Xt_SET_VALUE(widget, XtNmappedWhenManaged, True);
1880 /* create the windows for the specified frame and display them.
1881 Note that the widgets have already been created, and any
1882 necessary geometry calculations have already been done. */
1883 static void x_popup_frame(struct frame *f)
1885 Widget shell_widget = FRAME_X_SHELL_WIDGET(f);
1886 Widget frame_widget = FRAME_X_TEXT_WIDGET(f);
1887 struct device *d = XDEVICE(FRAME_DEVICE(f));
1889 /* Before mapping the window, make sure that the WMShell's notion of
1890 whether it should be iconified is synchronized with the EmacsFrame's
1893 if (FRAME_X_TOP_LEVEL_FRAME_P(f))
1894 x_wm_set_shell_iconic_p(shell_widget,
1895 ((EmacsFrame) frame_widget)
1896 ->emacs_frame.iconic);
1898 xemacs_XtPopup(shell_widget);
1900 if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
1901 XtMapWidget(shell_widget);
1903 /* We may have set f->visible to 1 in x_init_frame(), so undo
1905 FRAME_X_TOTALLY_VISIBLE_P(f) = 0;
1909 #ifdef EXTERNAL_WIDGET
1910 if (FRAME_X_EXTERNAL_WINDOW_P(f))
1911 ExternalShellReady(shell_widget, XtWindow(frame_widget),
1915 if (FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1916 /* tell the window manager about us. */
1917 x_wm_store_class_hints(shell_widget, XtName(frame_widget));
1919 #ifndef HAVE_WMCOMMAND
1920 x_wm_maybe_store_wm_command(f);
1921 #endif /* HAVE_WMCOMMAND */
1923 x_wm_hack_wm_protocols(shell_widget);
1927 #endif /* HAVE_XIM */
1930 /* Allow XEmacs to respond to EditRes requests. See the O'Reilly Xt */
1931 /* Intrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
1933 XtAddEventHandler(shell_widget, /* the shell widget in question */
1934 (EventMask) NoEventMask, /* OR with existing mask */
1935 True, /* called on non-maskable events? */
1936 (XtEventHandler) _XEditResCheckMessages, /* the handler */
1938 #endif /* HACK_EDITRES */
1942 XtCallbackRec dnd_transfer_cb_rec[2];
1944 dnd_transfer_cb_rec[0].callback = x_cde_transfer_callback;
1945 dnd_transfer_cb_rec[0].closure = (XtPointer) f;
1946 dnd_transfer_cb_rec[1].callback = NULL;
1947 dnd_transfer_cb_rec[1].closure = NULL;
1949 DtDndVaDropRegister(FRAME_X_TEXT_WIDGET(f),
1950 DtDND_FILENAME_TRANSFER |
1951 DtDND_BUFFER_TRANSFER, XmDROP_COPY,
1952 dnd_transfer_cb_rec, DtNtextIsBuffer, True,
1953 DtNregisterChildren, True,
1954 DtNpreserveRegistration, False, NULL);
1956 #endif /* HAVE_CDE */
1958 /* Do a stupid property change to force the server to generate a
1959 propertyNotify event so that the event_stream server timestamp will
1960 be initialized to something relevant to the time we created the window.
1962 XChangeProperty(XtDisplay(frame_widget), XtWindow(frame_widget),
1963 DEVICE_XATOM_WM_PROTOCOLS(d), XA_ATOM, 32,
1964 PropModeAppend, (unsigned char *)NULL, 0);
1966 x_send_synthetic_mouse_event(f);
1969 static void allocate_x_frame_struct(struct frame *f)
1971 /* zero out all slots. */
1972 f->frame_data = xnew_and_zero(struct x_frame);
1974 /* yeah, except the lisp ones */
1975 FRAME_X_ICON_PIXMAP(f) = Qnil;
1976 FRAME_X_ICON_PIXMAP_MASK(f) = Qnil;
1979 /************************************************************************/
1980 /* Lisp functions */
1981 /************************************************************************/
1983 static void x_init_frame_1(struct frame *f, Lisp_Object props)
1985 /* This function can GC */
1986 Lisp_Object device = FRAME_DEVICE(f);
1987 Lisp_Object lisp_window_id = Fplist_get(props, Qwindow_id, Qnil);
1988 Lisp_Object popup = Fplist_get(props, Qpopup, Qnil);
1989 Lisp_Object overridep = Fplist_get (props, Qoverride_redirect, Qnil);
1993 popup = Fselected_frame(device);
1994 CHECK_LIVE_FRAME(popup);
1995 if (!EQ(device, FRAME_DEVICE(XFRAME(popup))))
1996 signal_simple_error_2
1997 ("Parent must be on same device as frame", device,
2002 * Previously we set this only if NILP (DEVICE_SELECTED_FRAME (d))
2003 * to make sure that messages were displayed as soon as possible
2004 * if we're creating the first frame on a device. But it is
2005 * better to just set this all the time, so that when a new frame
2006 * is created that covers the selected frame, echo area status
2007 * messages can still be seen. f->visible is reset later if the
2008 * initially-unmapped property is found to be non-nil in the
2013 allocate_x_frame_struct(f);
2014 x_create_widgets(f, lisp_window_id, popup, overridep);
2017 static void x_init_frame_2(struct frame *f, Lisp_Object props)
2019 /* Set up the values of the widget/frame. A case could be made for putting
2020 this inside of the widget's initialize method. */
2022 update_frame_face_values(f);
2023 x_initialize_frame_size(f);
2025 * update_frame_title() can't be done here, because some of the
2026 * modeline specs depend on the frame's device having a selected
2027 * frame, and that may not have been set up yet. The redisplay
2028 * will update the frame title anyway, so nothing is lost.
2030 * It turns out it gives problems with FVWMs name based mapping.
2031 * We'll just need to be careful in the modeline specs.
2033 update_frame_title(f);
2036 static void x_init_frame_3(struct frame *f)
2038 /* Pop up the frame. */
2043 static void x_mark_frame(struct frame *f)
2045 mark_object(FRAME_X_ICON_PIXMAP(f));
2046 mark_object(FRAME_X_ICON_PIXMAP_MASK(f));
2049 static void x_set_frame_icon(struct frame *f)
2051 Pixmap x_pixmap, x_mask;
2053 if (IMAGE_INSTANCEP(f->icon)
2054 && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(f->icon))) {
2055 x_pixmap = XIMAGE_INSTANCE_X_PIXMAP(f->icon);
2056 x_mask = XIMAGE_INSTANCE_X_MASK(f->icon);
2062 /* Store the X data into the widget. */
2065 XtSetArg(al[0], XtNiconPixmap, x_pixmap);
2066 XtSetArg(al[1], XtNiconMask, x_mask);
2067 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
2071 static void x_set_frame_pointer(struct frame *f)
2073 XDefineCursor(XtDisplay(FRAME_X_TEXT_WIDGET(f)),
2074 XtWindow(FRAME_X_TEXT_WIDGET(f)),
2075 XIMAGE_INSTANCE_X_CURSOR(f->pointer));
2076 XSync(XtDisplay(FRAME_X_TEXT_WIDGET(f)), 0);
2079 static Lisp_Object x_get_frame_parent(struct frame *f)
2081 Widget parentwid = 0;
2083 Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNtransientFor, &parentwid);
2084 /* find the frame whose wid is parentwid */
2086 Lisp_Object frmcons;
2087 DEVICE_FRAME_LOOP(frmcons, XDEVICE(FRAME_DEVICE(f))) {
2088 Lisp_Object frame = XCAR(frmcons);
2089 if (FRAME_X_SHELL_WIDGET(XFRAME(frame)) == parentwid)
2096 DEFUN("x-window-id", Fx_window_id, 0, 1, 0, /*
2097 Get the ID of the X11 window.
2098 This gives us a chance to manipulate the Emacs window from within a
2099 different program. Since the ID is an unsigned long, we return it as
2105 struct frame *f = decode_x_frame(frame);
2107 int sz = snprintf(str, sizeof(str), "%lu", XtWindow(FRAME_X_TEXT_WIDGET(f)));
2108 assert(sz >= 0 && (size_t)sz < sizeof(str));
2109 return build_string(str);
2112 /************************************************************************/
2113 /* manipulating the X window */
2114 /************************************************************************/
2116 static void x_set_frame_position(struct frame *f, int xoff, int yoff)
2118 Widget w = FRAME_X_SHELL_WIDGET(f);
2119 Display *dpy = XtDisplay(w);
2120 Dimension frame_w = DisplayWidth(dpy, DefaultScreen(dpy));
2121 Dimension frame_h = DisplayHeight(dpy, DefaultScreen(dpy));
2122 Dimension shell_w, shell_h, shell_bord;
2126 XtSetArg(al[0], XtNwidth, &shell_w);
2127 XtSetArg(al[1], XtNheight, &shell_h);
2128 XtSetArg(al[2], XtNborderWidth, &shell_bord);
2129 XtGetValues(w, al, 3);
2132 xoff >= 0 && yoff >= 0 ? NorthWestGravity :
2133 xoff >= 0 ? SouthWestGravity :
2134 yoff >= 0 ? NorthEastGravity : SouthEastGravity;
2136 xoff += frame_w - shell_w - 2 * shell_bord;
2138 yoff += frame_h - shell_h - 2 * shell_bord;
2140 /* Update the hints so that, if this window is currently iconified, it will
2141 come back at the right place. We can't look at s->visible to determine
2142 whether it is iconified because it might not be up-to-date yet (the queue
2143 might not be processed). */
2144 XtSetArg(al[0], XtNwinGravity, win_gravity);
2145 XtSetArg(al[1], XtNx, xoff);
2146 XtSetArg(al[2], XtNy, yoff);
2147 XtSetValues(w, al, 3);
2149 /* Sometimes you will find that
2151 (set-frame-position (selected-frame) -50 -50)
2153 doesn't put the frame where you expect it to: i.e. it's closer to
2154 the lower-right corner than it should be, and it appears that the
2155 size of the WM decorations was not taken into account. This is
2156 *not* a problem with this function. Both mwm and twm have bugs
2157 in handling this situation. (mwm ignores the window gravity and
2158 always assumes NorthWest, except the first time you map the
2159 window; twm gets things almost right, but forgets to account for
2160 the border width of the top-level window.) This function does
2161 what it's supposed to according to the ICCCM, and I'm not about
2162 to hack around window-manager bugs. */
2165 /* This is not necessary under either mwm or twm */
2166 x_wm_mark_shell_position_user_specified(w);
2170 /* Call this to change the size of frame S's x-window. */
2172 static void x_set_frame_size(struct frame *f, int cols, int rows)
2174 EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), cols, rows);
2176 /* this is not correct. x_set_frame_size() is called from
2177 Fset_frame_size(), which may or may not have been called
2178 by the user (e.g. update_EmacsFrame() calls it when the font
2179 changes). For now, don't bother with getting this right. */
2180 x_wm_mark_shell_size_user_specified(FRAME_X_SHELL_WIDGET(f));
2184 static void x_set_mouse_position(struct window *w, int x, int y)
2186 struct frame *f = XFRAME(w->frame);
2188 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2189 XWarpPointer(display, None, XtWindow(FRAME_X_TEXT_WIDGET(f)),
2190 0, 0, 0, 0, w->pixel_left + x, w->pixel_top + y);
2194 x_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
2196 Display *display = DEVICE_X_DISPLAY(d);
2197 Window child_window;
2202 unsigned int keys_and_buttons;
2205 if (XQueryPointer(display, RootWindow(display, DefaultScreen(display)),
2206 &root_window, &child_window, &root_x, &root_y,
2207 &win_x, &win_y, &keys_and_buttons) == False)
2210 if (child_window == None)
2211 return 0; /* not over any window. */
2215 if (XTranslateCoordinates
2216 (display, root_window, win, root_x, root_y, &win_x, &win_y,
2217 &child_window) == False)
2221 if (child_window == None)
2225 /* At this point, win is the innermost window containing the pointer
2226 and win_x and win_y are the coordinates of that window. */
2227 f = x_any_window_to_frame(d, win);
2230 XSETFRAME(*frame, f);
2232 if (XTranslateCoordinates(display, win,
2233 XtWindow(FRAME_X_TEXT_WIDGET(f)),
2234 win_x, win_y, x, y, &child_window) == False)
2241 static void x_cant_notify_wm_error(void)
2243 error("Can't notify window manager of iconification.");
2246 /* Raise frame F. */
2247 static void x_raise_frame_1(struct frame *f, int force)
2249 if (FRAME_VISIBLE_P(f) || force) {
2250 Widget bottom_dialog;
2253 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2254 Window emacs_window = XtWindow(FRAME_X_SHELL_WIDGET(f));
2256 /* first raises all the dialog boxes, then put emacs just below the
2257 * bottom most dialog box */
2258 bottom_dialog = lw_raise_all_pop_up_widgets();
2259 if (bottom_dialog && XtWindow(bottom_dialog)) {
2260 xwc.sibling = XtWindow(bottom_dialog);
2261 xwc.stack_mode = Below;
2262 flags = CWSibling | CWStackMode;
2264 xwc.stack_mode = Above;
2265 flags = CWStackMode;
2268 if (!XReconfigureWMWindow(display, emacs_window,
2269 DefaultScreen(display), flags, &xwc))
2270 x_cant_notify_wm_error();
2274 static void x_raise_frame(struct frame *f)
2276 x_raise_frame_1(f, 1);
2279 /* Lower frame F. */
2280 static void x_lower_frame(struct frame *f)
2282 if (FRAME_VISIBLE_P(f)) {
2283 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2285 unsigned int flags = CWStackMode;
2287 xwc.stack_mode = Below;
2288 if (!XReconfigureWMWindow
2289 (display, XtWindow(FRAME_X_SHELL_WIDGET(f)),
2290 DefaultScreen(display), flags, &xwc))
2291 x_cant_notify_wm_error();
2295 static void x_enable_frame(struct frame *f)
2297 XtSetSensitive(FRAME_X_SHELL_WIDGET(f), True);
2300 static void x_disable_frame(struct frame *f)
2302 XtSetSensitive(FRAME_X_SHELL_WIDGET(f), False);
2305 /* Change from withdrawn state to mapped state. */
2306 static void x_make_frame_visible(struct frame *f)
2308 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2310 if (!FRAME_VISIBLE_P(f))
2311 XMapRaised(display, XtWindow(FRAME_X_SHELL_WIDGET(f)));
2313 x_raise_frame_1(f, 0);
2316 /* Change from mapped state to withdrawn state. */
2317 static void x_make_frame_invisible(struct frame *f)
2319 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2321 if (!FRAME_VISIBLE_P(f))
2324 if (!XWithdrawWindow(display,
2325 XtWindow(FRAME_X_SHELL_WIDGET(f)),
2326 DefaultScreen(display)))
2327 x_cant_notify_wm_error();
2330 static int x_frame_visible_p(struct frame *f)
2333 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2334 XWindowAttributes xwa;
2338 This is bad, very bad :-(
2339 It is not compatible with our tristate visible and
2340 it should never ever change the visibility for us, this leads to
2341 the frame-freeze problem under fvwm because with the pager
2343 Mappedness != Viewability != Visibility != Emacs f->visible
2345 This first unequalness is the reason for the frame freezing problem
2346 under fvwm (it happens when the frame is another fvwm-page)
2348 The second unequalness happen when it is on the same fvwm-page
2349 but in an invisible part of the visible screen.
2351 For now we just return the XEmacs internal value --- which might not be up
2352 to date. Is that a problem? ---. Otherwise we should
2353 use async visibility like in standard Emacs.
2356 if (!XGetWindowAttributes(display,
2357 XtWindow(FRAME_X_SHELL_WIDGET(f)), &xwa))
2360 result = xwa.map_state == IsViewable;
2361 /* In this implementation it should at least be != IsUnmapped
2364 f->visible = result;
2371 static int x_frame_totally_visible_p(struct frame *f)
2373 return FRAME_X_TOTALLY_VISIBLE_P(f);
2376 /* Change window state from mapped to iconified. */
2377 static void x_iconify_frame(struct frame *f)
2379 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2381 if (!XIconifyWindow(display,
2382 XtWindow(FRAME_X_SHELL_WIDGET(f)),
2383 DefaultScreen(display)))
2384 x_cant_notify_wm_error();
2389 /* Sets the X focus to frame f. */
2390 static void x_focus_on_frame(struct frame *f)
2392 XWindowAttributes xwa;
2393 Widget shell_widget;
2396 assert(FRAME_X_P(f));
2398 shell_widget = FRAME_X_SHELL_WIDGET(f);
2399 if (!XtWindow(shell_widget))
2402 #ifdef EXTERNAL_WIDGET
2403 if (FRAME_X_EXTERNAL_WINDOW_P(f))
2404 ExternalShellSetFocus(shell_widget);
2405 #endif /* EXTERNAL_WIDGET */
2407 /* Do the ICCCM focus change if the window is still visible.
2408 The s->visible flag might not be up-to-date, because we might
2409 not have processed magic events recently. So make a server
2410 round-trip to find out whether it's really mapped right now.
2411 We grab the server to do this, because that's the only way to
2412 eliminate the race condition.
2414 XGrabServer(XtDisplay(shell_widget));
2415 if (XGetWindowAttributes(XtDisplay(shell_widget),
2416 XtWindow(shell_widget), &xwa))
2417 /* JV: it is bad to change the visibility like this, so we don't for the
2418 moment, at least change_frame_visibility should be called
2419 Note also that under fvwm a frame can be Viewable (and thus Mapped)
2420 but still X-invisible
2421 f->visible = xwa.map_state == IsViewable; */
2422 viewable = xwa.map_state == IsViewable;
2427 XGetInputFocus(XtDisplay(shell_widget), &focus, &revert_to);
2428 /* Don't explicitly set the focus on this window unless the focus
2429 was on some other window (not PointerRoot). Note that, even when
2430 running a point-to-type window manager like *twm, there is always
2431 a focus window; the window manager maintains that based on the
2432 mouse position. If you set the "NoTitleFocus" option in these
2433 window managers, then the server itself maintains the focus via
2434 PointerRoot, and changing that to focus on the window would make
2435 the window grab the focus. Very bad.
2437 if (focus != PointerRoot) {
2438 XSetInputFocus(XtDisplay(shell_widget),
2439 XtWindow(shell_widget),
2441 DEVICE_X_MOUSE_TIMESTAMP
2442 (XDEVICE(FRAME_DEVICE(f))));
2443 XFlush(XtDisplay(shell_widget));
2446 XUngrabServer(XtDisplay(shell_widget));
2447 XFlush(XtDisplay(shell_widget)); /* hey, I'd like to DEBUG this... */
2450 /* Destroy the X window of frame F. */
2451 static void x_delete_frame(struct frame *f)
2455 #ifndef HAVE_WMCOMMAND
2456 if (FRAME_X_TOP_LEVEL_FRAME_P(f))
2457 x_wm_maybe_move_wm_command(f);
2458 #endif /* HAVE_WMCOMMAND */
2461 DtDndDropUnregister(FRAME_X_TEXT_WIDGET(f));
2462 #endif /* HAVE_CDE */
2464 assert(FRAME_X_SHELL_WIDGET(f) != 0);
2465 dpy = XtDisplay(FRAME_X_SHELL_WIDGET(f));
2467 #ifdef EXTERNAL_WIDGET
2468 expect_x_error(dpy);
2469 /* for obscure reasons having (I think) to do with the internal
2470 window-to-widget hierarchy maintained by Xt, we have to call
2471 XtUnrealizeWidget() here. Xt can really suck. */
2472 if (f->being_deleted)
2473 XtUnrealizeWidget(FRAME_X_SHELL_WIDGET(f));
2474 XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2475 x_error_occurred_p(dpy);
2477 XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2478 /* make sure the windows are really gone! */
2479 /* #### Is this REALLY necessary? */
2481 #endif /* EXTERNAL_WIDGET */
2483 FRAME_X_SHELL_WIDGET(f) = 0;
2485 if (FRAME_X_GEOM_FREE_ME_PLEASE(f)) {
2486 xfree(FRAME_X_GEOM_FREE_ME_PLEASE(f));
2487 FRAME_X_GEOM_FREE_ME_PLEASE(f) = 0;
2490 if (f->frame_data) {
2491 xfree(f->frame_data);
2496 static void x_update_frame_external_traits(struct frame *frm, Lisp_Object name)
2502 XSETFRAME(frame, frm);
2504 if (EQ(name, Qforeground)) {
2505 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
2508 if (!EQ(color, Vthe_null_color_instance)) {
2509 fgc = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(color));
2510 XtSetArg(al[ac], XtNforeground, (void *)fgc.pixel);
2513 } else if (EQ(name, Qbackground)) {
2514 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
2517 if (!EQ(color, Vthe_null_color_instance)) {
2518 bgc = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(color));
2519 XtSetArg(al[ac], XtNbackground, (void *)bgc.pixel);
2523 /* Really crappy way to force the modeline shadows to be
2524 redrawn. But effective. */
2525 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED(frm);
2526 MARK_FRAME_CHANGED(frm);
2527 } else if (EQ(name, Qfont)) {
2529 FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
2531 if (!EQ(font, Vthe_null_font_instance)) {
2532 XtSetArg(al[ac], XtNfont,
2534 FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font)));
2540 XtSetValues(FRAME_X_TEXT_WIDGET(frm), al, ac);
2542 #ifdef HAVE_TOOLBARS
2543 /* Setting the background clears the entire frame area
2544 including the toolbar so we force an immediate redraw of
2546 if (EQ(name, Qbackground))
2547 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
2549 #endif /* HAVE_TOOLBARS */
2551 /* Set window manager resize increment hints according to
2552 the new character size */
2553 if (EQ(name, Qfont))
2554 EmacsFrameRecomputeCellSize(FRAME_X_TEXT_WIDGET(frm));
2557 /************************************************************************/
2558 /* initialization */
2559 /************************************************************************/
2561 void syms_of_frame_x(void)
2563 defsymbol(&Qwindow_id, "window-id");
2564 defsymbol(&Qoverride_redirect, "override-redirect");
2565 defsymbol(&Qx_resource_name, "x-resource-name");
2567 DEFSUBR(Fx_window_id);
2569 DEFSUBR(Fcde_start_drag_internal);
2573 void console_type_create_frame_x(void)
2576 CONSOLE_HAS_METHOD(x, init_frame_1);
2577 CONSOLE_HAS_METHOD(x, init_frame_2);
2578 CONSOLE_HAS_METHOD(x, init_frame_3);
2579 CONSOLE_HAS_METHOD(x, mark_frame);
2580 CONSOLE_HAS_METHOD(x, focus_on_frame);
2581 CONSOLE_HAS_METHOD(x, delete_frame);
2582 CONSOLE_HAS_METHOD(x, get_mouse_position);
2583 CONSOLE_HAS_METHOD(x, set_mouse_position);
2584 CONSOLE_HAS_METHOD(x, raise_frame);
2585 CONSOLE_HAS_METHOD(x, lower_frame);
2586 CONSOLE_HAS_METHOD(x, enable_frame);
2587 CONSOLE_HAS_METHOD(x, disable_frame);
2588 CONSOLE_HAS_METHOD(x, make_frame_visible);
2589 CONSOLE_HAS_METHOD(x, make_frame_invisible);
2590 CONSOLE_HAS_METHOD(x, iconify_frame);
2591 CONSOLE_HAS_METHOD(x, set_frame_size);
2592 CONSOLE_HAS_METHOD(x, set_frame_position);
2593 CONSOLE_HAS_METHOD(x, frame_property);
2594 CONSOLE_HAS_METHOD(x, internal_frame_property_p);
2595 CONSOLE_HAS_METHOD(x, frame_properties);
2596 CONSOLE_HAS_METHOD(x, set_frame_properties);
2597 CONSOLE_HAS_METHOD(x, set_title_from_bufbyte);
2598 CONSOLE_HAS_METHOD(x, set_icon_name_from_bufbyte);
2599 CONSOLE_HAS_METHOD(x, frame_visible_p);
2600 CONSOLE_HAS_METHOD(x, frame_totally_visible_p);
2601 CONSOLE_HAS_METHOD(x, frame_iconified_p);
2602 CONSOLE_HAS_METHOD(x, set_frame_pointer);
2603 CONSOLE_HAS_METHOD(x, set_frame_icon);
2604 CONSOLE_HAS_METHOD(x, get_frame_parent);
2605 CONSOLE_HAS_METHOD(x, update_frame_external_traits);
2608 void vars_of_frame_x(void)
2610 #ifdef EXTERNAL_WIDGET
2611 Fprovide(intern("external-widget"));
2614 /* this call uses only safe functions from emacs.c */
2615 init_x_prop_symbols();
2617 DEFVAR_LISP("default-x-frame-plist", &Vdefault_x_frame_plist /*
2618 Plist of default frame-creation properties for X frames.
2619 These override what is specified in the resource database and in
2620 `default-frame-plist', but are overridden by the arguments to the
2621 particular call to `make-frame'.
2623 Note: In many cases, properties of a frame are available as specifiers
2624 instead of through the frame-properties mechanism.
2626 Here is a list of recognized frame properties, other than those
2627 documented in `set-frame-properties' (they can be queried and
2628 set at any time, except as otherwise noted):
2630 window-id The X window ID corresponding to the
2631 frame. May be set only at startup, and
2632 only if external widget support was
2633 compiled in; doing so causes the frame
2634 to be created as an "external widget"
2635 in another program that uses an existing
2636 window in the program rather than creating
2638 initially-unmapped If non-nil, the frame will not be visible
2639 when it is created. In this case, you
2640 need to call `make-frame-visible' to make
2642 popup If non-nil, it should be a frame, and this
2643 frame will be created as a "popup" frame
2644 whose parent is the given frame. This
2645 will make the window manager treat the
2646 frame as a dialog box, which may entail
2647 doing different things (e.g. not asking
2648 for positioning, and not iconifying
2649 separate from its parent).
2650 override-redirect If non-nil, the frame will not be subject to
2651 window-manager control. In particular, it
2652 will lack decorations, for more attractive
2653 appearance of balloon help, aka tooltips.
2654 inter-line-space Not currently implemented.
2655 toolbar-shadow-thickness Thickness of toolbar shadows.
2656 background-toolbar-color Color of toolbar background.
2657 bottom-toolbar-shadow-color Color of bottom shadows on toolbars.
2658 (*Not* specific to the bottom-toolbar.)
2659 top-toolbar-shadow-color Color of top shadows on toolbars.
2660 (*Not* specific to the top-toolbar.)
2661 internal-border-width Width of internal border around text area.
2662 border-width Width of external border around text area.
2663 top Y position (in pixels) of the upper-left
2664 outermost corner of the frame (i.e. the
2665 upper-left of the window-manager
2667 left X position (in pixels) of the upper-left
2668 outermost corner of the frame (i.e. the
2669 upper-left of the window-manager
2671 border-color Color of external border around text area.
2672 cursor-color Color of text cursor.
2674 See also `default-frame-plist', which specifies properties which apply
2675 to all frames, not just X frames.
2677 Vdefault_x_frame_plist = Qnil;
2679 x_console_methods->device_specific_frame_props =
2680 &Vdefault_x_frame_plist;