More warning suppressions
[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         int sz;
471
472         XColor color;
473         color.pixel = pixel;
474         XQueryColor(XtDisplay(w), w->core.colormap, &color);
475         sz = snprintf(buf, sizeof(buf), "#%04x%04x%04x", color.red, color.green, color.blue);
476         assert(sz>=0 && (size_t)sz < sizeof(buf));
477         return build_string(buf);
478 }
479
480 static void
481 x_get_top_level_position(Display * d, Window w, Position * x, Position * y)
482 {
483         Window root, parent = w, *children;
484         unsigned int nchildren;
485         XWindowAttributes xwa;
486
487         do {
488                 w = parent;
489                 if (!XQueryTree(d, w, &root, &parent, &children, &nchildren)) {
490                         *x = 0;
491                         *y = 0;
492                         return;
493                 }
494                 XFree(children);
495         }
496         while (root != parent);
497         XGetWindowAttributes(d, w, &xwa);
498         *x = xwa.x;
499         *y = xwa.y;
500 }
501
502 #if 0
503 static void x_smash_bastardly_shell_position(Widget shell)
504 {
505         /* Naturally those bastards who wrote Xt couldn't be bothered
506            to learn about race conditions and such.  We can't trust
507            the X and Y values to have any semblance of correctness,
508            so we smash the right values in place. */
509
510         /* We might be called before we've actually realized the window (if
511            we're checking for the minibuffer resource).  This will bomb in
512            that case so we don't bother calling it. */
513         if (XtWindow(shell))
514                 x_get_top_level_position(XtDisplay(shell), XtWindow(shell),
515                                          &shell->core.x, &shell->core.y);
516 }
517 #endif                          /* 0 */
518
519 static Lisp_Object x_frame_property(struct frame *f, Lisp_Object property)
520 {
521         Widget shell = FRAME_X_SHELL_WIDGET(f);
522         EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
523         Widget gw = (Widget) w;
524
525         if (EQ(Qleft, property) || EQ(Qtop, property)) {
526                 Position x, y;
527                 if (!XtWindow(shell))
528                         return Qzero;
529                 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
530                                          &y);
531                 if (EQ(Qleft, property))
532                         return make_int(x);
533                 if (EQ(Qtop, property))
534                         return make_int(y);
535         }
536         if (EQ(Qborder_width, property))
537                 return make_int(w->core.border_width);
538         if (EQ(Qinternal_border_width, property))
539                 return make_int(w->emacs_frame.internal_border_width);
540         if (EQ(Qborder_color, property))
541                 return color_to_string(gw, w->core.border_pixel);
542 #ifdef HAVE_TOOLBARS
543         if (EQ(Qtop_toolbar_shadow_color, property))
544                 return color_to_string(gw,
545                                        w->emacs_frame.top_toolbar_shadow_pixel);
546         if (EQ(Qbottom_toolbar_shadow_color, property))
547                 return color_to_string(gw,
548                                        w->emacs_frame.
549                                        bottom_toolbar_shadow_pixel);
550         if (EQ(Qbackground_toolbar_color, property))
551                 return color_to_string(gw,
552                                        w->emacs_frame.background_toolbar_pixel);
553         if (EQ(Qtoolbar_shadow_thickness, property))
554                 return make_int(w->emacs_frame.toolbar_shadow_thickness);
555 #endif                          /* HAVE_TOOLBARS */
556         if (EQ(Qinter_line_space, property))
557                 return make_int(w->emacs_frame.interline);
558         if (EQ(Qwindow_id, property))
559                 return Fx_window_id(make_frame(f));
560
561         return Qunbound;
562 }
563
564 static int x_internal_frame_property_p(struct frame *f, Lisp_Object property)
565 {
566         return EQ(property, Qleft)
567             || EQ(property, Qtop)
568             || EQ(property, Qborder_width)
569             || EQ(property, Qinternal_border_width)
570             || EQ(property, Qborder_color)
571 #ifdef HAVE_TOOLBARS
572             || EQ(property, Qtop_toolbar_shadow_color)
573             || EQ(property, Qbottom_toolbar_shadow_color)
574             || EQ(property, Qbackground_toolbar_color)
575             || EQ(property, Qtoolbar_shadow_thickness)
576 #endif                          /* HAVE_TOOLBARS */
577             || EQ(property, Qinter_line_space)
578             || EQ(property, Qwindow_id)
579             || STRINGP(property);
580 }
581
582 static Lisp_Object x_frame_properties(struct frame *f)
583 {
584         Lisp_Object props = Qnil;
585         Widget shell = FRAME_X_SHELL_WIDGET(f);
586         EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
587         Widget gw = (Widget) w;
588         Position x, y;
589
590         props = cons3(Qwindow_id, Fx_window_id(make_frame(f)), props);
591         props =
592             cons3(Qinter_line_space, make_int(w->emacs_frame.interline), props);
593
594 #ifdef HAVE_TOOLBARS
595         props = cons3(Qtoolbar_shadow_thickness,
596                       make_int(w->emacs_frame.toolbar_shadow_thickness), props);
597         props = cons3(Qbackground_toolbar_color,
598                       color_to_string(gw,
599                                       w->emacs_frame.background_toolbar_pixel),
600                       props);
601         props =
602             cons3(Qbottom_toolbar_shadow_color,
603                   color_to_string(gw,
604                                   w->emacs_frame.bottom_toolbar_shadow_pixel),
605                   props);
606         props =
607             cons3(Qtop_toolbar_shadow_color,
608                   color_to_string(gw, w->emacs_frame.top_toolbar_shadow_pixel),
609                   props);
610 #endif                          /* HAVE_TOOLBARS */
611
612         props = cons3(Qborder_color,
613                       color_to_string(gw, w->core.border_pixel), props);
614         props = cons3(Qinternal_border_width,
615                       make_int(w->emacs_frame.internal_border_width), props);
616         props = cons3(Qborder_width, make_int(w->core.border_width), props);
617
618         if (!XtWindow(shell))
619                 x = y = 0;
620         else
621                 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
622                                          &y);
623
624         props = cons3(Qtop, make_int(y), props);
625         props = cons3(Qleft, make_int(x), props);
626
627         return props;
628 }
629 \f
630 /* Functions called only from `x_set_frame_properties' to set
631    individual properties. */
632
633 static void
634 x_set_frame_text_value(struct frame *f, Bufbyte * value,
635                        String Xt_resource_name,
636                        String Xt_resource_encoding_name)
637 {
638         Atom encoding = XA_STRING;
639         String new_XtValue = (String) value;
640         String old_XtValue = NULL;
641
642 #ifdef MULE
643         Bufbyte *ptr;
644         /* Optimize for common ASCII case */
645         for (ptr = value; *ptr; ptr++)
646                 if (!BYTE_ASCII_P(*ptr)) {
647                         char *tmp;
648                         encoding = DEVICE_XATOM_COMPOUND_TEXT(
649                                 XDEVICE(FRAME_DEVICE(f)));
650                         C_STRING_TO_EXTERNAL(value, tmp, Qctext);
651                         new_XtValue = (String) tmp;
652                         break;
653                 }
654 #endif                          /* MULE */
655
656         /* #### Caching is device-independent - belongs in update_frame_title. */
657         Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), Xt_resource_name, &old_XtValue);
658         if (!old_XtValue || strcmp(new_XtValue, old_XtValue)) {
659                 Arg al[2];
660                 XtSetArg(al[0], Xt_resource_name, new_XtValue);
661                 XtSetArg(al[1], Xt_resource_encoding_name, encoding);
662                 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
663         }
664 }
665
666 static void x_set_title_from_bufbyte(struct frame *f, Bufbyte * name)
667 {
668         x_set_frame_text_value(f, name, XtNtitle, XtNtitleEncoding);
669 }
670
671 static void x_set_icon_name_from_bufbyte(struct frame *f, Bufbyte * name)
672 {
673         x_set_frame_text_value(f, name, XtNiconName, XtNiconNameEncoding);
674 }
675
676 /* Set the initial frame size as specified.  This function is used
677    when the frame's widgets have not yet been realized.  In this
678    case, it is not sufficient just to set the width and height of
679    the EmacsFrame widget, because they will be ignored when the
680    widget is realized (instead, the shell's geometry resource is
681    used). */
682
683 static void
684 x_set_initial_frame_size(struct frame *f, int flags, int x, int y,
685                          unsigned int w, unsigned int h)
686 {
687         char  shell_geom[255];
688         int   xval, yval;
689         char  xsign, ysign;
690         char  uspos = !!(flags & (XValue | YValue));
691         char  ussize = !!(flags & (WidthValue | HeightValue));
692         char *temp;
693         int   sz = 0;
694
695         /* assign the correct size to the EmacsFrame widget ... */
696         EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), w, h);
697
698         /* and also set the WMShell's geometry */
699         (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign =
700                                                           '+');
701         (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign =
702                                                           '+');
703
704         if (uspos && ussize)
705                 sz = snprintf(shell_geom, sizeof(shell_geom),
706                               "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign,
707                               yval);
708         else if (uspos)
709                 sz = snprintf(shell_geom, sizeof(shell_geom),
710                               "=%c%d%c%d", xsign, xval, ysign, yval);
711         else if (ussize)
712                 sz = snprintf(shell_geom, sizeof(shell_geom),
713                               "=%dx%d", w, h);
714         assert(sz >=0 && (size_t)sz < sizeof(shell_geom));
715         if (uspos || ussize) {
716                 temp = xnew_atomic_array(char, 1 + strlen(shell_geom));
717                 strcpy(temp, shell_geom);
718                 FRAME_X_GEOM_FREE_ME_PLEASE(f) = temp;
719         } else {
720                 temp = NULL;
721         }
722         Xt_SET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNgeometry, temp);
723 }
724
725 /* Report to X that a frame property of frame S is being set or changed.
726    If the property is not specially recognized, do nothing.
727  */
728
729 static void x_set_frame_properties(struct frame *f, Lisp_Object plist)
730 {
731         Position x, y;
732         Dimension width = 0, height = 0;
733         Bool width_specified_p = False;
734         Bool height_specified_p = False;
735         Bool x_position_specified_p = False;
736         Bool y_position_specified_p = False;
737         Bool internal_border_width_specified = False;
738         Lisp_Object tail;
739         Widget w;
740
741         /* We can be called after the X IO error handler has seen a
742            broken pipe on the relevant display. Don't do anything in
743            that case.  */
744         if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
745           return;
746
747         w = FRAME_X_TEXT_WIDGET (f);
748
749         for (tail = plist; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
750                 Lisp_Object prop = Fcar(tail);
751                 Lisp_Object val = Fcar(Fcdr(tail));
752
753                 if (STRINGP(prop)) {
754                         const char *extprop;
755
756                         if (XSTRING_LENGTH(prop) == 0)
757                                 continue;
758
759                         LISP_STRING_TO_EXTERNAL(prop, extprop, Qctext);
760                         if (STRINGP(val)) {
761                                 const Extbyte *extval;
762                                 Extcount extvallen;
763
764                                 TO_EXTERNAL_FORMAT(LISP_STRING, val,
765                                                    ALLOCA, (extval, extvallen),
766                                                    Qctext);
767                                 XtVaSetValues(w, XtVaTypedArg, extprop,
768                                               XtRString, extval, extvallen + 1,
769                                               NULL);
770                         } else
771                                 XtVaSetValues(w, XtVaTypedArg, extprop, XtRInt,
772                                               XINT(val), sizeof(int),
773                                               NULL);
774                 } else if (SYMBOLP(prop)) {
775                         Lisp_Object str = Fget(prop, Qx_resource_name, Qnil);
776                         int int_p = !NILP(Fget(prop, Qintegerp, Qnil));
777
778                         if (NILP(prop) || NILP(str)) {
779                                 /* Kludge to handle the font property. */
780                                 if (EQ(prop, Qfont)) {
781                                         /* If the value is not a string we silently ignore it. */
782                                         if (STRINGP(val)) {
783                                                 Lisp_Object frm, font_spec;
784
785                                                 XSETFRAME(frm, f);
786                                                 font_spec =
787                                                     Fget(Fget_face(Qdefault),
788                                                          Qfont, Qnil);
789
790                                                 Fadd_spec_to_specifier
791                                                     (font_spec, val, frm, Qnil,
792                                                      Qnil);
793                                                 update_frame_face_values(f);
794                                         }
795
796                                         continue;
797                                 } else
798                                         continue;
799                         }
800                         CHECK_STRING(str);
801
802                         /* Kludge the width/height so that we interpret them in characters
803                            instead of pixels.  Yuck yuck yuck. */
804                         if (!strcmp((char *)XSTRING_DATA(str), "width")) {
805                                 CHECK_INT(val);
806                                 width = XINT(val);
807                                 width_specified_p = True;
808                                 continue;
809                         }
810                         if (!strcmp((char *)XSTRING_DATA(str), "height")) {
811                                 CHECK_INT(val);
812                                 height = XINT(val);
813                                 height_specified_p = True;
814                                 continue;
815                         }
816                         /* Further kludge the x/y. */
817                         if (!strcmp((char *)XSTRING_DATA(str), "x")) {
818                                 CHECK_INT(val);
819                                 x = (Position) XINT(val);
820                                 x_position_specified_p = True;
821                                 continue;
822                         }
823                         if (!strcmp((char *)XSTRING_DATA(str), "y")) {
824                                 CHECK_INT(val);
825                                 y = (Position) XINT(val);
826                                 y_position_specified_p = True;
827                                 continue;
828                         }
829                         /* Have you figured out by now that this entire function is
830                            one gigantic kludge? */
831                         if (!strcmp((char *)XSTRING_DATA(str),
832                                     "internalBorderWidth")) {
833                                 internal_border_width_specified = True;
834                         }
835
836                         if (int_p) {
837                                 CHECK_INT(val);
838                                 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str),
839                                              XINT(val));
840                         } else if (EQ(val, Qt)) {
841                                 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str), True);       /* XtN... */
842                         } else if (EQ(val, Qnil)) {
843                                 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str), False);      /* XtN... */
844                         } else {
845                                 CHECK_STRING(val);
846                                 XtVaSetValues(w, XtVaTypedArg,
847                                               /* XtN... */
848                                               (char *)XSTRING_DATA(str),
849                                               XtRString,
850                                               XSTRING_DATA(val),
851                                               XSTRING_LENGTH(val) + 1,
852                                               NULL);
853                         }
854
855 #ifdef HAVE_SCROLLBARS
856                         if (!strcmp((char *)XSTRING_DATA(str), "scrollBarWidth")
857                             || !strcmp((char *)XSTRING_DATA(str),
858                                        "scrollBarHeight")) {
859                                 x_update_frame_scrollbars(f);
860                         }
861 #endif                          /* HAVE_SCROLLBARS */
862                 }
863         }
864
865         /* Kludge kludge kludge.   We need to deal with the size and position
866            specially. */
867         {
868                 int size_specified_p = width_specified_p || height_specified_p;
869                 int position_specified_p = x_position_specified_p ||
870                     y_position_specified_p;
871
872                 if (!width_specified_p)
873                         width = FRAME_WIDTH(f);
874                 if (!height_specified_p)
875                         height = FRAME_HEIGHT(f);
876
877                 /* Kludge kludge kludge kludge. */
878                 if (position_specified_p &&
879                     (!x_position_specified_p || !y_position_specified_p)) {
880                         Position dummy;
881                         Widget shell = FRAME_X_SHELL_WIDGET(f);
882                         x_get_top_level_position(XtDisplay(shell),
883                                                  XtWindow(shell),
884                                                  (x_position_specified_p ?
885                                                   &dummy : &x),
886                                                  (y_position_specified_p ?
887                                                   &dummy : &y));
888 #if 0
889                         x = (int)(FRAME_X_SHELL_WIDGET(f)->core.x);
890                         y = (int)(FRAME_X_SHELL_WIDGET(f)->core.y);
891 #endif
892                 }
893
894                 if (!f->init_finished) {
895                         int flags =
896                             (size_specified_p ? WidthValue | HeightValue : 0) |
897                             (position_specified_p ? XValue | YValue |
898                              (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0)
899                              : 0);
900                         if (size_specified_p
901                             || position_specified_p
902                             || internal_border_width_specified)
903                                 x_set_initial_frame_size(f, flags, x, y, width,
904                                                          height);
905                 } else {
906                         if (size_specified_p || internal_border_width_specified) {
907                                 Lisp_Object frame;
908                                 XSETFRAME(frame, f);
909                                 Fset_frame_size(frame, make_int(width),
910                                                 make_int(height), Qnil);
911                         }
912                         if (position_specified_p) {
913                                 Lisp_Object frame;
914                                 XSETFRAME(frame, f);
915                                 Fset_frame_position(frame, make_int(x),
916                                                     make_int(y));
917                         }
918                 }
919         }
920 }
921
922 static int frame_title_format_already_set;
923
924 static void maybe_set_frame_title_format(Widget shell)
925 {
926
927         /* Only do this if this is the first X frame we're creating.
928
929            If the *title resource (or -title option) was specified, then
930            set frame-title-format to its value.
931          */
932
933         if (!frame_title_format_already_set) {
934                 /* No doubt there's a less stupid way to do this. */
935                 char *results[2];
936                 XtResource resources[2];
937                 results[0] = results[1] = 0;
938                 resources[0].resource_name = XtNtitle;
939                 resources[0].resource_class = XtCTitle;
940                 resources[0].resource_type = XtRString;
941                 resources[0].resource_size = sizeof(String);
942                 resources[0].resource_offset = 0;
943                 resources[0].default_type = XtRString;
944                 resources[0].default_addr = 0;
945                 resources[1].resource_name = XtNiconName;
946                 resources[1].resource_class = XtCIconName;
947                 resources[1].resource_type = XtRString;
948                 resources[1].resource_size = sizeof(String);
949                 resources[1].resource_offset = sizeof(char *);
950                 resources[1].default_type = XtRString;
951                 resources[1].default_addr = 0;
952                 XtGetSubresources(XtParent(shell), (XtPointer) results,
953                                   shell->core.name,
954                                   shell->core.widget_class->core_class.
955                                   class_name, resources, XtNumber(resources), 0,
956                                   0);
957                 if (results[0])
958                         Vframe_title_format = build_string(results[0]);
959                 if (results[1])
960                         Vframe_icon_title_format = build_string(results[1]);
961         }
962
963         frame_title_format_already_set = 1;
964 }
965
966 #ifdef HAVE_CDE
967 #include <Dt/Dt.h>
968 #include <Dt/Dnd.h>
969
970 static Widget CurrentDragWidget = NULL;
971 static XtCallbackRec dnd_convert_cb_rec[2];
972 static XtCallbackRec dnd_destroy_cb_rec[2];
973 static int drag_not_done = 0;
974
975 static void
976 x_cde_destroy_callback(Widget widget, XtPointer clientData, XtPointer callData)
977 {
978         DtDndDragFinishCallbackStruct *dragFinishInfo =
979             (DtDndDragFinishCallbackStruct *) callData;
980         DtDndContext *dragData = dragFinishInfo->dragData;
981         int i;
982
983         /* free the items */
984         if (callData != NULL && dragData != NULL) {
985                 if (dragData->protocol == DtDND_BUFFER_TRANSFER) {
986                         for (i = 0; i < dragData->numItems; i++) {
987                                 XtFree((char *)dragData->data.buffers[i].bp);
988                                 if (dragData->data.buffers[i].name)
989                                         XtFree(dragData->data.buffers[i].name);
990                         }
991                 } else {
992                         for (i = 0; i < dragData->numItems; i++)
993                                 XtFree(dragData->data.files[i]);
994                 }
995         }
996
997         /* free the data string */
998         xfree(clientData);
999
1000         CurrentDragWidget = NULL;
1001 }
1002
1003 static void
1004 x_cde_convert_callback(Widget widget, XtPointer clientData, XtPointer callData)
1005 {
1006         DtDndConvertCallbackStruct *convertInfo =
1007             (DtDndConvertCallbackStruct *) callData;
1008         char *textdata = (char *)clientData;
1009         char *textptr = NULL;
1010         int i;
1011
1012         if (convertInfo == NULL) {
1013                 return;
1014         }
1015
1016         if ((convertInfo->dragData->protocol != DtDND_BUFFER_TRANSFER
1017              && convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER) ||
1018             (convertInfo->reason != DtCR_DND_CONVERT_DATA)) {
1019                 return;
1020         }
1021
1022         for (textptr = textdata, i = 0;
1023              i < convertInfo->dragData->numItems;
1024              textptr += strlen(textptr) + 1, i++) {
1025                 if (convertInfo->dragData->protocol == DtDND_BUFFER_TRANSFER) {
1026                         convertInfo->dragData->data.buffers[i].bp =
1027                             XtNewString(textptr);
1028                         convertInfo->dragData->data.buffers[i].size =
1029                             strlen(textptr);
1030                         convertInfo->dragData->data.buffers[i].name = NULL;
1031                 } else {
1032                         convertInfo->dragData->data.files[i] =
1033                             XtNewString(textptr);
1034                 }
1035         }
1036
1037         convertInfo->status = DtDND_SUCCESS;
1038 }
1039
1040 static Lisp_Object abort_current_drag(Lisp_Object arg)
1041 {
1042         if (CurrentDragWidget && drag_not_done) {
1043                 XmDragCancel(CurrentDragWidget);
1044                 CurrentDragWidget = NULL;
1045         }
1046         return arg;
1047 }
1048
1049 DEFUN("cde-start-drag-internal", Fcde_start_drag_internal, 3, 3, 0,     /*
1050 Start a CDE drag from a buffer.
1051 First argument is the event that started the drag (must be a
1052 button-press-event),
1053 second arg defines if the data should be treated as a buffer or
1054 a filename transfer (set to nil for buffer transfer),
1055 and the third argument is a list of data strings.
1056 WARNING: can only handle plain/text and file: transfers!
1057 */
1058       (event, dragtype, dragdata))
1059 {
1060         if (EVENTP(event)) {
1061                 struct frame *f = decode_x_frame(Fselected_frame(Qnil));
1062                 XEvent x_event;
1063                 Widget wid = FRAME_X_TEXT_WIDGET(f);
1064                 Display *display = XtDisplayOfObject(wid);
1065                 struct device *d = get_device_from_display(display);
1066                 struct x_device *xd = DEVICE_X_DATA(d);
1067                 XWindowAttributes win_attrib;
1068                 unsigned int modifier = 0, state = 0;
1069                 char *Ctext;
1070                 int numItems = 0, textlen = 0, pos = 0;
1071                 Lisp_Event *lisp_event = XEVENT(event);
1072                 Lisp_Object item = Qnil;
1073                 struct gcpro gcpro1;
1074
1075                 /* only drag if this is really a press */
1076                 if (EVENT_TYPE(lisp_event) != button_press_event
1077                     || !LISTP(dragdata))
1078                         return Qnil;
1079
1080                 GCPRO1(item);
1081
1082                 /*
1083                  * not so cross hack that converts a emacs event back to a XEvent
1084                  */
1085
1086                 x_event.xbutton.type = ButtonPress;
1087                 x_event.xbutton.send_event = False;
1088                 x_event.xbutton.display = XtDisplayOfObject(wid);
1089                 x_event.xbutton.window = XtWindowOfObject(wid);
1090                 x_event.xbutton.root = XRootWindow(x_event.xbutton.display, 0);
1091                 x_event.xbutton.subwindow = 0;
1092                 x_event.xbutton.time = lisp_event->timestamp;
1093                 x_event.xbutton.x = lisp_event->event.button.x;
1094                 x_event.xbutton.y = lisp_event->event.button.y;
1095                 if (Success == XGetWindowAttributes(x_event.xbutton.display,
1096                                                     x_event.xbutton.window,
1097                                                     &win_attrib)) {
1098                         x_event.xbutton.x_root =
1099                             win_attrib.x + lisp_event->event.button.x;
1100                         x_event.xbutton.y_root =
1101                             win_attrib.y + lisp_event->event.button.y;
1102                 } else {
1103                         x_event.xbutton.x_root = lisp_event->event.button.x;    /* this is wrong */
1104                         x_event.xbutton.y_root = lisp_event->event.button.y;
1105                 }
1106                 modifier = lisp_event->event.button.modifiers;
1107                 if (modifier & XEMACS_MOD_SHIFT)
1108                         state |= ShiftMask;
1109                 if (modifier & XEMACS_MOD_CONTROL)
1110                         state |= ControlMask;
1111                 if (modifier & XEMACS_MOD_META)
1112                         state |= xd->MetaMask;
1113                 if (modifier & XEMACS_MOD_SUPER)
1114                         state |= xd->SuperMask;
1115                 if (modifier & XEMACS_MOD_HYPER)
1116                         state |= xd->HyperMask;
1117                 if (modifier & XEMACS_MOD_ALT)
1118                         state |= xd->AltMask;
1119                 state |= Button1Mask << (lisp_event->event.button.button - 1);
1120
1121                 x_event.xbutton.state = state;
1122                 x_event.xbutton.button = lisp_event->event.button.button;
1123                 x_event.xkey.same_screen = True;
1124
1125                 /* convert data strings into a big string */
1126                 item = dragdata;
1127                 while (!NILP(item)) {
1128                         if (!STRINGP(XCAR(item))) {
1129                                 numItems = 0;
1130                                 break;
1131                         }
1132                         textlen += XSTRING_LENGTH(XCAR(item)) + 1;
1133                         numItems++;
1134                         item = XCDR(item);
1135                 }
1136
1137                 if (numItems) {
1138                         /*
1139                          * concatenate all strings given to one large string, with
1140                          * \0 as separator. List is ended by \0.
1141                          */
1142                         Ctext = (char*)xmalloc_atomic(textlen + 1);
1143                         Ctext[0] = 0;
1144
1145                         item = dragdata;
1146                         while (!NILP(item)) {
1147                                 if (!STRINGP(XCAR(item))) {
1148                                         numItems = 0;
1149                                         xfree(Ctext);
1150                                         Ctext = NULL;
1151                                         break;
1152                                 }
1153                                 strcpy(Ctext + pos,
1154                                        (const char *)XSTRING_DATA(XCAR(item)));
1155                                 pos += XSTRING_LENGTH(XCAR(item)) + 1;
1156                                 item = XCDR(item);
1157                         }
1158                         Ctext[pos] = 0;
1159
1160                         dnd_convert_cb_rec[0].callback = x_cde_convert_callback;
1161                         dnd_convert_cb_rec[0].closure = (XtPointer) Ctext;
1162                         dnd_convert_cb_rec[1].callback = NULL;
1163                         dnd_convert_cb_rec[1].closure = NULL;
1164
1165                         dnd_destroy_cb_rec[0].callback = x_cde_destroy_callback;
1166                         dnd_destroy_cb_rec[0].closure = (XtPointer) Ctext;
1167                         dnd_destroy_cb_rec[1].callback = NULL;
1168                         dnd_destroy_cb_rec[1].closure = NULL;
1169
1170                         CurrentDragWidget =
1171                             DtDndDragStart(wid, &x_event,
1172                                            (NILP(dragtype) ?
1173                                             DtDND_BUFFER_TRANSFER :
1174                                             DtDND_FILENAME_TRANSFER), numItems,
1175                                            XmDROP_COPY, dnd_convert_cb_rec,
1176                                            dnd_destroy_cb_rec, NULL, 0);
1177                 }
1178
1179                 UNGCPRO;
1180
1181                 return numItems ? Qt : Qnil;
1182         }
1183
1184         return Qnil;
1185 }
1186
1187 static void
1188 x_cde_transfer_callback(Widget widget, XtPointer clientData, XtPointer callData)
1189 {
1190         char *filePath, *hurl;
1191         int ii, enqueue = 1;
1192         Lisp_Object frame = Qnil;
1193         Lisp_Object l_type = Qnil;
1194         Lisp_Object l_data = Qnil;
1195         DtDndTransferCallbackStruct *transferInfo = NULL;
1196         struct gcpro gcpro1, gcpro2, gcpro3;
1197
1198         /*
1199            this needs to be changed to the new protocol:
1200            - we need the button, modifier and pointer states to create a
1201            correct misc_user_event
1202            - the data must be converted to the new format (URL/MIME)
1203          */
1204         /* return; */
1205
1206         transferInfo = (DtDndTransferCallbackStruct *) callData;
1207         if (transferInfo == NULL)
1208                 return;
1209
1210         GCPRO3(frame, l_type, l_data);
1211
1212         frame = make_frame((struct frame *)clientData);
1213
1214         if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER) {
1215                 l_type = Qdragdrop_URL;
1216
1217                 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
1218                         filePath = transferInfo->dropData->data.files[ii];
1219                         hurl = dnd_url_hexify_string((char *)filePath, "file:");
1220                         /* #### Mule-izing required */
1221                         l_data = Fcons(make_string((Bufbyte *) hurl,
1222                                                    strlen(hurl)), l_data);
1223                         xfree(hurl);
1224                 }
1225         } else if (transferInfo->dropData->protocol == DtDND_BUFFER_TRANSFER) {
1226                 int speccount = specpdl_depth();
1227
1228                 /* Problem: all buffers a treated as text/plain!!!
1229                    Solution: Also support DtDND_TEXT_TRANSFER
1230                    perhaps implementation of the Motif protocol
1231                    (which is the base of CDE) will clear this */
1232                 l_type = Qdragdrop_MIME;
1233                 record_unwind_protect(abort_current_drag, Qnil);
1234                 drag_not_done = 1;
1235                 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
1236                         /* let us forget this name thing for now... */
1237                         /* filePath = transferInfo->dropData->data.buffers[ii].name;
1238                            path = (filePath == NULL) ? Qnil
1239                            : make_string ((Bufbyte *)filePath, strlen (filePath)); */
1240                         /* what, if the data is no text, and how can I tell it? */
1241                         l_data =
1242                             Fcons(list3
1243                                   (list1
1244                                    (make_string((Bufbyte *) "text/plain", 10)),
1245                                    make_string((Bufbyte *) "8bit", 4),
1246                                    make_string((Bufbyte *) transferInfo->
1247                                                dropData->data.buffers[ii].bp,
1248                                                transferInfo->dropData->data.
1249                                                buffers[ii].size)), l_data);
1250                 }
1251                 drag_not_done = 0;
1252                 unbind_to(speccount, Qnil);
1253         } else                  /* the other cases: NOOP_TRANSFER */
1254                 enqueue = 0;
1255
1256         /* The Problem: no button and mods from CDE... */
1257         if (enqueue)
1258                 enqueue_misc_user_event_pos(frame, Qdragdrop_drop_dispatch,
1259                                             Fcons(l_type, l_data),
1260                                             0 /* this is the button */ ,
1261                                             0 /* these are the mods */ ,
1262                                             transferInfo->x, transferInfo->y);
1263
1264         UNGCPRO;
1265         return;
1266 }
1267 #endif                          /* HAVE_CDE */
1268
1269 \f
1270 /************************************************************************/
1271 /*                              widget creation                         */
1272 /************************************************************************/
1273
1274 /* The widget hierarchy is
1275
1276         argv[0]                 shell           container       FRAME-NAME
1277         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1278
1279    We accept geometry specs in this order:
1280
1281         *FRAME-NAME.geometry
1282         *EmacsFrame.geometry
1283         Emacs.geometry
1284
1285    Other possibilities for widget hierarchies might be
1286
1287         argv[0]                 frame           container       FRAME-NAME
1288         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1289    or
1290         argv[0]                 FRAME-NAME      container       FRAME-NAME
1291         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1292    or
1293         argv[0]                 FRAME-NAME      container       emacsTextPane
1294         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1295
1296 #ifdef EXTERNAL_WIDGET
1297    The ExternalShell widget is simply a replacement for the Shell widget
1298    which is able to deal with using an externally-supplied window instead
1299    of always creating its own.
1300 #endif
1301
1302 */
1303
1304 #ifdef EXTERNAL_WIDGET
1305
1306 static int is_valid_window(Window w, struct device *d)
1307 {
1308         XWindowAttributes xwa;
1309         Display *dpy = DEVICE_X_DISPLAY(d);
1310
1311         expect_x_error(dpy);
1312         XGetWindowAttributes(dpy, w, &xwa);
1313         return !x_error_occurred_p(dpy);
1314 }
1315
1316 #endif                          /* EXTERNAL_WIDGET */
1317
1318 /* This sends a synthetic mouse-motion event to the frame, if the mouse
1319    is over the frame.  This ensures that the cursor gets set properly
1320    before the user moves the mouse for the first time. */
1321
1322 static void x_send_synthetic_mouse_event(struct frame *f)
1323 {
1324         /* #### write this function. */
1325 }
1326
1327 static int first_x_frame_p(struct frame *f)
1328 {
1329         Lisp_Object rest = DEVICE_FRAME_LIST(XDEVICE(f->device));
1330         while (!NILP(rest) &&
1331                (f == XFRAME(XCAR(rest)) || !FRAME_X_P(XFRAME(XCAR(rest)))))
1332                 rest = XCDR(rest);
1333         return NILP(rest);
1334 }
1335
1336 /* Figure out what size the EmacsFrame widget should initially be,
1337    and set it.  Should be called after the default font has been
1338    determined but before the widget has been realized. */
1339
1340 static void x_initialize_frame_size(struct frame *f)
1341 {
1342         /* Geometry of the AppShell */
1343         int app_flags = 0;
1344         int app_x = 0;
1345         int app_y = 0;
1346         unsigned int app_w = 0;
1347         unsigned int app_h = 0;
1348
1349         /* Geometry of the EmacsFrame */
1350         int frame_flags = 0;
1351         int frame_x = 0;
1352         int frame_y = 0;
1353         unsigned int frame_w = 0;
1354         unsigned int frame_h = 0;
1355
1356         /* Hairily merged geometry */
1357         int x = 0;
1358         int y = 0;
1359         unsigned int w = 80;
1360         unsigned int h = 40;
1361         int flags = 0;
1362
1363         char *geom = 0, *ew_geom = 0;
1364         Boolean iconic_p = False, ew_iconic_p = False;
1365
1366         Widget wmshell = FRAME_X_SHELL_WIDGET(f);
1367         /* #### This may not be an ApplicationShell any more, with the 'popup
1368            frame property. */
1369         Widget app_shell = XtParent(wmshell);
1370         Widget ew = FRAME_X_TEXT_WIDGET(f);
1371
1372 /* set the position of the frame's root window now.  When the
1373    frame was created, the position was initialized to (0,0). */
1374         {
1375                 struct window *win = XWINDOW(f->root_window);
1376
1377                 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f)
1378                     + FRAME_LEFT_GUTTER_BOUNDS(f);
1379                 WINDOW_TOP(win) = FRAME_TOP_BORDER_END(f)
1380                     + FRAME_TOP_GUTTER_BOUNDS(f);
1381
1382                 if (!NILP(f->minibuffer_window)) {
1383                         win = XWINDOW(f->minibuffer_window);
1384                         WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f)
1385                             + FRAME_LEFT_GUTTER_BOUNDS(f);
1386                 }
1387         }
1388
1389 #ifdef EXTERNAL_WIDGET
1390         /* If we're an external widget, then the size of the frame is predetermined
1391            (by the client) and is not our decision to make. */
1392         if (FRAME_X_EXTERNAL_WINDOW_P(f))
1393                 return;
1394 #endif
1395
1396 #if 0
1397         /* #### this junk has not been tested; therefore it's
1398            probably wrong.  Doesn't really matter at this point because
1399            currently all frames are either top-level or external widgets. */
1400
1401         /* If we're not our own top-level window, then we shouldn't go messing around
1402            with top-level shells or "Emacs.geometry" or any such stuff.  Therefore,
1403            we do as follows to determine the size of the frame:
1404
1405            1) If a value for the frame's "geometry" resource was specified, then
1406            use it.  (This specifies a size in characters.)
1407            2) Else, if the "width" and "height" resources were specified, then
1408            leave them alone.  (This is a value in pixels.  Sorry, we can't break
1409            Xt conventions here.)
1410            3) Else, assume a size of 64x12.  (This is somewhat arbitrary, but
1411            it's unlikely that a size of 80x40 is desirable because we're probably
1412            inside of a dialog box.)
1413
1414            Set the widget's x, y, height, and width as determined.  Don't set the
1415            top-level container widget, because we don't necessarily know what it
1416            is. (Assume it is smart and pays attention to our values.)
1417          */
1418
1419         if (!FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1420                 Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1421                 if (ew_geom)
1422                         frame_flags = XParseGeometry(ew_geom,
1423                                                      &frame_x, &frame_y,
1424                                                      &frame_w, &frame_h);
1425                 if (!(frame_flags & (WidthValue | HeightValue))) {
1426                         Arg al[2];
1427                         XtSetArg(al[0], XtNwidth, &frame_w);
1428                         XtSetArg(al[1], XtNheight, &frame_h);
1429                         XtGetValues(ew, al, 2);
1430                         if (!frame_w && !frame_h) {
1431                                 frame_w = 64;
1432                                 frame_h = 12;
1433                                 frame_flags |= WidthValue | HeightValue;
1434                         }
1435                 }
1436                 if (frame_flags & (WidthValue | HeightValue))
1437                         EmacsFrameSetCharSize(ew, frame_w, frame_h);
1438                 if (frame_flags & (XValue | YValue)) {
1439                         Arg al[2];
1440                         XtSetArg(al[0], XtNwidth, &frame_w);
1441                         XtSetArg(al[1], XtNheight, &frame_h);
1442                         XtGetValues(ew, al, 2);
1443
1444                         if (frame_flags & XNegative)
1445                                 frame_x += frame_w;
1446                         if (frame_flags & YNegative)
1447                                 frame_y += frame_h;
1448
1449                         XtSetArg(al[0], XtNx, frame_x);
1450                         XtSetArg(al[1], XtNy, frame_y);
1451                         XtSetValues(ew, al, 2);
1452                 }
1453                 return;
1454         }
1455 #endif
1456
1457         /* OK, we're a top-level shell. */
1458
1459         if (!XtIsWMShell(wmshell))
1460                 abort();
1461
1462         /* If the EmacsFrame doesn't have a geometry but the shell does,
1463            treat that as the geometry of the frame.
1464            (Is this bogus? I'm not sure.) */
1465
1466         Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1467         if (!ew_geom) {
1468                 Xt_GET_VALUE(wmshell, XtNgeometry, &geom);
1469                 if (geom) {
1470                         ew_geom = geom;
1471                         Xt_SET_VALUE(ew, XtNgeometry, ew_geom);
1472                 }
1473         }
1474
1475         /* If the Shell is iconic, then the EmacsFrame is iconic.
1476            (Is this bogus? I'm not sure.) */
1477         Xt_GET_VALUE(ew, XtNiconic, &ew_iconic_p);
1478         if (!ew_iconic_p) {
1479                 Xt_GET_VALUE(wmshell, XtNiconic, &iconic_p);
1480                 if (iconic_p) {
1481                         ew_iconic_p = iconic_p;
1482                         Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1483                 }
1484         }
1485
1486         Xt_GET_VALUE(app_shell, XtNgeometry, &geom);
1487         if (geom)
1488                 app_flags =
1489                     XParseGeometry(geom, &app_x, &app_y, &app_w, &app_h);
1490
1491         if (ew_geom)
1492                 frame_flags = XParseGeometry(ew_geom,
1493                                              &frame_x, &frame_y,
1494                                              &frame_w, &frame_h);
1495
1496         if (first_x_frame_p(f)) {
1497                 /* If this is the first frame created:
1498                    ====================================
1499
1500                    - Use the ApplicationShell's size/position, if specified.
1501                    (This is "Emacs.geometry", or the "-geometry" command line arg.)
1502                    - Else use the EmacsFrame's size/position.
1503                    (This is "*FRAME-NAME.geometry")
1504
1505                    - If the AppShell is iconic, the frame should be iconic.
1506
1507                    AppShell comes first so that -geometry always applies to the first
1508                    frame created, even if there is an "every frame" entry in the
1509                    resource database.
1510                  */
1511                 if (app_flags & (XValue | YValue)) {
1512                         x = app_x;
1513                         y = app_y;
1514                         flags |=
1515                             (app_flags &
1516                              (XValue | YValue | XNegative | YNegative));
1517                 } else if (frame_flags & (XValue | YValue)) {
1518                         x = frame_x;
1519                         y = frame_y;
1520                         flags |=
1521                             (frame_flags &
1522                              (XValue | YValue | XNegative | YNegative));
1523                 }
1524
1525                 if (app_flags & (WidthValue | HeightValue)) {
1526                         w = app_w;
1527                         h = app_h;
1528                         flags |= (app_flags & (WidthValue | HeightValue));
1529                 } else if (frame_flags & (WidthValue | HeightValue)) {
1530                         w = frame_w;
1531                         h = frame_h;
1532                         flags |= (frame_flags & (WidthValue | HeightValue));
1533                 }
1534
1535                 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1536                 if (!ew_iconic_p) {
1537                         Xt_GET_VALUE(app_shell, XtNiconic, &iconic_p);
1538                         if (iconic_p) {
1539                                 ew_iconic_p = iconic_p;
1540                                 Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1541                         }
1542                 }
1543         } else {
1544                 /* If this is not the first frame created:
1545                    ========================================
1546
1547                    - use the EmacsFrame's size/position if specified
1548                    - Otherwise, use the ApplicationShell's size, but not position.
1549
1550                    So that means that one can specify the position of the first frame
1551                    with "Emacs.geometry" or `-geometry'; but can only specify the
1552                    position of subsequent frames with "*FRAME-NAME.geometry".
1553
1554                    AppShell comes second so that -geometry does not apply to subsequent
1555                    frames when there is an "every frame" entry in the resource db,
1556                    but does apply to the first frame.
1557                  */
1558                 if (frame_flags & (XValue | YValue)) {
1559                         x = frame_x;
1560                         y = frame_y;
1561                         flags |=
1562                             (frame_flags &
1563                              (XValue | YValue | XNegative | YNegative));
1564                 }
1565
1566                 if (frame_flags & (WidthValue | HeightValue)) {
1567                         w = frame_w;
1568                         h = frame_h;
1569                         flags |= (frame_flags & (WidthValue | HeightValue));
1570                 } else if (app_flags & (WidthValue | HeightValue)) {
1571                         w = app_w;
1572                         h = app_h;
1573                         flags |= (app_flags & (WidthValue | HeightValue));
1574                 }
1575         }
1576
1577         x_set_initial_frame_size(f, flags, x, y, w, h);
1578 }
1579
1580 static void x_get_layout_sizes(struct frame *f, Dimension * topbreadth)
1581 {
1582         int i;
1583
1584         /* compute height of all top-area widgets */
1585         for (i = 0, *topbreadth = 0; i < FRAME_X_NUM_TOP_WIDGETS(f); i++) {
1586                 Widget wid = FRAME_X_TOP_WIDGETS(f)[i];
1587                 if (wid && XtIsManaged(wid))
1588                         *topbreadth +=
1589                             wid->core.height + 2 * wid->core.border_width;
1590         }
1591 }
1592
1593 static void
1594 x_layout_widgets(Widget w, XtPointer client_data, XtPointer call_data)
1595 {
1596         struct frame *f = (struct frame *)client_data;
1597         EmacsManagerResizeStruct *emst = (EmacsManagerResizeStruct *) call_data;
1598         Dimension width = emst->width;
1599         Dimension height = emst->height;
1600         Widget text = FRAME_X_TEXT_WIDGET(f);
1601         Dimension textbord = text->core.border_width;
1602         Dimension topbreadth;
1603         Position text_x = 0, text_y = 0;
1604         int i;
1605
1606         x_get_layout_sizes(f, &topbreadth);
1607
1608         /* first the menubar and psheets ... */
1609         for (i = 0; i < FRAME_X_NUM_TOP_WIDGETS(f); i++) {
1610                 Widget wid = FRAME_X_TOP_WIDGETS(f)[i];
1611                 if (wid && XtIsManaged(wid)) {
1612                         Dimension bord = wid->core.border_width;
1613                         XtConfigureWidget(wid, 0, text_y,
1614                                           width - 2 * bord, wid->core.height,
1615                                           bord);
1616                         text_y += wid->core.height + 2 * bord;
1617                 }
1618         }
1619
1620 #ifdef HAVE_SCROLLBARS
1621         f->scrollbar_y_offset = topbreadth + textbord;
1622 #endif
1623
1624         /* finally the text area */
1625         {
1626                 Dimension nw = width - 2 * textbord;
1627                 Dimension nh = height - text_y - 2 * textbord;
1628
1629                 if (nh != f->pixheight || nw != f->pixwidth)
1630                         MARK_FRAME_SIZE_SLIPPED(f);
1631                 XtConfigureWidget(text, text_x, text_y, nw, nh, textbord);
1632         }
1633 }
1634
1635 static void
1636 x_do_query_geometry(Widget w, XtPointer client_data, XtPointer call_data)
1637 {
1638         struct frame *f = (struct frame *)client_data;
1639         EmacsManagerQueryGeometryStruct *emst =
1640             (EmacsManagerQueryGeometryStruct *) call_data;
1641         Widget text = FRAME_X_TEXT_WIDGET(f);
1642         Dimension textbord = text->core.border_width;
1643         Dimension topbreadth;
1644         XtWidgetGeometry req, repl;
1645         int mask = emst->request_mode & (CWWidth | CWHeight);
1646
1647         x_get_layout_sizes(f, &topbreadth);
1648
1649         /* Strip away menubar from suggested size, and ask the text widget
1650            what size it wants to be.  */
1651         req.request_mode = mask;
1652         if (mask & CWWidth)
1653                 req.width = emst->proposed_width - 2 * textbord;
1654         if (mask & CWHeight)
1655                 req.height = emst->proposed_height - topbreadth - 2 * textbord;
1656         XtQueryGeometry(text, &req, &repl);
1657
1658         /* Now add the menubar back again */
1659         emst->proposed_width = repl.width + 2 * textbord;
1660         emst->proposed_height = repl.height + topbreadth + 2 * textbord;
1661 }
1662
1663 /* Creates the widgets for a frame.
1664    lisp_window_id is a Lisp description of an X window or Xt
1665    widget to parse.
1666    parent is a frame to use as the parent.
1667    overridep if non-nil says to set the override-redirect setting.
1668
1669    This function does not create or map the windows.  (That is
1670    done by x_popup_frame().)
1671  */
1672 static void
1673 x_create_widgets(struct frame *f, Lisp_Object lisp_window_id,
1674                  Lisp_Object parent, Lisp_Object overridep)
1675 {
1676         struct device *d = XDEVICE(f->device);
1677         Visual *visual = DEVICE_X_VISUAL(d);
1678         int depth = DEVICE_X_DEPTH(d);
1679         Colormap cmap = DEVICE_X_COLORMAP(d);
1680 #ifdef EXTERNAL_WIDGET
1681         Window window_id = 0;
1682 #endif
1683         const char *name;
1684         Arg al[25];
1685         int ac = 0;
1686         Widget text, container, shell;
1687         Widget parentwid = 0;
1688 #ifdef HAVE_MENUBARS
1689         int menubar_visible;
1690         Widget menubar;
1691 #endif
1692
1693         if (STRINGP(f->name))
1694                 LISP_STRING_TO_EXTERNAL(f->name, name, Qctext);
1695         else
1696                 name = "emacs";
1697
1698         /* The widget hierarchy is
1699
1700            argv[0]                    shell           pane            FRAME-NAME
1701            ApplicationShell   EmacsShell      EmacsManager    EmacsFrame
1702
1703            (the type of the shell is ExternalShell if this frame is running
1704            in another client's window)
1705
1706            However the EmacsShell widget has WM_CLASS of FRAME-NAME/Emacs.
1707            Normally such shells have name/class shellname/appclass, which in this
1708            case would be "shell/Emacs" instead of "frame-name/Emacs".  We could
1709            also get around this by naming the shell "frame-name", but that would
1710            be confusing because the text area (the EmacsFrame widget inferior of
1711            the shell) is also called that.  So we just set the WM_CLASS property.
1712          */
1713
1714 #ifndef EXTERNAL_WIDGET
1715         if (!NILP(lisp_window_id))
1716                 error
1717                     ("support for external widgets was not enabled at compile-time");
1718 #else
1719         if (!NILP(lisp_window_id)) {
1720                 char *string;
1721
1722                 CHECK_STRING(lisp_window_id);
1723                 string = (char *)XSTRING_DATA(lisp_window_id);
1724                 if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
1725                         sscanf(string + 2, "%lxu", &window_id);
1726 #if 0
1727                 else if (string[0] == 'w') {
1728                         sscanf(string + 1, "%x", &parent_widget);
1729                         if (parent_widget)
1730                                 window_id = XtWindow(parent_widget);
1731                 }
1732 #endif
1733                 else
1734                         sscanf(string, "%lu", &window_id);
1735                 if (!is_valid_window(window_id, d))
1736                         error("Invalid window %lu", (unsigned long)window_id);
1737                 FRAME_X_EXTERNAL_WINDOW_P(f) = 1;
1738         } else
1739 #endif                          /* EXTERNAL_WIDGET */
1740                 FRAME_X_TOP_LEVEL_FRAME_P(f) = 1;
1741
1742         ac = 0;
1743         XtSetArg(al[ac], XtNallowShellResize, True);
1744         ac++;
1745 #ifdef LWLIB_USES_MOTIF
1746         /* Motif sucks beans.  Without this in here, it will delete the window
1747            out from under us when it receives a WM_DESTROY_WINDOW message
1748            from the WM. */
1749         XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING);
1750         ac++;
1751 #endif
1752
1753 #ifdef EXTERNAL_WIDGET
1754         if (window_id) {
1755                 XtSetArg(al[ac], XtNwindow, window_id);
1756                 ac++;
1757         } else
1758 #endif                          /* EXTERNAL_WIDGET */
1759         {
1760                 XtSetArg(al[ac], XtNinput, True);
1761                 ac++;
1762                 XtSetArg(al[ac], XtNminWidthCells, 10);
1763                 ac++;
1764                 XtSetArg(al[ac], XtNminHeightCells, 1);
1765                 ac++;
1766                 XtSetArg(al[ac], XtNvisual, visual);
1767                 ac++;
1768                 XtSetArg(al[ac], XtNdepth, depth);
1769                 ac++;
1770                 XtSetArg(al[ac], XtNcolormap, cmap);
1771                 ac++;
1772         }
1773
1774         if (!NILP(overridep)) {
1775                 XtSetArg(al[ac], XtNoverrideRedirect, True);
1776                 ac++;
1777         }
1778
1779         /* #### maybe we should check for FRAMEP instead? */
1780         if (!NILP(parent)) {
1781                 parentwid = FRAME_X_SHELL_WIDGET(XFRAME(parent));
1782                 XtSetArg(al[ac], XtNtransientFor, parentwid);
1783                 ac++;
1784         }
1785
1786         shell = XtCreatePopupShell("shell", (
1787 #ifdef EXTERNAL_WIDGET
1788                                                     window_id ?
1789                                                     externalShellWidgetClass :
1790 #endif
1791                                                     parentwid ?
1792                                                     transientEmacsShellWidgetClass
1793                                                     :
1794                                                     topLevelEmacsShellWidgetClass),
1795                                    parentwid ? parentwid :
1796                                    DEVICE_XT_APP_SHELL(d), al, ac);
1797         FRAME_X_SHELL_WIDGET(f) = shell;
1798         maybe_set_frame_title_format(shell);
1799
1800         /* Create the manager widget */
1801         ac = 0;
1802         XtSetArg(al[ac], XtNvisual, visual);
1803         ac++;
1804         XtSetArg(al[ac], XtNdepth, depth);
1805         ac++;
1806         XtSetArg(al[ac], XtNcolormap, cmap);
1807         ac++;
1808
1809         container = XtCreateWidget("container",
1810                                    emacsManagerWidgetClass, shell, al, ac);
1811         FRAME_X_CONTAINER_WIDGET(f) = container;
1812         XtAddCallback(container, XtNresizeCallback, x_layout_widgets,
1813                       (XtPointer) f);
1814         XtAddCallback(container, XtNqueryGeometryCallback, x_do_query_geometry,
1815                       (XtPointer) f);
1816
1817         /* Create the text area */
1818         ac = 0;
1819         XtSetArg(al[ac], XtNvisual, visual);
1820         ac++;
1821         XtSetArg(al[ac], XtNdepth, depth);
1822         ac++;
1823         XtSetArg(al[ac], XtNcolormap, cmap);
1824         ac++;
1825         XtSetArg(al[ac], XtNborderWidth, 0);
1826         ac++;                   /* should this be settable? */
1827         XtSetArg(al[ac], XtNemacsFrame, f);
1828         ac++;
1829         text = XtCreateWidget(name, emacsFrameClass, container, al, ac);
1830         FRAME_X_TEXT_WIDGET(f) = text;
1831
1832 #ifdef HAVE_MENUBARS
1833         /* Create the initial menubar widget. */
1834         menubar_visible = x_initialize_frame_menubar(f);
1835         FRAME_X_TOP_WIDGETS(f)[0] = menubar = FRAME_X_MENUBAR_WIDGET(f);
1836         FRAME_X_NUM_TOP_WIDGETS(f) = 1;
1837
1838         if (menubar_visible)
1839                 XtManageChild(menubar);
1840 #endif                          /* HAVE_MENUBARS */
1841         XtManageChild(text);
1842         XtManageChild(container);
1843 }
1844
1845 /* We used to call XtPopup() in x_popup_frame, but that doesn't give
1846    you control over whether the widget is initially mapped or not
1847    because XtPopup() makes an unconditional call to XMapRaised().
1848    Boy, those Xt designers were clever.
1849
1850    When we first removed it we only kept the XtRealizeWidget call in
1851    XtPopup.  For everything except HP's that was enough.  For HP's,
1852    though, the failure to call the popup callbacks resulted in XEmacs
1853    not accepting any input.  Bizarre but true.  Stupid but true.
1854
1855    So, in case there are any other gotchas floating out there along
1856    the same lines I've duplicated the majority of XtPopup here.  It
1857    assumes no grabs and that the widget is not already popped up, both
1858    valid assumptions for the one place this is called from. */
1859 static void xemacs_XtPopup(Widget widget)
1860 {
1861         ShellWidget shell_widget = (ShellWidget) widget;
1862         XtGrabKind call_data = XtGrabNone;
1863
1864         XtCallCallbacks(widget, XtNpopupCallback, (XtPointer) & call_data);
1865
1866         shell_widget->shell.popped_up = TRUE;
1867         shell_widget->shell.grab_kind = XtGrabNone;
1868         shell_widget->shell.spring_loaded = False;
1869
1870         if (shell_widget->shell.create_popup_child_proc != NULL)
1871                 (*(shell_widget->shell.create_popup_child_proc)) (widget);
1872
1873         /* The XtSetValues below are not in XtPopup menu.  We just want to
1874            make absolutely sure... */
1875         Xt_SET_VALUE(widget, XtNmappedWhenManaged, False);
1876         XtRealizeWidget(widget);
1877         Xt_SET_VALUE(widget, XtNmappedWhenManaged, True);
1878 }
1879
1880 /* create the windows for the specified frame and display them.
1881    Note that the widgets have already been created, and any
1882    necessary geometry calculations have already been done. */
1883 static void x_popup_frame(struct frame *f)
1884 {
1885         Widget shell_widget = FRAME_X_SHELL_WIDGET(f);
1886         Widget frame_widget = FRAME_X_TEXT_WIDGET(f);
1887         struct device *d = XDEVICE(FRAME_DEVICE(f));
1888
1889         /* Before mapping the window, make sure that the WMShell's notion of
1890            whether it should be iconified is synchronized with the EmacsFrame's
1891            notion.
1892          */
1893         if (FRAME_X_TOP_LEVEL_FRAME_P(f))
1894                 x_wm_set_shell_iconic_p(shell_widget,
1895                                         ((EmacsFrame) frame_widget)
1896                                         ->emacs_frame.iconic);
1897
1898         xemacs_XtPopup(shell_widget);
1899
1900         if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
1901                 XtMapWidget(shell_widget);
1902         else {
1903                 /* We may have set f->visible to 1 in x_init_frame(), so undo
1904                    that now. */
1905                 FRAME_X_TOTALLY_VISIBLE_P(f) = 0;
1906                 f->visible = 0;
1907         }
1908
1909 #ifdef EXTERNAL_WIDGET
1910         if (FRAME_X_EXTERNAL_WINDOW_P(f))
1911                 ExternalShellReady(shell_widget, XtWindow(frame_widget),
1912                                    KeyPressMask);
1913         else
1914 #endif
1915         if (FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1916                 /* tell the window manager about us. */
1917                 x_wm_store_class_hints(shell_widget, XtName(frame_widget));
1918
1919 #ifndef HAVE_WMCOMMAND
1920                 x_wm_maybe_store_wm_command(f);
1921 #endif                          /* HAVE_WMCOMMAND */
1922
1923                 x_wm_hack_wm_protocols(shell_widget);
1924         }
1925 #ifdef HAVE_XIM
1926         XIM_init_frame(f);
1927 #endif                          /* HAVE_XIM */
1928
1929 #ifdef HACK_EDITRES
1930         /* Allow XEmacs to respond to EditRes requests.  See the O'Reilly Xt */
1931         /* Intrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
1932         /* pp. 483-493. */
1933         XtAddEventHandler(shell_widget, /* the shell widget in question */
1934                           (EventMask) NoEventMask,      /* OR with existing mask */
1935                           True, /* called on non-maskable events? */
1936                           (XtEventHandler) _XEditResCheckMessages,      /* the handler */
1937                           NULL);
1938 #endif                          /* HACK_EDITRES */
1939
1940 #ifdef HAVE_CDE
1941         {
1942                 XtCallbackRec dnd_transfer_cb_rec[2];
1943
1944                 dnd_transfer_cb_rec[0].callback = x_cde_transfer_callback;
1945                 dnd_transfer_cb_rec[0].closure = (XtPointer) f;
1946                 dnd_transfer_cb_rec[1].callback = NULL;
1947                 dnd_transfer_cb_rec[1].closure = NULL;
1948
1949                 DtDndVaDropRegister(FRAME_X_TEXT_WIDGET(f),
1950                                     DtDND_FILENAME_TRANSFER |
1951                                     DtDND_BUFFER_TRANSFER, XmDROP_COPY,
1952                                     dnd_transfer_cb_rec, DtNtextIsBuffer, True,
1953                                     DtNregisterChildren, True,
1954                                     DtNpreserveRegistration, False, NULL);
1955         }
1956 #endif                          /* HAVE_CDE */
1957
1958         /* Do a stupid property change to force the server to generate a
1959            propertyNotify event so that the event_stream server timestamp will
1960            be initialized to something relevant to the time we created the window.
1961          */
1962         XChangeProperty(XtDisplay(frame_widget), XtWindow(frame_widget),
1963                         DEVICE_XATOM_WM_PROTOCOLS(d), XA_ATOM, 32,
1964                         PropModeAppend, (unsigned char *)NULL, 0);
1965
1966         x_send_synthetic_mouse_event(f);
1967 }
1968
1969 static void allocate_x_frame_struct(struct frame *f)
1970 {
1971         /* zero out all slots. */
1972         f->frame_data = xnew_and_zero(struct x_frame);
1973
1974         /* yeah, except the lisp ones */
1975         FRAME_X_ICON_PIXMAP(f) = Qnil;
1976         FRAME_X_ICON_PIXMAP_MASK(f) = Qnil;
1977 }
1978 \f
1979 /************************************************************************/
1980 /*                              Lisp functions                          */
1981 /************************************************************************/
1982
1983 static void x_init_frame_1(struct frame *f, Lisp_Object props)
1984 {
1985         /* This function can GC */
1986         Lisp_Object device = FRAME_DEVICE(f);
1987         Lisp_Object lisp_window_id = Fplist_get(props, Qwindow_id, Qnil);
1988         Lisp_Object popup = Fplist_get(props, Qpopup, Qnil);
1989         Lisp_Object overridep = Fplist_get (props, Qoverride_redirect, Qnil);
1990
1991         if (!NILP(popup)) {
1992                 if (EQ(popup, Qt))
1993                         popup = Fselected_frame(device);
1994                 CHECK_LIVE_FRAME(popup);
1995                 if (!EQ(device, FRAME_DEVICE(XFRAME(popup))))
1996                         signal_simple_error_2
1997                             ("Parent must be on same device as frame", device,
1998                              popup);
1999         }
2000
2001         /*
2002          * Previously we set this only if NILP (DEVICE_SELECTED_FRAME (d))
2003          * to make sure that messages were displayed as soon as possible
2004          * if we're creating the first frame on a device.  But it is
2005          * better to just set this all the time, so that when a new frame
2006          * is created that covers the selected frame, echo area status
2007          * messages can still be seen.  f->visible is reset later if the
2008          * initially-unmapped property is found to be non-nil in the
2009          * frame properties.
2010          */
2011         f->visible = 1;
2012
2013         allocate_x_frame_struct(f);
2014         x_create_widgets(f, lisp_window_id, popup, overridep);
2015 }
2016
2017 static void x_init_frame_2(struct frame *f, Lisp_Object props)
2018 {
2019         /* Set up the values of the widget/frame.  A case could be made for putting
2020            this inside of the widget's initialize method. */
2021
2022         update_frame_face_values(f);
2023         x_initialize_frame_size(f);
2024         /* Kyle:
2025          *   update_frame_title() can't be done here, because some of the
2026          *   modeline specs depend on the frame's device having a selected
2027          *   frame, and that may not have been set up yet.  The redisplay
2028          *   will update the frame title anyway, so nothing is lost.
2029          * JV:
2030          *   It turns out it gives problems with FVWMs name based mapping.
2031          *   We'll just  need to be careful in the modeline specs.
2032          */
2033         update_frame_title(f);
2034 }
2035
2036 static void x_init_frame_3(struct frame *f)
2037 {
2038         /* Pop up the frame. */
2039
2040         x_popup_frame(f);
2041 }
2042
2043 static void x_mark_frame(struct frame *f)
2044 {
2045         mark_object(FRAME_X_ICON_PIXMAP(f));
2046         mark_object(FRAME_X_ICON_PIXMAP_MASK(f));
2047 }
2048
2049 static void x_set_frame_icon(struct frame *f)
2050 {
2051         Pixmap x_pixmap, x_mask;
2052
2053         if (IMAGE_INSTANCEP(f->icon)
2054             && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(f->icon))) {
2055                 x_pixmap = XIMAGE_INSTANCE_X_PIXMAP(f->icon);
2056                 x_mask = XIMAGE_INSTANCE_X_MASK(f->icon);
2057         } else {
2058                 x_pixmap = 0;
2059                 x_mask = 0;
2060         }
2061
2062         /* Store the X data into the widget. */
2063         {
2064                 Arg al[2];
2065                 XtSetArg(al[0], XtNiconPixmap, x_pixmap);
2066                 XtSetArg(al[1], XtNiconMask, x_mask);
2067                 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
2068         }
2069 }
2070
2071 static void x_set_frame_pointer(struct frame *f)
2072 {
2073         XDefineCursor(XtDisplay(FRAME_X_TEXT_WIDGET(f)),
2074                       XtWindow(FRAME_X_TEXT_WIDGET(f)),
2075                       XIMAGE_INSTANCE_X_CURSOR(f->pointer));
2076         XSync(XtDisplay(FRAME_X_TEXT_WIDGET(f)), 0);
2077 }
2078
2079 static Lisp_Object x_get_frame_parent(struct frame *f)
2080 {
2081         Widget parentwid = 0;
2082
2083         Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNtransientFor, &parentwid);
2084         /* find the frame whose wid is parentwid */
2085         if (parentwid) {
2086                 Lisp_Object frmcons;
2087                 DEVICE_FRAME_LOOP(frmcons, XDEVICE(FRAME_DEVICE(f))) {
2088                         Lisp_Object frame = XCAR(frmcons);
2089                         if (FRAME_X_SHELL_WIDGET(XFRAME(frame)) == parentwid)
2090                                 return frame;
2091                 }
2092         }
2093         return Qnil;
2094 }
2095
2096 DEFUN("x-window-id", Fx_window_id, 0, 1, 0,     /*
2097 Get the ID of the X11 window.
2098 This gives us a chance to manipulate the Emacs window from within a
2099 different program.  Since the ID is an unsigned long, we return it as
2100 a string.
2101 */
2102       (frame))
2103 {
2104         char str[255];
2105         struct frame *f = decode_x_frame(frame);
2106
2107         int sz = snprintf(str, sizeof(str), "%lu", XtWindow(FRAME_X_TEXT_WIDGET(f)));
2108         assert(sz >= 0 && (size_t)sz < sizeof(str));
2109         return build_string(str);
2110 }
2111 \f
2112 /************************************************************************/
2113 /*                      manipulating the X window                       */
2114 /************************************************************************/
2115
2116 static void x_set_frame_position(struct frame *f, int xoff, int yoff)
2117 {
2118         Widget w = FRAME_X_SHELL_WIDGET(f);
2119         Display *dpy = XtDisplay(w);
2120         Dimension frame_w = DisplayWidth(dpy, DefaultScreen(dpy));
2121         Dimension frame_h = DisplayHeight(dpy, DefaultScreen(dpy));
2122         Dimension shell_w, shell_h, shell_bord;
2123         int win_gravity;
2124         Arg al[3];
2125
2126         XtSetArg(al[0], XtNwidth, &shell_w);
2127         XtSetArg(al[1], XtNheight, &shell_h);
2128         XtSetArg(al[2], XtNborderWidth, &shell_bord);
2129         XtGetValues(w, al, 3);
2130
2131         win_gravity =
2132             xoff >= 0 && yoff >= 0 ? NorthWestGravity :
2133             xoff >= 0 ? SouthWestGravity :
2134             yoff >= 0 ? NorthEastGravity : SouthEastGravity;
2135         if (xoff < 0)
2136                 xoff += frame_w - shell_w - 2 * shell_bord;
2137         if (yoff < 0)
2138                 yoff += frame_h - shell_h - 2 * shell_bord;
2139
2140         /* Update the hints so that, if this window is currently iconified, it will
2141            come back at the right place.  We can't look at s->visible to determine
2142            whether it is iconified because it might not be up-to-date yet (the queue
2143            might not be processed). */
2144         XtSetArg(al[0], XtNwinGravity, win_gravity);
2145         XtSetArg(al[1], XtNx, xoff);
2146         XtSetArg(al[2], XtNy, yoff);
2147         XtSetValues(w, al, 3);
2148
2149         /* Sometimes you will find that
2150
2151            (set-frame-position (selected-frame) -50 -50)
2152
2153            doesn't put the frame where you expect it to: i.e. it's closer to
2154            the lower-right corner than it should be, and it appears that the
2155            size of the WM decorations was not taken into account.  This is
2156            *not* a problem with this function.  Both mwm and twm have bugs
2157            in handling this situation. (mwm ignores the window gravity and
2158            always assumes NorthWest, except the first time you map the
2159            window; twm gets things almost right, but forgets to account for
2160            the border width of the top-level window.) This function does
2161            what it's supposed to according to the ICCCM, and I'm not about
2162            to hack around window-manager bugs. */
2163
2164 #if 0
2165         /* This is not necessary under either mwm or twm */
2166         x_wm_mark_shell_position_user_specified(w);
2167 #endif
2168 }
2169
2170 /* Call this to change the size of frame S's x-window. */
2171
2172 static void x_set_frame_size(struct frame *f, int cols, int rows)
2173 {
2174         EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), cols, rows);
2175 #if 0
2176         /* this is not correct.  x_set_frame_size() is called from
2177            Fset_frame_size(), which may or may not have been called
2178            by the user (e.g. update_EmacsFrame() calls it when the font
2179            changes).  For now, don't bother with getting this right. */
2180         x_wm_mark_shell_size_user_specified(FRAME_X_SHELL_WIDGET(f));
2181 #endif
2182 }
2183
2184 static void x_set_mouse_position(struct window *w, int x, int y)
2185 {
2186         struct frame *f = XFRAME(w->frame);
2187
2188         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2189         XWarpPointer(display, None, XtWindow(FRAME_X_TEXT_WIDGET(f)),
2190                      0, 0, 0, 0, w->pixel_left + x, w->pixel_top + y);
2191 }
2192
2193 static int
2194 x_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
2195 {
2196         Display *display = DEVICE_X_DISPLAY(d);
2197         Window child_window;
2198         Window root_window;
2199         Window win;
2200         int root_x, root_y;
2201         int win_x, win_y;
2202         unsigned int keys_and_buttons;
2203         struct frame *f;
2204
2205         if (XQueryPointer(display, RootWindow(display, DefaultScreen(display)),
2206                           &root_window, &child_window, &root_x, &root_y,
2207                           &win_x, &win_y, &keys_and_buttons) == False)
2208                 return 0;
2209
2210         if (child_window == None)
2211                 return 0;       /* not over any window. */
2212
2213         while (1) {
2214                 win = child_window;
2215                 if (XTranslateCoordinates
2216                     (display, root_window, win, root_x, root_y, &win_x, &win_y,
2217                      &child_window) == False)
2218                         /* Huh? */
2219                         return 0;
2220
2221                 if (child_window == None)
2222                         break;
2223         }
2224
2225         /* At this point, win is the innermost window containing the pointer
2226            and win_x and win_y are the coordinates of that window. */
2227         f = x_any_window_to_frame(d, win);
2228         if (!f)
2229                 return 0;
2230         XSETFRAME(*frame, f);
2231
2232         if (XTranslateCoordinates(display, win,
2233                                   XtWindow(FRAME_X_TEXT_WIDGET(f)),
2234                                   win_x, win_y, x, y, &child_window) == False)
2235                 /* Huh? */
2236                 return 0;
2237
2238         return 1;
2239 }
2240
2241 static void x_cant_notify_wm_error(void)
2242 {
2243         error("Can't notify window manager of iconification.");
2244 }
2245
2246 /* Raise frame F.  */
2247 static void x_raise_frame_1(struct frame *f, int force)
2248 {
2249         if (FRAME_VISIBLE_P(f) || force) {
2250                 Widget bottom_dialog;
2251                 XWindowChanges xwc;
2252                 unsigned int flags;
2253                 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2254                 Window emacs_window = XtWindow(FRAME_X_SHELL_WIDGET(f));
2255
2256                 /* first raises all the dialog boxes, then put emacs just below the
2257                  * bottom most dialog box */
2258                 bottom_dialog = lw_raise_all_pop_up_widgets();
2259                 if (bottom_dialog && XtWindow(bottom_dialog)) {
2260                         xwc.sibling = XtWindow(bottom_dialog);
2261                         xwc.stack_mode = Below;
2262                         flags = CWSibling | CWStackMode;
2263                 } else {
2264                         xwc.stack_mode = Above;
2265                         flags = CWStackMode;
2266                 }
2267
2268                 if (!XReconfigureWMWindow(display, emacs_window,
2269                                           DefaultScreen(display), flags, &xwc))
2270                         x_cant_notify_wm_error();
2271         }
2272 }
2273
2274 static void x_raise_frame(struct frame *f)
2275 {
2276         x_raise_frame_1(f, 1);
2277 }
2278
2279 /* Lower frame F.  */
2280 static void x_lower_frame(struct frame *f)
2281 {
2282         if (FRAME_VISIBLE_P(f)) {
2283                 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2284                 XWindowChanges xwc;
2285                 unsigned int flags = CWStackMode;
2286
2287                 xwc.stack_mode = Below;
2288                 if (!XReconfigureWMWindow
2289                     (display, XtWindow(FRAME_X_SHELL_WIDGET(f)),
2290                      DefaultScreen(display), flags, &xwc))
2291                         x_cant_notify_wm_error();
2292         }
2293 }
2294
2295 static void x_enable_frame(struct frame *f)
2296 {
2297         XtSetSensitive(FRAME_X_SHELL_WIDGET(f), True);
2298 }
2299
2300 static void x_disable_frame(struct frame *f)
2301 {
2302         XtSetSensitive(FRAME_X_SHELL_WIDGET(f), False);
2303 }
2304
2305 /* Change from withdrawn state to mapped state. */
2306 static void x_make_frame_visible(struct frame *f)
2307 {
2308         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2309
2310         if (!FRAME_VISIBLE_P(f))
2311                 XMapRaised(display, XtWindow(FRAME_X_SHELL_WIDGET(f)));
2312         else
2313                 x_raise_frame_1(f, 0);
2314 }
2315
2316 /* Change from mapped state to withdrawn state. */
2317 static void x_make_frame_invisible(struct frame *f)
2318 {
2319         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2320
2321         if (!FRAME_VISIBLE_P(f))
2322                 return;
2323
2324         if (!XWithdrawWindow(display,
2325                              XtWindow(FRAME_X_SHELL_WIDGET(f)),
2326                              DefaultScreen(display)))
2327                 x_cant_notify_wm_error();
2328 }
2329
2330 static int x_frame_visible_p(struct frame *f)
2331 {
2332 #if 0
2333         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2334         XWindowAttributes xwa;
2335         int result;
2336
2337         /* JV:
2338            This is bad, very bad :-(
2339            It is not compatible with our tristate visible and
2340            it should never ever change the visibility for us, this leads to
2341            the frame-freeze problem under fvwm because with the pager
2342
2343            Mappedness != Viewability != Visibility != Emacs f->visible
2344
2345            This first unequalness is the reason for the frame freezing problem
2346            under fvwm (it happens when the frame is another fvwm-page)
2347
2348            The second unequalness happen when it is on the same fvwm-page
2349            but in an invisible part of the visible screen.
2350
2351            For now we just return the XEmacs internal value --- which might not be up
2352            to date. Is that a problem? ---. Otherwise we should
2353            use async visibility like in standard Emacs.
2354          */
2355
2356         if (!XGetWindowAttributes(display,
2357                                   XtWindow(FRAME_X_SHELL_WIDGET(f)), &xwa))
2358                 result = 0;
2359         else
2360                 result = xwa.map_state == IsViewable;
2361         /* In this implementation it should at least be != IsUnmapped
2362            JV */
2363
2364         f->visible = result;
2365         return result;
2366 #endif                          /* 0 */
2367
2368         return f->visible;
2369 }
2370
2371 static int x_frame_totally_visible_p(struct frame *f)
2372 {
2373         return FRAME_X_TOTALLY_VISIBLE_P(f);
2374 }
2375
2376 /* Change window state from mapped to iconified. */
2377 static void x_iconify_frame(struct frame *f)
2378 {
2379         Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2380
2381         if (!XIconifyWindow(display,
2382                             XtWindow(FRAME_X_SHELL_WIDGET(f)),
2383                             DefaultScreen(display)))
2384                 x_cant_notify_wm_error();
2385
2386         f->iconified = 1;
2387 }
2388
2389 /* Sets the X focus to frame f. */
2390 static void x_focus_on_frame(struct frame *f)
2391 {
2392         XWindowAttributes xwa;
2393         Widget shell_widget;
2394         int viewable = 0;
2395
2396         assert(FRAME_X_P(f));
2397
2398         shell_widget = FRAME_X_SHELL_WIDGET(f);
2399         if (!XtWindow(shell_widget))
2400                 return;
2401
2402 #ifdef EXTERNAL_WIDGET
2403         if (FRAME_X_EXTERNAL_WINDOW_P(f))
2404                 ExternalShellSetFocus(shell_widget);
2405 #endif                          /* EXTERNAL_WIDGET */
2406
2407         /* Do the ICCCM focus change if the window is still visible.
2408            The s->visible flag might not be up-to-date, because we might
2409            not have processed magic events recently.  So make a server
2410            round-trip to find out whether it's really mapped right now.
2411            We grab the server to do this, because that's the only way to
2412            eliminate the race condition.
2413          */
2414         XGrabServer(XtDisplay(shell_widget));
2415         if (XGetWindowAttributes(XtDisplay(shell_widget),
2416                                  XtWindow(shell_widget), &xwa))
2417                 /* JV: it is bad to change the visibility like this, so we don't for the
2418                    moment, at least change_frame_visibility should be called
2419                    Note also that under fvwm a frame can be Viewable (and thus Mapped)
2420                    but still X-invisible
2421                    f->visible = xwa.map_state == IsViewable; */
2422                 viewable = xwa.map_state == IsViewable;
2423
2424         if (viewable) {
2425                 Window focus;
2426                 int revert_to;
2427                 XGetInputFocus(XtDisplay(shell_widget), &focus, &revert_to);
2428                 /* Don't explicitly set the focus on this window unless the focus
2429                    was on some other window (not PointerRoot).  Note that, even when
2430                    running a point-to-type window manager like *twm, there is always
2431                    a focus window; the window manager maintains that based on the
2432                    mouse position.  If you set the "NoTitleFocus" option in these
2433                    window managers, then the server itself maintains the focus via
2434                    PointerRoot, and changing that to focus on the window would make
2435                    the window grab the focus.  Very bad.
2436                  */
2437                 if (focus != PointerRoot) {
2438                         XSetInputFocus(XtDisplay(shell_widget),
2439                                        XtWindow(shell_widget),
2440                                        RevertToParent,
2441                                        DEVICE_X_MOUSE_TIMESTAMP
2442                                        (XDEVICE(FRAME_DEVICE(f))));
2443                         XFlush(XtDisplay(shell_widget));
2444                 }
2445         }
2446         XUngrabServer(XtDisplay(shell_widget));
2447         XFlush(XtDisplay(shell_widget));        /* hey, I'd like to DEBUG this... */
2448 }
2449
2450 /* Destroy the X window of frame F.  */
2451 static void x_delete_frame(struct frame *f)
2452 {
2453         Display *dpy;
2454
2455 #ifndef HAVE_WMCOMMAND
2456         if (FRAME_X_TOP_LEVEL_FRAME_P(f))
2457                 x_wm_maybe_move_wm_command(f);
2458 #endif                          /* HAVE_WMCOMMAND */
2459
2460 #ifdef HAVE_CDE
2461         DtDndDropUnregister(FRAME_X_TEXT_WIDGET(f));
2462 #endif                          /* HAVE_CDE */
2463
2464         assert(FRAME_X_SHELL_WIDGET(f) != 0);
2465         dpy = XtDisplay(FRAME_X_SHELL_WIDGET(f));
2466
2467 #ifdef EXTERNAL_WIDGET
2468         expect_x_error(dpy);
2469         /* for obscure reasons having (I think) to do with the internal
2470            window-to-widget hierarchy maintained by Xt, we have to call
2471            XtUnrealizeWidget() here.  Xt can really suck. */
2472         if (f->being_deleted)
2473                 XtUnrealizeWidget(FRAME_X_SHELL_WIDGET(f));
2474         XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2475         x_error_occurred_p(dpy);
2476 #else
2477         XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2478         /* make sure the windows are really gone! */
2479         /* #### Is this REALLY necessary? */
2480         XFlush(dpy);
2481 #endif                          /* EXTERNAL_WIDGET */
2482
2483         FRAME_X_SHELL_WIDGET(f) = 0;
2484
2485         if (FRAME_X_GEOM_FREE_ME_PLEASE(f)) {
2486                 xfree(FRAME_X_GEOM_FREE_ME_PLEASE(f));
2487                 FRAME_X_GEOM_FREE_ME_PLEASE(f) = 0;
2488         }
2489
2490         if (f->frame_data) {
2491                 xfree(f->frame_data);
2492                 f->frame_data = 0;
2493         }
2494 }
2495
2496 static void x_update_frame_external_traits(struct frame *frm, Lisp_Object name)
2497 {
2498         Arg al[10];
2499         int ac = 0;
2500         Lisp_Object frame;
2501
2502         XSETFRAME(frame, frm);
2503
2504         if (EQ(name, Qforeground)) {
2505                 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
2506                 XColor fgc;
2507
2508                 if (!EQ(color, Vthe_null_color_instance)) {
2509                         fgc = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(color));
2510                         XtSetArg(al[ac], XtNforeground, (void *)fgc.pixel);
2511                         ac++;
2512                 }
2513         } else if (EQ(name, Qbackground)) {
2514                 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
2515                 XColor bgc;
2516
2517                 if (!EQ(color, Vthe_null_color_instance)) {
2518                         bgc = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(color));
2519                         XtSetArg(al[ac], XtNbackground, (void *)bgc.pixel);
2520                         ac++;
2521                 }
2522
2523                 /* Really crappy way to force the modeline shadows to be
2524                    redrawn.  But effective. */
2525                 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED(frm);
2526                 MARK_FRAME_CHANGED(frm);
2527         } else if (EQ(name, Qfont)) {
2528                 Lisp_Object font =
2529                     FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
2530
2531                 if (!EQ(font, Vthe_null_font_instance)) {
2532                         XtSetArg(al[ac], XtNfont,
2533                                  (void *)
2534                                  FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font)));
2535                         ac++;
2536                 }
2537         } else
2538                 abort();
2539
2540         XtSetValues(FRAME_X_TEXT_WIDGET(frm), al, ac);
2541
2542 #ifdef HAVE_TOOLBARS
2543         /* Setting the background clears the entire frame area
2544            including the toolbar so we force an immediate redraw of
2545            it. */
2546         if (EQ(name, Qbackground))
2547                 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
2548                               (frm));
2549 #endif                          /* HAVE_TOOLBARS */
2550
2551         /* Set window manager resize increment hints according to
2552            the new character size */
2553         if (EQ(name, Qfont))
2554                 EmacsFrameRecomputeCellSize(FRAME_X_TEXT_WIDGET(frm));
2555 }
2556 \f
2557 /************************************************************************/
2558 /*                            initialization                            */
2559 /************************************************************************/
2560
2561 void syms_of_frame_x(void)
2562 {
2563         defsymbol(&Qwindow_id, "window-id");
2564         defsymbol(&Qoverride_redirect, "override-redirect");
2565         defsymbol(&Qx_resource_name, "x-resource-name");
2566
2567         DEFSUBR(Fx_window_id);
2568 #ifdef HAVE_CDE
2569         DEFSUBR(Fcde_start_drag_internal);
2570 #endif
2571 }
2572
2573 void console_type_create_frame_x(void)
2574 {
2575         /* frame methods */
2576         CONSOLE_HAS_METHOD(x, init_frame_1);
2577         CONSOLE_HAS_METHOD(x, init_frame_2);
2578         CONSOLE_HAS_METHOD(x, init_frame_3);
2579         CONSOLE_HAS_METHOD(x, mark_frame);
2580         CONSOLE_HAS_METHOD(x, focus_on_frame);
2581         CONSOLE_HAS_METHOD(x, delete_frame);
2582         CONSOLE_HAS_METHOD(x, get_mouse_position);
2583         CONSOLE_HAS_METHOD(x, set_mouse_position);
2584         CONSOLE_HAS_METHOD(x, raise_frame);
2585         CONSOLE_HAS_METHOD(x, lower_frame);
2586         CONSOLE_HAS_METHOD(x, enable_frame);
2587         CONSOLE_HAS_METHOD(x, disable_frame);
2588         CONSOLE_HAS_METHOD(x, make_frame_visible);
2589         CONSOLE_HAS_METHOD(x, make_frame_invisible);
2590         CONSOLE_HAS_METHOD(x, iconify_frame);
2591         CONSOLE_HAS_METHOD(x, set_frame_size);
2592         CONSOLE_HAS_METHOD(x, set_frame_position);
2593         CONSOLE_HAS_METHOD(x, frame_property);
2594         CONSOLE_HAS_METHOD(x, internal_frame_property_p);
2595         CONSOLE_HAS_METHOD(x, frame_properties);
2596         CONSOLE_HAS_METHOD(x, set_frame_properties);
2597         CONSOLE_HAS_METHOD(x, set_title_from_bufbyte);
2598         CONSOLE_HAS_METHOD(x, set_icon_name_from_bufbyte);
2599         CONSOLE_HAS_METHOD(x, frame_visible_p);
2600         CONSOLE_HAS_METHOD(x, frame_totally_visible_p);
2601         CONSOLE_HAS_METHOD(x, frame_iconified_p);
2602         CONSOLE_HAS_METHOD(x, set_frame_pointer);
2603         CONSOLE_HAS_METHOD(x, set_frame_icon);
2604         CONSOLE_HAS_METHOD(x, get_frame_parent);
2605         CONSOLE_HAS_METHOD(x, update_frame_external_traits);
2606 }
2607
2608 void vars_of_frame_x(void)
2609 {
2610 #ifdef EXTERNAL_WIDGET
2611         Fprovide(intern("external-widget"));
2612 #endif
2613
2614         /* this call uses only safe functions from emacs.c */
2615         init_x_prop_symbols();
2616
2617         DEFVAR_LISP("default-x-frame-plist", &Vdefault_x_frame_plist    /*
2618 Plist of default frame-creation properties for X frames.
2619 These override what is specified in the resource database and in
2620 `default-frame-plist', but are overridden by the arguments to the
2621 particular call to `make-frame'.
2622
2623 Note: In many cases, properties of a frame are available as specifiers
2624 instead of through the frame-properties mechanism.
2625
2626 Here is a list of recognized frame properties, other than those
2627 documented in `set-frame-properties' (they can be queried and
2628 set at any time, except as otherwise noted):
2629
2630 window-id                    The X window ID corresponding to the
2631                              frame.  May be set only at startup, and
2632                              only if external widget support was
2633                              compiled in; doing so causes the frame
2634                              to be created as an "external widget"
2635                              in another program that uses an existing
2636                              window in the program rather than creating
2637                              a new one.
2638 initially-unmapped           If non-nil, the frame will not be visible
2639                              when it is created.  In this case, you
2640                              need to call `make-frame-visible' to make
2641                              the frame appear.
2642 popup                        If non-nil, it should be a frame, and this
2643                              frame will be created as a "popup" frame
2644                              whose parent is the given frame.  This
2645                              will make the window manager treat the
2646                              frame as a dialog box, which may entail
2647                              doing different things (e.g. not asking
2648                              for positioning, and not iconifying
2649                              separate from its parent).
2650 override-redirect            If non-nil, the frame will not be subject to
2651                              window-manager control.  In particular, it
2652                              will lack decorations, for more attractive
2653                              appearance of balloon help, aka tooltips.
2654 inter-line-space             Not currently implemented.
2655 toolbar-shadow-thickness     Thickness of toolbar shadows.
2656 background-toolbar-color     Color of toolbar background.
2657 bottom-toolbar-shadow-color  Color of bottom shadows on toolbars.
2658                              (*Not* specific to the bottom-toolbar.)
2659 top-toolbar-shadow-color     Color of top shadows on toolbars.
2660                              (*Not* specific to the top-toolbar.)
2661 internal-border-width        Width of internal border around text area.
2662 border-width                 Width of external border around text area.
2663 top                          Y position (in pixels) of the upper-left
2664                              outermost corner of the frame (i.e. the
2665                              upper-left of the window-manager
2666                              decorations).
2667 left                         X position (in pixels) of the upper-left
2668                              outermost corner of the frame (i.e. the
2669                              upper-left of the window-manager
2670                              decorations).
2671 border-color                 Color of external border around text area.
2672 cursor-color                 Color of text cursor.
2673
2674 See also `default-frame-plist', which specifies properties which apply
2675 to all frames, not just X frames.
2676                                                                          */ );
2677         Vdefault_x_frame_plist = Qnil;
2678
2679         x_console_methods->device_specific_frame_props =
2680             &Vdefault_x_frame_plist;
2681 }