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