Initial git import
[sxemacs] / src / ui / X11 / frame-x.c
1 /* Functions for the X window system.
2    Copyright (C) 1989, 1992-5, 1997 Free Software Foundation, Inc.
3    Copyright (C) 1995, 1996 Ben Wing.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not synched with FSF. */
22
23 /* Substantially rewritten for XEmacs.  */
24
25 /* 7-8-00 !!#### This file needs definite Mule review. */
26
27 #include <config.h>
28 #include "lisp.h"
29
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>
37 #include "xmu.h"
38 #include "EmacsManager.h"
39 #include "EmacsFrameP.h"
40 #include "EmacsShell.h"
41 #ifdef EXTERNAL_WIDGET
42 #include "ExternalShell.h"
43 #endif
44 #include "glyphs-x.h"
45 #include "objects-x.h"
46 #include "scrollbar-x.h"
47
48 #include "buffer.h"
49 #include "events/events.h"
50 #include "extents.h"
51 #include "ui/faces.h"
52 #include "ui/frame.h"
53 #include "ui/window.h"
54 #include "ui/gutter.h"
55
56 #if defined (HAVE_OFFIX_DND) || defined (HAVE_CDE)
57 #include "events/events-mod.h"
58 #endif
59
60 /* Default properties to use when creating frames.  */
61 Lisp_Object Vdefault_x_frame_plist;
62
63 Lisp_Object Qoverride_redirect;
64 Lisp_Object Qwindow_id;
65 Lisp_Object Qx_resource_name;
66
67 EXFUN(Fx_window_id, 1);
68 \f
69 /************************************************************************/
70 /*                          helper functions                            */
71 /************************************************************************/
72
73 /* Return the Emacs frame-object corresponding to an X window */
74 struct frame *x_window_to_frame(struct device *d, Window wdesc)
75 {
76         Lisp_Object tail, frame;
77         struct frame *f;
78
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. */
82
83         for (tail = DEVICE_FRAME_LIST(d); CONSP(tail); tail = XCDR(tail)) {
84                 frame = XCAR(tail);
85                 if (!FRAMEP(frame))
86                         continue;
87                 f = XFRAME(frame);
88                 if (FRAME_X_P(f) && XtWindow(FRAME_X_TEXT_WIDGET(f)) == wdesc)
89                         return f;
90         }
91         return 0;
92 }
93
94 /* Like x_window_to_frame but also compares the window with the widget's
95    windows */
96 struct frame *x_any_window_to_frame(struct device *d, Window wdesc)
97 {
98         Widget w;
99         assert(DEVICE_X_P(d));
100
101         w = XtWindowToWidget(DEVICE_X_DISPLAY(d), wdesc);
102
103         if (!w)
104                 return 0;
105
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);
113 }
114
115 static struct frame *x_find_frame_for_window(struct device *d, Window wdesc)
116 {
117         Lisp_Object tail, frame;
118         struct frame *f;
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. */
122
123         for (tail = DEVICE_FRAME_LIST(d); CONSP(tail); tail = XCDR(tail)) {
124                 frame = XCAR(tail);
125                 f = XFRAME(frame);
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)))
130                         return f;
131
132                 /* Match if the window is one of the widgets at the top of the frame
133                    (menubar, Energize psheets). */
134
135                 /* Note: Jamie once said
136
137                    "Do *not* match if the window is this frame's psheet."
138
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. */
145
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. */
149
150                 /* Note:  we use to special case scrollbars but this turns out to be a bad idea
151                    because
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. */
158         }
159
160         return 0;
161 }
162
163 struct frame *x_any_widget_or_parent_to_frame(struct device *d, Widget widget)
164 {
165         while (widget) {
166                 struct frame *f = x_find_frame_for_window(d, XtWindow(widget));
167                 if (f)
168                         return f;
169                 widget = XtParent(widget);
170         }
171
172         return 0;
173 }
174
175 struct frame *decode_x_frame(Lisp_Object frame)
176 {
177         if (NILP(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);
184 }
185 \f
186 /************************************************************************/
187 /*                      window-manager interactions                     */
188 /************************************************************************/
189
190 #if 0
191 /* Not currently used. */
192
193 void x_wm_mark_shell_size_user_specified(Widget wmshell)
194 {
195         if (!XtIsWMShell(wmshell))
196                 abort();
197         EmacsShellSetSizeUserSpecified(wmshell);
198 }
199
200 void x_wm_mark_shell_position_user_specified(Widget wmshell)
201 {
202         if (!XtIsWMShell(wmshell))
203                 abort();
204         EmacsShellSetPositionUserSpecified(wmshell);
205 }
206
207 #endif
208
209 void x_wm_set_shell_iconic_p(Widget shell, int iconic_p)
210 {
211         if (!XtIsWMShell(shell))
212                 abort();
213
214         /* Because of questionable logic in Shell.c, this sequence can't work:
215
216            w = XtCreatePopupShell (...);
217            Xt_SET_VALUE (w, XtNiconic, True);
218            XtRealizeWidget (w);
219
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).
225
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?)
231          */
232         Xt_SET_VALUE(shell, XtNiconic, iconic_p);
233         EmacsShellSmashIconicHint(shell, iconic_p);
234 }
235
236 void x_wm_set_cell_size(Widget wmshell, int cw, int ch)
237 {
238         Arg al[2];
239
240         if (!XtIsWMShell(wmshell))
241                 abort();
242         if (cw <= 0 || ch <= 0)
243                 abort();
244
245         XtSetArg(al[0], XtNwidthInc, cw);
246         XtSetArg(al[1], XtNheightInc, ch);
247         XtSetValues(wmshell, al, 2);
248 }
249
250 void x_wm_set_variable_size(Widget wmshell, int width, int height)
251 {
252         Arg al[2];
253
254         if (!XtIsWMShell(wmshell))
255                 abort();
256 #ifdef DEBUG_GEOMETRY_MANAGEMENT
257         /* See comment in EmacsShell.c */
258         printf("x_wm_set_variable_size: %d %d\n", width, height);
259         fflush(stdout);
260 #endif
261
262         XtSetArg(al[0], XtNwidthCells, width);
263         XtSetArg(al[1], XtNheightCells, height);
264         XtSetValues(wmshell, al, 2);
265 }
266
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).
270  */
271 static void x_wm_hack_wm_protocols(Widget widget)
272 {
273         Display *dpy = XtDisplay(widget);
274         struct device *d = get_device_from_display(dpy);
275         Window w = XtWindow(widget);
276         int need_delete = 1;
277         int need_focus = 1;
278
279         assert(XtIsWMShell(widget));
280
281         {
282                 Atom type, *atoms = 0;
283                 int format = 0;
284                 unsigned long nitems = 0;
285                 unsigned long bytes_after;
286
287                 if (Success ==
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)
293                         while (nitems > 0) {
294                                 nitems--;
295                                 if (atoms[nitems] ==
296                                     DEVICE_XATOM_WM_DELETE_WINDOW(d))
297                                         need_delete = 0;
298                                 else if (atoms[nitems] ==
299                                          DEVICE_XATOM_WM_TAKE_FOCUS(d))
300                                         need_focus = 0;
301                         }
302                 if (atoms)
303                         XFree((char *)atoms);
304         }
305         {
306                 Atom props[10];
307                 int count = 0;
308                 if (need_delete)
309                         props[count++] = DEVICE_XATOM_WM_DELETE_WINDOW(d);
310                 if (need_focus)
311                         props[count++] = DEVICE_XATOM_WM_TAKE_FOCUS(d);
312                 if (count)
313                         XChangeProperty(dpy, w, DEVICE_XATOM_WM_PROTOCOLS(d),
314                                         XA_ATOM, 32, PropModeAppend,
315                                         (unsigned char *)props, count);
316         }
317 }
318
319 static void x_wm_store_class_hints(Widget shell, char *frame_name)
320 {
321         Display *dpy = XtDisplay(shell);
322         char *app_name, *app_class;
323         XClassHint classhint;
324
325         if (!XtIsWMShell(shell))
326                 abort();
327
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);
332 }
333
334 #ifndef HAVE_WMCOMMAND
335 static void x_wm_maybe_store_wm_command(struct frame *f)
336 {
337         Widget w = FRAME_X_SHELL_WIDGET(f);
338         struct device *d = XDEVICE(FRAME_DEVICE(f));
339
340         if (!XtIsWMShell(w))
341                 abort();
342
343         if (NILP(DEVICE_X_WM_COMMAND_FRAME(d))) {
344                 int argc;
345                 char **argv;
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);
350         }
351 }
352
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.
356  */
357 static void x_wm_maybe_move_wm_command(struct frame *f)
358 {
359         struct device *d = XDEVICE(FRAME_DEVICE(f));
360
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)))))
372                         rest = XCDR(rest);
373                 if (NILP(rest))
374                         return;
375                 f = XFRAME(XCAR(rest));
376
377                 x_wm_maybe_store_wm_command(f);
378
379         }
380 }
381 #endif                          /* !HAVE_WMCOMMAND */
382
383 static int x_frame_iconified_p(struct frame *f)
384 {
385         Atom actual_type;
386         int actual_format;
387         unsigned long nitems, bytesafter;
388         unsigned long *datap = 0;
389         Widget widget;
390         int result = 0;
391         struct device *d = XDEVICE(FRAME_DEVICE(f));
392
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,
398                                           &bytesafter,
399                                           (unsigned char **)((void*)&datap))
400             && datap) {
401                 if (nitems <= 2 /* "suggested" by ICCCM version 1 */
402                     && datap[0] == IconicState)
403                         result = 1;
404                 XFree((char *)datap);
405         }
406         return result;
407 }
408 \f
409 /************************************************************************/
410 /*                          frame properties                            */
411 /************************************************************************/
412
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. */
416
417 static void init_x_prop_symbols(void)
418 {
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)
423
424 #if 0                           /* this interferes with things. #### fix this right */
425         def(Qminibuffer, XtNminibuffer);
426         def(Qunsplittable, XtNunsplittable);
427 #endif
428         defi(Qinternal_border_width, XtNinternalBorderWidth);
429 #ifdef HAVE_TOOLBARS
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);
436 #endif
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);
454
455         /* inherited: */
456
457         def(Qborder_color, XtNborderColor);
458         defi(Qborder_width, XtNborderWidth);
459         defi(Qwidth, XtNwidth);
460         defi(Qheight, XtNheight);
461         defi(Qleft, XtNx);
462         defi(Qtop, XtNy);
463
464 #undef def
465 }
466
467 static Lisp_Object color_to_string(Widget w, unsigned long pixel)
468 {
469         char buf[255];
470
471         XColor color;
472         color.pixel = 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);
476 }
477
478 static void
479 x_get_top_level_position(Display * d, Window w, Position * x, Position * y)
480 {
481         Window root, parent = w, *children;
482         unsigned int nchildren;
483         XWindowAttributes xwa;
484
485         do {
486                 w = parent;
487                 if (!XQueryTree(d, w, &root, &parent, &children, &nchildren)) {
488                         *x = 0;
489                         *y = 0;
490                         return;
491                 }
492                 XFree(children);
493         }
494         while (root != parent);
495         XGetWindowAttributes(d, w, &xwa);
496         *x = xwa.x;
497         *y = xwa.y;
498 }
499
500 #if 0
501 static void x_smash_bastardly_shell_position(Widget shell)
502 {
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. */
507
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. */
511         if (XtWindow(shell))
512                 x_get_top_level_position(XtDisplay(shell), XtWindow(shell),
513                                          &shell->core.x, &shell->core.y);
514 }
515 #endif                          /* 0 */
516
517 static Lisp_Object x_frame_property(struct frame *f, Lisp_Object property)
518 {
519         Widget shell = FRAME_X_SHELL_WIDGET(f);
520         EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
521         Widget gw = (Widget) w;
522
523         if (EQ(Qleft, property) || EQ(Qtop, property)) {
524                 Position x, y;
525                 if (!XtWindow(shell))
526                         return Qzero;
527                 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
528                                          &y);
529                 if (EQ(Qleft, property))
530                         return make_int(x);
531                 if (EQ(Qtop, property))
532                         return make_int(y);
533         }
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);
540 #ifdef HAVE_TOOLBARS
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,
546                                        w->emacs_frame.
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));
558
559         return Qunbound;
560 }
561
562 static int x_internal_frame_property_p(struct frame *f, Lisp_Object property)
563 {
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)
569 #ifdef HAVE_TOOLBARS
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);
578 }
579
580 static Lisp_Object x_frame_properties(struct frame *f)
581 {
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;
586         Position x, y;
587
588         props = cons3(Qwindow_id, Fx_window_id(make_frame(f)), props);
589         props =
590             cons3(Qinter_line_space, make_int(w->emacs_frame.interline), props);
591
592 #ifdef HAVE_TOOLBARS
593         props = cons3(Qtoolbar_shadow_thickness,
594                       make_int(w->emacs_frame.toolbar_shadow_thickness), props);
595         props = cons3(Qbackground_toolbar_color,
596                       color_to_string(gw,
597                                       w->emacs_frame.background_toolbar_pixel),
598                       props);
599         props =
600             cons3(Qbottom_toolbar_shadow_color,
601                   color_to_string(gw,
602                                   w->emacs_frame.bottom_toolbar_shadow_pixel),
603                   props);
604         props =
605             cons3(Qtop_toolbar_shadow_color,
606                   color_to_string(gw, w->emacs_frame.top_toolbar_shadow_pixel),
607                   props);
608 #endif                          /* HAVE_TOOLBARS */
609
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);
615
616         if (!XtWindow(shell))
617                 x = y = 0;
618         else
619                 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
620                                          &y);
621
622         props = cons3(Qtop, make_int(y), props);
623         props = cons3(Qleft, make_int(x), props);
624
625         return props;
626 }
627 \f
628 /* Functions called only from `x_set_frame_properties' to set
629    individual properties. */
630
631 static void
632 x_set_frame_text_value(struct frame *f, Bufbyte * value,
633                        String Xt_resource_name,
634                        String Xt_resource_encoding_name)
635 {
636         Atom encoding = XA_STRING;
637         String new_XtValue = (String) value;
638         String old_XtValue = NULL;
639
640 #ifdef MULE
641         Bufbyte *ptr;
642         /* Optimize for common ASCII case */
643         for (ptr = value; *ptr; ptr++)
644                 if (!BYTE_ASCII_P(*ptr)) {
645                         char *tmp;
646                         encoding = DEVICE_XATOM_COMPOUND_TEXT(
647                                 XDEVICE(FRAME_DEVICE(f)));
648                         C_STRING_TO_EXTERNAL(value, tmp, Qctext);
649                         new_XtValue = (String) tmp;
650                         break;
651                 }
652 #endif                          /* MULE */
653
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)) {
657                 Arg al[2];
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);
661         }
662 }
663
664 static void x_set_title_from_bufbyte(struct frame *f, Bufbyte * name)
665 {
666         x_set_frame_text_value(f, name, XtNtitle, XtNtitleEncoding);
667 }
668
669 static void x_set_icon_name_from_bufbyte(struct frame *f, Bufbyte * name)
670 {
671         x_set_frame_text_value(f, name, XtNiconName, XtNiconNameEncoding);
672 }
673
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
679    used). */
680
681 static void
682 x_set_initial_frame_size(struct frame *f, int flags, int x, int y,
683                          unsigned int w, unsigned int h)
684 {
685         char shell_geom[255];
686         int xval, yval;
687         char xsign, ysign;
688         char uspos = !!(flags & (XValue | YValue));
689         char ussize = !!(flags & (WidthValue | HeightValue));
690         char *temp;
691
692         /* assign the correct size to the EmacsFrame widget ... */
693         EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), w, h);
694
695         /* and also set the WMShell's geometry */
696         (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign =
697                                                           '+');
698         (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign =
699                                                           '+');
700
701         if (uspos && ussize)
702                 sprintf(shell_geom, "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign,
703                         yval);
704         else if (uspos)
705                 sprintf(shell_geom, "=%c%d%c%d", xsign, xval, ysign, yval);
706         else if (ussize)
707                 sprintf(shell_geom, "=%dx%d", w, h);
708
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;
713         } else {
714                 temp = NULL;
715         }
716         Xt_SET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNgeometry, temp);
717 }
718
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.
721  */
722
723 static void x_set_frame_properties(struct frame *f, Lisp_Object plist)
724 {
725         Position x, y;
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;
732         Lisp_Object tail;
733         Widget w;
734
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
737            that case.  */
738         if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
739           return;
740
741         w = FRAME_X_TEXT_WIDGET (f);
742
743         for (tail = plist; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
744                 Lisp_Object prop = Fcar(tail);
745                 Lisp_Object val = Fcar(Fcdr(tail));
746
747                 if (STRINGP(prop)) {
748                         const char *extprop;
749
750                         if (XSTRING_LENGTH(prop) == 0)
751                                 continue;
752
753                         LISP_STRING_TO_EXTERNAL(prop, extprop, Qctext);
754                         if (STRINGP(val)) {
755                                 const Extbyte *extval;
756                                 Extcount extvallen;
757
758                                 TO_EXTERNAL_FORMAT(LISP_STRING, val,
759                                                    ALLOCA, (extval, extvallen),
760                                                    Qctext);
761                                 XtVaSetValues(w, XtVaTypedArg, extprop,
762                                               XtRString, extval, extvallen + 1,
763                                               NULL);
764                         } else
765                                 XtVaSetValues(w, XtVaTypedArg, extprop, XtRInt,
766                                               XINT(val), sizeof(int),
767                                               NULL);
768                 } else if (SYMBOLP(prop)) {
769                         Lisp_Object str = Fget(prop, Qx_resource_name, Qnil);
770                         int int_p = !NILP(Fget(prop, Qintegerp, Qnil));
771
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. */
776                                         if (STRINGP(val)) {
777                                                 Lisp_Object frm, font_spec;
778
779                                                 XSETFRAME(frm, f);
780                                                 font_spec =
781                                                     Fget(Fget_face(Qdefault),
782                                                          Qfont, Qnil);
783
784                                                 Fadd_spec_to_specifier
785                                                     (font_spec, val, frm, Qnil,
786                                                      Qnil);
787                                                 update_frame_face_values(f);
788                                         }
789
790                                         continue;
791                                 } else
792                                         continue;
793                         }
794                         CHECK_STRING(str);
795
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")) {
799                                 CHECK_INT(val);
800                                 width = XINT(val);
801                                 width_specified_p = True;
802                                 continue;
803                         }
804                         if (!strcmp((char *)XSTRING_DATA(str), "height")) {
805                                 CHECK_INT(val);
806                                 height = XINT(val);
807                                 height_specified_p = True;
808                                 continue;
809                         }
810                         /* Further kludge the x/y. */
811                         if (!strcmp((char *)XSTRING_DATA(str), "x")) {
812                                 CHECK_INT(val);
813                                 x = (Position) XINT(val);
814                                 x_position_specified_p = True;
815                                 continue;
816                         }
817                         if (!strcmp((char *)XSTRING_DATA(str), "y")) {
818                                 CHECK_INT(val);
819                                 y = (Position) XINT(val);
820                                 y_position_specified_p = True;
821                                 continue;
822                         }
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;
828                         }
829
830                         if (int_p) {
831                                 CHECK_INT(val);
832                                 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str),
833                                              XINT(val));
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... */
838                         } else {
839                                 CHECK_STRING(val);
840                                 XtVaSetValues(w, XtVaTypedArg,
841                                               /* XtN... */
842                                               (char *)XSTRING_DATA(str),
843                                               XtRString,
844                                               XSTRING_DATA(val),
845                                               XSTRING_LENGTH(val) + 1,
846                                               NULL);
847                         }
848
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);
854                         }
855 #endif                          /* HAVE_SCROLLBARS */
856                 }
857         }
858
859         /* Kludge kludge kludge.   We need to deal with the size and position
860            specially. */
861         {
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;
865
866                 if (!width_specified_p)
867                         width = FRAME_WIDTH(f);
868                 if (!height_specified_p)
869                         height = FRAME_HEIGHT(f);
870
871                 /* Kludge kludge kludge kludge. */
872                 if (position_specified_p &&
873                     (!x_position_specified_p || !y_position_specified_p)) {
874                         Position dummy;
875                         Widget shell = FRAME_X_SHELL_WIDGET(f);
876                         x_get_top_level_position(XtDisplay(shell),
877                                                  XtWindow(shell),
878                                                  (x_position_specified_p ?
879                                                   &dummy : &x),
880                                                  (y_position_specified_p ?
881                                                   &dummy : &y));
882 #if 0
883                         x = (int)(FRAME_X_SHELL_WIDGET(f)->core.x);
884                         y = (int)(FRAME_X_SHELL_WIDGET(f)->core.y);
885 #endif
886                 }
887
888                 if (!f->init_finished) {
889                         int flags =
890                             (size_specified_p ? WidthValue | HeightValue : 0) |
891                             (position_specified_p ? XValue | YValue |
892                              (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0)
893                              : 0);
894                         if (size_specified_p
895                             || position_specified_p
896                             || internal_border_width_specified)
897                                 x_set_initial_frame_size(f, flags, x, y, width,
898                                                          height);
899                 } else {
900                         if (size_specified_p || internal_border_width_specified) {
901                                 Lisp_Object frame;
902                                 XSETFRAME(frame, f);
903                                 Fset_frame_size(frame, make_int(width),
904                                                 make_int(height), Qnil);
905                         }
906                         if (position_specified_p) {
907                                 Lisp_Object frame;
908                                 XSETFRAME(frame, f);
909                                 Fset_frame_position(frame, make_int(x),
910                                                     make_int(y));
911                         }
912                 }
913         }
914 }
915
916 static int frame_title_format_already_set;
917
918 static void maybe_set_frame_title_format(Widget shell)
919 {
920
921         /* Only do this if this is the first X frame we're creating.
922
923            If the *title resource (or -title option) was specified, then
924            set frame-title-format to its value.
925          */
926
927         if (!frame_title_format_already_set) {
928                 /* No doubt there's a less stupid way to do this. */
929                 char *results[2];
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,
947                                   shell->core.name,
948                                   shell->core.widget_class->core_class.
949                                   class_name, resources, XtNumber(resources), 0,
950                                   0);
951                 if (results[0])
952                         Vframe_title_format = build_string(results[0]);
953                 if (results[1])
954                         Vframe_icon_title_format = build_string(results[1]);
955         }
956
957         frame_title_format_already_set = 1;
958 }
959
960 #ifdef HAVE_CDE
961 #include <Dt/Dt.h>
962 #include <Dt/Dnd.h>
963
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;
968
969 static void
970 x_cde_destroy_callback(Widget widget, XtPointer clientData, XtPointer callData)
971 {
972         DtDndDragFinishCallbackStruct *dragFinishInfo =
973             (DtDndDragFinishCallbackStruct *) callData;
974         DtDndContext *dragData = dragFinishInfo->dragData;
975         int i;
976
977         /* free the items */
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);
984                         }
985                 } else {
986                         for (i = 0; i < dragData->numItems; i++)
987                                 XtFree(dragData->data.files[i]);
988                 }
989         }
990
991         /* free the data string */
992         xfree(clientData);
993
994         CurrentDragWidget = NULL;
995 }
996
997 static void
998 x_cde_convert_callback(Widget widget, XtPointer clientData, XtPointer callData)
999 {
1000         DtDndConvertCallbackStruct *convertInfo =
1001             (DtDndConvertCallbackStruct *) callData;
1002         char *textdata = (char *)clientData;
1003         char *textptr = NULL;
1004         int i;
1005
1006         if (convertInfo == NULL) {
1007                 return;
1008         }
1009
1010         if ((convertInfo->dragData->protocol != DtDND_BUFFER_TRANSFER
1011              && convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER) ||
1012             (convertInfo->reason != DtCR_DND_CONVERT_DATA)) {
1013                 return;
1014         }
1015
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 =
1023                             strlen(textptr);
1024                         convertInfo->dragData->data.buffers[i].name = NULL;
1025                 } else {
1026                         convertInfo->dragData->data.files[i] =
1027                             XtNewString(textptr);
1028                 }
1029         }
1030
1031         convertInfo->status = DtDND_SUCCESS;
1032 }
1033
1034 static Lisp_Object abort_current_drag(Lisp_Object arg)
1035 {
1036         if (CurrentDragWidget && drag_not_done) {
1037                 XmDragCancel(CurrentDragWidget);
1038                 CurrentDragWidget = NULL;
1039         }
1040         return arg;
1041 }
1042
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!
1051 */
1052       (event, dragtype, dragdata))
1053 {
1054         if (EVENTP(event)) {
1055                 struct frame *f = decode_x_frame(Fselected_frame(Qnil));
1056                 XEvent x_event;
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;
1063                 char *Ctext;
1064                 int numItems = 0, textlen = 0, pos = 0;
1065                 Lisp_Event *lisp_event = XEVENT(event);
1066                 Lisp_Object item = Qnil;
1067                 struct gcpro gcpro1;
1068
1069                 /* only drag if this is really a press */
1070                 if (EVENT_TYPE(lisp_event) != button_press_event
1071                     || !LISTP(dragdata))
1072                         return Qnil;
1073
1074                 GCPRO1(item);
1075
1076                 /*
1077                  * not so cross hack that converts a emacs event back to a XEvent
1078                  */
1079
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,
1091                                                     &win_attrib)) {
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;
1096                 } else {
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;
1099                 }
1100                 modifier = lisp_event->event.button.modifiers;
1101                 if (modifier & XEMACS_MOD_SHIFT)
1102                         state |= ShiftMask;
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);
1114
1115                 x_event.xbutton.state = state;
1116                 x_event.xbutton.button = lisp_event->event.button.button;
1117                 x_event.xkey.same_screen = True;
1118
1119                 /* convert data strings into a big string */
1120                 item = dragdata;
1121                 while (!NILP(item)) {
1122                         if (!STRINGP(XCAR(item))) {
1123                                 numItems = 0;
1124                                 break;
1125                         }
1126                         textlen += XSTRING_LENGTH(XCAR(item)) + 1;
1127                         numItems++;
1128                         item = XCDR(item);
1129                 }
1130
1131                 if (numItems) {
1132                         /*
1133                          * concatenate all strings given to one large string, with
1134                          * \0 as separator. List is ended by \0.
1135                          */
1136                         Ctext = (char*)xmalloc_atomic(textlen + 1);
1137                         Ctext[0] = 0;
1138
1139                         item = dragdata;
1140                         while (!NILP(item)) {
1141                                 if (!STRINGP(XCAR(item))) {
1142                                         numItems = 0;
1143                                         xfree(Ctext);
1144                                         Ctext = NULL;
1145                                         break;
1146                                 }
1147                                 strcpy(Ctext + pos,
1148                                        (const char *)XSTRING_DATA(XCAR(item)));
1149                                 pos += XSTRING_LENGTH(XCAR(item)) + 1;
1150                                 item = XCDR(item);
1151                         }
1152                         Ctext[pos] = 0;
1153
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;
1158
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;
1163
1164                         CurrentDragWidget =
1165                             DtDndDragStart(wid, &x_event,
1166                                            (NILP(dragtype) ?
1167                                             DtDND_BUFFER_TRANSFER :
1168                                             DtDND_FILENAME_TRANSFER), numItems,
1169                                            XmDROP_COPY, dnd_convert_cb_rec,
1170                                            dnd_destroy_cb_rec, NULL, 0);
1171                 }
1172
1173                 UNGCPRO;
1174
1175                 return numItems ? Qt : Qnil;
1176         }
1177
1178         return Qnil;
1179 }
1180
1181 static void
1182 x_cde_transfer_callback(Widget widget, XtPointer clientData, XtPointer callData)
1183 {
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;
1191
1192         /*
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)
1197          */
1198         /* return; */
1199
1200         transferInfo = (DtDndTransferCallbackStruct *) callData;
1201         if (transferInfo == NULL)
1202                 return;
1203
1204         GCPRO3(frame, l_type, l_data);
1205
1206         frame = make_frame((struct frame *)clientData);
1207
1208         if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER) {
1209                 l_type = Qdragdrop_URL;
1210
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);
1217                         xfree(hurl);
1218                 }
1219         } else if (transferInfo->dropData->protocol == DtDND_BUFFER_TRANSFER) {
1220                 int speccount = specpdl_depth();
1221
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);
1228                 drag_not_done = 1;
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? */
1235                         l_data =
1236                             Fcons(list3
1237                                   (list1
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);
1244                 }
1245                 drag_not_done = 0;
1246                 unbind_to(speccount, Qnil);
1247         } else                  /* the other cases: NOOP_TRANSFER */
1248                 enqueue = 0;
1249
1250         /* The Problem: no button and mods from CDE... */
1251         if (enqueue)
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);
1257
1258         UNGCPRO;
1259         return;
1260 }
1261 #endif                          /* HAVE_CDE */
1262
1263 \f
1264 /************************************************************************/
1265 /*                              widget creation                         */
1266 /************************************************************************/
1267
1268 /* The widget hierarchy is
1269
1270         argv[0]                 shell           container       FRAME-NAME
1271         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1272
1273    We accept geometry specs in this order:
1274
1275         *FRAME-NAME.geometry
1276         *EmacsFrame.geometry
1277         Emacs.geometry
1278
1279    Other possibilities for widget hierarchies might be
1280
1281         argv[0]                 frame           container       FRAME-NAME
1282         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1283    or
1284         argv[0]                 FRAME-NAME      container       FRAME-NAME
1285         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1286    or
1287         argv[0]                 FRAME-NAME      container       emacsTextPane
1288         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1289
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.
1294 #endif
1295
1296 */
1297
1298 #ifdef EXTERNAL_WIDGET
1299
1300 static int is_valid_window(Window w, struct device *d)
1301 {
1302         XWindowAttributes xwa;
1303         Display *dpy = DEVICE_X_DISPLAY(d);
1304
1305         expect_x_error(dpy);
1306         XGetWindowAttributes(dpy, w, &xwa);
1307         return !x_error_occurred_p(dpy);
1308 }
1309
1310 #endif                          /* EXTERNAL_WIDGET */
1311
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. */
1315
1316 static void x_send_synthetic_mouse_event(struct frame *f)
1317 {
1318         /* #### write this function. */
1319 }
1320
1321 static int first_x_frame_p(struct frame *f)
1322 {
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)))))
1326                 rest = XCDR(rest);
1327         return NILP(rest);
1328 }
1329
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. */
1333
1334 static void x_initialize_frame_size(struct frame *f)
1335 {
1336         /* Geometry of the AppShell */
1337         int app_flags = 0;
1338         int app_x = 0;
1339         int app_y = 0;
1340         unsigned int app_w = 0;
1341         unsigned int app_h = 0;
1342
1343         /* Geometry of the EmacsFrame */
1344         int frame_flags = 0;
1345         int frame_x = 0;
1346         int frame_y = 0;
1347         unsigned int frame_w = 0;
1348         unsigned int frame_h = 0;
1349
1350         /* Hairily merged geometry */
1351         int x = 0;
1352         int y = 0;
1353         unsigned int w = 80;
1354         unsigned int h = 40;
1355         int flags = 0;
1356
1357         char *geom = 0, *ew_geom = 0;
1358         Boolean iconic_p = False, ew_iconic_p = False;
1359
1360         Widget wmshell = FRAME_X_SHELL_WIDGET(f);
1361         /* #### This may not be an ApplicationShell any more, with the 'popup
1362            frame property. */
1363         Widget app_shell = XtParent(wmshell);
1364         Widget ew = FRAME_X_TEXT_WIDGET(f);
1365
1366 /* set the position of the frame's root window now.  When the
1367    frame was created, the position was initialized to (0,0). */
1368         {
1369                 struct window *win = XWINDOW(f->root_window);
1370
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);
1375
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);
1380                 }
1381         }
1382
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))
1387                 return;
1388 #endif
1389
1390 #if 0
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. */
1394
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:
1398
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.)
1407
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.)
1411          */
1412
1413         if (!FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1414                 Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1415                 if (ew_geom)
1416                         frame_flags = XParseGeometry(ew_geom,
1417                                                      &frame_x, &frame_y,
1418                                                      &frame_w, &frame_h);
1419                 if (!(frame_flags & (WidthValue | HeightValue))) {
1420                         Arg al[2];
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) {
1425                                 frame_w = 64;
1426                                 frame_h = 12;
1427                                 frame_flags |= WidthValue | HeightValue;
1428                         }
1429                 }
1430                 if (frame_flags & (WidthValue | HeightValue))
1431                         EmacsFrameSetCharSize(ew, frame_w, frame_h);
1432                 if (frame_flags & (XValue | YValue)) {
1433                         Arg al[2];
1434                         XtSetArg(al[0], XtNwidth, &frame_w);
1435                         XtSetArg(al[1], XtNheight, &frame_h);
1436                         XtGetValues(ew, al, 2);
1437
1438                         if (frame_flags & XNegative)
1439                                 frame_x += frame_w;
1440                         if (frame_flags & YNegative)
1441                                 frame_y += frame_h;
1442
1443                         XtSetArg(al[0], XtNx, frame_x);
1444                         XtSetArg(al[1], XtNy, frame_y);
1445                         XtSetValues(ew, al, 2);
1446                 }
1447                 return;
1448         }
1449 #endif
1450
1451         /* OK, we're a top-level shell. */
1452
1453         if (!XtIsWMShell(wmshell))
1454                 abort();
1455
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.) */
1459
1460         Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1461         if (!ew_geom) {
1462                 Xt_GET_VALUE(wmshell, XtNgeometry, &geom);
1463                 if (geom) {
1464                         ew_geom = geom;
1465                         Xt_SET_VALUE(ew, XtNgeometry, ew_geom);
1466                 }
1467         }
1468
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);
1472         if (!ew_iconic_p) {
1473                 Xt_GET_VALUE(wmshell, XtNiconic, &iconic_p);
1474                 if (iconic_p) {
1475                         ew_iconic_p = iconic_p;
1476                         Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1477                 }
1478         }
1479
1480         Xt_GET_VALUE(app_shell, XtNgeometry, &geom);
1481         if (geom)
1482                 app_flags =
1483                     XParseGeometry(geom, &app_x, &app_y, &app_w, &app_h);
1484
1485         if (ew_geom)
1486                 frame_flags = XParseGeometry(ew_geom,
1487                                              &frame_x, &frame_y,
1488                                              &frame_w, &frame_h);
1489
1490         if (first_x_frame_p(f)) {
1491                 /* If this is the first frame created:
1492                    ====================================
1493
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")
1498
1499                    - If the AppShell is iconic, the frame should be iconic.
1500
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
1503                    resource database.
1504                  */
1505                 if (app_flags & (XValue | YValue)) {
1506                         x = app_x;
1507                         y = app_y;
1508                         flags |=
1509                             (app_flags &
1510                              (XValue | YValue | XNegative | YNegative));
1511                 } else if (frame_flags & (XValue | YValue)) {
1512                         x = frame_x;
1513                         y = frame_y;
1514                         flags |=
1515                             (frame_flags &
1516                              (XValue | YValue | XNegative | YNegative));
1517                 }
1518
1519                 if (app_flags & (WidthValue | HeightValue)) {
1520                         w = app_w;
1521                         h = app_h;
1522                         flags |= (app_flags & (WidthValue | HeightValue));
1523                 } else if (frame_flags & (WidthValue | HeightValue)) {
1524                         w = frame_w;
1525                         h = frame_h;
1526                         flags |= (frame_flags & (WidthValue | HeightValue));
1527                 }
1528
1529                 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1530                 if (!ew_iconic_p) {
1531                         Xt_GET_VALUE(app_shell, XtNiconic, &iconic_p);
1532                         if (iconic_p) {
1533                                 ew_iconic_p = iconic_p;
1534                                 Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1535                         }
1536                 }
1537         } else {
1538                 /* If this is not the first frame created:
1539                    ========================================
1540
1541                    - use the EmacsFrame's size/position if specified
1542                    - Otherwise, use the ApplicationShell's size, but not position.
1543
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".
1547
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.
1551                  */
1552                 if (frame_flags & (XValue | YValue)) {
1553                         x = frame_x;
1554                         y = frame_y;
1555                         flags |=
1556                             (frame_flags &
1557                              (XValue | YValue | XNegative | YNegative));
1558                 }
1559
1560                 if (frame_flags & (WidthValue | HeightValue)) {
1561                         w = frame_w;
1562                         h = frame_h;
1563                         flags |= (frame_flags & (WidthValue | HeightValue));
1564                 } else if (app_flags & (WidthValue | HeightValue)) {
1565                         w = app_w;
1566                         h = app_h;
1567                         flags |= (app_flags & (WidthValue | HeightValue));
1568                 }
1569         }
1570
1571         x_set_initial_frame_size(f, flags, x, y, w, h);
1572 }
1573
1574 static void x_get_layout_sizes(struct frame *f, Dimension * topbreadth)
1575 {
1576         int i;
1577
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))
1582                         *topbreadth +=
1583                             wid->core.height + 2 * wid->core.border_width;
1584         }
1585 }
1586
1587 static void
1588 x_layout_widgets(Widget w, XtPointer client_data, XtPointer call_data)
1589 {
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;
1598         int i;
1599
1600         x_get_layout_sizes(f, &topbreadth);
1601
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,
1609                                           bord);
1610                         text_y += wid->core.height + 2 * bord;
1611                 }
1612         }
1613
1614 #ifdef HAVE_SCROLLBARS
1615         f->scrollbar_y_offset = topbreadth + textbord;
1616 #endif
1617
1618         /* finally the text area */
1619         {
1620                 Dimension nw = width - 2 * textbord;
1621                 Dimension nh = height - text_y - 2 * textbord;
1622
1623                 if (nh != f->pixheight || nw != f->pixwidth)
1624                         MARK_FRAME_SIZE_SLIPPED(f);
1625                 XtConfigureWidget(text, text_x, text_y, nw, nh, textbord);
1626         }
1627 }
1628
1629 static void
1630 x_do_query_geometry(Widget w, XtPointer client_data, XtPointer call_data)
1631 {
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);
1640
1641         x_get_layout_sizes(f, &topbreadth);
1642
1643         /* Strip away menubar from suggested size, and ask the text widget
1644            what size it wants to be.  */
1645         req.request_mode = mask;
1646         if (mask & CWWidth)
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);
1651
1652         /* Now add the menubar back again */
1653         emst->proposed_width = repl.width + 2 * textbord;
1654         emst->proposed_height = repl.height + topbreadth + 2 * textbord;
1655 }
1656
1657 /* Creates the widgets for a frame.
1658    lisp_window_id is a Lisp description of an X window or Xt
1659    widget to parse.
1660    parent is a frame to use as the parent.
1661    overridep if non-nil says to set the override-redirect setting.
1662
1663    This function does not create or map the windows.  (That is
1664    done by x_popup_frame().)
1665  */
1666 static void
1667 x_create_widgets(struct frame *f, Lisp_Object lisp_window_id,
1668                  Lisp_Object parent, Lisp_Object overridep)
1669 {
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;
1676 #endif
1677         const char *name;
1678         Arg al[25];
1679         int ac = 0;
1680         Widget text, container, shell;
1681         Widget parentwid = 0;
1682 #ifdef HAVE_MENUBARS
1683         int menubar_visible;
1684         Widget menubar;
1685 #endif
1686
1687         if (STRINGP(f->name))
1688                 LISP_STRING_TO_EXTERNAL(f->name, name, Qctext);
1689         else
1690                 name = "emacs";
1691
1692         /* The widget hierarchy is
1693
1694            argv[0]                    shell           pane            FRAME-NAME
1695            ApplicationShell   EmacsShell      EmacsManager    EmacsFrame
1696
1697            (the type of the shell is ExternalShell if this frame is running
1698            in another client's window)
1699
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.
1706          */
1707
1708 #ifndef EXTERNAL_WIDGET
1709         if (!NILP(lisp_window_id))
1710                 error
1711                     ("support for external widgets was not enabled at compile-time");
1712 #else
1713         if (!NILP(lisp_window_id)) {
1714                 char *string;
1715
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);
1720 #if 0
1721                 else if (string[0] == 'w') {
1722                         sscanf(string + 1, "%x", &parent_widget);
1723                         if (parent_widget)
1724                                 window_id = XtWindow(parent_widget);
1725                 }
1726 #endif
1727                 else
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;
1732         } else
1733 #endif                          /* EXTERNAL_WIDGET */
1734                 FRAME_X_TOP_LEVEL_FRAME_P(f) = 1;
1735
1736         ac = 0;
1737         XtSetArg(al[ac], XtNallowShellResize, True);
1738         ac++;
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
1742            from the WM. */
1743         XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING);
1744         ac++;
1745 #endif
1746
1747 #ifdef EXTERNAL_WIDGET
1748         if (window_id) {
1749                 XtSetArg(al[ac], XtNwindow, window_id);
1750                 ac++;
1751         } else
1752 #endif                          /* EXTERNAL_WIDGET */
1753         {
1754                 XtSetArg(al[ac], XtNinput, True);
1755                 ac++;
1756                 XtSetArg(al[ac], XtNminWidthCells, 10);
1757                 ac++;
1758                 XtSetArg(al[ac], XtNminHeightCells, 1);
1759                 ac++;
1760                 XtSetArg(al[ac], XtNvisual, visual);
1761                 ac++;
1762                 XtSetArg(al[ac], XtNdepth, depth);
1763                 ac++;
1764                 XtSetArg(al[ac], XtNcolormap, cmap);
1765                 ac++;
1766         }
1767
1768         if (!NILP(overridep)) {
1769                 XtSetArg(al[ac], XtNoverrideRedirect, True);
1770                 ac++;
1771         }
1772
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);
1777                 ac++;
1778         }
1779
1780         shell = XtCreatePopupShell("shell", (
1781 #ifdef EXTERNAL_WIDGET
1782                                                     window_id ?
1783                                                     externalShellWidgetClass :
1784 #endif
1785                                                     parentwid ?
1786                                                     transientEmacsShellWidgetClass
1787                                                     :
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);
1793
1794         /* Create the manager widget */
1795         ac = 0;
1796         XtSetArg(al[ac], XtNvisual, visual);
1797         ac++;
1798         XtSetArg(al[ac], XtNdepth, depth);
1799         ac++;
1800         XtSetArg(al[ac], XtNcolormap, cmap);
1801         ac++;
1802
1803         container = XtCreateWidget("container",
1804                                    emacsManagerWidgetClass, shell, al, ac);
1805         FRAME_X_CONTAINER_WIDGET(f) = container;
1806         XtAddCallback(container, XtNresizeCallback, x_layout_widgets,
1807                       (XtPointer) f);
1808         XtAddCallback(container, XtNqueryGeometryCallback, x_do_query_geometry,
1809                       (XtPointer) f);
1810
1811         /* Create the text area */
1812         ac = 0;
1813         XtSetArg(al[ac], XtNvisual, visual);
1814         ac++;
1815         XtSetArg(al[ac], XtNdepth, depth);
1816         ac++;
1817         XtSetArg(al[ac], XtNcolormap, cmap);
1818         ac++;
1819         XtSetArg(al[ac], XtNborderWidth, 0);
1820         ac++;                   /* should this be settable? */
1821         XtSetArg(al[ac], XtNemacsFrame, f);
1822         ac++;
1823         text = XtCreateWidget(name, emacsFrameClass, container, al, ac);
1824         FRAME_X_TEXT_WIDGET(f) = text;
1825
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;
1831
1832         if (menubar_visible)
1833                 XtManageChild(menubar);
1834 #endif                          /* HAVE_MENUBARS */
1835         XtManageChild(text);
1836         XtManageChild(container);
1837 }
1838
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.
1843
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.
1848
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)
1854 {
1855         ShellWidget shell_widget = (ShellWidget) widget;
1856         XtGrabKind call_data = XtGrabNone;
1857
1858         XtCallCallbacks(widget, XtNpopupCallback, (XtPointer) & call_data);
1859
1860         shell_widget->shell.popped_up = TRUE;
1861         shell_widget->shell.grab_kind = XtGrabNone;
1862         shell_widget->shell.spring_loaded = False;
1863
1864         if (shell_widget->shell.create_popup_child_proc != NULL)
1865                 (*(shell_widget->shell.create_popup_child_proc)) (widget);
1866
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);
1872 }
1873
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)
1878 {
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));
1882
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
1885            notion.
1886          */
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);
1891
1892         xemacs_XtPopup(shell_widget);
1893
1894         if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
1895                 XtMapWidget(shell_widget);
1896         else {
1897                 /* We may have set f->visible to 1 in x_init_frame(), so undo
1898                    that now. */
1899                 FRAME_X_TOTALLY_VISIBLE_P(f) = 0;
1900                 f->visible = 0;
1901         }
1902
1903 #ifdef EXTERNAL_WIDGET
1904         if (FRAME_X_EXTERNAL_WINDOW_P(f))
1905                 ExternalShellReady(shell_widget, XtWindow(frame_widget),
1906                                    KeyPressMask);
1907         else
1908 #endif
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));
1912
1913 #ifndef HAVE_WMCOMMAND
1914                 x_wm_maybe_store_wm_command(f);
1915 #endif                          /* HAVE_WMCOMMAND */
1916
1917                 x_wm_hack_wm_protocols(shell_widget);
1918         }
1919 #ifdef HAVE_XIM
1920         XIM_init_frame(f);
1921 #endif                          /* HAVE_XIM */
1922
1923 #ifdef HACK_EDITRES
1924         /* Allow XEmacs to respond to EditRes requests.  See the O'Reilly Xt */
1925         /* Intrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
1926         /* pp. 483-493. */
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 */
1931                           NULL);
1932 #endif                          /* HACK_EDITRES */
1933
1934 #ifdef HAVE_CDE
1935         {
1936                 XtCallbackRec dnd_transfer_cb_rec[2];
1937
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;
1942
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);
1949         }
1950 #endif                          /* HAVE_CDE */
1951
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.
1955          */
1956         XChangeProperty(XtDisplay(frame_widget), XtWindow(frame_widget),
1957                         DEVICE_XATOM_WM_PROTOCOLS(d), XA_ATOM, 32,
1958                         PropModeAppend, (unsigned char *)NULL, 0);
1959
1960         x_send_synthetic_mouse_event(f);
1961 }
1962
1963 static void allocate_x_frame_struct(struct frame *f)
1964 {
1965         /* zero out all slots. */
1966         f->frame_data = xnew_and_zero(struct x_frame);
1967
1968         /* yeah, except the lisp ones */
1969         FRAME_X_ICON_PIXMAP(f) = Qnil;
1970         FRAME_X_ICON_PIXMAP_MASK(f) = Qnil;
1971 }
1972 \f
1973 /************************************************************************/
1974 /*                              Lisp functions                          */
1975 /************************************************************************/
1976
1977 static void x_init_frame_1(struct frame *f, Lisp_Object props)
1978 {
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);
1984
1985         if (!NILP(popup)) {
1986                 if (EQ(popup, Qt))
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,
1992                              popup);
1993         }
1994
1995         /*
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
2003          * frame properties.
2004          */
2005         f->visible = 1;
2006
2007         allocate_x_frame_struct(f);
2008         x_create_widgets(f, lisp_window_id, popup, overridep);
2009 }
2010
2011 static void x_init_frame_2(struct frame *f, Lisp_Object props)
2012 {
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. */
2015
2016         update_frame_face_values(f);
2017         x_initialize_frame_size(f);
2018         /* Kyle:
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.
2023          * JV:
2024          *   It turns out it gives problems with FVWMs name based mapping.
2025          *   We'll just  need to be careful in the modeline specs.
2026          */
2027         update_frame_title(f);
2028 }
2029
2030 static void x_init_frame_3(struct frame *f)
2031 {
2032         /* Pop up the frame. */
2033
2034         x_popup_frame(f);
2035 }
2036
2037 static void x_mark_frame(struct frame *f)
2038 {
2039         mark_object(FRAME_X_ICON_PIXMAP(f));
2040         mark_object(FRAME_X_ICON_PIXMAP_MASK(f));
2041 }
2042
2043 static void x_set_frame_icon(struct frame *f)
2044 {
2045         Pixmap x_pixmap, x_mask;
2046
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);
2051         } else {
2052                 x_pixmap = 0;
2053                 x_mask = 0;
2054         }
2055
2056         /* Store the X data into the widget. */
2057         {
2058                 Arg al[2];
2059                 XtSetArg(al[0], XtNiconPixmap, x_pixmap);
2060                 XtSetArg(al[1], XtNiconMask, x_mask);
2061                 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
2062         }
2063 }
2064
2065 static void x_set_frame_pointer(struct frame *f)
2066 {
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);
2071 }
2072
2073 static Lisp_Object x_get_frame_parent(struct frame *f)
2074 {
2075         Widget parentwid = 0;
2076
2077         Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNtransientFor, &parentwid);
2078         /* find the frame whose wid is parentwid */
2079         if (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)
2084                                 return frame;
2085                 }
2086         }
2087         return Qnil;
2088 }
2089
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
2094 a string.
2095 */
2096       (frame))
2097 {
2098         char str[255];
2099         struct frame *f = decode_x_frame(frame);
2100
2101         sprintf(str, "%lu", XtWindow(FRAME_X_TEXT_WIDGET(f)));
2102         return build_string(str);
2103 }
2104 \f
2105 /************************************************************************/
2106 /*                      manipulating the X window                       */
2107 /************************************************************************/
2108
2109 static void x_set_frame_position(struct frame *f, int xoff, int yoff)
2110 {
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;
2116         int win_gravity;
2117         Arg al[3];
2118
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);
2123
2124         win_gravity =
2125             xoff >= 0 && yoff >= 0 ? NorthWestGravity :
2126             xoff >= 0 ? SouthWestGravity :
2127             yoff >= 0 ? NorthEastGravity : SouthEastGravity;
2128         if (xoff < 0)
2129                 xoff += frame_w - shell_w - 2 * shell_bord;
2130         if (yoff < 0)
2131                 yoff += frame_h - shell_h - 2 * shell_bord;
2132
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);
2141
2142         /* Sometimes you will find that
2143
2144            (set-frame-position (selected-frame) -50 -50)
2145
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. */
2156
2157 #if 0
2158         /* This is not necessary under either mwm or twm */
2159         x_wm_mark_shell_position_user_specified(w);
2160 #endif
2161 }
2162
2163 /* Call this to change the size of frame S's x-window. */
2164
2165 static void x_set_frame_size(struct frame *f, int cols, int rows)
2166 {
2167         EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), cols, rows);
2168 #if 0
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));
2174 #endif
2175 }
2176
2177 static void x_set_mouse_position(struct window *w, int x, int y)
2178 {
2179         struct frame *f = XFRAME(w->frame);
2180
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);
2184 }
2185
2186 static int
2187 x_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
2188 {
2189         Display *display = DEVICE_X_DISPLAY(d);
2190         Window child_window;
2191         Window root_window;
2192         Window win;
2193         int root_x, root_y;
2194         int win_x, win_y;
2195         unsigned int keys_and_buttons;
2196         struct frame *f;
2197
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)
2201                 return 0;
2202
2203         if (child_window == None)
2204                 return 0;       /* not over any window. */
2205
2206         while (1) {
2207                 win = child_window;
2208                 if (XTranslateCoordinates
2209                     (display, root_window, win, root_x, root_y, &win_x, &win_y,
2210                      &child_window) == False)
2211                         /* Huh? */
2212                         return 0;
2213
2214                 if (child_window == None)
2215                         break;
2216         }
2217
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);
2221         if (!f)
2222                 return 0;
2223         XSETFRAME(*frame, f);
2224
2225         if (XTranslateCoordinates(display, win,
2226                                   XtWindow(FRAME_X_TEXT_WIDGET(f)),
2227                                   win_x, win_y, x, y, &child_window) == False)
2228                 /* Huh? */
2229                 return 0;
2230
2231         return 1;
2232 }
2233
2234 static void x_cant_notify_wm_error(void)
2235 {
2236         error("Can't notify window manager of iconification.");
2237 }
2238
2239 /* Raise frame F.  */
2240 static void x_raise_frame_1(struct frame *f, int force)
2241 {
2242         if (FRAME_VISIBLE_P(f) || force) {
2243                 Widget bottom_dialog;
2244                 XWindowChanges xwc;
2245                 unsigned int flags;
2246                 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2247                 Window emacs_window = XtWindow(FRAME_X_SHELL_WIDGET(f));
2248
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;
2256                 } else {
2257                         xwc.stack_mode = Above;
2258                         flags = CWStackMode;
2259                 }
2260
2261                 if (!XReconfigureWMWindow(display, emacs_window,
2262                                           DefaultScreen(display), flags, &xwc))
2263                         x_cant_notify_wm_error();
2264         }
2265 }
2266
2267 static void x_raise_frame(struct frame *f)
2268 {
2269         x_raise_frame_1(f, 1);
2270 }
2271
2272 /* Lower frame F.  */
2273 static void x_lower_frame(struct frame *f)
2274 {
2275         if (FRAME_VISIBLE_P(f)) {
2276                 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2277                 XWindowChanges xwc;
2278                 unsigned int flags = CWStackMode;
2279
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();
2285         }
2286 }
2287
2288 static void x_enable_frame(struct frame *f)
2289 {
2290         XtSetSensitive(FRAME_X_SHELL_WIDGET(f), True);
2291 }
2292
2293 static void x_disable_frame(struct frame *f)
2294 {
2295         XtSetSensitive(FRAME_X_SHELL_WIDGET(f), False);
2296 }
2297
2298 /* Change from withdrawn state to mapped state. */
2299 static void x_make_frame_visible(struct frame *f)
2300 {
2301         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2302
2303         if (!FRAME_VISIBLE_P(f))
2304                 XMapRaised(display, XtWindow(FRAME_X_SHELL_WIDGET(f)));
2305         else
2306                 x_raise_frame_1(f, 0);
2307 }
2308
2309 /* Change from mapped state to withdrawn state. */
2310 static void x_make_frame_invisible(struct frame *f)
2311 {
2312         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2313
2314         if (!FRAME_VISIBLE_P(f))
2315                 return;
2316
2317         if (!XWithdrawWindow(display,
2318                              XtWindow(FRAME_X_SHELL_WIDGET(f)),
2319                              DefaultScreen(display)))
2320                 x_cant_notify_wm_error();
2321 }
2322
2323 static int x_frame_visible_p(struct frame *f)
2324 {
2325 #if 0
2326         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2327         XWindowAttributes xwa;
2328         int result;
2329
2330         /* JV:
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
2335
2336            Mappedness != Viewability != Visibility != Emacs f->visible
2337
2338            This first unequalness is the reason for the frame freezing problem
2339            under fvwm (it happens when the frame is another fvwm-page)
2340
2341            The second unequalness happen when it is on the same fvwm-page
2342            but in an invisible part of the visible screen.
2343
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.
2347          */
2348
2349         if (!XGetWindowAttributes(display,
2350                                   XtWindow(FRAME_X_SHELL_WIDGET(f)), &xwa))
2351                 result = 0;
2352         else
2353                 result = xwa.map_state == IsViewable;
2354         /* In this implementation it should at least be != IsUnmapped
2355            JV */
2356
2357         f->visible = result;
2358         return result;
2359 #endif                          /* 0 */
2360
2361         return f->visible;
2362 }
2363
2364 static int x_frame_totally_visible_p(struct frame *f)
2365 {
2366         return FRAME_X_TOTALLY_VISIBLE_P(f);
2367 }
2368
2369 /* Change window state from mapped to iconified. */
2370 static void x_iconify_frame(struct frame *f)
2371 {
2372         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2373
2374         if (!XIconifyWindow(display,
2375                             XtWindow(FRAME_X_SHELL_WIDGET(f)),
2376                             DefaultScreen(display)))
2377                 x_cant_notify_wm_error();
2378
2379         f->iconified = 1;
2380 }
2381
2382 /* Sets the X focus to frame f. */
2383 static void x_focus_on_frame(struct frame *f)
2384 {
2385         XWindowAttributes xwa;
2386         Widget shell_widget;
2387         int viewable = 0;
2388
2389         assert(FRAME_X_P(f));
2390
2391         shell_widget = FRAME_X_SHELL_WIDGET(f);
2392         if (!XtWindow(shell_widget))
2393                 return;
2394
2395 #ifdef EXTERNAL_WIDGET
2396         if (FRAME_X_EXTERNAL_WINDOW_P(f))
2397                 ExternalShellSetFocus(shell_widget);
2398 #endif                          /* EXTERNAL_WIDGET */
2399
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.
2406          */
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;
2416
2417         if (viewable) {
2418                 Window focus;
2419                 int revert_to;
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.
2429                  */
2430                 if (focus != PointerRoot) {
2431                         XSetInputFocus(XtDisplay(shell_widget),
2432                                        XtWindow(shell_widget),
2433                                        RevertToParent,
2434                                        DEVICE_X_MOUSE_TIMESTAMP
2435                                        (XDEVICE(FRAME_DEVICE(f))));
2436                         XFlush(XtDisplay(shell_widget));
2437                 }
2438         }
2439         XUngrabServer(XtDisplay(shell_widget));
2440         XFlush(XtDisplay(shell_widget));        /* hey, I'd like to DEBUG this... */
2441 }
2442
2443 /* Destroy the X window of frame F.  */
2444 static void x_delete_frame(struct frame *f)
2445 {
2446         Display *dpy;
2447
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 */
2452
2453 #ifdef HAVE_CDE
2454         DtDndDropUnregister(FRAME_X_TEXT_WIDGET(f));
2455 #endif                          /* HAVE_CDE */
2456
2457         assert(FRAME_X_SHELL_WIDGET(f) != 0);
2458         dpy = XtDisplay(FRAME_X_SHELL_WIDGET(f));
2459
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);
2469 #else
2470         XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2471         /* make sure the windows are really gone! */
2472         /* #### Is this REALLY necessary? */
2473         XFlush(dpy);
2474 #endif                          /* EXTERNAL_WIDGET */
2475
2476         FRAME_X_SHELL_WIDGET(f) = 0;
2477
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;
2481         }
2482
2483         if (f->frame_data) {
2484                 xfree(f->frame_data);
2485                 f->frame_data = 0;
2486         }
2487 }
2488
2489 static void x_update_frame_external_traits(struct frame *frm, Lisp_Object name)
2490 {
2491         Arg al[10];
2492         int ac = 0;
2493         Lisp_Object frame;
2494
2495         XSETFRAME(frame, frm);
2496
2497         if (EQ(name, Qforeground)) {
2498                 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
2499                 XColor fgc;
2500
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);
2504                         ac++;
2505                 }
2506         } else if (EQ(name, Qbackground)) {
2507                 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
2508                 XColor bgc;
2509
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);
2513                         ac++;
2514                 }
2515
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)) {
2521                 Lisp_Object font =
2522                     FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
2523
2524                 if (!EQ(font, Vthe_null_font_instance)) {
2525                         XtSetArg(al[ac], XtNfont,
2526                                  (void *)
2527                                  FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font)));
2528                         ac++;
2529                 }
2530         } else
2531                 abort();
2532
2533         XtSetValues(FRAME_X_TEXT_WIDGET(frm), al, ac);
2534
2535 #ifdef HAVE_TOOLBARS
2536         /* Setting the background clears the entire frame area
2537            including the toolbar so we force an immediate redraw of
2538            it. */
2539         if (EQ(name, Qbackground))
2540                 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
2541                               (frm));
2542 #endif                          /* HAVE_TOOLBARS */
2543
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));
2548 }
2549 \f
2550 /************************************************************************/
2551 /*                            initialization                            */
2552 /************************************************************************/
2553
2554 void syms_of_frame_x(void)
2555 {
2556         defsymbol(&Qwindow_id, "window-id");
2557         defsymbol(&Qoverride_redirect, "override-redirect");
2558         defsymbol(&Qx_resource_name, "x-resource-name");
2559
2560         DEFSUBR(Fx_window_id);
2561 #ifdef HAVE_CDE
2562         DEFSUBR(Fcde_start_drag_internal);
2563 #endif
2564 }
2565
2566 void console_type_create_frame_x(void)
2567 {
2568         /* frame methods */
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);
2599 }
2600
2601 void vars_of_frame_x(void)
2602 {
2603 #ifdef EXTERNAL_WIDGET
2604         Fprovide(intern("external-widget"));
2605 #endif
2606
2607         /* this call uses only safe functions from emacs.c */
2608         init_x_prop_symbols();
2609
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'.
2615
2616 Note: In many cases, properties of a frame are available as specifiers
2617 instead of through the frame-properties mechanism.
2618
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):
2622
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
2630                              a new one.
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
2634                              the frame appear.
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
2659                              decorations).
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
2663                              decorations).
2664 border-color                 Color of external border around text area.
2665 cursor-color                 Color of text cursor.
2666
2667 See also `default-frame-plist', which specifies properties which apply
2668 to all frames, not just X frames.
2669                                                                          */ );
2670         Vdefault_x_frame_plist = Qnil;
2671
2672         x_console_methods->device_specific_frame_props =
2673             &Vdefault_x_frame_plist;
2674 }