(Fget_range_char_table): Fix serious problem when `range' is nil.
[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   {
1815     Dimension nw = width - 2*textbord;
1816     Dimension nh = height - text_y - 2*textbord;
1817
1818     if (nh != f->pixheight || nw != f->pixwidth)
1819       MARK_FRAME_SIZE_SLIPPED (f);
1820     XtConfigureWidget (text, text_x, text_y, nw, nh, textbord);
1821   }
1822 }
1823
1824 static void
1825 x_do_query_geometry (Widget w, XtPointer client_data, XtPointer call_data)
1826 {
1827   struct frame *f = (struct frame *) client_data;
1828   EmacsManagerQueryGeometryStruct *emst =
1829     (EmacsManagerQueryGeometryStruct *) call_data;
1830   Widget text = FRAME_X_TEXT_WIDGET (f);
1831   Dimension textbord = text->core.border_width;
1832   Dimension topbreadth;
1833   XtWidgetGeometry req, repl;
1834   int mask = emst->request_mode & (CWWidth | CWHeight);
1835
1836   x_get_layout_sizes (f, &topbreadth);
1837
1838   /* Strip away menubar from suggested size, and ask the text widget
1839      what size it wants to be.  */
1840   req.request_mode = mask;
1841   if (mask & CWWidth)
1842     req.width = emst->proposed_width - 2*textbord;
1843   if (mask & CWHeight)
1844     req.height = emst->proposed_height - topbreadth - 2*textbord;
1845   XtQueryGeometry (text, &req, &repl);
1846
1847   /* Now add the menubar back again */
1848   emst->proposed_width  = repl.width  + 2*textbord;
1849   emst->proposed_height = repl.height + topbreadth + 2*textbord;
1850 }
1851
1852 /* Creates the widgets for a frame.
1853    lisp_window_id is a Lisp description of an X window or Xt
1854    widget to parse.
1855
1856    This function does not create or map the windows.  (That is
1857    done by x_popup_frame().)
1858  */
1859 static void
1860 x_create_widgets (struct frame *f, Lisp_Object lisp_window_id,
1861                   Lisp_Object parent)
1862 {
1863   struct device *d = XDEVICE (f->device);
1864   Visual *visual = DEVICE_X_VISUAL (d);
1865   int depth = DEVICE_X_DEPTH (d);
1866   Colormap cmap = DEVICE_X_COLORMAP (d);
1867 #ifdef EXTERNAL_WIDGET
1868   Window window_id = 0;
1869 #endif
1870   const char *name;
1871   Arg al [25];
1872   int ac = 0;
1873   Widget text, container, shell;
1874   Widget parentwid = 0;
1875 #ifdef HAVE_MENUBARS
1876   int menubar_visible;
1877   Widget menubar;
1878 #endif
1879
1880   if (STRINGP (f->name))
1881     LISP_STRING_TO_EXTERNAL (f->name, name, Qctext);
1882   else
1883     name = "emacs";
1884
1885   /* The widget hierarchy is
1886
1887         argv[0]                 shell           pane            FRAME-NAME
1888         ApplicationShell        EmacsShell      EmacsManager    EmacsFrame
1889
1890         (the type of the shell is ExternalShell if this frame is running
1891         in another client's window)
1892
1893         However the EmacsShell widget has WM_CLASS of FRAME-NAME/Emacs.
1894         Normally such shells have name/class shellname/appclass, which in this
1895         case would be "shell/Emacs" instead of "frame-name/Emacs".  We could
1896         also get around this by naming the shell "frame-name", but that would
1897         be confusing because the text area (the EmacsFrame widget inferior of
1898         the shell) is also called that.  So we just set the WM_CLASS property.
1899    */
1900
1901 #ifndef EXTERNAL_WIDGET
1902   if (!NILP (lisp_window_id))
1903     error ("support for external widgets was not enabled at compile-time");
1904 #else
1905   if (!NILP (lisp_window_id))
1906     {
1907       char *string;
1908
1909       CHECK_STRING (lisp_window_id);
1910       string = (char *) XSTRING_DATA (lisp_window_id);
1911       if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
1912         sscanf (string+2, "%lxu", &window_id);
1913 #if 0
1914       else if (string[0] == 'w')
1915         {
1916           sscanf (string+1, "%x", &parent_widget);
1917           if (parent_widget)
1918             window_id = XtWindow (parent_widget);
1919         }
1920 #endif
1921       else
1922         sscanf (string, "%lu", &window_id);
1923       if (!is_valid_window (window_id, d))
1924         error ("Invalid window %lu", (unsigned long) window_id);
1925       FRAME_X_EXTERNAL_WINDOW_P (f) = 1;
1926     } else
1927 #endif /* EXTERNAL_WIDGET */
1928       FRAME_X_TOP_LEVEL_FRAME_P (f) = 1;
1929
1930   ac = 0;
1931   XtSetArg (al[ac], XtNallowShellResize, True); ac++;
1932 #ifdef LWLIB_USES_MOTIF
1933   /* Motif sucks beans.  Without this in here, it will delete the window
1934      out from under us when it receives a WM_DESTROY_WINDOW message
1935      from the WM. */
1936   XtSetArg (al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
1937 #endif
1938
1939 #ifdef EXTERNAL_WIDGET
1940   if (window_id)
1941     {
1942       XtSetArg (al[ac], XtNwindow, window_id); ac++;
1943     }
1944   else
1945 #endif /* EXTERNAL_WIDGET */
1946     {
1947       XtSetArg (al[ac], XtNinput, True);       ac++;
1948       XtSetArg (al[ac], XtNminWidthCells, 10); ac++;
1949       XtSetArg (al[ac], XtNminHeightCells, 1); ac++;
1950       XtSetArg (al[ac], XtNvisual, visual);    ac++;
1951       XtSetArg (al[ac], XtNdepth, depth);      ac++;
1952       XtSetArg (al[ac], XtNcolormap, cmap);    ac++;
1953     }
1954
1955   if (!NILP (parent))
1956     {
1957       parentwid = FRAME_X_SHELL_WIDGET (XFRAME (parent));
1958       XtSetArg (al[ac], XtNtransientFor, parentwid); ac++;
1959     }
1960
1961   shell = XtCreatePopupShell ("shell",
1962                               (
1963 #ifdef EXTERNAL_WIDGET
1964                                window_id ? externalShellWidgetClass :
1965 #endif
1966                                parentwid ? transientEmacsShellWidgetClass :
1967                                topLevelEmacsShellWidgetClass
1968                                ),
1969                               parentwid ? parentwid :
1970                               DEVICE_XT_APP_SHELL (d),
1971                               al, ac);
1972   FRAME_X_SHELL_WIDGET (f) = shell;
1973   maybe_set_frame_title_format (shell);
1974
1975   /* Create the manager widget */
1976   ac = 0;
1977   XtSetArg (al[ac], XtNvisual, visual); ac++;
1978   XtSetArg (al[ac], XtNdepth, depth); ac++;
1979   XtSetArg (al[ac], XtNcolormap, cmap); ac++;
1980
1981   container = XtCreateWidget ("container",
1982                               emacsManagerWidgetClass, shell, al, ac);
1983   FRAME_X_CONTAINER_WIDGET (f) = container;
1984   XtAddCallback (container, XtNresizeCallback, x_layout_widgets,
1985                  (XtPointer) f);
1986   XtAddCallback (container, XtNqueryGeometryCallback, x_do_query_geometry,
1987                  (XtPointer) f);
1988
1989   /* Create the text area */
1990   ac = 0;
1991   XtSetArg (al[ac], XtNvisual, visual); ac++;
1992   XtSetArg (al[ac], XtNdepth, depth); ac++;
1993   XtSetArg (al[ac], XtNcolormap, cmap); ac++;
1994   XtSetArg (al[ac], XtNborderWidth, 0); ac++; /* should this be settable? */
1995   XtSetArg (al[ac], XtNemacsFrame,  f); ac++;
1996   text = XtCreateWidget (name, emacsFrameClass, container, al, ac);
1997   FRAME_X_TEXT_WIDGET (f) = text;
1998
1999 #ifdef HAVE_MENUBARS
2000   /* Create the initial menubar widget. */
2001   menubar_visible = x_initialize_frame_menubar (f);
2002   FRAME_X_TOP_WIDGETS (f)[0] = menubar = FRAME_X_MENUBAR_WIDGET (f);
2003   FRAME_X_NUM_TOP_WIDGETS (f) = 1;
2004
2005   if (menubar_visible)
2006     XtManageChild (menubar);
2007 #endif /* HAVE_MENUBARS */
2008   XtManageChild (text);
2009   XtManageChild (container);
2010 }
2011
2012 /* We used to call XtPopup() in x_popup_frame, but that doesn't give
2013    you control over whether the widget is initially mapped or not
2014    because XtPopup() makes an unconditional call to XMapRaised().
2015    Boy, those Xt designers were clever.
2016
2017    When we first removed it we only kept the XtRealizeWidget call in
2018    XtPopup.  For everything except HP's that was enough.  For HP's,
2019    though, the failure to call the popup callbacks resulted in XEmacs
2020    not accepting any input.  Bizarre but true.  Stupid but true.
2021
2022    So, in case there are any other gotchas floating out there along
2023    the same lines I've duplicated the majority of XtPopup here.  It
2024    assumes no grabs and that the widget is not already popped up, both
2025    valid assumptions for the one place this is called from. */
2026 static void
2027 xemacs_XtPopup (Widget widget)
2028 {
2029   ShellWidget shell_widget = (ShellWidget) widget;
2030   XtGrabKind call_data = XtGrabNone;
2031
2032   XtCallCallbacks (widget, XtNpopupCallback, (XtPointer)&call_data);
2033
2034   shell_widget->shell.popped_up = TRUE;
2035   shell_widget->shell.grab_kind = XtGrabNone;
2036   shell_widget->shell.spring_loaded = False;
2037
2038   if (shell_widget->shell.create_popup_child_proc != NULL)
2039     (*(shell_widget->shell.create_popup_child_proc))(widget);
2040
2041   /* The XtSetValues below are not in XtPopup menu.  We just want to
2042      make absolutely sure... */
2043   Xt_SET_VALUE (widget, XtNmappedWhenManaged, False);
2044   XtRealizeWidget (widget);
2045   Xt_SET_VALUE (widget, XtNmappedWhenManaged, True);
2046 }
2047
2048 /* create the windows for the specified frame and display them.
2049    Note that the widgets have already been created, and any
2050    necessary geometry calculations have already been done. */
2051 static void
2052 x_popup_frame (struct frame *f)
2053 {
2054   Widget shell_widget = FRAME_X_SHELL_WIDGET (f);
2055   Widget frame_widget = FRAME_X_TEXT_WIDGET (f);
2056   struct device *d = XDEVICE (FRAME_DEVICE (f));
2057
2058   /* Before mapping the window, make sure that the WMShell's notion of
2059      whether it should be iconified is synchronized with the EmacsFrame's
2060      notion.
2061      */
2062   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2063     x_wm_set_shell_iconic_p (shell_widget,
2064                              ((EmacsFrame) frame_widget)
2065                              ->emacs_frame.iconic);
2066
2067   xemacs_XtPopup (shell_widget);
2068
2069   if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
2070     XtMapWidget (shell_widget);
2071   else
2072     {
2073       /* We may have set f->visible to 1 in x_init_frame(), so undo
2074          that now. */
2075       FRAME_X_TOTALLY_VISIBLE_P (f) = 0;
2076       f->visible = 0;
2077     }
2078
2079 #ifdef EXTERNAL_WIDGET
2080   if (FRAME_X_EXTERNAL_WINDOW_P (f))
2081     ExternalShellReady (shell_widget, XtWindow (frame_widget), KeyPressMask);
2082   else
2083 #endif
2084     if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2085       {
2086         /* tell the window manager about us. */
2087         x_wm_store_class_hints (shell_widget, XtName (frame_widget));
2088
2089 #ifndef HAVE_WMCOMMAND
2090         x_wm_maybe_store_wm_command (f);
2091 #endif /* HAVE_WMCOMMAND */
2092
2093         x_wm_hack_wm_protocols (shell_widget);
2094       }
2095
2096 #ifdef HAVE_XIM
2097   XIM_init_frame (f);
2098 #endif /* HAVE_XIM */
2099
2100 #ifdef HACK_EDITRES
2101   /* Allow XEmacs to respond to EditRes requests.  See the O'Reilly Xt */
2102   /* Intrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
2103   /* pp. 483-493. */
2104   XtAddEventHandler (shell_widget,           /* the shell widget in question */
2105                      (EventMask) NoEventMask,/* OR with existing mask */
2106                      True,                   /* called on non-maskable events? */
2107                      (XtEventHandler) _XEditResCheckMessages, /* the handler */
2108                      NULL);
2109 #endif /* HACK_EDITRES */
2110
2111 #ifdef HAVE_CDE
2112   {
2113     XtCallbackRec dnd_transfer_cb_rec[2];
2114
2115     dnd_transfer_cb_rec[0].callback = x_cde_transfer_callback;
2116     dnd_transfer_cb_rec[0].closure = (XtPointer) f;
2117     dnd_transfer_cb_rec[1].callback = NULL;
2118     dnd_transfer_cb_rec[1].closure = NULL;
2119
2120     DtDndVaDropRegister (FRAME_X_TEXT_WIDGET (f),
2121                          DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
2122                          XmDROP_COPY, dnd_transfer_cb_rec,
2123                          DtNtextIsBuffer, True,
2124                          DtNregisterChildren, True,
2125                          DtNpreserveRegistration, False,
2126                          NULL);
2127   }
2128 #endif /* HAVE_CDE */
2129
2130   /* Do a stupid property change to force the server to generate a
2131      propertyNotify event so that the event_stream server timestamp will
2132      be initialized to something relevant to the time we created the window.
2133      */
2134   XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
2135                    DEVICE_XATOM_WM_PROTOCOLS (d), XA_ATOM, 32, PropModeAppend,
2136                    (unsigned char*) NULL, 0);
2137
2138   x_send_synthetic_mouse_event (f);
2139 }
2140
2141 static void
2142 allocate_x_frame_struct (struct frame *f)
2143 {
2144   /* zero out all slots. */
2145   f->frame_data = xnew_and_zero (struct x_frame);
2146
2147   /* yeah, except the lisp ones */
2148   FRAME_X_ICON_PIXMAP (f) = Qnil;
2149   FRAME_X_ICON_PIXMAP_MASK (f) = Qnil;
2150 }
2151
2152 \f
2153 /************************************************************************/
2154 /*                              Lisp functions                          */
2155 /************************************************************************/
2156
2157 static void
2158 x_init_frame_1 (struct frame *f, Lisp_Object props)
2159 {
2160   /* This function can GC */
2161   Lisp_Object device = FRAME_DEVICE (f);
2162   Lisp_Object lisp_window_id = Fplist_get (props, Qwindow_id, Qnil);
2163   Lisp_Object popup = Fplist_get (props, Qpopup, Qnil);
2164
2165   if (!NILP (popup))
2166     {
2167       if (EQ (popup, Qt))
2168         popup = Fselected_frame (device);
2169       CHECK_LIVE_FRAME (popup);
2170       if (!EQ (device, FRAME_DEVICE (XFRAME (popup))))
2171         signal_simple_error_2 ("Parent must be on same device as frame",
2172                                device, popup);
2173     }
2174
2175   /*
2176    * Previously we set this only if NILP (DEVICE_SELECTED_FRAME (d))
2177    * to make sure that messages were displayed as soon as possible
2178    * if we're creating the first frame on a device.  But it is
2179    * better to just set this all the time, so that when a new frame
2180    * is created that covers the selected frame, echo area status
2181    * messages can still be seen.  f->visible is reset later if the
2182    * initially-unmapped property is found to be non-nil in the
2183    * frame properties.
2184    */
2185   f->visible = 1;
2186
2187   allocate_x_frame_struct (f);
2188   x_create_widgets (f, lisp_window_id, popup);
2189 }
2190
2191 static void
2192 x_init_frame_2 (struct frame *f, Lisp_Object props)
2193 {
2194   /* Set up the values of the widget/frame.  A case could be made for putting
2195      this inside of the widget's initialize method. */
2196
2197   update_frame_face_values (f);
2198   x_initialize_frame_size (f);
2199   /* Kyle:
2200    *   update_frame_title() can't be done here, because some of the
2201    *   modeline specs depend on the frame's device having a selected
2202    *   frame, and that may not have been set up yet.  The redisplay
2203    *   will update the frame title anyway, so nothing is lost.
2204    * JV:
2205    *   It turns out it gives problems with FVWMs name based mapping.
2206    *   We'll just  need to be careful in the modeline specs.
2207    */
2208   update_frame_title (f);
2209 }
2210
2211 static void
2212 x_init_frame_3 (struct frame *f)
2213 {
2214   /* Pop up the frame. */
2215
2216   x_popup_frame (f);
2217 }
2218
2219 static void
2220 x_mark_frame (struct frame *f)
2221 {
2222   mark_object (FRAME_X_ICON_PIXMAP (f));
2223   mark_object (FRAME_X_ICON_PIXMAP_MASK (f));
2224 }
2225
2226 static void
2227 x_set_frame_icon (struct frame *f)
2228 {
2229   Pixmap x_pixmap, x_mask;
2230
2231   if (IMAGE_INSTANCEP (f->icon)
2232       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (f->icon)))
2233     {
2234       x_pixmap = XIMAGE_INSTANCE_X_PIXMAP (f->icon);
2235       x_mask = XIMAGE_INSTANCE_X_MASK (f->icon);
2236     }
2237   else
2238     {
2239       x_pixmap = 0;
2240       x_mask = 0;
2241     }
2242
2243   /* Store the X data into the widget. */
2244   {
2245     Arg al [2];
2246     XtSetArg (al [0], XtNiconPixmap, x_pixmap);
2247     XtSetArg (al [1], XtNiconMask,   x_mask);
2248     XtSetValues (FRAME_X_SHELL_WIDGET (f), al, 2);
2249   }
2250 }
2251
2252 static void
2253 x_set_frame_pointer (struct frame *f)
2254 {
2255   XDefineCursor (XtDisplay (FRAME_X_TEXT_WIDGET (f)),
2256                  XtWindow (FRAME_X_TEXT_WIDGET (f)),
2257                  XIMAGE_INSTANCE_X_CURSOR (f->pointer));
2258   XSync (XtDisplay (FRAME_X_TEXT_WIDGET (f)), 0);
2259 }
2260
2261 static Lisp_Object
2262 x_get_frame_parent (struct frame *f)
2263 {
2264   Widget parentwid = 0;
2265
2266   Xt_GET_VALUE (FRAME_X_SHELL_WIDGET (f), XtNtransientFor, &parentwid);
2267   /* find the frame whose wid is parentwid */
2268   if (parentwid)
2269     {
2270       Lisp_Object frmcons;
2271       DEVICE_FRAME_LOOP (frmcons, XDEVICE (FRAME_DEVICE (f)))
2272         {
2273           Lisp_Object frame = XCAR (frmcons);
2274           if (FRAME_X_SHELL_WIDGET (XFRAME (frame)) == parentwid)
2275             return frame;
2276         }
2277     }
2278   return Qnil;
2279 }
2280
2281 DEFUN ("x-window-id", Fx_window_id, 0, 1, 0, /*
2282 Get the ID of the X11 window.
2283 This gives us a chance to manipulate the Emacs window from within a
2284 different program.  Since the ID is an unsigned long, we return it as
2285 a string.
2286 */
2287        (frame))
2288 {
2289   char str[255];
2290   struct frame *f = decode_x_frame (frame);
2291
2292   sprintf (str, "%lu", XtWindow (FRAME_X_TEXT_WIDGET (f)));
2293   return build_string (str);
2294 }
2295
2296 \f
2297 /************************************************************************/
2298 /*                      manipulating the X window                       */
2299 /************************************************************************/
2300
2301 static void
2302 x_set_frame_position (struct frame *f, int xoff, int yoff)
2303 {
2304   Widget w = FRAME_X_SHELL_WIDGET (f);
2305   Display *dpy = XtDisplay (w);
2306   Dimension frame_w = DisplayWidth  (dpy, DefaultScreen (dpy));
2307   Dimension frame_h = DisplayHeight (dpy, DefaultScreen (dpy));
2308   Dimension shell_w, shell_h, shell_bord;
2309   int win_gravity;
2310   Arg al [3];
2311
2312   XtSetArg (al [0], XtNwidth,       &shell_w);
2313   XtSetArg (al [1], XtNheight,      &shell_h);
2314   XtSetArg (al [2], XtNborderWidth, &shell_bord);
2315   XtGetValues (w, al, 3);
2316
2317   win_gravity =
2318     xoff >= 0 && yoff >= 0 ? NorthWestGravity :
2319     xoff >= 0 ? SouthWestGravity :
2320     yoff >= 0 ? NorthEastGravity :
2321     SouthEastGravity;
2322   if (xoff < 0)
2323     xoff += frame_w - shell_w - 2*shell_bord;
2324   if (yoff < 0)
2325     yoff += frame_h - shell_h - 2*shell_bord;
2326
2327   /* Update the hints so that, if this window is currently iconified, it will
2328      come back at the right place.  We can't look at s->visible to determine
2329      whether it is iconified because it might not be up-to-date yet (the queue
2330      might not be processed). */
2331   XtSetArg (al [0], XtNwinGravity, win_gravity);
2332   XtSetArg (al [1], XtNx, xoff);
2333   XtSetArg (al [2], XtNy, yoff);
2334   XtSetValues (w, al, 3);
2335
2336   /* Sometimes you will find that
2337
2338      (set-frame-position (selected-frame) -50 -50)
2339
2340      doesn't put the frame where you expect it to: i.e. it's closer to
2341      the lower-right corner than it should be, and it appears that the
2342      size of the WM decorations was not taken into account.  This is
2343      *not* a problem with this function.  Both mwm and twm have bugs
2344      in handling this situation. (mwm ignores the window gravity and
2345      always assumes NorthWest, except the first time you map the
2346      window; twm gets things almost right, but forgets to account for
2347      the border width of the top-level window.) This function does
2348      what it's supposed to according to the ICCCM, and I'm not about
2349      to hack around window-manager bugs. */
2350
2351 #if 0
2352   /* This is not necessary under either mwm or twm */
2353   x_wm_mark_shell_position_user_specified (w);
2354 #endif
2355 }
2356
2357 /* Call this to change the size of frame S's x-window. */
2358
2359 static void
2360 x_set_frame_size (struct frame *f, int cols, int rows)
2361 {
2362   EmacsFrameSetCharSize (FRAME_X_TEXT_WIDGET (f), cols, rows);
2363 #if 0
2364     /* this is not correct.  x_set_frame_size() is called from
2365        Fset_frame_size(), which may or may not have been called
2366        by the user (e.g. update_EmacsFrame() calls it when the font
2367        changes).  For now, don't bother with getting this right. */
2368   x_wm_mark_shell_size_user_specified (FRAME_X_SHELL_WIDGET (f));
2369 #endif
2370 }
2371
2372 static void
2373 x_set_mouse_position (struct window *w, int x, int y)
2374 {
2375   struct frame *f = XFRAME (w->frame);
2376
2377   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2378   XWarpPointer (display, None, XtWindow (FRAME_X_TEXT_WIDGET (f)),
2379                 0, 0, 0, 0, w->pixel_left + x, w->pixel_top + y);
2380 }
2381
2382 static int
2383 x_get_mouse_position (struct device *d, Lisp_Object *frame, int *x, int *y)
2384 {
2385   Display *display = DEVICE_X_DISPLAY (d);
2386   Window child_window;
2387   Window root_window;
2388   Window win;
2389   int root_x, root_y;
2390   int win_x, win_y;
2391   unsigned int keys_and_buttons;
2392   struct frame *f;
2393
2394   if (XQueryPointer (display, RootWindow (display, DefaultScreen (display)),
2395                      &root_window, &child_window, &root_x, &root_y,
2396                      &win_x, &win_y, &keys_and_buttons) == False)
2397     return 0;
2398
2399   if (child_window == None)
2400     return 0;   /* not over any window. */
2401
2402   while (1)
2403     {
2404       win = child_window;
2405       if (XTranslateCoordinates (display, root_window, win, root_x, root_y,
2406                                  &win_x, &win_y, &child_window) == False)
2407         /* Huh? */
2408         return 0;
2409
2410       if (child_window == None)
2411         break;
2412     }
2413
2414   /* At this point, win is the innermost window containing the pointer
2415      and win_x and win_y are the coordinates of that window. */
2416   f = x_any_window_to_frame (d, win);
2417   if (!f)
2418     return 0;
2419   XSETFRAME (*frame, f);
2420
2421   if (XTranslateCoordinates (display, win,
2422                              XtWindow (FRAME_X_TEXT_WIDGET (f)),
2423                              win_x, win_y, x, y, &child_window) == False)
2424     /* Huh? */
2425     return 0;
2426
2427   return 1;
2428 }
2429
2430 static void
2431 x_cant_notify_wm_error (void)
2432 {
2433   error ("Can't notify window manager of iconification.");
2434 }
2435
2436 /* Raise frame F.  */
2437 static void
2438 x_raise_frame_1 (struct frame *f, int force)
2439 {
2440   if (FRAME_VISIBLE_P (f) || force)
2441     {
2442       Widget bottom_dialog;
2443       XWindowChanges xwc;
2444       unsigned int flags;
2445       Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2446       Window emacs_window = XtWindow (FRAME_X_SHELL_WIDGET (f));
2447
2448       /* first raises all the dialog boxes, then put emacs just below the
2449        * bottom most dialog box */
2450       bottom_dialog = lw_raise_all_pop_up_widgets ();
2451       if (bottom_dialog && XtWindow (bottom_dialog))
2452         {
2453           xwc.sibling = XtWindow (bottom_dialog);
2454           xwc.stack_mode = Below;
2455           flags = CWSibling | CWStackMode;
2456         }
2457       else
2458         {
2459           xwc.stack_mode = Above;
2460           flags = CWStackMode;
2461         }
2462
2463       if (!XReconfigureWMWindow (display, emacs_window,
2464                                  DefaultScreen (display),
2465                                  flags, &xwc))
2466         x_cant_notify_wm_error ();
2467     }
2468 }
2469
2470 static void
2471 x_raise_frame (struct frame *f)
2472 {
2473   x_raise_frame_1 (f, 1);
2474 }
2475
2476 /* Lower frame F.  */
2477 static void
2478 x_lower_frame (struct frame *f)
2479 {
2480   if (FRAME_VISIBLE_P (f))
2481     {
2482       Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2483       XWindowChanges xwc;
2484       unsigned int flags = CWStackMode;
2485
2486       xwc.stack_mode = Below;
2487       if (!XReconfigureWMWindow (display, XtWindow (FRAME_X_SHELL_WIDGET (f)),
2488                                  DefaultScreen (display), flags, &xwc))
2489         x_cant_notify_wm_error ();
2490     }
2491 }
2492
2493 static void
2494 x_enable_frame (struct frame *f)
2495 {
2496   XtSetSensitive (FRAME_X_SHELL_WIDGET (f), True);
2497 }
2498
2499 static void
2500 x_disable_frame (struct frame *f)
2501 {
2502   XtSetSensitive (FRAME_X_SHELL_WIDGET (f), False);
2503 }
2504
2505 /* Change from withdrawn state to mapped state. */
2506 static void
2507 x_make_frame_visible (struct frame *f)
2508 {
2509   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2510
2511   if (!FRAME_VISIBLE_P(f))
2512     XMapRaised (display, XtWindow (FRAME_X_SHELL_WIDGET (f)));
2513   else
2514     x_raise_frame_1 (f, 0);
2515 }
2516
2517 /* Change from mapped state to withdrawn state. */
2518 static void
2519 x_make_frame_invisible (struct frame *f)
2520 {
2521   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2522
2523   if (!FRAME_VISIBLE_P(f))
2524     return;
2525
2526   if (!XWithdrawWindow (display,
2527                         XtWindow (FRAME_X_SHELL_WIDGET (f)),
2528                         DefaultScreen (display)))
2529     x_cant_notify_wm_error ();
2530 }
2531
2532 static int
2533 x_frame_visible_p (struct frame *f)
2534 {
2535 #if 0
2536   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2537   XWindowAttributes xwa;
2538   int result;
2539
2540   /* JV:
2541      This is bad, very bad :-(
2542      It is not compatible with our tristate visible and
2543      it should never ever change the visibility for us, this leads to
2544      the frame-freeze problem under fvwm because with the pager
2545
2546      Mappedness != Viewability != Visibility != Emacs f->visible
2547
2548      This first unequalness is the reason for the frame freezing problem
2549      under fvwm (it happens when the frame is another fvwm-page)
2550
2551      The second unequalness happen when it is on the same fvwm-page
2552      but in an invisible part of the visible screen.
2553
2554      For now we just return the XEmacs internal value --- which might not be up
2555      to date. Is that a problem? ---. Otherwise we should
2556      use async visibility like in standard Emacs.
2557      */
2558
2559   if (!XGetWindowAttributes (display,
2560                              XtWindow (FRAME_X_SHELL_WIDGET (f)),
2561                              &xwa))
2562     result = 0;
2563   else
2564     result = xwa.map_state == IsViewable;
2565   /* In this implementation it should at least be != IsUnmapped
2566      JV */
2567
2568   f->visible = result;
2569   return result;
2570 #endif /* 0 */
2571
2572   return f->visible;
2573 }
2574
2575 static int
2576 x_frame_totally_visible_p (struct frame *f)
2577 {
2578   return FRAME_X_TOTALLY_VISIBLE_P (f);
2579 }
2580
2581 /* Change window state from mapped to iconified. */
2582 static void
2583 x_iconify_frame (struct frame *f)
2584 {
2585   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2586
2587   if (!XIconifyWindow (display,
2588                        XtWindow (FRAME_X_SHELL_WIDGET (f)),
2589                        DefaultScreen (display)))
2590     x_cant_notify_wm_error ();
2591
2592   f->iconified = 1;
2593 }
2594
2595 /* Sets the X focus to frame f. */
2596 static void
2597 x_focus_on_frame (struct frame *f)
2598 {
2599   XWindowAttributes xwa;
2600   Widget shell_widget;
2601   int viewable = 0;
2602
2603   assert (FRAME_X_P (f));
2604
2605   shell_widget = FRAME_X_SHELL_WIDGET (f);
2606   if (!XtWindow (shell_widget))
2607     return;
2608
2609 #ifdef EXTERNAL_WIDGET
2610   if (FRAME_X_EXTERNAL_WINDOW_P (f))
2611     ExternalShellSetFocus (shell_widget);
2612 #endif /* EXTERNAL_WIDGET */
2613
2614   /* Do the ICCCM focus change if the window is still visible.
2615      The s->visible flag might not be up-to-date, because we might
2616      not have processed magic events recently.  So make a server
2617      round-trip to find out whether it's really mapped right now.
2618      We grab the server to do this, because that's the only way to
2619      eliminate the race condition.
2620    */
2621   XGrabServer (XtDisplay (shell_widget));
2622   if (XGetWindowAttributes (XtDisplay (shell_widget),
2623                             XtWindow (shell_widget),
2624                             &xwa))
2625     /* JV: it is bad to change the visibility like this, so we don't for the
2626        moment, at least change_frame_visibility should be called
2627        Note also that under fvwm a frame can be Viewable (and thus Mapped)
2628        but still X-invisible
2629     f->visible = xwa.map_state == IsViewable; */
2630     viewable = xwa.map_state == IsViewable;
2631
2632
2633   if (viewable)
2634     {
2635       Window focus;
2636       int revert_to;
2637       XGetInputFocus (XtDisplay (shell_widget), &focus, &revert_to);
2638       /* Don't explicitly set the focus on this window unless the focus
2639          was on some other window (not PointerRoot).  Note that, even when
2640          running a point-to-type window manager like *twm, there is always
2641          a focus window; the window manager maintains that based on the
2642          mouse position.  If you set the "NoTitleFocus" option in these
2643          window managers, then the server itself maintains the focus via
2644          PointerRoot, and changing that to focus on the window would make
2645          the window grab the focus.  Very bad.
2646          */
2647       if (focus != PointerRoot)
2648         {
2649           XSetInputFocus (XtDisplay (shell_widget),
2650                           XtWindow (shell_widget),
2651                           RevertToParent,
2652                           DEVICE_X_MOUSE_TIMESTAMP
2653                           (XDEVICE (FRAME_DEVICE (f))));
2654           XFlush (XtDisplay (shell_widget));
2655         }
2656     }
2657   XUngrabServer (XtDisplay (shell_widget));
2658   XFlush (XtDisplay (shell_widget)); /* hey, I'd like to DEBUG this... */
2659 }
2660
2661 /* Destroy the X window of frame F.  */
2662 static void
2663 x_delete_frame (struct frame *f)
2664 {
2665   Display *dpy;
2666
2667 #ifndef HAVE_WMCOMMAND
2668   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2669     x_wm_maybe_move_wm_command (f);
2670 #endif /* HAVE_WMCOMMAND */
2671
2672 #ifdef HAVE_CDE
2673   DtDndDropUnregister (FRAME_X_TEXT_WIDGET (f));
2674 #endif /* HAVE_CDE */
2675
2676   assert (FRAME_X_SHELL_WIDGET (f) != 0);
2677   dpy = XtDisplay (FRAME_X_SHELL_WIDGET (f));
2678
2679 #ifdef EXTERNAL_WIDGET
2680   expect_x_error (dpy);
2681   /* for obscure reasons having (I think) to do with the internal
2682      window-to-widget hierarchy maintained by Xt, we have to call
2683      XtUnrealizeWidget() here.  Xt can really suck. */
2684   if (f->being_deleted)
2685     XtUnrealizeWidget (FRAME_X_SHELL_WIDGET (f));
2686   XtDestroyWidget (FRAME_X_SHELL_WIDGET (f));
2687   x_error_occurred_p (dpy);
2688 #else
2689   XtDestroyWidget (FRAME_X_SHELL_WIDGET (f));
2690   /* make sure the windows are really gone! */
2691   /* #### Is this REALLY necessary? */
2692   XFlush (dpy);
2693 #endif /* EXTERNAL_WIDGET */
2694
2695   FRAME_X_SHELL_WIDGET (f) = 0;
2696
2697   if (FRAME_X_GEOM_FREE_ME_PLEASE (f))
2698     {
2699       xfree (FRAME_X_GEOM_FREE_ME_PLEASE (f));
2700       FRAME_X_GEOM_FREE_ME_PLEASE (f) = 0;
2701     }
2702
2703   if (f->frame_data)
2704     {
2705       xfree (f->frame_data);
2706       f->frame_data = 0;
2707     }
2708 }
2709
2710 static void
2711 x_update_frame_external_traits (struct frame* frm, Lisp_Object name)
2712 {
2713   Arg al[10];
2714   int ac = 0;
2715   Lisp_Object frame;
2716
2717   XSETFRAME(frame, frm);
2718
2719   if (EQ (name, Qforeground))
2720    {
2721      Lisp_Object color = FACE_FOREGROUND (Vdefault_face, frame);
2722      XColor fgc;
2723
2724      if (!EQ (color, Vthe_null_color_instance))
2725        {
2726          fgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
2727          XtSetArg (al[ac], XtNforeground, (void *) fgc.pixel); ac++;
2728        }
2729    }
2730   else if (EQ (name, Qbackground))
2731    {
2732      Lisp_Object color = FACE_BACKGROUND (Vdefault_face, frame);
2733      XColor bgc;
2734
2735      if (!EQ (color, Vthe_null_color_instance))
2736        {
2737          bgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
2738          XtSetArg (al[ac], XtNbackground, (void *) bgc.pixel); ac++;
2739        }
2740
2741      /* Really crappy way to force the modeline shadows to be
2742         redrawn.  But effective. */
2743      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (frm);
2744      MARK_FRAME_CHANGED (frm);
2745    }
2746   else if (EQ (name, Qfont))
2747    {
2748      Lisp_Object font = FACE_FONT (Vdefault_face, frame, Vcharset_ascii);
2749
2750      if (!EQ (font, Vthe_null_font_instance))
2751        {
2752          XtSetArg (al[ac], XtNfont,
2753                    (void *) FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
2754          ac++;
2755        }
2756    }
2757   else
2758    ABORT ();
2759
2760   XtSetValues (FRAME_X_TEXT_WIDGET (frm), al, ac);
2761
2762 #ifdef HAVE_TOOLBARS
2763   /* Setting the background clears the entire frame area
2764     including the toolbar so we force an immediate redraw of
2765     it. */
2766   if (EQ (name, Qbackground))
2767     MAYBE_DEVMETH (XDEVICE (frm->device), redraw_frame_toolbars, (frm));
2768 #endif /* HAVE_TOOLBARS */
2769
2770   /* Set window manager resize increment hints according to
2771      the new character size */
2772   if (EQ (name, Qfont))
2773     EmacsFrameRecomputeCellSize (FRAME_X_TEXT_WIDGET (frm));
2774 }
2775
2776 \f
2777 /************************************************************************/
2778 /*                            initialization                            */
2779 /************************************************************************/
2780
2781 void
2782 syms_of_frame_x (void)
2783 {
2784   defsymbol (&Qwindow_id, "window-id");
2785   defsymbol (&Qx_resource_name, "x-resource-name");
2786
2787   DEFSUBR (Fx_window_id);
2788 #ifdef HAVE_CDE
2789   DEFSUBR (Fcde_start_drag_internal);
2790 #endif
2791 #ifdef HAVE_OFFIX_DND
2792   DEFSUBR (Foffix_start_drag_internal);
2793 #endif
2794 }
2795
2796 void
2797 console_type_create_frame_x (void)
2798 {
2799   /* frame methods */
2800   CONSOLE_HAS_METHOD (x, init_frame_1);
2801   CONSOLE_HAS_METHOD (x, init_frame_2);
2802   CONSOLE_HAS_METHOD (x, init_frame_3);
2803   CONSOLE_HAS_METHOD (x, mark_frame);
2804   CONSOLE_HAS_METHOD (x, focus_on_frame);
2805   CONSOLE_HAS_METHOD (x, delete_frame);
2806   CONSOLE_HAS_METHOD (x, get_mouse_position);
2807   CONSOLE_HAS_METHOD (x, set_mouse_position);
2808   CONSOLE_HAS_METHOD (x, raise_frame);
2809   CONSOLE_HAS_METHOD (x, lower_frame);
2810   CONSOLE_HAS_METHOD (x, enable_frame);
2811   CONSOLE_HAS_METHOD (x, disable_frame);
2812   CONSOLE_HAS_METHOD (x, make_frame_visible);
2813   CONSOLE_HAS_METHOD (x, make_frame_invisible);
2814   CONSOLE_HAS_METHOD (x, iconify_frame);
2815   CONSOLE_HAS_METHOD (x, set_frame_size);
2816   CONSOLE_HAS_METHOD (x, set_frame_position);
2817   CONSOLE_HAS_METHOD (x, frame_property);
2818   CONSOLE_HAS_METHOD (x, internal_frame_property_p);
2819   CONSOLE_HAS_METHOD (x, frame_properties);
2820   CONSOLE_HAS_METHOD (x, set_frame_properties);
2821   CONSOLE_HAS_METHOD (x, set_title_from_bufbyte);
2822   CONSOLE_HAS_METHOD (x, set_icon_name_from_bufbyte);
2823   CONSOLE_HAS_METHOD (x, frame_visible_p);
2824   CONSOLE_HAS_METHOD (x, frame_totally_visible_p);
2825   CONSOLE_HAS_METHOD (x, frame_iconified_p);
2826   CONSOLE_HAS_METHOD (x, set_frame_pointer);
2827   CONSOLE_HAS_METHOD (x, set_frame_icon);
2828   CONSOLE_HAS_METHOD (x, get_frame_parent);
2829   CONSOLE_HAS_METHOD (x, update_frame_external_traits);
2830 }
2831
2832 void
2833 vars_of_frame_x (void)
2834 {
2835 #ifdef EXTERNAL_WIDGET
2836   Fprovide (intern ("external-widget"));
2837 #endif
2838
2839   /* this call uses only safe functions from emacs.c */
2840   init_x_prop_symbols ();
2841
2842   DEFVAR_LISP ("default-x-frame-plist", &Vdefault_x_frame_plist /*
2843 Plist of default frame-creation properties for X frames.
2844 These override what is specified in the resource database and in
2845 `default-frame-plist', but are overridden by the arguments to the
2846 particular call to `make-frame'.
2847
2848 Note: In many cases, properties of a frame are available as specifiers
2849 instead of through the frame-properties mechanism.
2850
2851 Here is a list of recognized frame properties, other than those
2852 documented in `set-frame-properties' (they can be queried and
2853 set at any time, except as otherwise noted):
2854
2855   window-id                     The X window ID corresponding to the
2856                                 frame.  May be set only at startup, and
2857                                 only if external widget support was
2858                                 compiled in; doing so causes the frame
2859                                 to be created as an "external widget"
2860                                 in another program that uses an existing
2861                                 window in the program rather than creating
2862                                 a new one.
2863   initially-unmapped            If non-nil, the frame will not be visible
2864                                 when it is created.  In this case, you
2865                                 need to call `make-frame-visible' to make
2866                                 the frame appear.
2867   popup                         If non-nil, it should be a frame, and this
2868                                 frame will be created as a "popup" frame
2869                                 whose parent is the given frame.  This
2870                                 will make the window manager treat the
2871                                 frame as a dialog box, which may entail
2872                                 doing different things (e.g. not asking
2873                                 for positioning, and not iconifying
2874                                 separate from its parent).
2875   inter-line-space              Not currently implemented.
2876   toolbar-shadow-thickness      Thickness of toolbar shadows.
2877   background-toolbar-color      Color of toolbar background.
2878   bottom-toolbar-shadow-color   Color of bottom shadows on toolbars.
2879                                 (*Not* specific to the bottom-toolbar.)
2880   top-toolbar-shadow-color      Color of top shadows on toolbars.
2881                                 (*Not* specific to the top-toolbar.)
2882   internal-border-width         Width of internal border around text area.
2883   border-width                  Width of external border around text area.
2884   top                           Y position (in pixels) of the upper-left
2885                                 outermost corner of the frame (i.e. the
2886                                 upper-left of the window-manager
2887                                 decorations).
2888   left                          X position (in pixels) of the upper-left
2889                                 outermost corner of the frame (i.e. the
2890                                 upper-left of the window-manager
2891                                 decorations).
2892   border-color                  Color of external border around text area.
2893   cursor-color                  Color of text cursor.
2894
2895 See also `default-frame-plist', which specifies properties which apply
2896 to all frames, not just X frames.
2897 */ );
2898   Vdefault_x_frame_plist = Qnil;
2899
2900   x_console_methods->device_specific_frame_props = &Vdefault_x_frame_plist;
2901 }