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