XEmacs 21.2-b2
[chise/xemacs-chise.git.1] / src / 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 XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: Not synched with FSF. */
23
24 /* Substantially rewritten for XEmacs.  */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "console-x.h"
30 #include "xintrinsicp.h"        /* CoreP.h needs this */
31 #include <X11/CoreP.h>          /* Numerous places access the fields of
32                                    a core widget directly.  We could
33                                    use XtGetValues(), but ... */
34 #include <X11/Shell.h>
35 #include <X11/ShellP.h>
36 #include "xmu.h"
37 #include "EmacsManager.h"
38 #include "EmacsFrameP.h"
39 #include "EmacsShell.h"
40 #ifdef EXTERNAL_WIDGET
41 #include "ExternalShell.h"
42 #endif
43 #include "glyphs-x.h"
44 #include "objects-x.h"
45 #include "scrollbar-x.h"
46
47 #include "buffer.h"
48 #include "events.h"
49 #include "extents.h"
50 #include "faces.h"
51 #include "frame.h"
52 #include "window.h"
53
54 #ifdef HAVE_DRAGNDROP
55 #include "dragdrop.h"
56 #endif
57
58 #ifdef HAVE_OFFIX_DND
59 #include "offix.h"
60 #endif
61 #if defined (HAVE_OFFIX_DND) || defined (HAVE_CDE)
62 #include "events-mod.h"
63 #endif
64
65 /* Default properties to use when creating frames.  */
66 Lisp_Object Vdefault_x_frame_plist;
67
68 Lisp_Object Qwindow_id;
69 Lisp_Object Qx_resource_name;
70
71 EXFUN (Fx_window_id, 1);
72
73 \f
74 /************************************************************************/
75 /*                          helper functions                            */
76 /************************************************************************/
77
78 /* Return the Emacs frame-object corresponding to an X window */
79 struct frame *
80 x_window_to_frame (struct device *d, Window wdesc)
81 {
82   Lisp_Object tail, frame;
83   struct frame *f;
84
85   /* This function was previously written to accept only a window argument
86      (and to loop over all devices looking for a matching window), but
87      that is incorrect because window ID's are not unique across displays. */
88
89   for (tail = DEVICE_FRAME_LIST (d); CONSP (tail); tail = XCDR (tail))
90     {
91       frame = XCAR (tail);
92       if (!FRAMEP (frame))
93         continue;
94       f = XFRAME (frame);
95       if (FRAME_X_P (f) && XtWindow (FRAME_X_TEXT_WIDGET (f)) == wdesc)
96         return f;
97     }
98   return 0;
99 }
100
101 /* Like x_window_to_frame but also compares the window with the widget's
102    windows */
103 struct frame *
104 x_any_window_to_frame (struct device *d, Window wdesc)
105 {
106   Lisp_Object tail, frame;
107   struct frame *f;
108
109   assert (DEVICE_X_P (d));
110
111   /* This function was previously written to accept only a window argument
112      (and to loop over all devices looking for a matching window), but
113      that is incorrect because window ID's are not unique across displays. */
114
115   for (tail = DEVICE_FRAME_LIST (d); CONSP (tail); tail = XCDR (tail))
116     {
117       int i;
118
119       frame = XCAR (tail);
120       f = XFRAME (frame);
121       /* This frame matches if the window is any of its widgets. */
122       if (wdesc == XtWindow (FRAME_X_SHELL_WIDGET (f)) ||
123           wdesc == XtWindow (FRAME_X_CONTAINER_WIDGET (f)) ||
124           wdesc == XtWindow (FRAME_X_TEXT_WIDGET (f)))
125         return f;
126
127       /* Match if the window is one of the widgets at the top of the frame
128          (menubar, Energize psheets). */
129
130       /* Note: Jamie once said
131
132          "Do *not* match if the window is this frame's psheet."
133
134          But this is wrong and will screw up some functions that expect
135          x_any_window_to_frame() to work as advertised.  I think the reason
136          for this statement is that, in the old (broken) event loop, where
137          not all events went through XtDispatchEvent(), psheet events
138          would incorrectly get sucked away by Emacs if this function matched
139          on psheet widgets. */
140
141       for (i = 0; i < FRAME_X_NUM_TOP_WIDGETS (f); i++)
142         {
143           Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
144           if (wid && XtIsManaged (wid) && wdesc == XtWindow (wid))
145             return f;
146         }
147
148 #ifdef HAVE_SCROLLBARS
149       /* Match if the window is one of this frame's scrollbars. */
150       if (x_window_is_scrollbar (f, wdesc))
151         return f;
152 #endif
153     }
154
155   return 0;
156 }
157
158 struct frame *
159 x_any_widget_or_parent_to_frame (struct device *d, Widget widget)
160 {
161   while (widget)
162     {
163       struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
164       if (f)
165         return f;
166       widget = XtParent (widget);
167     }
168
169   return 0;
170 }
171
172 struct frame *
173 decode_x_frame (Lisp_Object frame)
174 {
175   if (NILP (frame))
176     XSETFRAME (frame, selected_frame ());
177   CHECK_LIVE_FRAME (frame);
178   /* this will also catch dead frames, but putting in the above check
179      results in a more useful error */
180   CHECK_X_FRAME (frame);
181   return XFRAME (frame);
182 }
183
184 \f
185 /************************************************************************/
186 /*                      window-manager interactions                     */
187 /************************************************************************/
188
189 #if 0
190 /* Not currently used. */
191
192 void
193 x_wm_mark_shell_size_user_specified (Widget wmshell)
194 {
195   if (! XtIsWMShell (wmshell)) abort ();
196   EmacsShellSetSizeUserSpecified (wmshell);
197 }
198
199 void
200 x_wm_mark_shell_position_user_specified (Widget wmshell)
201 {
202   if (! XtIsWMShell (wmshell)) abort ();
203   EmacsShellSetPositionUserSpecified (wmshell);
204 }
205
206 #endif
207
208 void
209 x_wm_set_shell_iconic_p (Widget shell, int iconic_p)
210 {
211   if (! XtIsWMShell (shell)) abort ();
212
213   /* Because of questionable logic in Shell.c, this sequence can't work:
214
215        w = XtCreatePopupShell (...);
216        Xt_SET_VALUE (w, XtNiconic, True);
217        XtRealizeWidget (w);
218
219      The iconic resource is only consulted at initialization time (when
220      XtCreatePopupShell is called) instead of at realization time (just
221      before the window gets created, which would be more sensible) or
222      at management-time (just before the window gets mapped, which would
223      be most sensible of all).
224
225      The bug is that Shell's SetValues method doesn't do anything to
226      w->wm.wm_hints.initial_state until after the widget has been realized.
227      Calls to XtSetValues are ignored in the window between creation and
228      realization.  This is true of MIT X11R5 patch level 25, at least.
229      (Apparently some other versions of Xt don't have this bug?)
230    */
231   Xt_SET_VALUE (shell, XtNiconic, iconic_p);
232   EmacsShellSmashIconicHint (shell, iconic_p);
233 }
234
235 void
236 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
251 x_wm_set_variable_size (Widget wmshell, int width, int height)
252 {
253   Arg al [2];
254
255   if (!XtIsWMShell (wmshell))
256     abort ();
257 #ifdef DEBUG_GEOMETRY_MANAGEMENT
258   /* See comment in EmacsShell.c */
259   printf ("x_wm_set_variable_size: %d %d\n", width, height);
260   fflush (stdout);
261 #endif
262
263   XtSetArg (al [0], XtNwidthCells,  width);
264   XtSetArg (al [1], XtNheightCells, height);
265   XtSetValues (wmshell, al, 2);
266 }
267
268 /* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS
269    and WM_DELETE_WINDOW, then add them.  (They may already be present
270    because of the toolkit (Motif adds them, for example, but Xt doesn't).
271  */
272 static void
273 x_wm_hack_wm_protocols (Widget widget)
274 {
275   Display *dpy = XtDisplay (widget);
276   struct device *d = get_device_from_display (dpy);
277   Window w = XtWindow (widget);
278   int need_delete = 1;
279   int need_focus = 1;
280
281   if (!XtIsWMShell (widget))
282     abort ();
283
284   {
285     Atom type, *atoms = 0;
286     int format = 0;
287     unsigned long nitems = 0;
288     unsigned long bytes_after;
289
290     if (Success == XGetWindowProperty (dpy, w, DEVICE_XATOM_WM_PROTOCOLS (d),
291                                        0, 100, False, XA_ATOM,
292                                        &type, &format, &nitems, &bytes_after,
293                                        (unsigned char **) &atoms)
294         && format == 32 && type == XA_ATOM)
295       while (nitems > 0)
296         {
297           nitems--;
298           if (atoms [nitems] == DEVICE_XATOM_WM_DELETE_WINDOW (d))
299             need_delete = 0;
300           else if (atoms [nitems] == DEVICE_XATOM_WM_TAKE_FOCUS (d))
301             need_focus = 0;
302         }
303     if (atoms) XFree ((char *) atoms);
304   }
305   {
306     Atom props [10];
307     int count = 0;
308     if (need_delete) props[count++] = DEVICE_XATOM_WM_DELETE_WINDOW (d);
309     if (need_focus)  props[count++] = DEVICE_XATOM_WM_TAKE_FOCUS (d);
310     if (count)
311       XChangeProperty (dpy, w, DEVICE_XATOM_WM_PROTOCOLS (d), XA_ATOM, 32,
312                        PropModeAppend, (unsigned char *) props, count);
313   }
314 }
315
316 static void
317 x_wm_store_class_hints (Widget shell, char *frame_name)
318 {
319   Display *dpy = XtDisplay (shell);
320   char *app_name, *app_class;
321   XClassHint classhint;
322
323   if (!XtIsWMShell (shell))
324     abort ();
325
326   XtGetApplicationNameAndClass (dpy, &app_name, &app_class);
327   classhint.res_name = frame_name;
328   classhint.res_class = app_class;
329   XSetClassHint (dpy, XtWindow (shell), &classhint);
330 }
331
332 #ifndef HAVE_SESSION
333 static void
334 x_wm_maybe_store_wm_command (struct frame *f)
335 {
336   Widget w = FRAME_X_SHELL_WIDGET (f);
337   struct device *d = XDEVICE (FRAME_DEVICE (f));
338
339   if (!XtIsWMShell (w))
340     abort ();
341
342   if (NILP (DEVICE_X_WM_COMMAND_FRAME (d)))
343     {
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
358 x_wm_maybe_move_wm_command (struct frame *f)
359 {
360   struct device *d = XDEVICE (FRAME_DEVICE (f));
361
362   /* There may not be a frame in DEVICE_X_WM_COMMAND_FRAME()
363      if we C-c'ed at startup at the right time. */
364   if (FRAMEP (DEVICE_X_WM_COMMAND_FRAME (d))
365       && f == XFRAME (DEVICE_X_WM_COMMAND_FRAME (d)))
366     {
367       Lisp_Object rest = DEVICE_FRAME_LIST (d);
368       DEVICE_X_WM_COMMAND_FRAME (d) = Qnil;
369       /* find some random other X frame that is not this one, or give up */
370       /* skip non-top-level (ExternalClient) frames */
371       while (!NILP (rest) &&
372              (f == XFRAME (XCAR (rest)) ||
373               !FRAME_X_TOP_LEVEL_FRAME_P (XFRAME (XCAR (rest)))))
374         rest = XCDR (rest);
375       if (NILP (rest))
376         return;
377       f = XFRAME (XCAR (rest));
378
379       x_wm_maybe_store_wm_command (f);
380
381     }
382 }
383 #endif /* !HAVE_SESSION */
384
385 static int
386 x_frame_iconified_p (struct frame *f)
387 {
388   Atom actual_type;
389   int actual_format;
390   unsigned long nitems, bytesafter;
391   unsigned long *datap = 0;
392   Widget widget;
393   int result = 0;
394   struct device *d = XDEVICE (FRAME_DEVICE (f));
395
396   widget = FRAME_X_SHELL_WIDGET (f);
397   if (Success == XGetWindowProperty (XtDisplay (widget), XtWindow (widget),
398                                      DEVICE_XATOM_WM_STATE (d), 0, 2, False,
399                                      DEVICE_XATOM_WM_STATE (d), &actual_type,
400                                      &actual_format, &nitems, &bytesafter,
401                                      (unsigned char **) &datap)
402       && datap)
403     {
404       if (nitems <= 2   /* "suggested" by ICCCM version 1 */
405           && datap[0] == IconicState)
406         result = 1;
407       XFree ((char *) datap);
408     }
409   return result;
410 }
411
412 \f
413 /************************************************************************/
414 /*                          frame properties                            */
415 /************************************************************************/
416
417 /* Connect the frame-property names (symbols) to the corresponding
418    X Resource Manager names.  The name of a property, as a Lisp symbol,
419    has an `x-resource-name' property which is a Lisp_String. */
420
421 static void
422 init_x_prop_symbols (void)
423 {
424 #define def(sym, rsrc) \
425    pure_put (sym, Qx_resource_name, build_string (rsrc))
426 #define defi(sym,rsrc) \
427    def (sym, rsrc); pure_put (sym, Qintegerp, Qt)
428
429 #if 0 /* this interferes with things. #### fix this right */
430   def (Qminibuffer, XtNminibuffer);
431   def (Qunsplittable, XtNunsplittable);
432 #endif
433   defi(Qinternal_border_width, XtNinternalBorderWidth);
434 #ifdef HAVE_TOOLBARS
435   def (Qtop_toolbar_shadow_color, XtNtopToolBarShadowColor);
436   def (Qbottom_toolbar_shadow_color, XtNbottomToolBarShadowColor);
437   def (Qbackground_toolbar_color, XtNbackgroundToolBarColor);
438   def (Qtop_toolbar_shadow_pixmap, XtNtopToolBarShadowPixmap);
439   def (Qbottom_toolbar_shadow_pixmap, XtNbottomToolBarShadowPixmap);
440   defi(Qtoolbar_shadow_thickness, XtNtoolBarShadowThickness);
441 #endif
442   def (Qscrollbar_placement, XtNscrollBarPlacement);
443   defi(Qinter_line_space, XtNinterline);
444   /* font, foreground */
445   def (Qiconic, XtNiconic);
446   def (Qbar_cursor, XtNbarCursor);
447   def (Qvisual_bell, XtNvisualBell);
448   defi(Qbell_volume, XtNbellVolume);
449   def (Qpointer_background, XtNpointerBackground);
450   def (Qpointer_color, XtNpointerColor);
451   def (Qtext_pointer, XtNtextPointer);
452   def (Qspace_pointer, XtNspacePointer);
453   def (Qmodeline_pointer, XtNmodeLinePointer);
454   def (Qgc_pointer, XtNgcPointer);
455   /* geometry, initial_geometry */
456   def (Qinitially_unmapped, XtNinitiallyUnmapped);
457   /* preferred_width, preferred_height */
458   def (Quse_backing_store, XtNuseBackingStore);
459
460   /* inherited: */
461
462   def (Qborder_color, XtNborderColor);
463   defi(Qborder_width, XtNborderWidth);
464   defi(Qwidth, XtNwidth);
465   defi(Qheight, XtNheight);
466   defi(Qleft, XtNx);
467   defi(Qtop, XtNy);
468
469 #undef def
470 }
471
472 static Lisp_Object
473 color_to_string (Widget w, unsigned long pixel)
474 {
475   char buf[255];
476
477   XColor color;
478   color.pixel = pixel;
479   XQueryColor (XtDisplay (w), w->core.colormap, &color);
480   sprintf (buf, "#%04x%04x%04x", color.red, color.green, color.blue);
481   return build_string (buf);
482 }
483
484 static void
485 x_get_top_level_position (Display *d, Window w, Position *x, Position *y)
486 {
487   Window root, parent = w, *children;
488   unsigned int nchildren;
489   XWindowAttributes xwa;
490
491   do
492     {
493       w = parent;
494       if (!XQueryTree (d, w, &root, &parent, &children, &nchildren))
495         {
496           *x = 0;
497           *y = 0;
498           return;
499         }
500       XFree (children);
501     }
502   while (root != parent);
503   XGetWindowAttributes (d, w, &xwa);
504   *x = xwa.x;
505   *y = xwa.y;
506 }
507
508 #if 0
509 static void
510 x_smash_bastardly_shell_position (Widget shell)
511 {
512   /* Naturally those bastards who wrote Xt couldn't be bothered
513      to learn about race conditions and such.  We can't trust
514      the X and Y values to have any semblance of correctness,
515      so we smash the right values in place. */
516
517  /* We might be called before we've actually realized the window (if
518      we're checking for the minibuffer resource).  This will bomb in
519      that case so we don't bother calling it. */
520   if (XtWindow (shell))
521     x_get_top_level_position (XtDisplay (shell), XtWindow (shell),
522                               &shell->core.x, &shell->core.y);
523 }
524 #endif /* 0 */
525
526 static Lisp_Object
527 x_frame_property (struct frame *f, Lisp_Object property)
528 {
529   Widget shell = FRAME_X_SHELL_WIDGET (f);
530   EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
531   Widget gw = (Widget) w;
532
533   if (EQ (Qleft, property) || EQ (Qtop, property))
534     {
535       Position x, y;
536       if (!XtWindow(shell))
537         return Qzero;
538       x_get_top_level_position (XtDisplay (shell), XtWindow (shell), &x, &y);
539       if (EQ (Qleft, property)) return make_int (x);
540       if (EQ (Qtop,  property)) return make_int (y);
541     }
542   if (EQ (Qborder_width, property))
543     return make_int (w->core.border_width);
544   if (EQ (Qinternal_border_width, property))
545     return make_int (w->emacs_frame.internal_border_width);
546   if (EQ (Qborder_color, property))
547     return color_to_string (gw, w->core.border_pixel);
548 #ifdef HAVE_TOOLBARS
549   if (EQ (Qtop_toolbar_shadow_color, property))
550     return color_to_string (gw, w->emacs_frame.top_toolbar_shadow_pixel);
551   if (EQ (Qbottom_toolbar_shadow_color, property))
552     return color_to_string (gw, w->emacs_frame.bottom_toolbar_shadow_pixel);
553   if (EQ (Qbackground_toolbar_color, property))
554     return color_to_string (gw, w->emacs_frame.background_toolbar_pixel);
555   if (EQ (Qtoolbar_shadow_thickness, property))
556     return make_int (w->emacs_frame.toolbar_shadow_thickness);
557 #endif /* HAVE_TOOLBARS */
558   if (EQ (Qinter_line_space, property))
559     return make_int (w->emacs_frame.interline);
560   if (EQ (Qwindow_id, property))
561     return Fx_window_id (make_frame (f));
562
563   return Qunbound;
564 }
565
566 static int
567 x_internal_frame_property_p (struct frame *f, Lisp_Object property)
568 {
569   return EQ (property, Qleft)
570     || EQ (property, Qtop)
571     || EQ (property, Qborder_width)
572     || EQ (property, Qinternal_border_width)
573     || EQ (property, Qborder_color)
574 #ifdef HAVE_TOOLBARS
575     || EQ (property, Qtop_toolbar_shadow_color)
576     || EQ (property, Qbottom_toolbar_shadow_color)
577     || EQ (property, Qbackground_toolbar_color)
578     || EQ (property, Qtoolbar_shadow_thickness)
579 #endif /* HAVE_TOOLBARS */
580     || EQ (property, Qinter_line_space)
581     || EQ (property, Qwindow_id)
582     || STRINGP (property);
583 }
584
585 static Lisp_Object
586 x_frame_properties (struct frame *f)
587 {
588   Lisp_Object props = Qnil;
589   Widget shell = FRAME_X_SHELL_WIDGET (f);
590   EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
591   Widget gw = (Widget) w;
592   Position x, y;
593
594   props = cons3 (Qwindow_id, Fx_window_id (make_frame (f)), props);
595   props = cons3 (Qinter_line_space, make_int (w->emacs_frame.interline), props);
596
597 #ifdef HAVE_TOOLBARS
598   props = cons3 (Qtoolbar_shadow_thickness,
599                  make_int (w->emacs_frame.toolbar_shadow_thickness),
600                  props);
601   props = cons3 (Qbackground_toolbar_color,
602                  color_to_string (gw, w->emacs_frame.background_toolbar_pixel),
603                  props);
604   props = cons3 (Qbottom_toolbar_shadow_color,
605                  color_to_string (gw, w->emacs_frame.bottom_toolbar_shadow_pixel),
606                  props);
607   props = 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, &y);
622
623   props = cons3 (Qtop,  make_int (y), props);
624   props = cons3 (Qleft, make_int (x), props);
625
626   return props;
627 }
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       {
648         CONST char * tmp;
649         encoding = DEVICE_XATOM_COMPOUND_TEXT (XDEVICE (FRAME_DEVICE (f)));
650         GET_C_CHARPTR_EXT_CTEXT_DATA_ALLOCA ((CONST char *) value, tmp);
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     {
660       Arg al[2];
661       XtSetArg (al[0], Xt_resource_name, new_XtValue);
662       XtSetArg (al[1], Xt_resource_encoding_name, encoding);
663       XtSetValues (FRAME_X_SHELL_WIDGET (f), al, 2);
664     }
665 }
666
667 static void
668 x_set_title_from_bufbyte (struct frame *f, Bufbyte *name)
669 {
670   x_set_frame_text_value (f, name, XtNtitle, XtNtitleEncoding);
671 }
672
673 static void
674 x_set_icon_name_from_bufbyte (struct frame *f, Bufbyte *name)
675 {
676   x_set_frame_text_value (f, name, XtNiconName, XtNiconNameEncoding);
677 }
678
679 /* Set the initial frame size as specified.  This function is used
680    when the frame's widgets have not yet been realized.  In this
681    case, it is not sufficient just to set the width and height of
682    the EmacsFrame widget, because they will be ignored when the
683    widget is realized (instead, the shell's geometry resource is
684    used). */
685
686 static void
687 x_set_initial_frame_size (struct frame *f, int flags, int x, int y,
688                           unsigned int w, unsigned int h)
689 {
690   char shell_geom [255];
691   int xval, yval;
692   char xsign, ysign;
693   char uspos = !!(flags & (XValue | YValue));
694   char ussize = !!(flags & (WidthValue | HeightValue));
695   char *temp;
696
697   /* assign the correct size to the EmacsFrame widget ... */
698   EmacsFrameSetCharSize (FRAME_X_TEXT_WIDGET (f), w, h);
699
700   /* and also set the WMShell's geometry */
701   (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign = '+');
702   (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign = '+');
703
704   if (uspos && ussize)
705     sprintf (shell_geom, "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign, yval);
706   else if (uspos)
707     sprintf (shell_geom, "=%c%d%c%d", xsign, xval, ysign, yval);
708   else if (ussize)
709     sprintf (shell_geom, "=%dx%d", w, h);
710
711   if (uspos || ussize)
712     {
713       temp = (char *) xmalloc (1 + strlen (shell_geom));
714       strcpy (temp, shell_geom);
715       FRAME_X_GEOM_FREE_ME_PLEASE (f) = temp;
716     }
717   else
718     temp = NULL;
719
720   Xt_SET_VALUE (FRAME_X_SHELL_WIDGET (f), XtNgeometry, temp);
721 }
722
723 /* Report to X that a frame property of frame S is being set or changed.
724    If the property is not specially recognized, do nothing.
725  */
726
727 static void
728 x_set_frame_properties (struct frame *f, Lisp_Object plist)
729 {
730   Position x, y;
731   Dimension width = 0, height = 0;
732   Bool width_specified_p = False;
733   Bool height_specified_p = False;
734   Bool x_position_specified_p = False;
735   Bool y_position_specified_p = False;
736   Bool internal_border_width_specified = False;
737   Lisp_Object tail;
738   Widget w = FRAME_X_TEXT_WIDGET (f);
739
740   for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
741     {
742       Lisp_Object prop = Fcar (tail);
743       Lisp_Object val = Fcar (Fcdr (tail));
744
745       if (STRINGP (prop))
746         {
747           CONST char *extprop;
748
749           if (XSTRING_LENGTH (prop) == 0)
750             continue;
751
752           GET_C_STRING_CTEXT_DATA_ALLOCA (prop, extprop);
753           if (STRINGP (val))
754             {
755               CONST Extbyte *extval;
756               Extcount extvallen;
757
758               GET_STRING_CTEXT_DATA_ALLOCA (val, extval, extvallen);
759               XtVaSetValues (w, XtVaTypedArg, extprop,
760                              XtRString, extval, extvallen + 1,
761                              (XtArgVal) NULL);
762             }
763           else
764             XtVaSetValues (w, XtVaTypedArg, extprop, XtRInt,
765                            XINT (val), sizeof (int),
766                            (XtArgVal) NULL);
767         }
768       else if (SYMBOLP (prop))
769         {
770           Lisp_Object str = Fget (prop, Qx_resource_name, Qnil);
771           int int_p = !NILP (Fget (prop, Qintegerp, Qnil));
772
773           if (NILP (prop) || NILP (str))
774             {
775               /* Kludge to handle the font property. */
776               if (EQ (prop, Qfont))
777                 {
778                   /* If the value is not a string we silently ignore it. */
779                   if (STRINGP (val))
780                     {
781                       Lisp_Object frm, font_spec;
782
783                       XSETFRAME (frm, f);
784                       font_spec = Fget (Fget_face (Qdefault), Qfont, Qnil);
785
786                       Fadd_spec_to_specifier (font_spec, val, frm, Qnil, Qnil);
787                       update_frame_face_values (f);
788                     }
789
790                   continue;
791                 }
792               else
793                 continue;
794             }
795           CHECK_STRING (str);
796
797           /* Kludge the width/height so that we interpret them in characters
798              instead of pixels.  Yuck yuck yuck. */
799           if (!strcmp ((char *) XSTRING_DATA (str), "width"))
800             {
801               CHECK_INT (val);
802               width = XINT (val);
803               width_specified_p = True;
804               continue;
805             }
806           if (!strcmp ((char *) XSTRING_DATA (str), "height"))
807             {
808               CHECK_INT (val);
809               height = XINT (val);
810               height_specified_p = True;
811               continue;
812             }
813           /* Further kludge the x/y. */
814           if (!strcmp ((char *) XSTRING_DATA (str), "x"))
815             {
816               CHECK_INT (val);
817               x = (Position) XINT (val);
818               x_position_specified_p = True;
819               continue;
820             }
821           if (!strcmp ((char *) XSTRING_DATA (str), "y"))
822             {
823               CHECK_INT (val);
824               y = (Position) XINT (val);
825               y_position_specified_p = True;
826               continue;
827             }
828           /* Have you figured out by now that this entire function is
829              one gigantic kludge? */
830           if (!strcmp ((char *) XSTRING_DATA (str),
831                        "internalBorderWidth"))
832             {
833               internal_border_width_specified = True;
834             }
835
836           if (int_p)
837             {
838               CHECK_INT (val);
839               Xt_SET_VALUE (w, (char *) XSTRING_DATA (str), XINT (val));
840             }
841           else if (EQ (val, Qt))
842             {
843               Xt_SET_VALUE (w, (char *) XSTRING_DATA (str), True); /* XtN...*/
844             }
845           else if (EQ (val, Qnil))
846             {
847               Xt_SET_VALUE (w, (char *) XSTRING_DATA (str), False); /* XtN...*/
848             }
849           else
850             {
851               CHECK_STRING (val);
852               XtVaSetValues (w, XtVaTypedArg,
853                              /* XtN... */
854                              (char *) XSTRING_DATA (str),
855                              XtRString,
856                              XSTRING_DATA (val),
857                              XSTRING_LENGTH (val) + 1,
858                              (XtArgVal) NULL);
859             }
860
861 #ifdef HAVE_SCROLLBARS
862           if (!strcmp ((char *) XSTRING_DATA (str), "scrollBarWidth")
863               || !strcmp ((char *) XSTRING_DATA (str),
864                           "scrollBarHeight"))
865             {
866               x_update_frame_scrollbars (f);
867             }
868 #endif /* HAVE_SCROLLBARS */
869         }
870     }
871
872   /* Kludge kludge kludge.   We need to deal with the size and position
873    specially. */
874   {
875     int size_specified_p = width_specified_p || height_specified_p;
876     int position_specified_p = x_position_specified_p ||
877       y_position_specified_p;
878
879     if (!width_specified_p)
880       width = FRAME_WIDTH (f);
881     if (!height_specified_p)
882       height = FRAME_HEIGHT (f);
883
884     /* Kludge kludge kludge kludge. */
885     if (position_specified_p &&
886         (!x_position_specified_p || !y_position_specified_p))
887       {
888         Position dummy;
889         Widget shell = FRAME_X_SHELL_WIDGET (f);
890         x_get_top_level_position (XtDisplay (shell), XtWindow (shell),
891                                   (x_position_specified_p ? &dummy : &x),
892                                   (y_position_specified_p ? &dummy : &y));
893 #if 0
894         x = (int) (FRAME_X_SHELL_WIDGET (f)->core.x);
895         y = (int) (FRAME_X_SHELL_WIDGET (f)->core.y);
896 #endif
897       }
898
899     if (!f->init_finished)
900       {
901         int flags = (size_specified_p ? WidthValue | HeightValue : 0) |
902           (position_specified_p ?
903            XValue | YValue | (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0)
904            : 0);
905         if (size_specified_p
906             || position_specified_p
907             || internal_border_width_specified)
908           x_set_initial_frame_size (f, flags, x, y, width, height);
909       }
910     else
911       {
912         if (size_specified_p || internal_border_width_specified)
913           {
914             Lisp_Object frame;
915             XSETFRAME (frame, f);
916             Fset_frame_size (frame, make_int (width),
917                               make_int (height), Qnil);
918           }
919         if (position_specified_p)
920           {
921             Lisp_Object frame;
922             XSETFRAME (frame, f);
923             Fset_frame_position (frame, make_int (x), make_int (y));
924           }
925       }
926   }
927 }
928
929 static int frame_title_format_already_set;
930
931 static void
932 maybe_set_frame_title_format (Widget shell)
933 {
934
935   /* Only do this if this is the first X frame we're creating.
936
937      If the *title resource (or -title option) was specified, then
938      set frame-title-format to its value.
939      */
940
941   if (!frame_title_format_already_set)
942     {
943       /* No doubt there's a less stupid way to do this. */
944       char *results [2];
945       XtResource resources [2];
946       results [0] = results [1] = 0;
947       resources [0].resource_name = XtNtitle;
948       resources [0].resource_class = XtCTitle;
949       resources [0].resource_type = XtRString;
950       resources [0].resource_size = sizeof (String);
951       resources [0].resource_offset = 0;
952       resources [0].default_type = XtRString;
953       resources [0].default_addr = 0;
954       resources [1].resource_name = XtNiconName;
955       resources [1].resource_class = XtCIconName;
956       resources [1].resource_type = XtRString;
957       resources [1].resource_size = sizeof (String);
958       resources [1].resource_offset = sizeof (char *);
959       resources [1].default_type = XtRString;
960       resources [1].default_addr = 0;
961       XtGetSubresources (XtParent (shell), (XtPointer) results,
962                          shell->core.name,
963                          shell->core.widget_class->core_class.class_name,
964                          resources, XtNumber (resources), 0, 0);
965       if (results[0])
966         Vframe_title_format = build_string (results[0]);
967       if (results[1])
968         Vframe_icon_title_format = build_string (results[1]);
969     }
970
971   frame_title_format_already_set = 1;
972 }
973
974 #ifdef HAVE_CDE
975 #include <Dt/Dt.h>
976 #include <Dt/Dnd.h>
977
978 static Widget CurrentDragWidget = NULL;
979 static XtCallbackRec dnd_convert_cb_rec[2];
980 static XtCallbackRec dnd_destroy_cb_rec[2];
981 static int drag_not_done = 0;
982
983 static void
984 x_cde_destroy_callback (Widget widget, XtPointer clientData,
985                         XtPointer callData)
986 {
987   DtDndDragFinishCallbackStruct *dragFinishInfo =
988     (DtDndDragFinishCallbackStruct *)callData;
989   DtDndContext *dragData = dragFinishInfo->dragData;
990   int i;
991
992   /* free the items */
993   if (callData != NULL && dragData != NULL)
994     {
995       if (dragData->protocol == DtDND_BUFFER_TRANSFER)
996         {
997           for (i = 0; i < dragData->numItems; i++)
998             {
999               XtFree(dragData->data.buffers[i].bp);
1000               if (dragData->data.buffers[i].name)
1001                 XtFree(dragData->data.buffers[i].name);
1002             }
1003         }
1004       else
1005         {
1006           for (i = 0; i < dragData->numItems; i++)
1007             XtFree(dragData->data.files[i]);
1008         }
1009     }
1010
1011   /* free the data string */
1012   xfree (clientData);
1013
1014   CurrentDragWidget = NULL;
1015 }
1016
1017 static void
1018 x_cde_convert_callback (Widget widget, XtPointer clientData,
1019                         XtPointer callData)
1020 {
1021   DtDndConvertCallbackStruct *convertInfo =
1022     (DtDndConvertCallbackStruct *) callData;
1023   char *textdata = (char *) clientData;
1024   char *textptr = NULL;
1025   int i;
1026
1027   if (convertInfo == NULL)
1028     {
1029       return;
1030     }
1031
1032   if ((convertInfo->dragData->protocol != DtDND_BUFFER_TRANSFER
1033       && convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER) ||
1034      (convertInfo->reason != DtCR_DND_CONVERT_DATA))
1035     {
1036       return;
1037     }
1038
1039   for (textptr=textdata, i=0;
1040        i<convertInfo->dragData->numItems;
1041        textptr+=strlen(textptr)+1, i++)
1042     {
1043       if (convertInfo->dragData->protocol == DtDND_BUFFER_TRANSFER)
1044         {
1045           convertInfo->dragData->data.buffers[i].bp = XtNewString(textptr);
1046           convertInfo->dragData->data.buffers[i].size = strlen(textptr);
1047           convertInfo->dragData->data.buffers[i].name = NULL;
1048         }
1049       else
1050         {
1051           convertInfo->dragData->data.files[i] = XtNewString(textptr);
1052         }
1053     }
1054
1055   convertInfo->status = DtDND_SUCCESS;
1056 }
1057
1058 static Lisp_Object
1059 abort_current_drag(Lisp_Object arg)
1060 {
1061   if (CurrentDragWidget && drag_not_done)
1062     {
1063       XmDragCancel(CurrentDragWidget);
1064       CurrentDragWidget = NULL;
1065     }
1066   return arg;
1067 }
1068
1069 DEFUN ("cde-start-drag-internal", Fcde_start_drag_internal, 3, 3, 0, /*
1070 Start a CDE drag from a buffer.
1071 First argument is the event that started the drag (must be a
1072 button-press-event),
1073 second arg defines if the data should be treated as a buffer or
1074 a filename transfer (set to nil for buffer transfer),
1075 and the third argument is a list of data strings.
1076 WARNING: can only handle plain/text and file: transfers!
1077 */
1078        (event, dragtype, dragdata))
1079 {
1080   if (EVENTP (event))
1081     {
1082       struct frame *f = decode_x_frame (Fselected_frame (Qnil));
1083       XEvent x_event;
1084       Widget wid = FRAME_X_TEXT_WIDGET (f);
1085       Display *display = XtDisplayOfObject (wid);
1086       struct device *d    = get_device_from_display (display);
1087       struct x_device *xd = DEVICE_X_DATA (d);
1088       XWindowAttributes win_attrib;
1089       unsigned int modifier = 0, state = 0;
1090       char *Ctext;
1091       int numItems = 0, textlen = 0, pos = 0;
1092       struct Lisp_Event *lisp_event = XEVENT(event);
1093       Lisp_Object item = Qnil;
1094       struct gcpro gcpro1;
1095
1096       /* only drag if this is really a press */
1097       if (EVENT_TYPE(lisp_event) != button_press_event
1098           || !LISTP(dragdata))
1099         return Qnil;
1100
1101       GCPRO1 (item);
1102
1103       /*
1104        * not so cross hack that converts a emacs event back to a XEvent
1105        */
1106
1107       x_event.xbutton.type = ButtonPress;
1108       x_event.xbutton.send_event = False;
1109       x_event.xbutton.display = XtDisplayOfObject(wid);
1110       x_event.xbutton.window = XtWindowOfObject(wid);
1111       x_event.xbutton.root = XRootWindow(x_event.xbutton.display, 0);
1112       x_event.xbutton.subwindow = 0;
1113       x_event.xbutton.time = lisp_event->timestamp;
1114       x_event.xbutton.x = lisp_event->event.button.x;
1115       x_event.xbutton.y = lisp_event->event.button.y;
1116       if (Success == XGetWindowAttributes (x_event.xbutton.display,
1117                                            x_event.xbutton.window,
1118                                            &win_attrib))
1119         {
1120           x_event.xbutton.x_root = win_attrib.x + lisp_event->event.button.x;
1121           x_event.xbutton.y_root = win_attrib.y + lisp_event->event.button.y;
1122         }
1123       else
1124         {
1125           x_event.xbutton.x_root = lisp_event->event.button.x; /* this is wrong */
1126           x_event.xbutton.y_root = lisp_event->event.button.y;
1127         }
1128       modifier = lisp_event->event.button.modifiers;
1129       if (modifier & MOD_SHIFT)   state |= ShiftMask;
1130       if (modifier & MOD_CONTROL) state |= ControlMask;
1131       if (modifier & MOD_META)    state |= xd->MetaMask;
1132       if (modifier & MOD_SUPER)   state |= xd->SuperMask;
1133       if (modifier & MOD_HYPER)   state |= xd->HyperMask;
1134       if (modifier & MOD_ALT)     state |= xd->AltMask;
1135       state |= Button1Mask << (lisp_event->event.button.button-1);
1136
1137       x_event.xbutton.state = state;
1138       x_event.xbutton.button = lisp_event->event.button.button;
1139       x_event.xkey.same_screen = True;
1140
1141       /* convert data strings into a big string */
1142       item = dragdata;
1143       while (!NILP (item))
1144         {
1145           if (!STRINGP (XCAR (item)))
1146             {
1147               numItems=0;
1148               break;
1149             }
1150           textlen += XSTRING_LENGTH (XCAR (item)) + 1;
1151           numItems++;
1152           item = XCDR (item);
1153         }
1154         
1155       if (numItems)
1156         {
1157           /*
1158            * concatenate all strings given to one large string, with
1159            * \0 as separator. List is ended by \0.
1160            */
1161           Ctext = (char *)xmalloc (textlen+1);
1162           Ctext[0] = 0;
1163           
1164           item = dragdata;
1165           while (!NILP (item))
1166             {
1167               if (!STRINGP (XCAR (item)))
1168                 {
1169                   numItems=0;
1170                   xfree(Ctext);
1171                   Ctext=NULL;
1172                   break;
1173                 }
1174               strcpy (Ctext+pos, (CONST char *)XSTRING_DATA (XCAR (item)));
1175               pos += XSTRING_LENGTH (XCAR (item)) + 1;
1176               item = XCDR (item);
1177             }
1178           Ctext[pos] = 0;
1179           
1180           dnd_convert_cb_rec[0].callback = x_cde_convert_callback;
1181           dnd_convert_cb_rec[0].closure  = (XtPointer) Ctext;
1182           dnd_convert_cb_rec[1].callback = NULL;
1183           dnd_convert_cb_rec[1].closure  = NULL;
1184           
1185           dnd_destroy_cb_rec[0].callback = x_cde_destroy_callback;
1186           dnd_destroy_cb_rec[0].closure  = (XtPointer) Ctext;
1187           dnd_destroy_cb_rec[1].callback = NULL;
1188           dnd_destroy_cb_rec[1].closure  = NULL;
1189
1190           CurrentDragWidget =
1191             DtDndDragStart (wid, &x_event,
1192                             (NILP(dragtype)?DtDND_BUFFER_TRANSFER:DtDND_FILENAME_TRANSFER),
1193                             numItems,
1194                             XmDROP_COPY,
1195                             dnd_convert_cb_rec,
1196                             dnd_destroy_cb_rec,
1197                             NULL, 0);
1198         }
1199
1200       UNGCPRO;
1201           
1202       return numItems?Qt:Qnil;
1203     }
1204
1205   return Qnil;
1206 }
1207
1208 static void
1209 x_cde_transfer_callback (Widget widget, XtPointer clientData,
1210                          XtPointer callData)
1211 {
1212   char *filePath, *hurl;
1213   int ii, enqueue=1;
1214   Lisp_Object frame = Qnil;
1215   Lisp_Object l_type = Qnil;
1216   Lisp_Object l_data = Qnil;
1217   DtDndTransferCallbackStruct *transferInfo = NULL;
1218   struct gcpro gcpro1, gcpro2, gcpro3;
1219
1220   /*
1221     this needs to be changed to the new protocol:
1222     - we need the button, modifier and pointer states to create a
1223       correct misc_user_event
1224     - the data must be converted to the new format (URL/MIME)
1225   */
1226   /* return; */
1227
1228   transferInfo = (DtDndTransferCallbackStruct *) callData;
1229   if (transferInfo == NULL)
1230     return;
1231
1232   GCPRO3 (frame, l_type, l_data);
1233
1234   frame = make_frame ((struct frame *) clientData);
1235
1236   if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER)
1237     {
1238       l_type = Qdragdrop_URL;
1239
1240       for (ii = 0; ii < transferInfo->dropData->numItems; ii++)
1241         {
1242           filePath = transferInfo->dropData->data.files[ii];
1243           hurl = dnd_url_hexify_string ((char *)filePath, "file:");
1244           /* ### Mule-izing required */
1245           l_data = Fcons (make_string ((Bufbyte* )hurl,
1246                                        strlen (hurl)),
1247                           l_data);
1248           xfree (hurl);
1249         }
1250     }
1251   else if (transferInfo->dropData->protocol == DtDND_BUFFER_TRANSFER)
1252     {
1253       int speccount = specpdl_depth();
1254
1255       /* Problem: all buffers a treated as text/plain!!!
1256          Solution: Also support DtDND_TEXT_TRANSFER
1257          perhaps implementation of the Motif protocol
1258          (which is the base of CDE) will clear this */
1259       l_type = Qdragdrop_MIME;
1260       record_unwind_protect(abort_current_drag, Qnil);
1261       drag_not_done = 1;
1262       for (ii = 0; ii < transferInfo->dropData->numItems; ii++)
1263         {
1264           /* let us forget this name thing for now... */
1265           /* filePath = transferInfo->dropData->data.buffers[ii].name;
1266              path = (filePath == NULL) ? Qnil
1267              : make_string ((Bufbyte *)filePath, strlen (filePath)); */
1268           /* what, if the data is no text, and how can I tell it? */
1269           l_data = Fcons ( list3 ( list1 ( make_string ((Bufbyte *)"text/plain", 10) ),
1270                                    make_string ((Bufbyte *)"8bit", 4),
1271                                    make_string ((Bufbyte *)transferInfo->dropData->data.buffers[ii].bp, 
1272                                                 transferInfo->dropData->data.buffers[ii].size) ),
1273                            l_data );
1274         }
1275       drag_not_done = 0;
1276       unbind_to(speccount, Qnil);
1277     }
1278   else /* the other cases: NOOP_TRANSFER */
1279     enqueue=0;
1280
1281   /* The Problem: no button and mods from CDE... */
1282   if (enqueue)  
1283     enqueue_misc_user_event_pos ( frame, Qdragdrop_drop_dispatch,
1284                                   Fcons (l_type, l_data),
1285                                   0 /* this is the button */,
1286                                   0 /* these are the mods */,
1287                                   transferInfo->x,
1288                                   transferInfo->y);
1289
1290   UNGCPRO;
1291   return;
1292 }
1293 #endif /* HAVE_CDE */
1294
1295 #ifdef HAVE_OFFIX_DND
1296
1297 DEFUN ("offix-start-drag-internal", Foffix_start_drag_internal, 2, 3, 0, /*
1298 Start a OffiX drag from a buffer.
1299 First arg is the event that started the drag,
1300 second arg should be some string, and the third
1301 is the type of the data (this should be an int).
1302 The type defaults to DndText (4).
1303 */
1304        (event, data, dtyp))
1305 {
1306   if (EVENTP(event))
1307     {
1308       struct frame *f = decode_x_frame (Fselected_frame (Qnil));
1309       XEvent x_event;
1310       Widget wid = FRAME_X_TEXT_WIDGET (f);
1311       Display *display = XtDisplayOfObject (wid);
1312       struct device *d    = get_device_from_display (display);
1313       struct x_device *xd = DEVICE_X_DATA (d);
1314       XWindowAttributes win_attrib;
1315       unsigned int modifier = 0, state = 0;
1316       char *dnd_data = NULL;
1317       unsigned long dnd_len = 0;
1318       int dnd_typ = DndText, dnd_dealloc = 0;
1319       struct Lisp_Event *lisp_event = XEVENT(event);
1320
1321       /* only drag if this is really a press */
1322       if (EVENT_TYPE(lisp_event) != button_press_event)
1323         return Qnil;
1324
1325       /* get the desired type */
1326       if (!NILP (dtyp) && INTP (dtyp))
1327         dnd_typ = XINT (dtyp);
1328
1329       if (dnd_typ == DndFiles)
1330         {
1331           Lisp_Object run = data;
1332           int len = 0;
1333
1334           if (NILP ( Flistp (data)))
1335             return Qnil;
1336
1337           /* construct the data from a list of files */
1338           dnd_len = 1;
1339           dnd_data = (char *) xmalloc (1);
1340           *dnd_data = 0;
1341           while (!NILP (run))
1342             {
1343               if (!STRINGP (XCAR (run)))
1344                 {
1345                   xfree (dnd_data);
1346                   return Qnil;
1347                 }
1348               len = XSTRING_LENGTH (XCAR (run)) + 1;
1349               dnd_data = (char *) xrealloc (dnd_data, dnd_len + len);
1350               strcpy (dnd_data + dnd_len - 1, (CONST char *)XSTRING_DATA (XCAR (run)));
1351               dnd_len += len;
1352               run = XCDR (run);
1353             }
1354
1355           dnd_data[dnd_len - 1] = 0; /* the list-ending zero */
1356           dnd_dealloc = 1;
1357
1358         }
1359       else
1360         {
1361           if (!STRINGP (data))
1362             return Qnil;
1363
1364           /* and whats with MULE data ??? */
1365           dnd_data = (char *)XSTRING_DATA (data);
1366           dnd_len  = XSTRING_LENGTH (data) + 1; /* the zero */
1367
1368         }
1369
1370       /*
1371        * not so cross hack that converts a emacs event back to a XEvent
1372        */
1373
1374       x_event.xbutton.type = ButtonPress;
1375       x_event.xbutton.send_event = False;
1376       x_event.xbutton.display = XtDisplayOfObject(wid);
1377       x_event.xbutton.window = XtWindowOfObject(wid);
1378       x_event.xbutton.root = XRootWindow(x_event.xkey.display, 0);
1379       x_event.xbutton.subwindow = 0;
1380       x_event.xbutton.time = lisp_event->timestamp;
1381       x_event.xbutton.x = lisp_event->event.button.x;
1382       x_event.xbutton.y = lisp_event->event.button.y;
1383       if (Success == XGetWindowAttributes (x_event.xbutton.display,
1384                                            x_event.xbutton.window,
1385                                            &win_attrib))
1386         {
1387           x_event.xbutton.x_root = win_attrib.x + lisp_event->event.button.x;
1388           x_event.xbutton.y_root = win_attrib.y + lisp_event->event.button.y;
1389         }
1390       else
1391         {
1392           x_event.xbutton.x_root = lisp_event->event.button.x; /* this is wrong */
1393           x_event.xbutton.y_root = lisp_event->event.button.y;
1394         }
1395
1396       modifier = lisp_event->event.button.modifiers;
1397       if (modifier & MOD_SHIFT)   state |= ShiftMask;
1398       if (modifier & MOD_CONTROL) state |= ControlMask;
1399       if (modifier & MOD_META)    state |= xd->MetaMask;
1400       if (modifier & MOD_SUPER)   state |= xd->SuperMask;
1401       if (modifier & MOD_HYPER)   state |= xd->HyperMask;
1402       if (modifier & MOD_ALT)     state |= xd->AltMask;
1403       state |= Button1Mask << (lisp_event->event.button.button-1);
1404
1405       x_event.xbutton.state = state;
1406       x_event.xbutton.button = lisp_event->event.button.button;
1407       x_event.xkey.same_screen = True;
1408
1409       DndSetData(dnd_typ, (unsigned char *)dnd_data, dnd_len);
1410       if (dnd_dealloc)
1411         xfree (dnd_data);
1412
1413       /* the next thing blocks everything... */
1414       if (DndHandleDragging(wid, &x_event))
1415         return Qt;
1416     }
1417   return Qnil;
1418 }
1419
1420 #endif /* HAVE_OFFIX_DND */
1421
1422 \f
1423 /************************************************************************/
1424 /*                              widget creation                         */
1425 /************************************************************************/
1426
1427 /* The widget hierarchy is
1428
1429         argv[0]                 shell           container       FRAME-NAME
1430         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1431
1432    We accept geometry specs in this order:
1433
1434         *FRAME-NAME.geometry
1435         *EmacsFrame.geometry
1436         Emacs.geometry
1437
1438    Other possibilities for widget hierarchies might be
1439
1440         argv[0]                 frame           container       FRAME-NAME
1441         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1442    or
1443         argv[0]                 FRAME-NAME      container       FRAME-NAME
1444         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1445    or
1446         argv[0]                 FRAME-NAME      container       emacsTextPane
1447         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1448
1449 #ifdef EXTERNAL_WIDGET
1450    The ExternalShell widget is simply a replacement for the Shell widget
1451    which is able to deal with using an externally-supplied window instead
1452    of always creating its own.
1453 #endif
1454
1455 */
1456
1457 #ifdef EXTERNAL_WIDGET
1458
1459 static int
1460 is_valid_window (Window w, struct device *d)
1461 {
1462   XWindowAttributes xwa;
1463   Display *dpy = DEVICE_X_DISPLAY (d);
1464
1465   expect_x_error (dpy);
1466   XGetWindowAttributes (dpy, w, &xwa);
1467   return !x_error_occurred_p (dpy);
1468 }
1469
1470 #endif /* EXTERNAL_WIDGET */
1471
1472 /* This sends a synthetic mouse-motion event to the frame, if the mouse
1473    is over the frame.  This ensures that the cursor gets set properly
1474    before the user moves the mouse for the first time. */
1475
1476 static void
1477 x_send_synthetic_mouse_event (struct frame *f)
1478 {
1479   /* #### write this function. */
1480 }
1481
1482 static int
1483 first_x_frame_p (struct frame *f)
1484 {
1485   Lisp_Object rest = DEVICE_FRAME_LIST (XDEVICE (f->device));
1486   while (!NILP (rest) &&
1487          (f == XFRAME (XCAR (rest)) ||
1488           !FRAME_X_P (XFRAME (XCAR (rest)))))
1489     rest = XCDR (rest);
1490   return NILP (rest);
1491 }
1492
1493 /* Figure out what size the EmacsFrame widget should initially be,
1494    and set it.  Should be called after the default font has been
1495    determined but before the widget has been realized. */
1496
1497 static void
1498 x_initialize_frame_size (struct frame *f)
1499 {
1500   /* Geometry of the AppShell */
1501   int app_flags = 0;
1502   int app_x = 0;
1503   int app_y = 0;
1504   unsigned int app_w = 0;
1505   unsigned int app_h = 0;
1506
1507   /* Geometry of the EmacsFrame */
1508   int frame_flags = 0;
1509   int frame_x = 0;
1510   int frame_y = 0;
1511   unsigned int frame_w = 0;
1512   unsigned int frame_h = 0;
1513
1514   /* Hairily merged geometry */
1515   int x = 0;
1516   int y = 0;
1517   unsigned int w = 80;
1518   unsigned int h = 40;
1519   int flags = 0;
1520
1521   char *geom = 0, *ew_geom = 0;
1522   Boolean iconic_p = False, ew_iconic_p = False;
1523
1524   Widget wmshell = FRAME_X_SHELL_WIDGET (f);
1525   /* #### This may not be an ApplicationShell any more, with the 'popup
1526      frame property. */
1527   Widget app_shell = XtParent (wmshell);
1528   Widget ew = FRAME_X_TEXT_WIDGET (f);
1529
1530 /* set the position of the frame's root window now.  When the
1531    frame was created, the position was initialized to (0,0). */
1532   {
1533     struct window *win = XWINDOW (f->root_window);
1534
1535     WINDOW_LEFT (win) = FRAME_LEFT_BORDER_END (f);
1536     WINDOW_TOP (win) = FRAME_TOP_BORDER_END (f);
1537
1538     if (!NILP (f->minibuffer_window))
1539       {
1540         win = XWINDOW (f->minibuffer_window);
1541         WINDOW_LEFT (win) = FRAME_LEFT_BORDER_END (f);
1542       }
1543   }
1544
1545 #ifdef EXTERNAL_WIDGET
1546   /* If we're an external widget, then the size of the frame is predetermined
1547      (by the client) and is not our decision to make. */
1548   if (FRAME_X_EXTERNAL_WINDOW_P (f))
1549     return;
1550 #endif
1551
1552 #if 0
1553   /* #### this junk has not been tested; therefore it's
1554      probably wrong.  Doesn't really matter at this point because
1555      currently all frames are either top-level or external widgets. */
1556
1557   /* If we're not our own top-level window, then we shouldn't go messing around
1558      with top-level shells or "Emacs.geometry" or any such stuff.  Therefore,
1559      we do as follows to determine the size of the frame:
1560
1561      1) If a value for the frame's "geometry" resource was specified, then
1562         use it.  (This specifies a size in characters.)
1563      2) Else, if the "width" and "height" resources were specified, then
1564         leave them alone.  (This is a value in pixels.  Sorry, we can't break
1565         Xt conventions here.)
1566      3) Else, assume a size of 64x12.  (This is somewhat arbitrary, but
1567         it's unlikely that a size of 80x40 is desirable because we're probably
1568         inside of a dialog box.)
1569
1570      Set the widget's x, y, height, and width as determined.  Don't set the
1571      top-level container widget, because we don't necessarily know what it
1572      is. (Assume it is smart and pays attention to our values.)
1573   */
1574
1575   if (!FRAME_X_TOP_LEVEL_FRAME_P (f))
1576     {
1577       Xt_GET_VALUE (ew, XtNgeometry, &ew_geom);
1578       if (ew_geom)
1579         frame_flags = XParseGeometry (ew_geom,
1580                                       &frame_x, &frame_y,
1581                                       &frame_w, &frame_h);
1582       if (! (frame_flags & (WidthValue | HeightValue)))
1583         {
1584           Arg al[2];
1585           XtSetArg (al [0], XtNwidth,  &frame_w);
1586           XtSetArg (al [1], XtNheight, &frame_h);
1587           XtGetValues (ew, al, 2);
1588           if (!frame_w && !frame_h)
1589             {
1590               frame_w = 64;
1591               frame_h = 12;
1592               frame_flags |= WidthValue | HeightValue;
1593             }
1594         }
1595       if (frame_flags & (WidthValue | HeightValue))
1596         EmacsFrameSetCharSize (ew, frame_w, frame_h);
1597       if (frame_flags & (XValue | YValue))
1598         {
1599           Arg al[2];
1600           XtSetArg (al [0], XtNwidth,  &frame_w);
1601           XtSetArg (al [1], XtNheight, &frame_h);
1602           XtGetValues (ew, al, 2);
1603
1604           if (frame_flags & XNegative)
1605             frame_x += frame_w;
1606           if (frame_flags & YNegative)
1607             frame_y += frame_h;
1608
1609           XtSetArg (al [0], XtNx, frame_x);
1610           XtSetArg (al [1], XtNy, frame_y);
1611           XtSetValues (ew, al, 2);
1612         }
1613       return;
1614     }
1615 #endif
1616
1617   /* OK, we're a top-level shell. */
1618
1619   if (!XtIsWMShell (wmshell))
1620     abort ();
1621
1622   /* If the EmacsFrame doesn't have a geometry but the shell does,
1623      treat that as the geometry of the frame.
1624      (Is this bogus? I'm not sure.) */
1625
1626   Xt_GET_VALUE (ew, XtNgeometry, &ew_geom);
1627   if (!ew_geom)
1628     {
1629       Xt_GET_VALUE (wmshell, XtNgeometry, &geom);
1630       if (geom)
1631         {
1632           ew_geom = geom;
1633           Xt_SET_VALUE (ew, XtNgeometry, ew_geom);
1634         }
1635     }
1636
1637   /* If the Shell is iconic, then the EmacsFrame is iconic.
1638      (Is this bogus? I'm not sure.) */
1639   Xt_GET_VALUE (ew, XtNiconic, &ew_iconic_p);
1640   if (!ew_iconic_p)
1641     {
1642       Xt_GET_VALUE (wmshell, XtNiconic, &iconic_p);
1643       if (iconic_p)
1644         {
1645           ew_iconic_p = iconic_p;
1646           Xt_SET_VALUE (ew, XtNiconic, iconic_p);
1647         }
1648     }
1649
1650   Xt_GET_VALUE (app_shell, XtNgeometry, &geom);
1651   if (geom)
1652     app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
1653
1654   if (ew_geom)
1655     frame_flags = XParseGeometry (ew_geom,
1656                                   &frame_x, &frame_y,
1657                                   &frame_w, &frame_h);
1658
1659   if (first_x_frame_p (f))
1660     {
1661       /* If this is the first frame created:
1662          ====================================
1663
1664          - Use the ApplicationShell's size/position, if specified.
1665            (This is "Emacs.geometry", or the "-geometry" command line arg.)
1666          - Else use the EmacsFrame's size/position.
1667            (This is "*FRAME-NAME.geometry")
1668
1669          - If the AppShell is iconic, the frame should be iconic.
1670
1671          AppShell comes first so that -geometry always applies to the first
1672          frame created, even if there is an "every frame" entry in the
1673          resource database.
1674        */
1675       if (app_flags & (XValue | YValue))
1676         {
1677           x = app_x; y = app_y;
1678           flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
1679         }
1680       else if (frame_flags & (XValue | YValue))
1681         {
1682           x = frame_x; y = frame_y;
1683           flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
1684         }
1685
1686       if (app_flags & (WidthValue | HeightValue))
1687         {
1688           w = app_w; h = app_h;
1689           flags |= (app_flags & (WidthValue | HeightValue));
1690         }
1691       else if (frame_flags & (WidthValue | HeightValue))
1692         {
1693           w = frame_w; h = frame_h;
1694           flags |= (frame_flags & (WidthValue | HeightValue));
1695         }
1696
1697       /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1698       if (!ew_iconic_p)
1699         {
1700           Xt_GET_VALUE (app_shell, XtNiconic, &iconic_p);
1701           if (iconic_p)
1702             {
1703               ew_iconic_p = iconic_p;
1704               Xt_SET_VALUE (ew, XtNiconic, iconic_p);
1705             }
1706         }
1707     }
1708   else
1709     {
1710       /* If this is not the first frame created:
1711          ========================================
1712
1713          - use the EmacsFrame's size/position if specified
1714          - Otherwise, use the ApplicationShell's size, but not position.
1715
1716          So that means that one can specify the position of the first frame
1717          with "Emacs.geometry" or `-geometry'; but can only specify the
1718          position of subsequent frames with "*FRAME-NAME.geometry".
1719
1720          AppShell comes second so that -geometry does not apply to subsequent
1721          frames when there is an "every frame" entry in the resource db,
1722          but does apply to the first frame.
1723        */
1724       if (frame_flags & (XValue | YValue))
1725         {
1726           x = frame_x; y = frame_y;
1727           flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
1728         }
1729
1730       if (frame_flags & (WidthValue | HeightValue))
1731         {
1732           w = frame_w; h = frame_h;
1733           flags |= (frame_flags & (WidthValue | HeightValue));
1734         }
1735       else if (app_flags & (WidthValue | HeightValue))
1736         {
1737           w = app_w;
1738           h = app_h;
1739           flags |= (app_flags & (WidthValue | HeightValue));
1740         }
1741     }
1742
1743   x_set_initial_frame_size (f, flags, x, y, w, h);
1744 }
1745
1746 static void
1747 x_get_layout_sizes (struct frame *f, Dimension *topbreadth)
1748 {
1749   int i;
1750
1751   /* compute height of all top-area widgets */
1752   for (i=0, *topbreadth = 0; i<FRAME_X_NUM_TOP_WIDGETS (f); i++)
1753     {
1754       Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
1755       if (wid && XtIsManaged (wid))
1756         *topbreadth += wid->core.height + 2*wid->core.border_width;
1757     }
1758 }
1759
1760 static void
1761 x_layout_widgets (Widget w, XtPointer client_data, XtPointer call_data)
1762 {
1763   struct frame *f = (struct frame *) client_data;
1764   EmacsManagerResizeStruct *emst = (EmacsManagerResizeStruct *) call_data;
1765   Dimension width = emst->width;
1766   Dimension height = emst->height;
1767   Widget text = FRAME_X_TEXT_WIDGET (f);
1768   Dimension textbord = text->core.border_width;
1769   Dimension topbreadth;
1770   Position text_x = 0, text_y = 0;
1771   int i;
1772
1773   x_get_layout_sizes (f, &topbreadth);
1774
1775   /* first the menubar and psheets ... */
1776   for (i=0; i<FRAME_X_NUM_TOP_WIDGETS (f); i++)
1777     {
1778       Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
1779       if (wid && XtIsManaged (wid))
1780         {
1781           Dimension bord = wid->core.border_width;
1782           XtConfigureWidget (wid, 0, text_y,
1783                              width - 2*bord, wid->core.height,
1784                              bord);
1785           text_y += wid->core.height + 2*bord;
1786         }
1787     }
1788
1789 #ifdef HAVE_SCROLLBARS
1790   f->scrollbar_y_offset = topbreadth + textbord;
1791 #endif
1792
1793   /* finally the text area */
1794   XtConfigureWidget (text, text_x, text_y,
1795                      width - 2*textbord,
1796                      height - text_y - 2*textbord,
1797                      textbord);
1798 }
1799
1800 static void
1801 x_do_query_geometry (Widget w, XtPointer client_data, XtPointer call_data)
1802 {
1803   struct frame *f = (struct frame *) client_data;
1804   EmacsManagerQueryGeometryStruct *emst =
1805     (EmacsManagerQueryGeometryStruct *) call_data;
1806   Widget text = FRAME_X_TEXT_WIDGET (f);
1807   Dimension textbord = text->core.border_width;
1808   Dimension topbreadth;
1809   XtWidgetGeometry req, repl;
1810   int mask = emst->request_mode & (CWWidth | CWHeight);
1811
1812   x_get_layout_sizes (f, &topbreadth);
1813
1814   /* Strip away menubar from suggested size, and ask the text widget
1815      what size it wants to be.  */
1816   req.request_mode = mask;
1817   if (mask & CWWidth)
1818     req.width = emst->proposed_width - 2*textbord;
1819   if (mask & CWHeight)
1820     req.height = emst->proposed_height - topbreadth - 2*textbord;
1821   XtQueryGeometry (text, &req, &repl);
1822
1823   /* Now add the menubar back again */
1824   emst->proposed_width  = repl.width  + 2*textbord;
1825   emst->proposed_height = repl.height + topbreadth + 2*textbord;
1826 }
1827
1828 /* Creates the widgets for a frame.
1829    lisp_window_id is a Lisp description of an X window or Xt
1830    widget to parse.
1831
1832    This function does not create or map the windows.  (That is
1833    done by x_popup_frame().)
1834  */
1835 static void
1836 x_create_widgets (struct frame *f, Lisp_Object lisp_window_id,
1837                   Lisp_Object parent)
1838 {
1839   struct device *d = XDEVICE (f->device);
1840   Visual *visual = DEVICE_X_VISUAL (d);
1841   int depth = DEVICE_X_DEPTH (d);
1842   Colormap cmap = DEVICE_X_COLORMAP (d);
1843 #ifdef EXTERNAL_WIDGET
1844   Window window_id = 0;
1845 #endif
1846   CONST char *name;
1847   Arg al [25];
1848   int ac = 0;
1849   Widget text, container, shell;
1850   Widget parentwid = 0;
1851 #ifdef HAVE_MENUBARS
1852   int menubar_visible;
1853   Widget menubar;
1854 #endif
1855
1856   if (STRINGP (f->name))
1857     GET_C_STRING_CTEXT_DATA_ALLOCA (f->name, name);
1858   else
1859     name = "emacs";
1860
1861   /* The widget hierarchy is
1862
1863         argv[0]                 shell           pane            FRAME-NAME
1864         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1865
1866         (the type of the shell is ExternalShell if this frame is running
1867         in another client's window)
1868
1869         However the EmacsShell widget has WM_CLASS of FRAME-NAME/Emacs.
1870         Normally such shells have name/class shellname/appclass, which in this
1871         case would be "shell/Emacs" instead of "frame-name/Emacs".  We could
1872         also get around this by naming the shell "frame-name", but that would
1873         be confusing because the text area (the EmacsFrame widget inferior of
1874         the shell) is also called that.  So we just set the WM_CLASS property.
1875    */
1876
1877 #ifndef EXTERNAL_WIDGET
1878   if (!NILP (lisp_window_id))
1879     error ("support for external widgets was not enabled at compile-time");
1880 #else
1881   if (!NILP (lisp_window_id))
1882     {
1883       char *string;
1884
1885       CHECK_STRING (lisp_window_id);
1886       string = (char *) (XSTRING_DATA (lisp_window_id));
1887       if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
1888         sscanf (string+2, "%lxu", &window_id);
1889 #if 0
1890       else if (string[0] == 'w')
1891         {
1892           sscanf (string+1, "%x", &parent_widget);
1893           if (parent_widget)
1894             window_id = XtWindow (parent_widget);
1895         }
1896 #endif
1897       else
1898         sscanf (string, "%lu", &window_id);
1899       if (!is_valid_window (window_id, d))
1900         error ("Invalid window %lu", (unsigned long) window_id);
1901       FRAME_X_EXTERNAL_WINDOW_P (f) = 1;
1902     } else
1903 #endif /* EXTERNAL_WIDGET */
1904       FRAME_X_TOP_LEVEL_FRAME_P (f) = 1;
1905
1906   ac = 0;
1907   XtSetArg (al[ac], XtNallowShellResize, True); ac++;
1908 #ifdef LWLIB_USES_MOTIF
1909   /* Motif sucks beans.  Without this in here, it will delete the window
1910      out from under us when it receives a WM_DESTROY_WINDOW message
1911      from the WM. */
1912   XtSetArg (al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
1913 #endif
1914
1915 #ifdef EXTERNAL_WIDGET
1916   if (window_id)
1917     {
1918       XtSetArg (al[ac], XtNwindow, window_id); ac++;
1919     }
1920   else
1921 #endif /* EXTERNAL_WIDGET */
1922     {
1923       XtSetArg (al[ac], XtNinput, True);       ac++;
1924       XtSetArg (al[ac], XtNminWidthCells, 10); ac++;
1925       XtSetArg (al[ac], XtNminHeightCells, 1); ac++;
1926       XtSetArg (al[ac], XtNvisual, visual); ac++;
1927       XtSetArg (al[ac], XtNdepth, depth);   ac++;
1928       XtSetArg (al[ac], XtNcolormap, cmap); ac++;
1929     }
1930
1931   if (!NILP (parent))
1932     {
1933       parentwid = FRAME_X_SHELL_WIDGET (XFRAME (parent));
1934       XtSetArg (al[ac], XtNtransientFor, parentwid); ac++;
1935     }
1936
1937   shell = XtCreatePopupShell ("shell",
1938                               (
1939 #ifdef EXTERNAL_WIDGET
1940                                window_id ? externalShellWidgetClass :
1941 #endif
1942                                parentwid ? transientEmacsShellWidgetClass :
1943                                topLevelEmacsShellWidgetClass
1944                                ),
1945                               parentwid ? parentwid :
1946                               DEVICE_XT_APP_SHELL (d),
1947                               al, ac);
1948   FRAME_X_SHELL_WIDGET (f) = shell;
1949   maybe_set_frame_title_format (shell);
1950
1951   /* Create the manager widget */
1952   ac = 0;
1953   XtSetArg (al[ac], XtNvisual, visual); ac++;
1954   XtSetArg (al[ac], XtNdepth, depth); ac++;
1955   XtSetArg (al[ac], XtNcolormap, cmap); ac++;
1956
1957   container = XtCreateWidget ("container",
1958                               emacsManagerWidgetClass, shell, al, ac);
1959   FRAME_X_CONTAINER_WIDGET (f) = container;
1960   XtAddCallback (container, XtNresizeCallback, x_layout_widgets,
1961                  (XtPointer) f);
1962   XtAddCallback (container, XtNqueryGeometryCallback, x_do_query_geometry,
1963                  (XtPointer) f);
1964
1965   /* Create the text area */
1966   ac = 0;
1967   XtSetArg (al[ac], XtNvisual, visual); ac++;
1968   XtSetArg (al[ac], XtNdepth, depth); ac++;
1969   XtSetArg (al[ac], XtNcolormap, cmap); ac++;
1970   XtSetArg (al[ac], XtNborderWidth, 0); ac++; /* should this be settable? */
1971   XtSetArg (al[ac], XtNemacsFrame,  f); ac++;
1972   text = XtCreateWidget (name, emacsFrameClass, container, al, ac);
1973   FRAME_X_TEXT_WIDGET (f) = text;
1974
1975 #ifdef HAVE_MENUBARS
1976   /* Create the initial menubar widget. */
1977   menubar_visible = x_initialize_frame_menubar (f);
1978   FRAME_X_TOP_WIDGETS (f)[0] = menubar = FRAME_X_MENUBAR_WIDGET (f);
1979   FRAME_X_NUM_TOP_WIDGETS (f) = 1;
1980
1981   if (menubar_visible)
1982     XtManageChild (menubar);
1983 #endif /* HAVE_MENUBARS */
1984   XtManageChild (text);
1985   XtManageChild (container);
1986 }
1987
1988 /* We used to call XtPopup() in x_popup_frame, but that doesn't give
1989    you control over whether the widget is initially mapped or not
1990    because XtPopup() makes an unconditional call to XMapRaised().
1991    Boy, those Xt designers were clever.
1992
1993    When we first removed it we only kept the XtRealizeWidget call in
1994    XtPopup.  For everything except HP's that was enough.  For HP's,
1995    though, the failure to call the popup callbacks resulted in XEmacs
1996    not accepting any input.  Bizarre but true.  Stupid but true.
1997
1998    So, in case there are any other gotches floating out there along
1999    the same lines I've duplicated the majority of XtPopup here.  It
2000    assumes no grabs and that the widget is not already popped up, both
2001    valid assumptions for the one place this is called from. */
2002 static void
2003 xemacs_XtPopup (Widget widget)
2004 {
2005   ShellWidget shell_widget = (ShellWidget) widget;
2006   XtGrabKind call_data = XtGrabNone;
2007
2008   XtCallCallbacks (widget, XtNpopupCallback, (XtPointer)&call_data);
2009
2010   shell_widget->shell.popped_up = TRUE;
2011   shell_widget->shell.grab_kind = XtGrabNone;
2012   shell_widget->shell.spring_loaded = False;
2013
2014   if (shell_widget->shell.create_popup_child_proc != NULL)
2015     (*(shell_widget->shell.create_popup_child_proc))(widget);
2016
2017   /* The XtSetValues below are not in XtPopup menu.  We just want to
2018      make absolutely sure... */
2019   Xt_SET_VALUE (widget, XtNmappedWhenManaged, False);
2020   XtRealizeWidget (widget);
2021   Xt_SET_VALUE (widget, XtNmappedWhenManaged, True);
2022 }
2023
2024 #ifdef HAVE_CDE
2025 /* Does this have to be non-automatic? */
2026 /* hack frame to respond to dnd messages */
2027 static XtCallbackRec dnd_transfer_cb_rec[2];
2028 #endif /* HAVE_CDE */
2029
2030 /* create the windows for the specified frame and display them.
2031    Note that the widgets have already been created, and any
2032    necessary geometry calculations have already been done. */
2033 static void
2034 x_popup_frame (struct frame *f)
2035 {
2036   Widget shell_widget = FRAME_X_SHELL_WIDGET (f);
2037   Widget frame_widget = FRAME_X_TEXT_WIDGET (f);
2038   struct device *d = XDEVICE (FRAME_DEVICE (f));
2039
2040   /* Before mapping the window, make sure that the WMShell's notion of
2041      whether it should be iconified is synchronized with the EmacsFrame's
2042      notion.
2043      */
2044   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2045     x_wm_set_shell_iconic_p (shell_widget,
2046                              ((EmacsFrame) frame_widget)
2047                              ->emacs_frame.iconic);
2048
2049   xemacs_XtPopup (shell_widget);
2050
2051   if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
2052     XtMapWidget (shell_widget);
2053   else
2054     {
2055       /* We may have set f->visible to 1 in x_init_frame(), so undo
2056          that now. */
2057       FRAME_X_TOTALLY_VISIBLE_P (f) = 0;
2058       f->visible = 0;
2059     }
2060
2061 #ifdef EXTERNAL_WIDGET
2062   if (FRAME_X_EXTERNAL_WINDOW_P (f))
2063     ExternalShellReady (shell_widget, XtWindow (frame_widget), KeyPressMask);
2064   else
2065 #endif
2066     if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2067       {
2068         /* tell the window manager about us. */
2069         x_wm_store_class_hints (shell_widget, XtName (frame_widget));
2070
2071 #ifndef HAVE_SESSION
2072         x_wm_maybe_store_wm_command (f);
2073 #endif /* HAVE_SESSION */
2074
2075         x_wm_hack_wm_protocols (shell_widget);
2076       }
2077
2078 #ifdef HAVE_XIM
2079   XIM_init_frame (f);
2080 #endif /* HAVE_XIM */
2081
2082 #ifdef HACK_EDITRES
2083   /* Allow XEmacs to respond to EditRes requests.  See the O'Reilly Xt */
2084   /* Instrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
2085   /* pp. 483-493. */
2086   XtAddEventHandler (shell_widget,           /* the shell widget in question */
2087                      (EventMask) NoEventMask,/* OR with existing mask */
2088                      True,                   /* called on non-maskable events? */
2089                      (XtEventHandler) _XEditResCheckMessages, /* the handler */
2090                      NULL);
2091 #endif /* HACK_EDITRES */
2092
2093 #ifdef HAVE_CDE
2094   {
2095     dnd_transfer_cb_rec[0].callback = x_cde_transfer_callback;
2096     dnd_transfer_cb_rec[0].closure = (XtPointer) f;
2097     dnd_transfer_cb_rec[1].callback = NULL;
2098     dnd_transfer_cb_rec[1].closure = NULL;
2099
2100     DtDndVaDropRegister (FRAME_X_TEXT_WIDGET (f),
2101                          DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
2102                          XmDROP_COPY, dnd_transfer_cb_rec,
2103                          DtNtextIsBuffer, True,
2104                          DtNregisterChildren, True, 
2105                          DtNpreserveRegistration, False,
2106                          NULL);
2107   }
2108 #endif /* HAVE_CDE */
2109
2110   /* Do a stupid property change to force the server to generate a
2111      propertyNotify event so that the event_stream server timestamp will
2112      be initialized to something relevant to the time we created the window.
2113      */
2114   XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
2115                    DEVICE_XATOM_WM_PROTOCOLS (d), XA_ATOM, 32, PropModeAppend,
2116                    (unsigned char*) NULL, 0);
2117
2118   x_send_synthetic_mouse_event (f);
2119 }
2120
2121 static void
2122 allocate_x_frame_struct (struct frame *f)
2123 {
2124   /* zero out all slots. */
2125   f->frame_data = xnew_and_zero (struct x_frame);
2126
2127   /* yeah, except the lisp ones */
2128   FRAME_X_ICON_PIXMAP (f) = Qnil;
2129   FRAME_X_ICON_PIXMAP_MASK (f) = Qnil;
2130 }
2131
2132 \f
2133 /************************************************************************/
2134 /*                              Lisp functions                          */
2135 /************************************************************************/
2136
2137 static void
2138 x_init_frame_1 (struct frame *f, Lisp_Object props)
2139 {
2140   /* This function can GC */
2141   Lisp_Object device = FRAME_DEVICE (f);
2142   Lisp_Object lisp_window_id = Fplist_get (props, Qwindow_id, Qnil);
2143   Lisp_Object popup = Fplist_get (props, Qpopup, Qnil);
2144
2145   if (!NILP (popup))
2146     {
2147       if (EQ (popup, Qt))
2148         popup = Fselected_frame (device);
2149       CHECK_LIVE_FRAME (popup);
2150       if (!EQ (device, FRAME_DEVICE (XFRAME (popup))))
2151         signal_simple_error_2 ("Parent must be on same device as frame",
2152                                device, popup);
2153     }
2154
2155   /*
2156    * Previously we set this only if NILP (DEVICE_SELECTED_FRAME (d))
2157    * to make sure that messages were displayed as soon as possible
2158    * if we're creating the first frame on a device.  But it is
2159    * better to just set this all the time, so that when a new frame
2160    * is created that covers the selected frame, echo area status
2161    * messages can still be seen.  f->visible is reset later if the
2162    * initially-unmapped property is found to be non-nil in the
2163    * frame properties.
2164    */
2165   f->visible = 1;
2166
2167   allocate_x_frame_struct (f);
2168   x_create_widgets (f, lisp_window_id, popup);
2169 }
2170
2171 static void
2172 x_init_frame_2 (struct frame *f, Lisp_Object props)
2173 {
2174   /* Set up the values of the widget/frame.  A case could be made for putting
2175      this inside of the widget's initialize method. */
2176
2177   update_frame_face_values (f);
2178   x_initialize_frame_size (f);
2179   /* Kyle:
2180    *   update_frame_title() can't be done here, because some of the
2181    *   modeline specs depend on the frame's device having a selected
2182    *   frame, and that may not have been set up yet.  The redisplay
2183    *   will update the frame title anyway, so nothing is lost.
2184    * JV:
2185    *   It turns out it gives problems with FVWMs name based mapping.
2186    *   We'll just  need to be carefull in the modeline specs.
2187    */
2188   update_frame_title (f); 
2189 }
2190
2191 static void
2192 x_init_frame_3 (struct frame *f)
2193 {
2194   /* Pop up the frame. */
2195
2196   x_popup_frame (f);
2197 }
2198
2199 static void
2200 x_mark_frame (struct frame *f, void (*markobj) (Lisp_Object))
2201 {
2202   ((markobj) (FRAME_X_ICON_PIXMAP (f)));
2203   ((markobj) (FRAME_X_ICON_PIXMAP_MASK (f)));
2204 }
2205
2206 static void
2207 x_set_frame_icon (struct frame *f)
2208 {
2209   Pixmap x_pixmap, x_mask;
2210
2211   if (IMAGE_INSTANCEP (f->icon)
2212       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (f->icon)))
2213     {
2214       x_pixmap = XIMAGE_INSTANCE_X_PIXMAP (f->icon);
2215       x_mask = XIMAGE_INSTANCE_X_MASK (f->icon);
2216     }
2217   else
2218     {
2219       x_pixmap = 0;
2220       x_mask = 0;
2221     }
2222
2223   /* Store the X data into the widget. */
2224   {
2225     Arg al [2];
2226     XtSetArg (al [0], XtNiconPixmap, x_pixmap);
2227     XtSetArg (al [1], XtNiconMask,   x_mask);
2228     XtSetValues (FRAME_X_SHELL_WIDGET (f), al, 2);
2229   }
2230 }
2231
2232 static void
2233 x_set_frame_pointer (struct frame *f)
2234 {
2235   XDefineCursor (XtDisplay (FRAME_X_TEXT_WIDGET (f)),
2236                  XtWindow (FRAME_X_TEXT_WIDGET (f)),
2237                  XIMAGE_INSTANCE_X_CURSOR (f->pointer));
2238   XSync (XtDisplay (FRAME_X_TEXT_WIDGET (f)), 0);
2239 }
2240
2241 static Lisp_Object
2242 x_get_frame_parent (struct frame *f)
2243 {
2244   Widget parentwid = 0;
2245
2246   Xt_GET_VALUE (FRAME_X_SHELL_WIDGET (f), XtNtransientFor, &parentwid);
2247   /* find the frame whose wid is parentwid */
2248   if (parentwid)
2249     {
2250       Lisp_Object frmcons;
2251       DEVICE_FRAME_LOOP (frmcons, XDEVICE (FRAME_DEVICE (f)))
2252         {
2253           Lisp_Object frame = XCAR (frmcons);
2254           if (FRAME_X_SHELL_WIDGET (XFRAME (frame)) == parentwid)
2255             return frame;
2256         }
2257     }
2258   return Qnil;
2259 }
2260
2261 DEFUN ("x-window-id", Fx_window_id, 0, 1, 0, /*
2262 Get the ID of the X11 window.
2263 This gives us a chance to manipulate the Emacs window from within a
2264 different program.  Since the ID is an unsigned long, we return it as
2265 a string.
2266 */
2267        (frame))
2268 {
2269   char str[255];
2270   struct frame *f = decode_x_frame (frame);
2271
2272   sprintf (str, "%lu", XtWindow (FRAME_X_TEXT_WIDGET (f)));
2273   return build_string (str);
2274 }
2275
2276 \f
2277 /************************************************************************/
2278 /*                      manipulating the X window                       */
2279 /************************************************************************/
2280
2281 static void
2282 x_set_frame_position (struct frame *f, int xoff, int yoff)
2283 {
2284   Widget w = FRAME_X_SHELL_WIDGET (f);
2285   Display *dpy = XtDisplay (w);
2286   Dimension frame_w = DisplayWidth  (dpy, DefaultScreen (dpy));
2287   Dimension frame_h = DisplayHeight (dpy, DefaultScreen (dpy));
2288   Dimension shell_w, shell_h, shell_bord;
2289   int win_gravity;
2290   Arg al [3];
2291
2292   XtSetArg (al [0], XtNwidth,       &shell_w);
2293   XtSetArg (al [1], XtNheight,      &shell_h);
2294   XtSetArg (al [2], XtNborderWidth, &shell_bord);
2295   XtGetValues (w, al, 3);
2296
2297   win_gravity =
2298     xoff >= 0 && yoff >= 0 ? NorthWestGravity :
2299     xoff >= 0 ? SouthWestGravity :
2300     yoff >= 0 ? NorthEastGravity :
2301     SouthEastGravity;
2302   if (xoff < 0)
2303     xoff += frame_w - shell_w - 2*shell_bord;
2304   if (yoff < 0)
2305     yoff += frame_h - shell_h - 2*shell_bord;
2306
2307   /* Update the hints so that, if this window is currently iconified, it will
2308      come back at the right place.  We can't look at s->visible to determine
2309      whether it is iconified because it might not be up-to-date yet (the queue
2310      might not be processed). */
2311   XtSetArg (al [0], XtNwinGravity, win_gravity);
2312   XtSetArg (al [1], XtNx, xoff);
2313   XtSetArg (al [2], XtNy, yoff);
2314   XtSetValues (w, al, 3);
2315
2316   /* Sometimes you will find that
2317
2318      (set-frame-position (selected-frame) -50 -50)
2319
2320      doesn't put the frame where you expect it to: i.e. it's closer to
2321      the lower-right corner than it should be, and it appears that the
2322      size of the WM decorations was not taken into account.  This is
2323      *not* a problem with this function.  Both mwm and twm have bugs
2324      in handling this situation. (mwm ignores the window gravity and
2325      always assumes NorthWest, except the first time you map the
2326      window; twm gets things almost right, but forgets to account for
2327      the border width of the top-level window.) This function does
2328      what it's supposed to according to the ICCCM, and I'm not about
2329      to hack around window-manager bugs. */
2330
2331 #if 0
2332   /* This is not necessary under either mwm or twm */
2333   x_wm_mark_shell_position_user_specified (w);
2334 #endif
2335 }
2336
2337 /* Call this to change the size of frame S's x-window. */
2338
2339 static void
2340 x_set_frame_size (struct frame *f, int cols, int rows)
2341 {
2342   EmacsFrameSetCharSize (FRAME_X_TEXT_WIDGET (f), cols, rows);
2343 #if 0
2344     /* this is not correct.  x_set_frame_size() is called from
2345        Fset_frame_size(), which may or may not have been called
2346        by the user (e.g. update_EmacsFrame() calls it when the font
2347        changes).  For now, don't bother with getting this right. */
2348   x_wm_mark_shell_size_user_specified (FRAME_X_SHELL_WIDGET (f));
2349 #endif
2350 }
2351
2352 static void
2353 x_set_mouse_position (struct window *w, int x, int y)
2354 {
2355   struct frame *f = XFRAME (w->frame);
2356
2357   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2358   XWarpPointer (display, None, XtWindow (FRAME_X_TEXT_WIDGET (f)),
2359                 0, 0, 0, 0, w->pixel_left + x, w->pixel_top + y);
2360 }
2361
2362 static int
2363 x_get_mouse_position (struct device *d, Lisp_Object *frame, int *x, int *y)
2364 {
2365   Display *display = DEVICE_X_DISPLAY (d);
2366   Window child_window;
2367   Window root_window;
2368   Window win;
2369   int root_x, root_y;
2370   int win_x, win_y;
2371   unsigned int keys_and_buttons;
2372   struct frame *f;
2373
2374   if (XQueryPointer (display, RootWindow (display, DefaultScreen (display)),
2375                      &root_window, &child_window, &root_x, &root_y,
2376                      &win_x, &win_y, &keys_and_buttons) == False)
2377     return 0;
2378
2379   if (child_window == None)
2380     return 0;   /* not over any window. */
2381
2382   while (1)
2383     {
2384       win = child_window;
2385       if (XTranslateCoordinates (display, root_window, win, root_x, root_y,
2386                                  &win_x, &win_y, &child_window) == False)
2387         /* Huh? */
2388         return 0;
2389
2390       if (child_window == None)
2391         break;
2392     }
2393
2394   /* At this point, win is the innermost window containing the pointer
2395      and win_x and win_y are the coordinates of that window. */
2396   f = x_any_window_to_frame (d, win);
2397   if (!f)
2398     return 0;
2399   XSETFRAME (*frame, f);
2400
2401   if (XTranslateCoordinates (display, win,
2402                              XtWindow (FRAME_X_TEXT_WIDGET (f)),
2403                              win_x, win_y, x, y, &child_window) == False)
2404     /* Huh? */
2405     return 0;
2406
2407   return 1;
2408 }
2409
2410 static void
2411 x_cant_notify_wm_error (void)
2412 {
2413   error ("Can't notify window manager of iconification.");
2414 }
2415
2416 /* Raise frame F.  */
2417 static void
2418 x_raise_frame_1 (struct frame *f, int force)
2419 {
2420   if (FRAME_VISIBLE_P (f) || force)
2421     {
2422       Widget bottom_dialog;
2423       XWindowChanges xwc;
2424       unsigned int flags;
2425       Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2426       Window emacs_window = XtWindow (FRAME_X_SHELL_WIDGET (f));
2427
2428       /* first raises all the dialog boxes, then put emacs just below the
2429        * bottom most dialog box */
2430       bottom_dialog = lw_raise_all_pop_up_widgets ();
2431       if (bottom_dialog && XtWindow (bottom_dialog))
2432         {
2433           xwc.sibling = XtWindow (bottom_dialog);
2434           xwc.stack_mode = Below;
2435           flags = CWSibling | CWStackMode;
2436         }
2437       else
2438         {
2439           xwc.stack_mode = Above;
2440           flags = CWStackMode;
2441         }
2442
2443       if (!XReconfigureWMWindow (display, emacs_window,
2444                                  DefaultScreen (display),
2445                                  flags, &xwc))
2446         x_cant_notify_wm_error ();
2447     }
2448 }
2449
2450 static void
2451 x_raise_frame (struct frame *f)
2452 {
2453   x_raise_frame_1 (f, 1);
2454 }
2455
2456 /* Lower frame F.  */
2457 static void
2458 x_lower_frame (struct frame *f)
2459 {
2460   if (FRAME_VISIBLE_P (f))
2461     {
2462       Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2463       XWindowChanges xwc;
2464       unsigned int flags = CWStackMode;
2465
2466       xwc.stack_mode = Below;
2467       if (!XReconfigureWMWindow (display, XtWindow (FRAME_X_SHELL_WIDGET (f)),
2468                                  DefaultScreen (display), flags, &xwc))
2469         x_cant_notify_wm_error ();
2470     }
2471 }
2472
2473 /* Change from withdrawn state to mapped state. */
2474 static void
2475 x_make_frame_visible (struct frame *f)
2476 {
2477   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2478
2479   if (!FRAME_VISIBLE_P(f))
2480     XMapRaised (display, XtWindow (FRAME_X_SHELL_WIDGET (f)));
2481   else
2482     x_raise_frame_1 (f, 0);
2483 }
2484
2485 /* Change from mapped state to withdrawn state. */
2486 static void
2487 x_make_frame_invisible (struct frame *f)
2488 {
2489   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2490
2491   if (!FRAME_VISIBLE_P(f))
2492     return;
2493
2494   if (!XWithdrawWindow (display,
2495                         XtWindow (FRAME_X_SHELL_WIDGET (f)),
2496                         DefaultScreen (display)))
2497     x_cant_notify_wm_error ();
2498 }
2499
2500 static int
2501 x_frame_visible_p (struct frame *f)
2502 {
2503 #if 0
2504   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2505   XWindowAttributes xwa;
2506   int result;
2507
2508   /* JV:
2509      This is bad, very bad :-(
2510      It is not compatible with our tristate visible and
2511      it should never ever change the visibility for us, this leads to
2512      the frame-freeze problem under fvwm because with the pager
2513
2514      Mappedness != Viewability != Visibility != Emacs f->visible
2515
2516      This first unequalness is the reason for the frame freezing problem
2517      under fvwm (it happens when the frame is another fvwm-page)
2518
2519      The second unequalness happen when it is on the same fvwm-page
2520      but in an invisible part of the visible screen.
2521
2522      For now we just return the XEmacs internal value --- which might not be up
2523      to date. Is that a problem? ---. Otherwise we should
2524      use async visibility like in standard Emacs.
2525      */
2526
2527   if (!XGetWindowAttributes (display,
2528                              XtWindow (FRAME_X_SHELL_WIDGET (f)),
2529                              &xwa))
2530     result = 0;
2531   else
2532     result = xwa.map_state == IsViewable;
2533   /* In this implementation it should at least be != IsUnmapped
2534      JV */
2535
2536   f->visible = result;
2537   return result;
2538 #endif /* 0 */
2539
2540   return f->visible;
2541 }
2542
2543 static int
2544 x_frame_totally_visible_p (struct frame *f)
2545 {
2546   return FRAME_X_TOTALLY_VISIBLE_P (f);
2547 }
2548
2549 /* Change window state from mapped to iconified. */
2550 static void
2551 x_iconify_frame (struct frame *f)
2552 {
2553   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2554
2555   if (!XIconifyWindow (display,
2556                        XtWindow (FRAME_X_SHELL_WIDGET (f)),
2557                        DefaultScreen (display)))
2558     x_cant_notify_wm_error ();
2559
2560   f->iconified = 1;
2561 }
2562
2563 /* Sets the X focus to frame f. */
2564 static void
2565 x_focus_on_frame (struct frame *f)
2566 {
2567   XWindowAttributes xwa;
2568   Widget shell_widget;
2569   int viewable = 0;
2570
2571   assert (FRAME_X_P (f));
2572
2573   shell_widget = FRAME_X_SHELL_WIDGET (f);
2574   if (!XtWindow (shell_widget))
2575     return;
2576
2577 #ifdef EXTERNAL_WIDGET
2578   if (FRAME_X_EXTERNAL_WINDOW_P (f))
2579     ExternalShellSetFocus (shell_widget);
2580 #endif /* EXTERNAL_WIDGET */
2581
2582   /* Do the ICCCM focus change if the window is still visible.
2583      The s->visible flag might not be up-to-date, because we might
2584      not have processed magic events recently.  So make a server
2585      round-trip to find out whether it's really mapped right now.
2586      We grab the server to do this, because that's the only way to
2587      eliminate the race condition.
2588    */
2589   XGrabServer (XtDisplay (shell_widget));
2590   if (XGetWindowAttributes (XtDisplay (shell_widget),
2591                             XtWindow (shell_widget),
2592                             &xwa))
2593     /* JV: it is bad to change the visibility like this, so we don't for the
2594        moment, at least change_frame_visibility should be called
2595        Note also that under fvwm a frame can be Viewable (and thus Mapped)
2596        but still X-invisible
2597     f->visible = xwa.map_state == IsViewable; */
2598     viewable = xwa.map_state == IsViewable;
2599
2600
2601   if (viewable)
2602     {
2603       Window focus;
2604       int revert_to;
2605       XGetInputFocus (XtDisplay (shell_widget), &focus, &revert_to);
2606       /* Don't explicitly set the focus on this window unless the focus
2607          was on some other window (not PointerRoot).  Note that, even when
2608          running a point-to-type window manager like *twm, there is always
2609          a focus window; the window manager maintains that based on the
2610          mouse position.  If you set the "NoTitleFocus" option in these
2611          window managers, then the server itself maintains the focus via
2612          PointerRoot, and changing that to focus on the window would make
2613          the window grab the focus.  Very bad.
2614          */
2615       if (focus != PointerRoot)
2616         {
2617           XSetInputFocus (XtDisplay (shell_widget),
2618                           XtWindow (shell_widget),
2619                           RevertToParent,
2620                           DEVICE_X_MOUSE_TIMESTAMP
2621                           (XDEVICE (FRAME_DEVICE (f))));
2622           XFlush (XtDisplay (shell_widget));
2623         }
2624     }
2625   XUngrabServer (XtDisplay (shell_widget));
2626   XFlush (XtDisplay (shell_widget)); /* hey, I'd like to DEBUG this... */
2627 }
2628
2629 /* Destroy the X window of frame S.  */
2630 static void
2631 x_delete_frame (struct frame *f)
2632 {
2633   Widget w = FRAME_X_SHELL_WIDGET (f);
2634
2635 #ifndef HAVE_SESSION
2636   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2637     x_wm_maybe_move_wm_command (f);
2638 #endif /* HAVE_SESSION */
2639
2640 #ifdef EXTERNAL_WIDGET
2641   {
2642     Display *dpy = XtDisplay (w);
2643     expect_x_error (dpy);
2644     /* for obscure reasons having (I think) to do with the internal
2645        window-to-widget hierarchy maintained by Xt, we have to call
2646        XtUnrealizeWidget() here.  Xt can really suck. */
2647     if (f->being_deleted)
2648       XtUnrealizeWidget (w);
2649     XtDestroyWidget (w);
2650     x_error_occurred_p (dpy);
2651   }
2652 #else
2653   XtDestroyWidget (w);
2654   XFlush (XtDisplay(w));   /* make sure the windows are really gone! */
2655 #endif /* EXTERNAL_WIDGET */
2656
2657   if (FRAME_X_GEOM_FREE_ME_PLEASE (f))
2658     xfree (FRAME_X_GEOM_FREE_ME_PLEASE (f));
2659   xfree (f->frame_data);
2660   f->frame_data = 0;
2661 }
2662
2663 static void
2664 x_update_frame_external_traits (struct frame* frm, Lisp_Object name)
2665 {
2666   Arg av[10];
2667   int ac = 0;
2668   Lisp_Object frame = Qnil;
2669
2670   XSETFRAME(frame, frm);
2671
2672   if (EQ (name, Qforeground))
2673    {
2674      Lisp_Object color = FACE_FOREGROUND (Vdefault_face, frame);
2675      XColor fgc;
2676
2677      if (!EQ (color, Vthe_null_color_instance))
2678        {
2679          fgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
2680          XtSetArg (av[ac], XtNforeground, (void *) fgc.pixel); ac++;
2681        }
2682    }
2683   else if (EQ (name, Qbackground))
2684    {
2685      Lisp_Object color = FACE_BACKGROUND (Vdefault_face, frame);
2686      XColor bgc;
2687
2688      if (!EQ (color, Vthe_null_color_instance))
2689        {
2690          bgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
2691          XtSetArg (av[ac], XtNbackground, (void *) bgc.pixel); ac++;
2692        }
2693
2694      /* Really crappy way to force the modeline shadows to be
2695         redrawn.  But effective. */
2696      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (frm);
2697      MARK_FRAME_CHANGED (frm);
2698    }
2699   else if (EQ (name, Qfont))
2700    {
2701      Lisp_Object font = FACE_FONT (Vdefault_face, frame, Vcharset_ascii);
2702
2703      if (!EQ (font, Vthe_null_font_instance))
2704        XtSetArg (av[ac], XtNfont,
2705                  (void *) FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
2706      ac++;
2707    }
2708   else
2709    abort ();
2710
2711   XtSetValues (FRAME_X_TEXT_WIDGET (frm), av, ac);
2712
2713 #ifdef HAVE_TOOLBARS
2714   /* Setting the background clears the entire frame area
2715     including the toolbar so we force an immediate redraw of
2716     it. */
2717   if (EQ (name, Qbackground))
2718     MAYBE_DEVMETH (XDEVICE (frm->device), redraw_frame_toolbars, (frm));
2719 #endif /* HAVE_TOOLBARS */
2720
2721   /* Set window manager resize increment hints according to
2722      the new character size */
2723   if (EQ (name, Qfont))
2724     EmacsFrameRecomputeCellSize (FRAME_X_TEXT_WIDGET (frm));
2725 }
2726
2727 \f
2728 /************************************************************************/
2729 /*                            initialization                            */
2730 /************************************************************************/
2731
2732 void
2733 syms_of_frame_x (void)
2734 {
2735   defsymbol (&Qwindow_id, "window-id");
2736   defsymbol (&Qx_resource_name, "x-resource-name");
2737
2738   DEFSUBR (Fx_window_id);
2739 #ifdef HAVE_CDE
2740   DEFSUBR (Fcde_start_drag_internal);
2741 #endif
2742 #ifdef HAVE_OFFIX_DND
2743   DEFSUBR (Foffix_start_drag_internal);
2744 #endif
2745 }
2746
2747 void
2748 console_type_create_frame_x (void)
2749 {
2750   /* frame methods */
2751   CONSOLE_HAS_METHOD (x, init_frame_1);
2752   CONSOLE_HAS_METHOD (x, init_frame_2);
2753   CONSOLE_HAS_METHOD (x, init_frame_3);
2754   CONSOLE_HAS_METHOD (x, mark_frame);
2755   CONSOLE_HAS_METHOD (x, focus_on_frame);
2756   CONSOLE_HAS_METHOD (x, delete_frame);
2757   CONSOLE_HAS_METHOD (x, get_mouse_position);
2758   CONSOLE_HAS_METHOD (x, set_mouse_position);
2759   CONSOLE_HAS_METHOD (x, raise_frame);
2760   CONSOLE_HAS_METHOD (x, lower_frame);
2761   CONSOLE_HAS_METHOD (x, make_frame_visible);
2762   CONSOLE_HAS_METHOD (x, make_frame_invisible);
2763   CONSOLE_HAS_METHOD (x, iconify_frame);
2764   CONSOLE_HAS_METHOD (x, set_frame_size);
2765   CONSOLE_HAS_METHOD (x, set_frame_position);
2766   CONSOLE_HAS_METHOD (x, frame_property);
2767   CONSOLE_HAS_METHOD (x, internal_frame_property_p);
2768   CONSOLE_HAS_METHOD (x, frame_properties);
2769   CONSOLE_HAS_METHOD (x, set_frame_properties);
2770   CONSOLE_HAS_METHOD (x, set_title_from_bufbyte);
2771   CONSOLE_HAS_METHOD (x, set_icon_name_from_bufbyte);
2772   CONSOLE_HAS_METHOD (x, frame_visible_p);
2773   CONSOLE_HAS_METHOD (x, frame_totally_visible_p);
2774   CONSOLE_HAS_METHOD (x, frame_iconified_p);
2775   CONSOLE_HAS_METHOD (x, set_frame_pointer);
2776   CONSOLE_HAS_METHOD (x, set_frame_icon);
2777   CONSOLE_HAS_METHOD (x, get_frame_parent);
2778   CONSOLE_HAS_METHOD (x, update_frame_external_traits);
2779 }
2780
2781 void
2782 vars_of_frame_x (void)
2783 {
2784 #ifdef EXTERNAL_WIDGET
2785   Fprovide (intern ("external-widget"));
2786 #endif
2787
2788   /* this call uses only safe functions from emacs.c */
2789   init_x_prop_symbols ();
2790
2791   DEFVAR_LISP ("default-x-frame-plist", &Vdefault_x_frame_plist /*
2792 Plist of default frame-creation properties for X frames.
2793 These override what is specified in the resource database and in
2794 `default-frame-plist', but are overridden by the arguments to the
2795 particular call to `make-frame'.
2796
2797 Note: In many cases, properties of a frame are available as specifiers
2798 instead of through the frame-properties mechanism.
2799
2800 Here is a list of recognized frame properties, other than those
2801 documented in `set-frame-properties' (they can be queried and
2802 set at any time, except as otherwise noted):
2803
2804   window-id                     The X window ID corresponding to the
2805                                 frame.  May be set only at startup, and
2806                                 only if external widget support was
2807                                 compiled in; doing so causes the frame
2808                                 to be created as an "external widget"
2809                                 in another program that uses an existing
2810                                 window in the program rather than creating
2811                                 a new one.
2812   initially-unmapped            If non-nil, the frame will not be visible
2813                                 when it is created.  In this case, you
2814                                 need to call `make-frame-visible' to make
2815                                 the frame appear.
2816   popup                         If non-nil, it should be a frame, and this
2817                                 frame will be created as a "popup" frame
2818                                 whose parent is the given frame.  This
2819                                 will make the window manager treat the
2820                                 frame as a dialog box, which may entail
2821                                 doing different things (e.g. not asking
2822                                 for positioning, and not iconifying
2823                                 separate from its parent).
2824   inter-line-space              Not currently implemented.
2825   toolbar-shadow-thickness      Thickness of toolbar shadows.
2826   background-toolbar-color      Color of toolbar background.
2827   bottom-toolbar-shadow-color   Color of bottom shadows on toolbars.
2828                                 (*Not* specific to the bottom-toolbar.)
2829   top-toolbar-shadow-color      Color of top shadows on toolbars.
2830                                 (*Not* specific to the top-toolbar.)
2831   internal-border-width         Width of internal border around text area.
2832   border-width                  Width of external border around text area.
2833   top                           Y position (in pixels) of the upper-left
2834                                 outermost corner of the frame (i.e. the
2835                                 upper-left of the window-manager
2836                                 decorations).
2837   left                          X position (in pixels) of the upper-left
2838                                 outermost corner of the frame (i.e. the
2839                                 upper-left of the window-manager
2840                                 decorations).
2841   border-color                  Color of external border around text area.
2842   cursor-color                  Color of text cursor.
2843
2844 See also `default-frame-plist', which specifies properties which apply
2845 to all frames, not just X frames.
2846 */ );
2847   Vdefault_x_frame_plist = Qnil;
2848
2849   x_console_methods->device_specific_frame_props = &Vdefault_x_frame_plist;
2850 }