This commit was generated by cvs2svn to compensate for changes in r5670,
[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 /* 7-8-00 !!#### This file needs definite Mule review. */
27
28 #include <config.h>
29 #include "lisp.h"
30
31 #include "console-x.h"
32 #include "xintrinsicp.h"        /* CoreP.h needs this */
33 #include <X11/CoreP.h>          /* Numerous places access the fields of
34                                    a core widget directly.  We could
35                                    use XtGetValues(), but ... */
36 #include <X11/Shell.h>
37 #include <X11/ShellP.h>
38 #include "xmu.h"
39 #include "EmacsManager.h"
40 #include "EmacsFrameP.h"
41 #include "EmacsShell.h"
42 #ifdef EXTERNAL_WIDGET
43 #include "ExternalShell.h"
44 #endif
45 #include "glyphs-x.h"
46 #include "objects-x.h"
47 #include "scrollbar-x.h"
48
49 #include "buffer.h"
50 #include "events.h"
51 #include "extents.h"
52 #include "faces.h"
53 #include "frame.h"
54 #include "window.h"
55 #include "gutter.h"
56
57 #ifdef HAVE_DRAGNDROP
58 #include "dragdrop.h"
59 #endif
60
61 #ifdef HAVE_OFFIX_DND
62 #include "offix.h"
63 #endif
64 #if defined (HAVE_OFFIX_DND) || defined (HAVE_CDE)
65 #include "events-mod.h"
66 #endif
67
68 /* Default properties to use when creating frames.  */
69 Lisp_Object Vdefault_x_frame_plist;
70
71 Lisp_Object Qwindow_id;
72 Lisp_Object Qx_resource_name;
73
74 EXFUN (Fx_window_id, 1);
75
76 \f
77 /************************************************************************/
78 /*                          helper functions                            */
79 /************************************************************************/
80
81 /* Return the Emacs frame-object corresponding to an X window */
82 struct frame *
83 x_window_to_frame (struct device *d, Window wdesc)
84 {
85   Lisp_Object tail, frame;
86   struct frame *f;
87
88   /* This function was previously written to accept only a window argument
89      (and to loop over all devices looking for a matching window), but
90      that is incorrect because window ID's are not unique across displays. */
91
92   for (tail = DEVICE_FRAME_LIST (d); CONSP (tail); tail = XCDR (tail))
93     {
94       frame = XCAR (tail);
95       if (!FRAMEP (frame))
96         continue;
97       f = XFRAME (frame);
98       if (FRAME_X_P (f) && XtWindow (FRAME_X_TEXT_WIDGET (f)) == wdesc)
99         return f;
100     }
101   return 0;
102 }
103
104 /* Like x_window_to_frame but also compares the window with the widget's
105    windows */
106 struct frame *
107 x_any_window_to_frame (struct device *d, Window wdesc)
108 {
109   Widget w;
110   assert (DEVICE_X_P (d));
111
112   w = XtWindowToWidget (DEVICE_X_DISPLAY (d), wdesc);
113
114   if (!w)
115     return 0;
116
117   /* We used to map over all frames here and then map over all widgets
118      belonging to that frame. However it turns out that this was very fragile
119      as it requires our display structures to be in sync _and_ that the
120      loop is told about every new widget somebody adds. Therefore we
121      now let Xt find it for us (which does a bottom-up search which
122      could even be faster) */
123   return  x_any_widget_or_parent_to_frame (d, w);
124 }
125
126 static struct frame *
127 x_find_frame_for_window (struct device *d, Window wdesc)
128 {
129   Lisp_Object tail, frame;
130   struct frame *f;
131   /* This function was previously written to accept only a window argument
132      (and to loop over all devices looking for a matching window), but
133      that is incorrect because window ID's are not unique across displays. */
134
135   for (tail = DEVICE_FRAME_LIST (d); CONSP (tail); tail = XCDR (tail))
136     {
137       frame = XCAR (tail);
138       f = XFRAME (frame);
139       /* This frame matches if the window is any of its widgets. */
140       if (wdesc == XtWindow (FRAME_X_SHELL_WIDGET (f)) ||
141           wdesc == XtWindow (FRAME_X_CONTAINER_WIDGET (f)) ||
142           wdesc == XtWindow (FRAME_X_TEXT_WIDGET (f)))
143         return f;
144
145       /* Match if the window is one of the widgets at the top of the frame
146          (menubar, Energize psheets). */
147
148       /* Note: Jamie once said
149
150          "Do *not* match if the window is this frame's psheet."
151
152          But this is wrong and will screw up some functions that expect
153          x_any_window_to_frame() to work as advertised.  I think the reason
154          for this statement is that, in the old (broken) event loop, where
155          not all events went through XtDispatchEvent(), psheet events
156          would incorrectly get sucked away by Emacs if this function matched
157          on psheet widgets. */
158
159       /* Note: that this called only from
160          x_any_widget_or_parent_to_frame it is unnecessary to iterate
161          over the top level widgets. */
162
163       /* Note:  we use to special case scrollbars but this turns out to be a bad idea
164          because
165          1. We sometimes get events for _unmapped_ scrollbars and our
166          callers don't want us to fail.
167          2. Starting with the 21.2 widget stuff there are now loads of
168          widgets to check and it is easy to forget adding them in a loop here.
169          See x_any_window_to_frame
170          3. We pick up all widgets now anyway. */
171     }
172
173   return 0;
174 }
175
176 struct frame *
177 x_any_widget_or_parent_to_frame (struct device *d, Widget widget)
178 {
179   while (widget)
180     {
181       struct frame *f = x_find_frame_for_window (d, XtWindow (widget));
182       if (f)
183         return f;
184       widget = XtParent (widget);
185     }
186
187   return 0;
188 }
189
190 struct frame *
191 decode_x_frame (Lisp_Object frame)
192 {
193   if (NILP (frame))
194     XSETFRAME (frame, selected_frame ());
195   CHECK_LIVE_FRAME (frame);
196   /* this will also catch dead frames, but putting in the above check
197      results in a more useful error */
198   CHECK_X_FRAME (frame);
199   return XFRAME (frame);
200 }
201
202 \f
203 /************************************************************************/
204 /*                      window-manager interactions                     */
205 /************************************************************************/
206
207 #if 0
208 /* Not currently used. */
209
210 void
211 x_wm_mark_shell_size_user_specified (Widget wmshell)
212 {
213   if (! XtIsWMShell (wmshell)) abort ();
214   EmacsShellSetSizeUserSpecified (wmshell);
215 }
216
217 void
218 x_wm_mark_shell_position_user_specified (Widget wmshell)
219 {
220   if (! XtIsWMShell (wmshell)) abort ();
221   EmacsShellSetPositionUserSpecified (wmshell);
222 }
223
224 #endif
225
226 void
227 x_wm_set_shell_iconic_p (Widget shell, int iconic_p)
228 {
229   if (! XtIsWMShell (shell)) abort ();
230
231   /* Because of questionable logic in Shell.c, this sequence can't work:
232
233        w = XtCreatePopupShell (...);
234        Xt_SET_VALUE (w, XtNiconic, True);
235        XtRealizeWidget (w);
236
237      The iconic resource is only consulted at initialization time (when
238      XtCreatePopupShell is called) instead of at realization time (just
239      before the window gets created, which would be more sensible) or
240      at management-time (just before the window gets mapped, which would
241      be most sensible of all).
242
243      The bug is that Shell's SetValues method doesn't do anything to
244      w->wm.wm_hints.initial_state until after the widget has been realized.
245      Calls to XtSetValues are ignored in the window between creation and
246      realization.  This is true of MIT X11R5 patch level 25, at least.
247      (Apparently some other versions of Xt don't have this bug?)
248    */
249   Xt_SET_VALUE (shell, XtNiconic, iconic_p);
250   EmacsShellSmashIconicHint (shell, iconic_p);
251 }
252
253 void
254 x_wm_set_cell_size (Widget wmshell, int cw, int ch)
255 {
256   Arg al [2];
257
258   if (!XtIsWMShell (wmshell))
259     abort ();
260   if (cw <= 0 || ch <= 0)
261     abort ();
262
263   XtSetArg (al [0], XtNwidthInc,  cw);
264   XtSetArg (al [1], XtNheightInc, ch);
265   XtSetValues (wmshell, al, 2);
266 }
267
268 void
269 x_wm_set_variable_size (Widget wmshell, int width, int height)
270 {
271   Arg al [2];
272
273   if (!XtIsWMShell (wmshell))
274     abort ();
275 #ifdef DEBUG_GEOMETRY_MANAGEMENT
276   /* See comment in EmacsShell.c */
277   printf ("x_wm_set_variable_size: %d %d\n", width, height);
278   fflush (stdout);
279 #endif
280
281   XtSetArg (al [0], XtNwidthCells,  width);
282   XtSetArg (al [1], XtNheightCells, height);
283   XtSetValues (wmshell, al, 2);
284 }
285
286 /* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS
287    and WM_DELETE_WINDOW, then add them.  (They may already be present
288    because of the toolkit (Motif adds them, for example, but Xt doesn't).
289  */
290 static void
291 x_wm_hack_wm_protocols (Widget widget)
292 {
293   Display *dpy = XtDisplay (widget);
294   struct device *d = get_device_from_display (dpy);
295   Window w = XtWindow (widget);
296   int need_delete = 1;
297   int need_focus = 1;
298
299   assert (XtIsWMShell (widget));
300
301   {
302     Atom type, *atoms = 0;
303     int format = 0;
304     unsigned long nitems = 0;
305     unsigned long bytes_after;
306
307     if (Success == XGetWindowProperty (dpy, w, DEVICE_XATOM_WM_PROTOCOLS (d),
308                                        0, 100, False, XA_ATOM,
309                                        &type, &format, &nitems, &bytes_after,
310                                        (unsigned char **) &atoms)
311         && format == 32 && type == XA_ATOM)
312       while (nitems > 0)
313         {
314           nitems--;
315           if (atoms [nitems] == DEVICE_XATOM_WM_DELETE_WINDOW (d))
316             need_delete = 0;
317           else if (atoms [nitems] == DEVICE_XATOM_WM_TAKE_FOCUS (d))
318             need_focus = 0;
319         }
320     if (atoms) XFree ((char *) atoms);
321   }
322   {
323     Atom props [10];
324     int count = 0;
325     if (need_delete) props[count++] = DEVICE_XATOM_WM_DELETE_WINDOW (d);
326     if (need_focus)  props[count++] = DEVICE_XATOM_WM_TAKE_FOCUS (d);
327     if (count)
328       XChangeProperty (dpy, w, DEVICE_XATOM_WM_PROTOCOLS (d), XA_ATOM, 32,
329                        PropModeAppend, (unsigned char *) props, count);
330   }
331 }
332
333 static void
334 x_wm_store_class_hints (Widget shell, char *frame_name)
335 {
336   Display *dpy = XtDisplay (shell);
337   char *app_name, *app_class;
338   XClassHint classhint;
339
340   if (!XtIsWMShell (shell))
341     abort ();
342
343   XtGetApplicationNameAndClass (dpy, &app_name, &app_class);
344   classhint.res_name = frame_name;
345   classhint.res_class = app_class;
346   XSetClassHint (dpy, XtWindow (shell), &classhint);
347 }
348
349 #ifndef HAVE_WMCOMMAND
350 static void
351 x_wm_maybe_store_wm_command (struct frame *f)
352 {
353   Widget w = FRAME_X_SHELL_WIDGET (f);
354   struct device *d = XDEVICE (FRAME_DEVICE (f));
355
356   if (!XtIsWMShell (w))
357     abort ();
358
359   if (NILP (DEVICE_X_WM_COMMAND_FRAME (d)))
360     {
361       int argc;
362       char **argv;
363       make_argc_argv (Vcommand_line_args, &argc, &argv);
364       XSetCommand (XtDisplay (w), XtWindow (w), argv, argc);
365       free_argc_argv (argv);
366       XSETFRAME (DEVICE_X_WM_COMMAND_FRAME (d), f);
367     }
368 }
369
370 /* If we're deleting the frame on which the WM_COMMAND property has been
371    set, then move that property to another frame so that there is exactly
372    one frame that has that property set.
373  */
374 static void
375 x_wm_maybe_move_wm_command (struct frame *f)
376 {
377   struct device *d = XDEVICE (FRAME_DEVICE (f));
378
379   /* There may not be a frame in DEVICE_X_WM_COMMAND_FRAME()
380      if we C-c'ed at startup at the right time. */
381   if (FRAMEP (DEVICE_X_WM_COMMAND_FRAME (d))
382       && f == XFRAME (DEVICE_X_WM_COMMAND_FRAME (d)))
383     {
384       Lisp_Object rest = DEVICE_FRAME_LIST (d);
385       DEVICE_X_WM_COMMAND_FRAME (d) = Qnil;
386       /* find some random other X frame that is not this one, or give up */
387       /* skip non-top-level (ExternalClient) frames */
388       while (!NILP (rest) &&
389              (f == XFRAME (XCAR (rest)) ||
390               !FRAME_X_TOP_LEVEL_FRAME_P (XFRAME (XCAR (rest)))))
391         rest = XCDR (rest);
392       if (NILP (rest))
393         return;
394       f = XFRAME (XCAR (rest));
395
396       x_wm_maybe_store_wm_command (f);
397
398     }
399 }
400 #endif /* !HAVE_WMCOMMAND */
401
402 static int
403 x_frame_iconified_p (struct frame *f)
404 {
405   Atom actual_type;
406   int actual_format;
407   unsigned long nitems, bytesafter;
408   unsigned long *datap = 0;
409   Widget widget;
410   int result = 0;
411   struct device *d = XDEVICE (FRAME_DEVICE (f));
412
413   widget = FRAME_X_SHELL_WIDGET (f);
414   if (Success == XGetWindowProperty (XtDisplay (widget), XtWindow (widget),
415                                      DEVICE_XATOM_WM_STATE (d), 0, 2, False,
416                                      DEVICE_XATOM_WM_STATE (d), &actual_type,
417                                      &actual_format, &nitems, &bytesafter,
418                                      (unsigned char **) &datap)
419       && datap)
420     {
421       if (nitems <= 2   /* "suggested" by ICCCM version 1 */
422           && datap[0] == IconicState)
423         result = 1;
424       XFree ((char *) datap);
425     }
426   return result;
427 }
428
429 \f
430 /************************************************************************/
431 /*                          frame properties                            */
432 /************************************************************************/
433
434 /* Connect the frame-property names (symbols) to the corresponding
435    X Resource Manager names.  The name of a property, as a Lisp symbol,
436    has an `x-resource-name' property which is a Lisp_String. */
437
438 static void
439 init_x_prop_symbols (void)
440 {
441 #define def(sym, rsrc) \
442    Fput (sym, Qx_resource_name, build_string (rsrc))
443 #define defi(sym,rsrc) \
444    def (sym, rsrc); Fput (sym, Qintegerp, Qt)
445
446 #if 0 /* this interferes with things. #### fix this right */
447   def (Qminibuffer, XtNminibuffer);
448   def (Qunsplittable, XtNunsplittable);
449 #endif
450   defi(Qinternal_border_width, XtNinternalBorderWidth);
451 #ifdef HAVE_TOOLBARS
452   def (Qtop_toolbar_shadow_color, XtNtopToolBarShadowColor);
453   def (Qbottom_toolbar_shadow_color, XtNbottomToolBarShadowColor);
454   def (Qbackground_toolbar_color, XtNbackgroundToolBarColor);
455   def (Qtop_toolbar_shadow_pixmap, XtNtopToolBarShadowPixmap);
456   def (Qbottom_toolbar_shadow_pixmap, XtNbottomToolBarShadowPixmap);
457   defi(Qtoolbar_shadow_thickness, XtNtoolBarShadowThickness);
458 #endif
459   def (Qscrollbar_placement, XtNscrollBarPlacement);
460   defi(Qinter_line_space, XtNinterline);
461   /* font, foreground */
462   def (Qiconic, XtNiconic);
463   def (Qbar_cursor, XtNbarCursor);
464   def (Qvisual_bell, XtNvisualBell);
465   defi(Qbell_volume, XtNbellVolume);
466   def (Qpointer_background, XtNpointerBackground);
467   def (Qpointer_color, XtNpointerColor);
468   def (Qtext_pointer, XtNtextPointer);
469   def (Qspace_pointer, XtNspacePointer);
470   def (Qmodeline_pointer, XtNmodeLinePointer);
471   def (Qgc_pointer, XtNgcPointer);
472   /* geometry, initial_geometry */
473   def (Qinitially_unmapped, XtNinitiallyUnmapped);
474   /* preferred_width, preferred_height */
475   def (Quse_backing_store, XtNuseBackingStore);
476
477   /* inherited: */
478
479   def (Qborder_color, XtNborderColor);
480   defi(Qborder_width, XtNborderWidth);
481   defi(Qwidth, XtNwidth);
482   defi(Qheight, XtNheight);
483   defi(Qleft, XtNx);
484   defi(Qtop, XtNy);
485
486 #undef def
487 }
488
489 static Lisp_Object
490 color_to_string (Widget w, unsigned long pixel)
491 {
492   char buf[255];
493
494   XColor color;
495   color.pixel = pixel;
496   XQueryColor (XtDisplay (w), w->core.colormap, &color);
497   sprintf (buf, "#%04x%04x%04x", color.red, color.green, color.blue);
498   return build_string (buf);
499 }
500
501 static void
502 x_get_top_level_position (Display *d, Window w, Position *x, Position *y)
503 {
504   Window root, parent = w, *children;
505   unsigned int nchildren;
506   XWindowAttributes xwa;
507
508   do
509     {
510       w = parent;
511       if (!XQueryTree (d, w, &root, &parent, &children, &nchildren))
512         {
513           *x = 0;
514           *y = 0;
515           return;
516         }
517       XFree (children);
518     }
519   while (root != parent);
520   XGetWindowAttributes (d, w, &xwa);
521   *x = xwa.x;
522   *y = xwa.y;
523 }
524
525 #if 0
526 static void
527 x_smash_bastardly_shell_position (Widget shell)
528 {
529   /* Naturally those bastards who wrote Xt couldn't be bothered
530      to learn about race conditions and such.  We can't trust
531      the X and Y values to have any semblance of correctness,
532      so we smash the right values in place. */
533
534  /* We might be called before we've actually realized the window (if
535      we're checking for the minibuffer resource).  This will bomb in
536      that case so we don't bother calling it. */
537   if (XtWindow (shell))
538     x_get_top_level_position (XtDisplay (shell), XtWindow (shell),
539                               &shell->core.x, &shell->core.y);
540 }
541 #endif /* 0 */
542
543 static Lisp_Object
544 x_frame_property (struct frame *f, Lisp_Object property)
545 {
546   Widget shell = FRAME_X_SHELL_WIDGET (f);
547   EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
548   Widget gw = (Widget) w;
549
550   if (EQ (Qleft, property) || EQ (Qtop, property))
551     {
552       Position x, y;
553       if (!XtWindow(shell))
554         return Qzero;
555       x_get_top_level_position (XtDisplay (shell), XtWindow (shell), &x, &y);
556       if (EQ (Qleft, property)) return make_int (x);
557       if (EQ (Qtop,  property)) return make_int (y);
558     }
559   if (EQ (Qborder_width, property))
560     return make_int (w->core.border_width);
561   if (EQ (Qinternal_border_width, property))
562     return make_int (w->emacs_frame.internal_border_width);
563   if (EQ (Qborder_color, property))
564     return color_to_string (gw, w->core.border_pixel);
565 #ifdef HAVE_TOOLBARS
566   if (EQ (Qtop_toolbar_shadow_color, property))
567     return color_to_string (gw, w->emacs_frame.top_toolbar_shadow_pixel);
568   if (EQ (Qbottom_toolbar_shadow_color, property))
569     return color_to_string (gw, w->emacs_frame.bottom_toolbar_shadow_pixel);
570   if (EQ (Qbackground_toolbar_color, property))
571     return color_to_string (gw, w->emacs_frame.background_toolbar_pixel);
572   if (EQ (Qtoolbar_shadow_thickness, property))
573     return make_int (w->emacs_frame.toolbar_shadow_thickness);
574 #endif /* HAVE_TOOLBARS */
575   if (EQ (Qinter_line_space, property))
576     return make_int (w->emacs_frame.interline);
577   if (EQ (Qwindow_id, property))
578     return Fx_window_id (make_frame (f));
579
580   return Qunbound;
581 }
582
583 static int
584 x_internal_frame_property_p (struct frame *f, Lisp_Object property)
585 {
586   return EQ (property, Qleft)
587     || EQ (property, Qtop)
588     || EQ (property, Qborder_width)
589     || EQ (property, Qinternal_border_width)
590     || EQ (property, Qborder_color)
591 #ifdef HAVE_TOOLBARS
592     || EQ (property, Qtop_toolbar_shadow_color)
593     || EQ (property, Qbottom_toolbar_shadow_color)
594     || EQ (property, Qbackground_toolbar_color)
595     || EQ (property, Qtoolbar_shadow_thickness)
596 #endif /* HAVE_TOOLBARS */
597     || EQ (property, Qinter_line_space)
598     || EQ (property, Qwindow_id)
599     || STRINGP (property);
600 }
601
602 static Lisp_Object
603 x_frame_properties (struct frame *f)
604 {
605   Lisp_Object props = Qnil;
606   Widget shell = FRAME_X_SHELL_WIDGET (f);
607   EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
608   Widget gw = (Widget) w;
609   Position x, y;
610
611   props = cons3 (Qwindow_id, Fx_window_id (make_frame (f)), props);
612   props = cons3 (Qinter_line_space, make_int (w->emacs_frame.interline), props);
613
614 #ifdef HAVE_TOOLBARS
615   props = cons3 (Qtoolbar_shadow_thickness,
616                  make_int (w->emacs_frame.toolbar_shadow_thickness),
617                  props);
618   props = cons3 (Qbackground_toolbar_color,
619                  color_to_string (gw, w->emacs_frame.background_toolbar_pixel),
620                  props);
621   props = cons3 (Qbottom_toolbar_shadow_color,
622                  color_to_string (gw, w->emacs_frame.bottom_toolbar_shadow_pixel),
623                  props);
624   props = cons3 (Qtop_toolbar_shadow_color,
625                  color_to_string (gw, w->emacs_frame.top_toolbar_shadow_pixel),
626                  props);
627 #endif /* HAVE_TOOLBARS */
628
629   props = cons3 (Qborder_color,
630                  color_to_string (gw, w->core.border_pixel), props);
631   props = cons3 (Qinternal_border_width,
632                  make_int (w->emacs_frame.internal_border_width), props);
633   props = cons3 (Qborder_width, make_int (w->core.border_width), props);
634
635   if (!XtWindow(shell))
636     x = y = 0;
637   else
638     x_get_top_level_position (XtDisplay (shell), XtWindow (shell), &x, &y);
639
640   props = cons3 (Qtop,  make_int (y), props);
641   props = cons3 (Qleft, make_int (x), props);
642
643   return props;
644 }
645
646 \f
647 /* Functions called only from `x_set_frame_properties' to set
648    individual properties. */
649
650 static void
651 x_set_frame_text_value (struct frame *f, Bufbyte *value,
652                         String Xt_resource_name,
653                         String Xt_resource_encoding_name)
654 {
655   Atom encoding = XA_STRING;
656   String new_XtValue = (String) value;
657   String old_XtValue = NULL;
658
659 #ifdef MULE
660   Bufbyte *ptr;
661   /* Optimize for common ASCII case */
662   for (ptr = value; *ptr; ptr++)
663     if (!BYTE_ASCII_P (*ptr))
664       {
665         const char * tmp;
666         encoding = DEVICE_XATOM_COMPOUND_TEXT (XDEVICE (FRAME_DEVICE (f)));
667         C_STRING_TO_EXTERNAL (value, tmp, Qctext);
668         new_XtValue = (String) tmp;
669         break;
670       }
671 #endif /* MULE */
672
673   /* #### Caching is device-independent - belongs in update_frame_title. */
674   Xt_GET_VALUE (FRAME_X_SHELL_WIDGET (f), Xt_resource_name, &old_XtValue);
675   if (!old_XtValue || strcmp (new_XtValue, old_XtValue))
676     {
677       Arg al[2];
678       XtSetArg (al[0], Xt_resource_name, new_XtValue);
679       XtSetArg (al[1], Xt_resource_encoding_name, encoding);
680       XtSetValues (FRAME_X_SHELL_WIDGET (f), al, 2);
681     }
682 }
683
684 static void
685 x_set_title_from_bufbyte (struct frame *f, Bufbyte *name)
686 {
687   x_set_frame_text_value (f, name, XtNtitle, XtNtitleEncoding);
688 }
689
690 static void
691 x_set_icon_name_from_bufbyte (struct frame *f, Bufbyte *name)
692 {
693   x_set_frame_text_value (f, name, XtNiconName, XtNiconNameEncoding);
694 }
695
696 /* Set the initial frame size as specified.  This function is used
697    when the frame's widgets have not yet been realized.  In this
698    case, it is not sufficient just to set the width and height of
699    the EmacsFrame widget, because they will be ignored when the
700    widget is realized (instead, the shell's geometry resource is
701    used). */
702
703 static void
704 x_set_initial_frame_size (struct frame *f, int flags, int x, int y,
705                           unsigned int w, unsigned int h)
706 {
707   char shell_geom [255];
708   int xval, yval;
709   char xsign, ysign;
710   char uspos = !!(flags & (XValue | YValue));
711   char ussize = !!(flags & (WidthValue | HeightValue));
712   char *temp;
713
714   /* assign the correct size to the EmacsFrame widget ... */
715   EmacsFrameSetCharSize (FRAME_X_TEXT_WIDGET (f), w, h);
716
717   /* and also set the WMShell's geometry */
718   (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign = '+');
719   (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign = '+');
720
721   if (uspos && ussize)
722     sprintf (shell_geom, "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign, yval);
723   else if (uspos)
724     sprintf (shell_geom, "=%c%d%c%d", xsign, xval, ysign, yval);
725   else if (ussize)
726     sprintf (shell_geom, "=%dx%d", w, h);
727
728   if (uspos || ussize)
729     {
730       temp = (char *) xmalloc (1 + strlen (shell_geom));
731       strcpy (temp, shell_geom);
732       FRAME_X_GEOM_FREE_ME_PLEASE (f) = temp;
733     }
734   else
735     temp = NULL;
736
737   Xt_SET_VALUE (FRAME_X_SHELL_WIDGET (f), XtNgeometry, temp);
738 }
739
740 /* Report to X that a frame property of frame S is being set or changed.
741    If the property is not specially recognized, do nothing.
742  */
743
744 static void
745 x_set_frame_properties (struct frame *f, Lisp_Object plist)
746 {
747   Position x, y;
748   Dimension width = 0, height = 0;
749   Bool width_specified_p = False;
750   Bool height_specified_p = False;
751   Bool x_position_specified_p = False;
752   Bool y_position_specified_p = False;
753   Bool internal_border_width_specified = False;
754   Lisp_Object tail;
755   Widget w = FRAME_X_TEXT_WIDGET (f);
756
757   for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
758     {
759       Lisp_Object prop = Fcar (tail);
760       Lisp_Object val = Fcar (Fcdr (tail));
761
762       if (STRINGP (prop))
763         {
764           const char *extprop;
765
766           if (XSTRING_LENGTH (prop) == 0)
767             continue;
768
769           LISP_STRING_TO_EXTERNAL (prop, extprop, Qctext);
770           if (STRINGP (val))
771             {
772               const Extbyte *extval;
773               Extcount extvallen;
774
775               TO_EXTERNAL_FORMAT (LISP_STRING, val,
776                                   ALLOCA, (extval, extvallen),
777                                   Qctext);
778               XtVaSetValues (w, XtVaTypedArg, extprop,
779                              XtRString, extval, extvallen + 1,
780                              (XtArgVal) NULL);
781             }
782           else
783             XtVaSetValues (w, XtVaTypedArg, extprop, XtRInt,
784                            XINT (val), sizeof (int),
785                            (XtArgVal) NULL);
786         }
787       else if (SYMBOLP (prop))
788         {
789           Lisp_Object str = Fget (prop, Qx_resource_name, Qnil);
790           int int_p = !NILP (Fget (prop, Qintegerp, Qnil));
791
792           if (NILP (prop) || NILP (str))
793             {
794               /* Kludge to handle the font property. */
795               if (EQ (prop, Qfont))
796                 {
797                   /* If the value is not a string we silently ignore it. */
798                   if (STRINGP (val))
799                     {
800                       Lisp_Object frm, font_spec;
801
802                       XSETFRAME (frm, f);
803                       font_spec = Fget (Fget_face (Qdefault), Qfont, Qnil);
804
805                       Fadd_spec_to_specifier (font_spec, val, frm, Qnil, Qnil);
806                       update_frame_face_values (f);
807                     }
808
809                   continue;
810                 }
811               else
812                 continue;
813             }
814           CHECK_STRING (str);
815
816           /* Kludge the width/height so that we interpret them in characters
817              instead of pixels.  Yuck yuck yuck. */
818           if (!strcmp ((char *) XSTRING_DATA (str), "width"))
819             {
820               CHECK_INT (val);
821               width = XINT (val);
822               width_specified_p = True;
823               continue;
824             }
825           if (!strcmp ((char *) XSTRING_DATA (str), "height"))
826             {
827               CHECK_INT (val);
828               height = XINT (val);
829               height_specified_p = True;
830               continue;
831             }
832           /* Further kludge the x/y. */
833           if (!strcmp ((char *) XSTRING_DATA (str), "x"))
834             {
835               CHECK_INT (val);
836               x = (Position) XINT (val);
837               x_position_specified_p = True;
838               continue;
839             }
840           if (!strcmp ((char *) XSTRING_DATA (str), "y"))
841             {
842               CHECK_INT (val);
843               y = (Position) XINT (val);
844               y_position_specified_p = True;
845               continue;
846             }
847           /* Have you figured out by now that this entire function is
848              one gigantic kludge? */
849           if (!strcmp ((char *) XSTRING_DATA (str),
850                        "internalBorderWidth"))
851             {
852               internal_border_width_specified = True;
853             }
854
855           if (int_p)
856             {
857               CHECK_INT (val);
858               Xt_SET_VALUE (w, (char *) XSTRING_DATA (str), XINT (val));
859             }
860           else if (EQ (val, Qt))
861             {
862               Xt_SET_VALUE (w, (char *) XSTRING_DATA (str), True); /* XtN...*/
863             }
864           else if (EQ (val, Qnil))
865             {
866               Xt_SET_VALUE (w, (char *) XSTRING_DATA (str), False); /* XtN...*/
867             }
868           else
869             {
870               CHECK_STRING (val);
871               XtVaSetValues (w, XtVaTypedArg,
872                              /* XtN... */
873                              (char *) XSTRING_DATA (str),
874                              XtRString,
875                              XSTRING_DATA (val),
876                              XSTRING_LENGTH (val) + 1,
877                              (XtArgVal) NULL);
878             }
879
880 #ifdef HAVE_SCROLLBARS
881           if (!strcmp ((char *) XSTRING_DATA (str), "scrollBarWidth")
882               || !strcmp ((char *) XSTRING_DATA (str),
883                           "scrollBarHeight"))
884             {
885               x_update_frame_scrollbars (f);
886             }
887 #endif /* HAVE_SCROLLBARS */
888         }
889     }
890
891   /* Kludge kludge kludge.   We need to deal with the size and position
892    specially. */
893   {
894     int size_specified_p = width_specified_p || height_specified_p;
895     int position_specified_p = x_position_specified_p ||
896       y_position_specified_p;
897
898     if (!width_specified_p)
899       width = FRAME_WIDTH (f);
900     if (!height_specified_p)
901       height = FRAME_HEIGHT (f);
902
903     /* Kludge kludge kludge kludge. */
904     if (position_specified_p &&
905         (!x_position_specified_p || !y_position_specified_p))
906       {
907         Position dummy;
908         Widget shell = FRAME_X_SHELL_WIDGET (f);
909         x_get_top_level_position (XtDisplay (shell), XtWindow (shell),
910                                   (x_position_specified_p ? &dummy : &x),
911                                   (y_position_specified_p ? &dummy : &y));
912 #if 0
913         x = (int) (FRAME_X_SHELL_WIDGET (f)->core.x);
914         y = (int) (FRAME_X_SHELL_WIDGET (f)->core.y);
915 #endif
916       }
917
918     if (!f->init_finished)
919       {
920         int flags = (size_specified_p ? WidthValue | HeightValue : 0) |
921           (position_specified_p ?
922            XValue | YValue | (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0)
923            : 0);
924         if (size_specified_p
925             || position_specified_p
926             || internal_border_width_specified)
927           x_set_initial_frame_size (f, flags, x, y, width, height);
928       }
929     else
930       {
931         if (size_specified_p || internal_border_width_specified)
932           {
933             Lisp_Object frame;
934             XSETFRAME (frame, f);
935             Fset_frame_size (frame, make_int (width),
936                               make_int (height), Qnil);
937           }
938         if (position_specified_p)
939           {
940             Lisp_Object frame;
941             XSETFRAME (frame, f);
942             Fset_frame_position (frame, make_int (x), make_int (y));
943           }
944       }
945   }
946 }
947
948 static int frame_title_format_already_set;
949
950 static void
951 maybe_set_frame_title_format (Widget shell)
952 {
953
954   /* Only do this if this is the first X frame we're creating.
955
956      If the *title resource (or -title option) was specified, then
957      set frame-title-format to its value.
958      */
959
960   if (!frame_title_format_already_set)
961     {
962       /* No doubt there's a less stupid way to do this. */
963       char *results [2];
964       XtResource resources [2];
965       results [0] = results [1] = 0;
966       resources [0].resource_name = XtNtitle;
967       resources [0].resource_class = XtCTitle;
968       resources [0].resource_type = XtRString;
969       resources [0].resource_size = sizeof (String);
970       resources [0].resource_offset = 0;
971       resources [0].default_type = XtRString;
972       resources [0].default_addr = 0;
973       resources [1].resource_name = XtNiconName;
974       resources [1].resource_class = XtCIconName;
975       resources [1].resource_type = XtRString;
976       resources [1].resource_size = sizeof (String);
977       resources [1].resource_offset = sizeof (char *);
978       resources [1].default_type = XtRString;
979       resources [1].default_addr = 0;
980       XtGetSubresources (XtParent (shell), (XtPointer) results,
981                          shell->core.name,
982                          shell->core.widget_class->core_class.class_name,
983                          resources, XtNumber (resources), 0, 0);
984       if (results[0])
985         Vframe_title_format = build_string (results[0]);
986       if (results[1])
987         Vframe_icon_title_format = build_string (results[1]);
988     }
989
990   frame_title_format_already_set = 1;
991 }
992
993 #ifdef HAVE_CDE
994 #include <Dt/Dt.h>
995 #include <Dt/Dnd.h>
996
997 static Widget CurrentDragWidget = NULL;
998 static XtCallbackRec dnd_convert_cb_rec[2];
999 static XtCallbackRec dnd_destroy_cb_rec[2];
1000 static int drag_not_done = 0;
1001
1002 static void
1003 x_cde_destroy_callback (Widget widget, XtPointer clientData,
1004                         XtPointer callData)
1005 {
1006   DtDndDragFinishCallbackStruct *dragFinishInfo =
1007     (DtDndDragFinishCallbackStruct *)callData;
1008   DtDndContext *dragData = dragFinishInfo->dragData;
1009   int i;
1010
1011   /* free the items */
1012   if (callData != NULL && dragData != NULL)
1013     {
1014       if (dragData->protocol == DtDND_BUFFER_TRANSFER)
1015         {
1016           for (i = 0; i < dragData->numItems; i++)
1017             {
1018               XtFree((char *) dragData->data.buffers[i].bp);
1019               if (dragData->data.buffers[i].name)
1020                 XtFree(dragData->data.buffers[i].name);
1021             }
1022         }
1023       else
1024         {
1025           for (i = 0; i < dragData->numItems; i++)
1026             XtFree(dragData->data.files[i]);
1027         }
1028     }
1029
1030   /* free the data string */
1031   xfree (clientData);
1032
1033   CurrentDragWidget = NULL;
1034 }
1035
1036 static void
1037 x_cde_convert_callback (Widget widget, XtPointer clientData,
1038                         XtPointer callData)
1039 {
1040   DtDndConvertCallbackStruct *convertInfo =
1041     (DtDndConvertCallbackStruct *) callData;
1042   char *textdata = (char *) clientData;
1043   char *textptr = NULL;
1044   int i;
1045
1046   if (convertInfo == NULL)
1047     {
1048       return;
1049     }
1050
1051   if ((convertInfo->dragData->protocol != DtDND_BUFFER_TRANSFER
1052       && convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER) ||
1053      (convertInfo->reason != DtCR_DND_CONVERT_DATA))
1054     {
1055       return;
1056     }
1057
1058   for (textptr=textdata, i=0;
1059        i<convertInfo->dragData->numItems;
1060        textptr+=strlen(textptr)+1, i++)
1061     {
1062       if (convertInfo->dragData->protocol == DtDND_BUFFER_TRANSFER)
1063         {
1064           convertInfo->dragData->data.buffers[i].bp = XtNewString(textptr);
1065           convertInfo->dragData->data.buffers[i].size = strlen(textptr);
1066           convertInfo->dragData->data.buffers[i].name = NULL;
1067         }
1068       else
1069         {
1070           convertInfo->dragData->data.files[i] = XtNewString(textptr);
1071         }
1072     }
1073
1074   convertInfo->status = DtDND_SUCCESS;
1075 }
1076
1077 static Lisp_Object
1078 abort_current_drag(Lisp_Object arg)
1079 {
1080   if (CurrentDragWidget && drag_not_done)
1081     {
1082       XmDragCancel(CurrentDragWidget);
1083       CurrentDragWidget = NULL;
1084     }
1085   return arg;
1086 }
1087
1088 DEFUN ("cde-start-drag-internal", Fcde_start_drag_internal, 3, 3, 0, /*
1089 Start a CDE drag from a buffer.
1090 First argument is the event that started the drag (must be a
1091 button-press-event),
1092 second arg defines if the data should be treated as a buffer or
1093 a filename transfer (set to nil for buffer transfer),
1094 and the third argument is a list of data strings.
1095 WARNING: can only handle plain/text and file: transfers!
1096 */
1097        (event, dragtype, dragdata))
1098 {
1099   if (EVENTP (event))
1100     {
1101       struct frame *f = decode_x_frame (Fselected_frame (Qnil));
1102       XEvent x_event;
1103       Widget wid = FRAME_X_TEXT_WIDGET (f);
1104       Display *display = XtDisplayOfObject (wid);
1105       struct device *d    = get_device_from_display (display);
1106       struct x_device *xd = DEVICE_X_DATA (d);
1107       XWindowAttributes win_attrib;
1108       unsigned int modifier = 0, state = 0;
1109       char *Ctext;
1110       int numItems = 0, textlen = 0, pos = 0;
1111       Lisp_Event *lisp_event = XEVENT (event);
1112       Lisp_Object item = Qnil;
1113       struct gcpro gcpro1;
1114
1115       /* only drag if this is really a press */
1116       if (EVENT_TYPE(lisp_event) != button_press_event
1117           || !LISTP(dragdata))
1118         return Qnil;
1119
1120       GCPRO1 (item);
1121
1122       /*
1123        * not so cross hack that converts a emacs event back to a XEvent
1124        */
1125
1126       x_event.xbutton.type = ButtonPress;
1127       x_event.xbutton.send_event = False;
1128       x_event.xbutton.display = XtDisplayOfObject(wid);
1129       x_event.xbutton.window = XtWindowOfObject(wid);
1130       x_event.xbutton.root = XRootWindow(x_event.xbutton.display, 0);
1131       x_event.xbutton.subwindow = 0;
1132       x_event.xbutton.time = lisp_event->timestamp;
1133       x_event.xbutton.x = lisp_event->event.button.x;
1134       x_event.xbutton.y = lisp_event->event.button.y;
1135       if (Success == XGetWindowAttributes (x_event.xbutton.display,
1136                                            x_event.xbutton.window,
1137                                            &win_attrib))
1138         {
1139           x_event.xbutton.x_root = win_attrib.x + lisp_event->event.button.x;
1140           x_event.xbutton.y_root = win_attrib.y + lisp_event->event.button.y;
1141         }
1142       else
1143         {
1144           x_event.xbutton.x_root = lisp_event->event.button.x; /* this is wrong */
1145           x_event.xbutton.y_root = lisp_event->event.button.y;
1146         }
1147       modifier = lisp_event->event.button.modifiers;
1148       if (modifier & XEMACS_MOD_SHIFT)   state |= ShiftMask;
1149       if (modifier & XEMACS_MOD_CONTROL) state |= ControlMask;
1150       if (modifier & XEMACS_MOD_META)    state |= xd->MetaMask;
1151       if (modifier & XEMACS_MOD_SUPER)   state |= xd->SuperMask;
1152       if (modifier & XEMACS_MOD_HYPER)   state |= xd->HyperMask;
1153       if (modifier & XEMACS_MOD_ALT)     state |= xd->AltMask;
1154       state |= Button1Mask << (lisp_event->event.button.button-1);
1155
1156       x_event.xbutton.state = state;
1157       x_event.xbutton.button = lisp_event->event.button.button;
1158       x_event.xkey.same_screen = True;
1159
1160       /* convert data strings into a big string */
1161       item = dragdata;
1162       while (!NILP (item))
1163         {
1164           if (!STRINGP (XCAR (item)))
1165             {
1166               numItems=0;
1167               break;
1168             }
1169           textlen += XSTRING_LENGTH (XCAR (item)) + 1;
1170           numItems++;
1171           item = XCDR (item);
1172         }
1173
1174       if (numItems)
1175         {
1176           /*
1177            * concatenate all strings given to one large string, with
1178            * \0 as separator. List is ended by \0.
1179            */
1180           Ctext = (char *)xmalloc (textlen+1);
1181           Ctext[0] = 0;
1182
1183           item = dragdata;
1184           while (!NILP (item))
1185             {
1186               if (!STRINGP (XCAR (item)))
1187                 {
1188                   numItems=0;
1189                   xfree(Ctext);
1190                   Ctext=NULL;
1191                   break;
1192                 }
1193               strcpy (Ctext+pos, (const char *)XSTRING_DATA (XCAR (item)));
1194               pos += XSTRING_LENGTH (XCAR (item)) + 1;
1195               item = XCDR (item);
1196             }
1197           Ctext[pos] = 0;
1198
1199           dnd_convert_cb_rec[0].callback = x_cde_convert_callback;
1200           dnd_convert_cb_rec[0].closure  = (XtPointer) Ctext;
1201           dnd_convert_cb_rec[1].callback = NULL;
1202           dnd_convert_cb_rec[1].closure  = NULL;
1203
1204           dnd_destroy_cb_rec[0].callback = x_cde_destroy_callback;
1205           dnd_destroy_cb_rec[0].closure  = (XtPointer) Ctext;
1206           dnd_destroy_cb_rec[1].callback = NULL;
1207           dnd_destroy_cb_rec[1].closure  = NULL;
1208
1209           CurrentDragWidget =
1210             DtDndDragStart (wid, &x_event,
1211                             (NILP(dragtype)?DtDND_BUFFER_TRANSFER:DtDND_FILENAME_TRANSFER),
1212                             numItems,
1213                             XmDROP_COPY,
1214                             dnd_convert_cb_rec,
1215                             dnd_destroy_cb_rec,
1216                             NULL, 0);
1217         }
1218
1219       UNGCPRO;
1220
1221       return numItems?Qt:Qnil;
1222     }
1223
1224   return Qnil;
1225 }
1226
1227 static void
1228 x_cde_transfer_callback (Widget widget, XtPointer clientData,
1229                          XtPointer callData)
1230 {
1231   char *filePath, *hurl;
1232   int ii, enqueue=1;
1233   Lisp_Object frame = Qnil;
1234   Lisp_Object l_type = Qnil;
1235   Lisp_Object l_data = Qnil;
1236   DtDndTransferCallbackStruct *transferInfo = NULL;
1237   struct gcpro gcpro1, gcpro2, gcpro3;
1238
1239   /*
1240     this needs to be changed to the new protocol:
1241     - we need the button, modifier and pointer states to create a
1242       correct misc_user_event
1243     - the data must be converted to the new format (URL/MIME)
1244   */
1245   /* return; */
1246
1247   transferInfo = (DtDndTransferCallbackStruct *) callData;
1248   if (transferInfo == NULL)
1249     return;
1250
1251   GCPRO3 (frame, l_type, l_data);
1252
1253   frame = make_frame ((struct frame *) clientData);
1254
1255   if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER)
1256     {
1257       l_type = Qdragdrop_URL;
1258
1259       for (ii = 0; ii < transferInfo->dropData->numItems; ii++)
1260         {
1261           filePath = transferInfo->dropData->data.files[ii];
1262           hurl = dnd_url_hexify_string ((char *)filePath, "file:");
1263           /* #### Mule-izing required */
1264           l_data = Fcons (make_string ((Bufbyte* )hurl,
1265                                        strlen (hurl)),
1266                           l_data);
1267           xfree (hurl);
1268         }
1269     }
1270   else if (transferInfo->dropData->protocol == DtDND_BUFFER_TRANSFER)
1271     {
1272       int speccount = specpdl_depth();
1273
1274       /* Problem: all buffers a treated as text/plain!!!
1275          Solution: Also support DtDND_TEXT_TRANSFER
1276          perhaps implementation of the Motif protocol
1277          (which is the base of CDE) will clear this */
1278       l_type = Qdragdrop_MIME;
1279       record_unwind_protect(abort_current_drag, Qnil);
1280       drag_not_done = 1;
1281       for (ii = 0; ii < transferInfo->dropData->numItems; ii++)
1282         {
1283           /* let us forget this name thing for now... */
1284           /* filePath = transferInfo->dropData->data.buffers[ii].name;
1285              path = (filePath == NULL) ? Qnil
1286              : make_string ((Bufbyte *)filePath, strlen (filePath)); */
1287           /* what, if the data is no text, and how can I tell it? */
1288           l_data = Fcons ( list3 ( list1 ( make_string ((Bufbyte *)"text/plain", 10) ),
1289                                    make_string ((Bufbyte *)"8bit", 4),
1290                                    make_string ((Bufbyte *)transferInfo->dropData->data.buffers[ii].bp,
1291                                                 transferInfo->dropData->data.buffers[ii].size) ),
1292                            l_data );
1293         }
1294       drag_not_done = 0;
1295       unbind_to(speccount, Qnil);
1296     }
1297   else /* the other cases: NOOP_TRANSFER */
1298     enqueue=0;
1299
1300   /* The Problem: no button and mods from CDE... */
1301   if (enqueue)
1302     enqueue_misc_user_event_pos ( frame, Qdragdrop_drop_dispatch,
1303                                   Fcons (l_type, l_data),
1304                                   0 /* this is the button */,
1305                                   0 /* these are the mods */,
1306                                   transferInfo->x,
1307                                   transferInfo->y);
1308
1309   UNGCPRO;
1310   return;
1311 }
1312 #endif /* HAVE_CDE */
1313
1314 #ifdef HAVE_OFFIX_DND
1315
1316 DEFUN ("offix-start-drag-internal", Foffix_start_drag_internal, 2, 3, 0, /*
1317 Start a OffiX drag from a buffer.
1318 First arg is the event that started the drag,
1319 second arg should be some string, and the third
1320 is the type of the data (this should be an int).
1321 The type defaults to DndText (4).
1322 */
1323        (event, data, dtyp))
1324 {
1325   if (EVENTP(event))
1326     {
1327       struct frame *f = decode_x_frame (Fselected_frame (Qnil));
1328       XEvent x_event;
1329       Widget wid = FRAME_X_TEXT_WIDGET (f);
1330       Display *display = XtDisplayOfObject (wid);
1331       struct device *d    = get_device_from_display (display);
1332       struct x_device *xd = DEVICE_X_DATA (d);
1333       XWindowAttributes win_attrib;
1334       unsigned int modifier = 0, state = 0;
1335       char *dnd_data = NULL;
1336       unsigned long dnd_len = 0;
1337       int dnd_typ = DndText, dnd_dealloc = 0;
1338       Lisp_Event *lisp_event = XEVENT (event);
1339
1340       /* only drag if this is really a press */
1341       if (EVENT_TYPE(lisp_event) != button_press_event)
1342         return Qnil;
1343
1344       /* get the desired type */
1345       if (!NILP (dtyp) && INTP (dtyp))
1346         dnd_typ = XINT (dtyp);
1347
1348       if (dnd_typ == DndFiles)
1349         {
1350           Lisp_Object run = data;
1351           int len = 0;
1352
1353           if (NILP ( Flistp (data)))
1354             return Qnil;
1355
1356           /* construct the data from a list of files */
1357           dnd_len = 1;
1358           dnd_data = (char *) xmalloc (1);
1359           *dnd_data = 0;
1360           while (!NILP (run))
1361             {
1362               if (!STRINGP (XCAR (run)))
1363                 {
1364                   xfree (dnd_data);
1365                   return Qnil;
1366                 }
1367               len = XSTRING_LENGTH (XCAR (run)) + 1;
1368               dnd_data = (char *) xrealloc (dnd_data, dnd_len + len);
1369               strcpy (dnd_data + dnd_len - 1, (const char *)XSTRING_DATA (XCAR (run)));
1370               dnd_len += len;
1371               run = XCDR (run);
1372             }
1373
1374           dnd_data[dnd_len - 1] = 0; /* the list-ending zero */
1375           dnd_dealloc = 1;
1376
1377         }
1378       else
1379         {
1380           if (!STRINGP (data))
1381             return Qnil;
1382
1383           /* and what's with MULE data ??? */
1384           dnd_data = (char *)XSTRING_DATA (data);
1385           dnd_len  = XSTRING_LENGTH (data) + 1; /* the zero */
1386
1387         }
1388
1389       /* not so gross hack that converts an emacs event back to a XEvent */
1390
1391       x_event.xbutton.type = ButtonPress;
1392       x_event.xbutton.send_event = False;
1393       x_event.xbutton.display = XtDisplayOfObject(wid);
1394       x_event.xbutton.window = XtWindowOfObject(wid);
1395       x_event.xbutton.root = XRootWindow(x_event.xkey.display, 0);
1396       x_event.xbutton.subwindow = 0;
1397       x_event.xbutton.time = lisp_event->timestamp;
1398       x_event.xbutton.x = lisp_event->event.button.x;
1399       x_event.xbutton.y = lisp_event->event.button.y;
1400       if (Success == XGetWindowAttributes (x_event.xbutton.display,
1401                                            x_event.xbutton.window,
1402                                            &win_attrib))
1403         {
1404           x_event.xbutton.x_root = win_attrib.x + lisp_event->event.button.x;
1405           x_event.xbutton.y_root = win_attrib.y + lisp_event->event.button.y;
1406         }
1407       else
1408         {
1409           x_event.xbutton.x_root = lisp_event->event.button.x; /* this is wrong */
1410           x_event.xbutton.y_root = lisp_event->event.button.y;
1411         }
1412
1413       modifier = lisp_event->event.button.modifiers;
1414       if (modifier & XEMACS_MOD_SHIFT)   state |= ShiftMask;
1415       if (modifier & XEMACS_MOD_CONTROL) state |= ControlMask;
1416       if (modifier & XEMACS_MOD_META)    state |= xd->MetaMask;
1417       if (modifier & XEMACS_MOD_SUPER)   state |= xd->SuperMask;
1418       if (modifier & XEMACS_MOD_HYPER)   state |= xd->HyperMask;
1419       if (modifier & XEMACS_MOD_ALT)     state |= xd->AltMask;
1420       state |= Button1Mask << (lisp_event->event.button.button-1);
1421
1422       x_event.xbutton.state = state;
1423       x_event.xbutton.button = lisp_event->event.button.button;
1424       x_event.xkey.same_screen = True;
1425
1426       DndSetData(dnd_typ, (unsigned char *)dnd_data, dnd_len);
1427       if (dnd_dealloc)
1428         xfree (dnd_data);
1429
1430       /* the next thing blocks everything... */
1431       if (DndHandleDragging(wid, &x_event))
1432         return Qt;
1433     }
1434   return Qnil;
1435 }
1436
1437 #endif /* HAVE_OFFIX_DND */
1438
1439 \f
1440 /************************************************************************/
1441 /*                              widget creation                         */
1442 /************************************************************************/
1443
1444 /* The widget hierarchy is
1445
1446         argv[0]                 shell           container       FRAME-NAME
1447         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1448
1449    We accept geometry specs in this order:
1450
1451         *FRAME-NAME.geometry
1452         *EmacsFrame.geometry
1453         Emacs.geometry
1454
1455    Other possibilities for widget hierarchies might be
1456
1457         argv[0]                 frame           container       FRAME-NAME
1458         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1459    or
1460         argv[0]                 FRAME-NAME      container       FRAME-NAME
1461         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1462    or
1463         argv[0]                 FRAME-NAME      container       emacsTextPane
1464         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1465
1466 #ifdef EXTERNAL_WIDGET
1467    The ExternalShell widget is simply a replacement for the Shell widget
1468    which is able to deal with using an externally-supplied window instead
1469    of always creating its own.
1470 #endif
1471
1472 */
1473
1474 #ifdef EXTERNAL_WIDGET
1475
1476 static int
1477 is_valid_window (Window w, struct device *d)
1478 {
1479   XWindowAttributes xwa;
1480   Display *dpy = DEVICE_X_DISPLAY (d);
1481
1482   expect_x_error (dpy);
1483   XGetWindowAttributes (dpy, w, &xwa);
1484   return !x_error_occurred_p (dpy);
1485 }
1486
1487 #endif /* EXTERNAL_WIDGET */
1488
1489 /* This sends a synthetic mouse-motion event to the frame, if the mouse
1490    is over the frame.  This ensures that the cursor gets set properly
1491    before the user moves the mouse for the first time. */
1492
1493 static void
1494 x_send_synthetic_mouse_event (struct frame *f)
1495 {
1496   /* #### write this function. */
1497 }
1498
1499 static int
1500 first_x_frame_p (struct frame *f)
1501 {
1502   Lisp_Object rest = DEVICE_FRAME_LIST (XDEVICE (f->device));
1503   while (!NILP (rest) &&
1504          (f == XFRAME (XCAR (rest)) ||
1505           !FRAME_X_P (XFRAME (XCAR (rest)))))
1506     rest = XCDR (rest);
1507   return NILP (rest);
1508 }
1509
1510 /* Figure out what size the EmacsFrame widget should initially be,
1511    and set it.  Should be called after the default font has been
1512    determined but before the widget has been realized. */
1513
1514 static void
1515 x_initialize_frame_size (struct frame *f)
1516 {
1517   /* Geometry of the AppShell */
1518   int app_flags = 0;
1519   int app_x = 0;
1520   int app_y = 0;
1521   unsigned int app_w = 0;
1522   unsigned int app_h = 0;
1523
1524   /* Geometry of the EmacsFrame */
1525   int frame_flags = 0;
1526   int frame_x = 0;
1527   int frame_y = 0;
1528   unsigned int frame_w = 0;
1529   unsigned int frame_h = 0;
1530
1531   /* Hairily merged geometry */
1532   int x = 0;
1533   int y = 0;
1534   unsigned int w = 80;
1535   unsigned int h = 40;
1536   int flags = 0;
1537
1538   char *geom = 0, *ew_geom = 0;
1539   Boolean iconic_p = False, ew_iconic_p = False;
1540
1541   Widget wmshell = FRAME_X_SHELL_WIDGET (f);
1542   /* #### This may not be an ApplicationShell any more, with the 'popup
1543      frame property. */
1544   Widget app_shell = XtParent (wmshell);
1545   Widget ew = FRAME_X_TEXT_WIDGET (f);
1546
1547 /* set the position of the frame's root window now.  When the
1548    frame was created, the position was initialized to (0,0). */
1549   {
1550     struct window *win = XWINDOW (f->root_window);
1551
1552     WINDOW_LEFT (win) = FRAME_LEFT_BORDER_END (f)
1553       + FRAME_LEFT_GUTTER_BOUNDS (f);
1554     WINDOW_TOP (win) = FRAME_TOP_BORDER_END (f)
1555       + FRAME_TOP_GUTTER_BOUNDS (f);
1556
1557     if (!NILP (f->minibuffer_window))
1558       {
1559         win = XWINDOW (f->minibuffer_window);
1560         WINDOW_LEFT (win) = FRAME_LEFT_BORDER_END (f)
1561           + FRAME_LEFT_GUTTER_BOUNDS (f);
1562       }
1563   }
1564
1565 #ifdef EXTERNAL_WIDGET
1566   /* If we're an external widget, then the size of the frame is predetermined
1567      (by the client) and is not our decision to make. */
1568   if (FRAME_X_EXTERNAL_WINDOW_P (f))
1569     return;
1570 #endif
1571
1572 #if 0
1573   /* #### this junk has not been tested; therefore it's
1574      probably wrong.  Doesn't really matter at this point because
1575      currently all frames are either top-level or external widgets. */
1576
1577   /* If we're not our own top-level window, then we shouldn't go messing around
1578      with top-level shells or "Emacs.geometry" or any such stuff.  Therefore,
1579      we do as follows to determine the size of the frame:
1580
1581      1) If a value for the frame's "geometry" resource was specified, then
1582         use it.  (This specifies a size in characters.)
1583      2) Else, if the "width" and "height" resources were specified, then
1584         leave them alone.  (This is a value in pixels.  Sorry, we can't break
1585         Xt conventions here.)
1586      3) Else, assume a size of 64x12.  (This is somewhat arbitrary, but
1587         it's unlikely that a size of 80x40 is desirable because we're probably
1588         inside of a dialog box.)
1589
1590      Set the widget's x, y, height, and width as determined.  Don't set the
1591      top-level container widget, because we don't necessarily know what it
1592      is. (Assume it is smart and pays attention to our values.)
1593   */
1594
1595   if (!FRAME_X_TOP_LEVEL_FRAME_P (f))
1596     {
1597       Xt_GET_VALUE (ew, XtNgeometry, &ew_geom);
1598       if (ew_geom)
1599         frame_flags = XParseGeometry (ew_geom,
1600                                       &frame_x, &frame_y,
1601                                       &frame_w, &frame_h);
1602       if (! (frame_flags & (WidthValue | HeightValue)))
1603         {
1604           Arg al[2];
1605           XtSetArg (al [0], XtNwidth,  &frame_w);
1606           XtSetArg (al [1], XtNheight, &frame_h);
1607           XtGetValues (ew, al, 2);
1608           if (!frame_w && !frame_h)
1609             {
1610               frame_w = 64;
1611               frame_h = 12;
1612               frame_flags |= WidthValue | HeightValue;
1613             }
1614         }
1615       if (frame_flags & (WidthValue | HeightValue))
1616         EmacsFrameSetCharSize (ew, frame_w, frame_h);
1617       if (frame_flags & (XValue | YValue))
1618         {
1619           Arg al[2];
1620           XtSetArg (al [0], XtNwidth,  &frame_w);
1621           XtSetArg (al [1], XtNheight, &frame_h);
1622           XtGetValues (ew, al, 2);
1623
1624           if (frame_flags & XNegative)
1625             frame_x += frame_w;
1626           if (frame_flags & YNegative)
1627             frame_y += frame_h;
1628
1629           XtSetArg (al [0], XtNx, frame_x);
1630           XtSetArg (al [1], XtNy, frame_y);
1631           XtSetValues (ew, al, 2);
1632         }
1633       return;
1634     }
1635 #endif
1636
1637   /* OK, we're a top-level shell. */
1638
1639   if (!XtIsWMShell (wmshell))
1640     abort ();
1641
1642   /* If the EmacsFrame doesn't have a geometry but the shell does,
1643      treat that as the geometry of the frame.
1644      (Is this bogus? I'm not sure.) */
1645
1646   Xt_GET_VALUE (ew, XtNgeometry, &ew_geom);
1647   if (!ew_geom)
1648     {
1649       Xt_GET_VALUE (wmshell, XtNgeometry, &geom);
1650       if (geom)
1651         {
1652           ew_geom = geom;
1653           Xt_SET_VALUE (ew, XtNgeometry, ew_geom);
1654         }
1655     }
1656
1657   /* If the Shell is iconic, then the EmacsFrame is iconic.
1658      (Is this bogus? I'm not sure.) */
1659   Xt_GET_VALUE (ew, XtNiconic, &ew_iconic_p);
1660   if (!ew_iconic_p)
1661     {
1662       Xt_GET_VALUE (wmshell, XtNiconic, &iconic_p);
1663       if (iconic_p)
1664         {
1665           ew_iconic_p = iconic_p;
1666           Xt_SET_VALUE (ew, XtNiconic, iconic_p);
1667         }
1668     }
1669
1670   Xt_GET_VALUE (app_shell, XtNgeometry, &geom);
1671   if (geom)
1672     app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
1673
1674   if (ew_geom)
1675     frame_flags = XParseGeometry (ew_geom,
1676                                   &frame_x, &frame_y,
1677                                   &frame_w, &frame_h);
1678
1679   if (first_x_frame_p (f))
1680     {
1681       /* If this is the first frame created:
1682          ====================================
1683
1684          - Use the ApplicationShell's size/position, if specified.
1685            (This is "Emacs.geometry", or the "-geometry" command line arg.)
1686          - Else use the EmacsFrame's size/position.
1687            (This is "*FRAME-NAME.geometry")
1688
1689          - If the AppShell is iconic, the frame should be iconic.
1690
1691          AppShell comes first so that -geometry always applies to the first
1692          frame created, even if there is an "every frame" entry in the
1693          resource database.
1694        */
1695       if (app_flags & (XValue | YValue))
1696         {
1697           x = app_x; y = app_y;
1698           flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
1699         }
1700       else if (frame_flags & (XValue | YValue))
1701         {
1702           x = frame_x; y = frame_y;
1703           flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
1704         }
1705
1706       if (app_flags & (WidthValue | HeightValue))
1707         {
1708           w = app_w; h = app_h;
1709           flags |= (app_flags & (WidthValue | HeightValue));
1710         }
1711       else if (frame_flags & (WidthValue | HeightValue))
1712         {
1713           w = frame_w; h = frame_h;
1714           flags |= (frame_flags & (WidthValue | HeightValue));
1715         }
1716
1717       /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1718       if (!ew_iconic_p)
1719         {
1720           Xt_GET_VALUE (app_shell, XtNiconic, &iconic_p);
1721           if (iconic_p)
1722             {
1723               ew_iconic_p = iconic_p;
1724               Xt_SET_VALUE (ew, XtNiconic, iconic_p);
1725             }
1726         }
1727     }
1728   else
1729     {
1730       /* If this is not the first frame created:
1731          ========================================
1732
1733          - use the EmacsFrame's size/position if specified
1734          - Otherwise, use the ApplicationShell's size, but not position.
1735
1736          So that means that one can specify the position of the first frame
1737          with "Emacs.geometry" or `-geometry'; but can only specify the
1738          position of subsequent frames with "*FRAME-NAME.geometry".
1739
1740          AppShell comes second so that -geometry does not apply to subsequent
1741          frames when there is an "every frame" entry in the resource db,
1742          but does apply to the first frame.
1743        */
1744       if (frame_flags & (XValue | YValue))
1745         {
1746           x = frame_x; y = frame_y;
1747           flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
1748         }
1749
1750       if (frame_flags & (WidthValue | HeightValue))
1751         {
1752           w = frame_w; h = frame_h;
1753           flags |= (frame_flags & (WidthValue | HeightValue));
1754         }
1755       else if (app_flags & (WidthValue | HeightValue))
1756         {
1757           w = app_w;
1758           h = app_h;
1759           flags |= (app_flags & (WidthValue | HeightValue));
1760         }
1761     }
1762
1763   x_set_initial_frame_size (f, flags, x, y, w, h);
1764 }
1765
1766 static void
1767 x_get_layout_sizes (struct frame *f, Dimension *topbreadth)
1768 {
1769   int i;
1770
1771   /* compute height of all top-area widgets */
1772   for (i=0, *topbreadth = 0; i<FRAME_X_NUM_TOP_WIDGETS (f); i++)
1773     {
1774       Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
1775       if (wid && XtIsManaged (wid))
1776         *topbreadth += wid->core.height + 2*wid->core.border_width;
1777     }
1778 }
1779
1780 static void
1781 x_layout_widgets (Widget w, XtPointer client_data, XtPointer call_data)
1782 {
1783   struct frame *f = (struct frame *) client_data;
1784   EmacsManagerResizeStruct *emst = (EmacsManagerResizeStruct *) call_data;
1785   Dimension width = emst->width;
1786   Dimension height = emst->height;
1787   Widget text = FRAME_X_TEXT_WIDGET (f);
1788   Dimension textbord = text->core.border_width;
1789   Dimension topbreadth;
1790   Position text_x = 0, text_y = 0;
1791   int i;
1792
1793   x_get_layout_sizes (f, &topbreadth);
1794
1795   /* first the menubar and psheets ... */
1796   for (i=0; i<FRAME_X_NUM_TOP_WIDGETS (f); i++)
1797     {
1798       Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
1799       if (wid && XtIsManaged (wid))
1800         {
1801           Dimension bord = wid->core.border_width;
1802           XtConfigureWidget (wid, 0, text_y,
1803                              width - 2*bord, wid->core.height,
1804                              bord);
1805           text_y += wid->core.height + 2*bord;
1806         }
1807     }
1808
1809 #ifdef HAVE_SCROLLBARS
1810   f->scrollbar_y_offset = topbreadth + textbord;
1811 #endif
1812
1813   /* finally the text area */
1814   XtConfigureWidget (text, text_x, text_y,
1815                      width - 2*textbord,
1816                      height - text_y - 2*textbord,
1817                      textbord);
1818 }
1819
1820 static void
1821 x_do_query_geometry (Widget w, XtPointer client_data, XtPointer call_data)
1822 {
1823   struct frame *f = (struct frame *) client_data;
1824   EmacsManagerQueryGeometryStruct *emst =
1825     (EmacsManagerQueryGeometryStruct *) call_data;
1826   Widget text = FRAME_X_TEXT_WIDGET (f);
1827   Dimension textbord = text->core.border_width;
1828   Dimension topbreadth;
1829   XtWidgetGeometry req, repl;
1830   int mask = emst->request_mode & (CWWidth | CWHeight);
1831
1832   x_get_layout_sizes (f, &topbreadth);
1833
1834   /* Strip away menubar from suggested size, and ask the text widget
1835      what size it wants to be.  */
1836   req.request_mode = mask;
1837   if (mask & CWWidth)
1838     req.width = emst->proposed_width - 2*textbord;
1839   if (mask & CWHeight)
1840     req.height = emst->proposed_height - topbreadth - 2*textbord;
1841   XtQueryGeometry (text, &req, &repl);
1842
1843   /* Now add the menubar back again */
1844   emst->proposed_width  = repl.width  + 2*textbord;
1845   emst->proposed_height = repl.height + topbreadth + 2*textbord;
1846 }
1847
1848 /* Creates the widgets for a frame.
1849    lisp_window_id is a Lisp description of an X window or Xt
1850    widget to parse.
1851
1852    This function does not create or map the windows.  (That is
1853    done by x_popup_frame().)
1854  */
1855 static void
1856 x_create_widgets (struct frame *f, Lisp_Object lisp_window_id,
1857                   Lisp_Object parent)
1858 {
1859   struct device *d = XDEVICE (f->device);
1860   Visual *visual = DEVICE_X_VISUAL (d);
1861   int depth = DEVICE_X_DEPTH (d);
1862   Colormap cmap = DEVICE_X_COLORMAP (d);
1863 #ifdef EXTERNAL_WIDGET
1864   Window window_id = 0;
1865 #endif
1866   const char *name;
1867   Arg al [25];
1868   int ac = 0;
1869   Widget text, container, shell;
1870   Widget parentwid = 0;
1871 #ifdef HAVE_MENUBARS
1872   int menubar_visible;
1873   Widget menubar;
1874 #endif
1875
1876   if (STRINGP (f->name))
1877     LISP_STRING_TO_EXTERNAL (f->name, name, 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 static void
2490 x_enable_frame (struct frame *f)
2491 {
2492   XtSetSensitive (FRAME_X_SHELL_WIDGET (f), True);
2493 }
2494
2495 static void
2496 x_disable_frame (struct frame *f)
2497 {
2498   XtSetSensitive (FRAME_X_SHELL_WIDGET (f), False);
2499 }
2500
2501 /* Change from withdrawn state to mapped state. */
2502 static void
2503 x_make_frame_visible (struct frame *f)
2504 {
2505   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2506
2507   if (!FRAME_VISIBLE_P(f))
2508     XMapRaised (display, XtWindow (FRAME_X_SHELL_WIDGET (f)));
2509   else
2510     x_raise_frame_1 (f, 0);
2511 }
2512
2513 /* Change from mapped state to withdrawn state. */
2514 static void
2515 x_make_frame_invisible (struct frame *f)
2516 {
2517   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2518
2519   if (!FRAME_VISIBLE_P(f))
2520     return;
2521
2522   if (!XWithdrawWindow (display,
2523                         XtWindow (FRAME_X_SHELL_WIDGET (f)),
2524                         DefaultScreen (display)))
2525     x_cant_notify_wm_error ();
2526 }
2527
2528 static int
2529 x_frame_visible_p (struct frame *f)
2530 {
2531 #if 0
2532   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2533   XWindowAttributes xwa;
2534   int result;
2535
2536   /* JV:
2537      This is bad, very bad :-(
2538      It is not compatible with our tristate visible and
2539      it should never ever change the visibility for us, this leads to
2540      the frame-freeze problem under fvwm because with the pager
2541
2542      Mappedness != Viewability != Visibility != Emacs f->visible
2543
2544      This first unequalness is the reason for the frame freezing problem
2545      under fvwm (it happens when the frame is another fvwm-page)
2546
2547      The second unequalness happen when it is on the same fvwm-page
2548      but in an invisible part of the visible screen.
2549
2550      For now we just return the XEmacs internal value --- which might not be up
2551      to date. Is that a problem? ---. Otherwise we should
2552      use async visibility like in standard Emacs.
2553      */
2554
2555   if (!XGetWindowAttributes (display,
2556                              XtWindow (FRAME_X_SHELL_WIDGET (f)),
2557                              &xwa))
2558     result = 0;
2559   else
2560     result = xwa.map_state == IsViewable;
2561   /* In this implementation it should at least be != IsUnmapped
2562      JV */
2563
2564   f->visible = result;
2565   return result;
2566 #endif /* 0 */
2567
2568   return f->visible;
2569 }
2570
2571 static int
2572 x_frame_totally_visible_p (struct frame *f)
2573 {
2574   return FRAME_X_TOTALLY_VISIBLE_P (f);
2575 }
2576
2577 /* Change window state from mapped to iconified. */
2578 static void
2579 x_iconify_frame (struct frame *f)
2580 {
2581   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2582
2583   if (!XIconifyWindow (display,
2584                        XtWindow (FRAME_X_SHELL_WIDGET (f)),
2585                        DefaultScreen (display)))
2586     x_cant_notify_wm_error ();
2587
2588   f->iconified = 1;
2589 }
2590
2591 /* Sets the X focus to frame f. */
2592 static void
2593 x_focus_on_frame (struct frame *f)
2594 {
2595   XWindowAttributes xwa;
2596   Widget shell_widget;
2597   int viewable = 0;
2598
2599   assert (FRAME_X_P (f));
2600
2601   shell_widget = FRAME_X_SHELL_WIDGET (f);
2602   if (!XtWindow (shell_widget))
2603     return;
2604
2605 #ifdef EXTERNAL_WIDGET
2606   if (FRAME_X_EXTERNAL_WINDOW_P (f))
2607     ExternalShellSetFocus (shell_widget);
2608 #endif /* EXTERNAL_WIDGET */
2609
2610   /* Do the ICCCM focus change if the window is still visible.
2611      The s->visible flag might not be up-to-date, because we might
2612      not have processed magic events recently.  So make a server
2613      round-trip to find out whether it's really mapped right now.
2614      We grab the server to do this, because that's the only way to
2615      eliminate the race condition.
2616    */
2617   XGrabServer (XtDisplay (shell_widget));
2618   if (XGetWindowAttributes (XtDisplay (shell_widget),
2619                             XtWindow (shell_widget),
2620                             &xwa))
2621     /* JV: it is bad to change the visibility like this, so we don't for the
2622        moment, at least change_frame_visibility should be called
2623        Note also that under fvwm a frame can be Viewable (and thus Mapped)
2624        but still X-invisible
2625     f->visible = xwa.map_state == IsViewable; */
2626     viewable = xwa.map_state == IsViewable;
2627
2628
2629   if (viewable)
2630     {
2631       Window focus;
2632       int revert_to;
2633       XGetInputFocus (XtDisplay (shell_widget), &focus, &revert_to);
2634       /* Don't explicitly set the focus on this window unless the focus
2635          was on some other window (not PointerRoot).  Note that, even when
2636          running a point-to-type window manager like *twm, there is always
2637          a focus window; the window manager maintains that based on the
2638          mouse position.  If you set the "NoTitleFocus" option in these
2639          window managers, then the server itself maintains the focus via
2640          PointerRoot, and changing that to focus on the window would make
2641          the window grab the focus.  Very bad.
2642          */
2643       if (focus != PointerRoot)
2644         {
2645           XSetInputFocus (XtDisplay (shell_widget),
2646                           XtWindow (shell_widget),
2647                           RevertToParent,
2648                           DEVICE_X_MOUSE_TIMESTAMP
2649                           (XDEVICE (FRAME_DEVICE (f))));
2650           XFlush (XtDisplay (shell_widget));
2651         }
2652     }
2653   XUngrabServer (XtDisplay (shell_widget));
2654   XFlush (XtDisplay (shell_widget)); /* hey, I'd like to DEBUG this... */
2655 }
2656
2657 /* Destroy the X window of frame F.  */
2658 static void
2659 x_delete_frame (struct frame *f)
2660 {
2661   Display *dpy;
2662
2663 #ifndef HAVE_WMCOMMAND
2664   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2665     x_wm_maybe_move_wm_command (f);
2666 #endif /* HAVE_WMCOMMAND */
2667
2668 #ifdef HAVE_CDE
2669   DtDndDropUnregister (FRAME_X_TEXT_WIDGET (f));
2670 #endif /* HAVE_CDE */
2671
2672   assert (FRAME_X_SHELL_WIDGET (f) != 0);
2673   dpy = XtDisplay (FRAME_X_SHELL_WIDGET (f));
2674
2675 #ifdef EXTERNAL_WIDGET
2676   expect_x_error (dpy);
2677   /* for obscure reasons having (I think) to do with the internal
2678      window-to-widget hierarchy maintained by Xt, we have to call
2679      XtUnrealizeWidget() here.  Xt can really suck. */
2680   if (f->being_deleted)
2681     XtUnrealizeWidget (FRAME_X_SHELL_WIDGET (f));
2682   XtDestroyWidget (FRAME_X_SHELL_WIDGET (f));
2683   x_error_occurred_p (dpy);
2684 #else
2685   XtDestroyWidget (FRAME_X_SHELL_WIDGET (f));
2686   /* make sure the windows are really gone! */
2687   /* #### Is this REALLY necessary? */
2688   XFlush (dpy);
2689 #endif /* EXTERNAL_WIDGET */
2690
2691   FRAME_X_SHELL_WIDGET (f) = 0;
2692
2693   if (FRAME_X_GEOM_FREE_ME_PLEASE (f))
2694     {
2695       xfree (FRAME_X_GEOM_FREE_ME_PLEASE (f));
2696       FRAME_X_GEOM_FREE_ME_PLEASE (f) = 0;
2697     }
2698
2699   if (f->frame_data)
2700     {
2701       xfree (f->frame_data);
2702       f->frame_data = 0;
2703     }
2704 }
2705
2706 static void
2707 x_update_frame_external_traits (struct frame* frm, Lisp_Object name)
2708 {
2709   Arg al[10];
2710   int ac = 0;
2711   Lisp_Object frame;
2712
2713   XSETFRAME(frame, frm);
2714
2715   if (EQ (name, Qforeground))
2716    {
2717      Lisp_Object color = FACE_FOREGROUND (Vdefault_face, frame);
2718      XColor fgc;
2719
2720      if (!EQ (color, Vthe_null_color_instance))
2721        {
2722          fgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
2723          XtSetArg (al[ac], XtNforeground, (void *) fgc.pixel); ac++;
2724        }
2725    }
2726   else if (EQ (name, Qbackground))
2727    {
2728      Lisp_Object color = FACE_BACKGROUND (Vdefault_face, frame);
2729      XColor bgc;
2730
2731      if (!EQ (color, Vthe_null_color_instance))
2732        {
2733          bgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
2734          XtSetArg (al[ac], XtNbackground, (void *) bgc.pixel); ac++;
2735        }
2736
2737      /* Really crappy way to force the modeline shadows to be
2738         redrawn.  But effective. */
2739      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (frm);
2740      MARK_FRAME_CHANGED (frm);
2741    }
2742   else if (EQ (name, Qfont))
2743    {
2744      Lisp_Object font = FACE_FONT (Vdefault_face, frame, Vcharset_ascii);
2745
2746      if (!EQ (font, Vthe_null_font_instance))
2747        XtSetArg (al[ac], XtNfont,
2748                  (void *) FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
2749      ac++;
2750    }
2751   else
2752    abort ();
2753
2754   XtSetValues (FRAME_X_TEXT_WIDGET (frm), al, ac);
2755
2756 #ifdef HAVE_TOOLBARS
2757   /* Setting the background clears the entire frame area
2758     including the toolbar so we force an immediate redraw of
2759     it. */
2760   if (EQ (name, Qbackground))
2761     MAYBE_DEVMETH (XDEVICE (frm->device), redraw_frame_toolbars, (frm));
2762 #endif /* HAVE_TOOLBARS */
2763
2764   /* Set window manager resize increment hints according to
2765      the new character size */
2766   if (EQ (name, Qfont))
2767     EmacsFrameRecomputeCellSize (FRAME_X_TEXT_WIDGET (frm));
2768 }
2769
2770 \f
2771 /************************************************************************/
2772 /*                            initialization                            */
2773 /************************************************************************/
2774
2775 void
2776 syms_of_frame_x (void)
2777 {
2778   defsymbol (&Qwindow_id, "window-id");
2779   defsymbol (&Qx_resource_name, "x-resource-name");
2780
2781   DEFSUBR (Fx_window_id);
2782 #ifdef HAVE_CDE
2783   DEFSUBR (Fcde_start_drag_internal);
2784 #endif
2785 #ifdef HAVE_OFFIX_DND
2786   DEFSUBR (Foffix_start_drag_internal);
2787 #endif
2788 }
2789
2790 void
2791 console_type_create_frame_x (void)
2792 {
2793   /* frame methods */
2794   CONSOLE_HAS_METHOD (x, init_frame_1);
2795   CONSOLE_HAS_METHOD (x, init_frame_2);
2796   CONSOLE_HAS_METHOD (x, init_frame_3);
2797   CONSOLE_HAS_METHOD (x, mark_frame);
2798   CONSOLE_HAS_METHOD (x, focus_on_frame);
2799   CONSOLE_HAS_METHOD (x, delete_frame);
2800   CONSOLE_HAS_METHOD (x, get_mouse_position);
2801   CONSOLE_HAS_METHOD (x, set_mouse_position);
2802   CONSOLE_HAS_METHOD (x, raise_frame);
2803   CONSOLE_HAS_METHOD (x, lower_frame);
2804   CONSOLE_HAS_METHOD (x, enable_frame);
2805   CONSOLE_HAS_METHOD (x, disable_frame);
2806   CONSOLE_HAS_METHOD (x, make_frame_visible);
2807   CONSOLE_HAS_METHOD (x, make_frame_invisible);
2808   CONSOLE_HAS_METHOD (x, iconify_frame);
2809   CONSOLE_HAS_METHOD (x, set_frame_size);
2810   CONSOLE_HAS_METHOD (x, set_frame_position);
2811   CONSOLE_HAS_METHOD (x, frame_property);
2812   CONSOLE_HAS_METHOD (x, internal_frame_property_p);
2813   CONSOLE_HAS_METHOD (x, frame_properties);
2814   CONSOLE_HAS_METHOD (x, set_frame_properties);
2815   CONSOLE_HAS_METHOD (x, set_title_from_bufbyte);
2816   CONSOLE_HAS_METHOD (x, set_icon_name_from_bufbyte);
2817   CONSOLE_HAS_METHOD (x, frame_visible_p);
2818   CONSOLE_HAS_METHOD (x, frame_totally_visible_p);
2819   CONSOLE_HAS_METHOD (x, frame_iconified_p);
2820   CONSOLE_HAS_METHOD (x, set_frame_pointer);
2821   CONSOLE_HAS_METHOD (x, set_frame_icon);
2822   CONSOLE_HAS_METHOD (x, get_frame_parent);
2823   CONSOLE_HAS_METHOD (x, update_frame_external_traits);
2824 }
2825
2826 void
2827 vars_of_frame_x (void)
2828 {
2829 #ifdef EXTERNAL_WIDGET
2830   Fprovide (intern ("external-widget"));
2831 #endif
2832
2833   /* this call uses only safe functions from emacs.c */
2834   init_x_prop_symbols ();
2835
2836   DEFVAR_LISP ("default-x-frame-plist", &Vdefault_x_frame_plist /*
2837 Plist of default frame-creation properties for X frames.
2838 These override what is specified in the resource database and in
2839 `default-frame-plist', but are overridden by the arguments to the
2840 particular call to `make-frame'.
2841
2842 Note: In many cases, properties of a frame are available as specifiers
2843 instead of through the frame-properties mechanism.
2844
2845 Here is a list of recognized frame properties, other than those
2846 documented in `set-frame-properties' (they can be queried and
2847 set at any time, except as otherwise noted):
2848
2849   window-id                     The X window ID corresponding to the
2850                                 frame.  May be set only at startup, and
2851                                 only if external widget support was
2852                                 compiled in; doing so causes the frame
2853                                 to be created as an "external widget"
2854                                 in another program that uses an existing
2855                                 window in the program rather than creating
2856                                 a new one.
2857   initially-unmapped            If non-nil, the frame will not be visible
2858                                 when it is created.  In this case, you
2859                                 need to call `make-frame-visible' to make
2860                                 the frame appear.
2861   popup                         If non-nil, it should be a frame, and this
2862                                 frame will be created as a "popup" frame
2863                                 whose parent is the given frame.  This
2864                                 will make the window manager treat the
2865                                 frame as a dialog box, which may entail
2866                                 doing different things (e.g. not asking
2867                                 for positioning, and not iconifying
2868                                 separate from its parent).
2869   inter-line-space              Not currently implemented.
2870   toolbar-shadow-thickness      Thickness of toolbar shadows.
2871   background-toolbar-color      Color of toolbar background.
2872   bottom-toolbar-shadow-color   Color of bottom shadows on toolbars.
2873                                 (*Not* specific to the bottom-toolbar.)
2874   top-toolbar-shadow-color      Color of top shadows on toolbars.
2875                                 (*Not* specific to the top-toolbar.)
2876   internal-border-width         Width of internal border around text area.
2877   border-width                  Width of external border around text area.
2878   top                           Y position (in pixels) of the upper-left
2879                                 outermost corner of the frame (i.e. the
2880                                 upper-left of the window-manager
2881                                 decorations).
2882   left                          X position (in pixels) of the upper-left
2883                                 outermost corner of the frame (i.e. the
2884                                 upper-left of the window-manager
2885                                 decorations).
2886   border-color                  Color of external border around text area.
2887   cursor-color                  Color of text cursor.
2888
2889 See also `default-frame-plist', which specifies properties which apply
2890 to all frames, not just X frames.
2891 */ );
2892   Vdefault_x_frame_plist = Qnil;
2893
2894   x_console_methods->device_specific_frame_props = &Vdefault_x_frame_plist;
2895 }