diff src/widget.c @ 5626:93bb7e0935ba

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Tue, 18 Jan 1994 23:47:41 +0000
parents
children 3929b3fb37ee
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widget.c	Tue Jan 18 23:47:41 1994 +0000
@@ -0,0 +1,900 @@
+/* The emacs frame widget.
+   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Emacs 19 face widget ported by Fred Pierresteguy */
+
+#include <stdio.h>
+#include "config.h"
+#include "lisp.h"
+#include "xterm.h"
+
+#include "frame.h"
+
+#include "dispextern.h"
+
+
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include "widgetprv.h"
+#include <X11/Shell.h>
+#include <X11/ShellP.h>
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/* This sucks: this is the first default that x-faces.el tries.  This won't
+   be used unless neither the "Emacs.EmacsFrame" resource nor the
+   "Emacs.EmacsFrame" resource is set; the frame
+   may have the wrong default size if this font doesn't exist, but some other
+   font that x-faces.el does.  The workaround is to specify some font in the
+   resource database; I don't know a solution other than duplicating the font-
+   searching code from x-faces.el in this file.
+
+   This also means that if "Emacs.EmacsFrame" is specified as a non-
+   existent font, then Xt is going to substitute "XtDefaultFont" for it,
+   which is a different size than this one.  The solution for this is to
+   make x-faces.el try to use XtDefaultFont.  The problem with that is that
+   XtDefaultFont is almost certainly variable-width.
+
+   #### Perhaps we could have this code explicitly set XtDefaultFont to this?
+ */
+#define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"
+
+
+static void EmacsFrameInitialize (Widget, Widget, ArgList, Cardinal *);
+static void EmacsFrameDestroy (Widget);
+static void EmacsFrameRealize (Widget, XtValueMask*, XSetWindowAttributes*);
+void EmacsFrameResize (Widget widget);
+static Boolean EmacsFrameSetValues (Widget, Widget, Widget,
+				     ArgList, Cardinal *);
+static XtGeometryResult EmacsFrameQueryGeometry (Widget, XtWidgetGeometry*,
+						  XtWidgetGeometry*);
+
+
+#undef XtOffset
+#define XtOffset(p_type,field) \
+	((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
+#define offset(field) XtOffset(EmacsFrame, emacs_frame.field)
+
+static XtResource resources[] = {
+  {XtNgeometry, XtCGeometry, XtRString, sizeof(String),
+     offset (geometry), XtRString, (XtPointer) 0},
+  {XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean),
+     offset (iconic), XtRImmediate, (XtPointer) False},
+
+  {XtNemacsFrame, XtCEmacsFrame, XtRPointer, sizeof (XtPointer),
+     offset (frame), XtRImmediate, 0},
+
+  {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
+     offset (minibuffer), XtRImmediate, (XtPointer)0},
+  {XtNunsplittable, XtCUnsplittable, XtRBoolean, sizeof (Boolean),
+     offset (unsplittable), XtRImmediate, (XtPointer)0},
+  {XtNinternalBorderWidth, XtCInternalBorderWidth, XtRInt, sizeof (int),
+     offset (internal_border_width), XtRImmediate, (XtPointer)4},
+  {XtNinterline, XtCInterline, XtRInt, sizeof (int),
+     offset (interline), XtRImmediate, (XtPointer)0},
+  {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+     offset(font),XtRString, DEFAULT_FACE_FONT},
+  {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+     offset(foreground_pixel), XtRString, "XtDefaultForeground"},
+  {XtNcursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+     offset(cursor_color), XtRString, "XtDefaultForeground"},
+  {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
+     offset (bar_cursor), XtRImmediate, (XtPointer)0},
+  {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
+     offset (visual_bell), XtRImmediate, (XtPointer)0},
+  {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
+     offset (bell_volume), XtRImmediate, (XtPointer)0},
+};
+
+#undef offset
+
+/*
+static XtActionsRec
+emacsFrameActionsTable [] = {
+  {"keypress",  key_press},
+  {"focus_in",  emacs_frame_focus_handler},
+  {"focus_out", emacs_frame_focus_handler},
+};
+
+static char
+emacsFrameTranslations [] = "\
+<KeyPress>: keypress()\n\
+<FocusIn>:  focus_in()\n\
+<FocusOut>: focus_out()\n\
+";
+*/
+
+EmacsFrameClassRec emacsFrameClassRec = {
+    { /* core fields */
+    /* superclass		*/	&widgetClassRec,
+    /* class_name		*/	"EmacsFrame",
+    /* widget_size		*/	sizeof(EmacsFrameRec),
+    /* class_initialize		*/	0,
+    /* class_part_initialize	*/	0,
+    /* class_inited		*/	FALSE,
+    /* initialize		*/	EmacsFrameInitialize,
+    /* initialize_hook		*/	0,
+    /* realize			*/	EmacsFrameRealize,
+    /* actions			*/	0, /*emacsFrameActionsTable*/
+    /* num_actions		*/	0, /*XtNumber (emacsFrameActionsTable)*/
+    /* resources		*/	resources,
+    /* resource_count		*/	XtNumber(resources),
+    /* xrm_class		*/	NULLQUARK,
+    /* compress_motion		*/	TRUE,
+    /* compress_exposure	*/	TRUE,
+    /* compress_enterleave	*/	TRUE,
+    /* visible_interest		*/	FALSE,
+    /* destroy			*/	EmacsFrameDestroy,
+    /* resize			*/	EmacsFrameResize,
+    /* expose			*/	XtInheritExpose,
+    /* set_values		*/	EmacsFrameSetValues,
+    /* set_values_hook		*/	0,
+    /* set_values_almost	*/	XtInheritSetValuesAlmost,
+    /* get_values_hook		*/	0,
+    /* accept_focus		*/	XtInheritAcceptFocus,
+    /* version			*/	XtVersion,
+    /* callback_private		*/	0,
+    /* tm_table			*/	0, /*emacsFrameTranslations*/
+    /* query_geometry		*/	EmacsFrameQueryGeometry,
+    /* display_accelerator	*/	XtInheritDisplayAccelerator,
+    /* extension		*/	0
+    }
+};
+
+WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
+
+static void
+get_default_char_pixel_size (EmacsFrame ew, int* pixel_width,
+			     int* pixel_height)
+{
+/*
+  *pixel_width = XTextWidth (ew->emacs_frame.font, "n", 1);
+  *pixel_height =
+    ew->emacs_frame.font->ascent + ew->emacs_frame.font->descent;
+*/
+  struct frame* f = ew->emacs_frame.frame;
+  *pixel_width = FONT_WIDTH (f->display.x->font);
+  *pixel_height = FONT_HEIGHT (f->display.x->font);
+}
+
+static void
+pixel_to_char_size (EmacsFrame ew,
+		    Dimension pixel_width, Dimension pixel_height,
+		    int* char_width, int* char_height)
+{
+  struct frame* f = ew->emacs_frame.frame;
+  *char_width = PIXEL_TO_CHAR_WIDTH (f, pixel_width);
+  *char_height = PIXEL_TO_CHAR_HEIGHT (f, pixel_height);
+}
+
+static void
+char_to_pixel_size (EmacsFrame ew, int char_width, int char_height,
+		    Dimension* pixel_width, Dimension* pixel_height)
+{
+  struct frame* f = ew->emacs_frame.frame;
+  *pixel_width = CHAR_TO_PIXEL_WIDTH (f, char_width);
+  *pixel_height = CHAR_TO_PIXEL_HEIGHT (f, char_height);
+}
+
+static void
+round_size_to_char (EmacsFrame ew,
+		    Dimension in_width, Dimension in_height,
+		    Dimension* out_width, Dimension* out_height)
+{
+  int char_width;
+  int char_height;
+  pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
+  char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
+}
+
+static Widget
+get_wm_shell (Widget w)
+{
+  Widget wmshell;
+
+  for (wmshell = XtParent (w);
+       wmshell && !XtIsWMShell (wmshell);
+       wmshell = XtParent (wmshell));
+
+  return wmshell;
+}
+
+static void
+mark_shell_size_user_specified (Widget wmshell)
+{
+  if (! XtIsWMShell (wmshell)) abort ();
+  /* This is kind of sleazy, but I can't see how else to tell it to make it
+     mark the WM_SIZE_HINTS size as user specified when appropriate. */
+  ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
+}
+
+
+/* Can't have static frame locals because of some broken compilers.
+   Normally, initializing a variable like this doesn't work in emacs,
+   but it's ok in this file because it must come after lastfile (and
+   thus have its data not go into text space) because Xt needs to
+   write to initialized data objects too.
+ */
+static Boolean first_frame_p = True;
+
+static void
+set_frame_size (EmacsFrame ew)
+{
+  /* The widget hierarchy is
+
+	argv[0]			emacsShell	pane	Frame-NAME
+	ApplicationShell	EmacsShell	Paned	EmacsFrame
+
+     We accept geometry specs in this order:
+
+	*Frame-NAME.geometry
+	*EmacsFrame.geometry
+	Emacs.geometry
+
+     Other possibilities for widget hierarchies might be
+
+	argv[0]			frame		pane	Frame-NAME
+	ApplicationShell	EmacsShell	Paned	EmacsFrame
+     or
+	argv[0]			Frame-NAME	pane	Frame-NAME
+	ApplicationShell	EmacsShell	Paned	EmacsFrame
+     or
+	argv[0]			Frame-NAME	pane	emacsTextPane
+	ApplicationShell	EmacsFrame	Paned	EmacsTextPane
+
+     With the current setup, the text-display-area is the part which is
+     an emacs "frame", since that's the only part managed by emacs proper
+     (the menubar and the parent of the menubar and all that sort of thing
+     are managed by lwlib.)
+
+     The EmacsShell widget is simply a replacement for the Shell widget 
+     which is able to deal with using an externally-supplied window instead
+     of always creating its own.  It is not actually emacs specific, and
+     should possibly have class "Shell" instead of "EmacsShell" to simplify
+     the resources.
+
+   */
+
+  /* Geometry of the AppShell */
+  int app_flags = 0;
+  int app_x = 0;
+  int app_y = 0;
+  unsigned int app_w = 0;
+  unsigned int app_h = 0;
+  
+  /* Geometry of the EmacsFrame */
+  int frame_flags = 0;
+  int frame_x = 0;
+  int frame_y = 0;
+  unsigned int frame_w = 0;
+  unsigned int frame_h = 0;
+  
+  /* Hairily merged geometry */
+  int x = 0;
+  int y = 0;
+  unsigned int w = ew->emacs_frame.frame->width;
+  unsigned int h = ew->emacs_frame.frame->height;
+  int flags = 0;
+  
+  Widget wmshell = get_wm_shell ((Widget) ew);
+  Widget app_shell = XtParent ((Widget) wmshell);
+  
+  
+  if (! XtIsSubclass (wmshell, shellWidgetClass)) abort ();
+  if (! XtIsSubclass (app_shell, shellWidgetClass)) abort ();
+
+  /* If the EmacsFrame doesn't have a geometry but the shell does,
+     treat that as the geometry of the frame.  (Is this bogus?
+     I'm not sure.) */
+  if (ew->emacs_frame.geometry == 0)
+    XtVaGetValues (wmshell, XtNgeometry, &ew->emacs_frame.geometry, 0);
+
+  /* If the Shell is iconic, then the EmacsFrame is iconic.  (Is
+     this bogus? I'm not sure.) */
+  if (!ew->emacs_frame.iconic)
+    XtVaGetValues (wmshell, XtNiconic, &ew->emacs_frame.iconic, 0);
+  
+  
+  {
+    char *geom = 0;
+    XtVaGetValues (app_shell, XtNgeometry, &geom, 0);
+    if (geom)
+      app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
+  }
+  
+  if (ew->emacs_frame.geometry)
+    frame_flags = XParseGeometry (ew->emacs_frame.geometry,
+				   &frame_x, &frame_y,
+				   &frame_w, &frame_h);
+  
+  if (first_frame_p)
+    {
+      /* If this is the first frame created:
+         ====================================
+
+         - Use the ApplicationShell's size/position, if specified.
+           (This is "Emacs.geometry", or the "-geometry" command line arg.)
+         - Else use the EmacsFrame's size/position.
+           (This is "*Frame-NAME.geometry")
+
+	 - If the AppShell is iconic, the frame should be iconic.
+
+	 AppShell comes first so that -geometry always applies to the first
+	 frame created, even if there is an "every frame" entry in the
+	 resource database.
+       */
+      if (app_flags & (XValue | YValue))
+	{
+	  x = app_x; y = app_y;
+	  flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
+	}
+      else if (frame_flags & (XValue | YValue))
+	{
+	  x = frame_x; y = frame_y;
+	  flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
+	}
+
+      if (app_flags & (WidthValue | HeightValue))
+	{
+	  w = app_w; h = app_h;
+	  flags |= (app_flags & (WidthValue | HeightValue));
+	}
+      else if (frame_flags & (WidthValue | HeightValue))
+	{
+	  w = frame_w; h = frame_h;
+	  flags |= (frame_flags & (WidthValue | HeightValue));
+	}
+
+      /* If the AppShell is iconic, then the EmacsFrame is iconic. */
+      if (!ew->emacs_frame.iconic)
+	XtVaGetValues (app_shell, XtNiconic, &ew->emacs_frame.iconic, 0);
+
+      first_frame_p = False;
+    }
+  else
+    {
+      /* If this is not the first frame created:
+         ========================================
+
+         - use the EmacsFrame's size/position if specified
+         - Otherwise, use the ApplicationShell's size, but not position.
+
+         So that means that one can specify the position of the first frame
+         with "Emacs.geometry" or `-geometry'; but can only specify the
+	 position of subsequent frames with "*Frame-NAME.geometry".
+
+	 AppShell comes second so that -geometry does not apply to subsequent
+	 frames when there is an "every frame" entry in the resource db,
+	 but does apply to the first frame.
+       */
+      if (frame_flags & (XValue | YValue))
+	{
+	  x = frame_x; y = frame_y;
+	  flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
+	}
+
+      if (frame_flags & (WidthValue | HeightValue))
+	{
+	  w = frame_w; h = frame_h;
+	  flags |= (frame_flags & (WidthValue | HeightValue));
+	}
+      else if (app_flags & (WidthValue | HeightValue))
+	{
+	  w = app_w;
+	  h = app_h;
+	  flags |= (app_flags & (WidthValue | HeightValue));
+	}
+    }
+
+  {
+    struct frame* frame = ew->emacs_frame.frame;
+    Dimension pixel_width, pixel_height;
+    char shell_position [32];
+
+    /* Take into account the size of the scrollbar */
+    frame->display.x->vertical_scroll_bar_extra
+      = (FRAME_HAS_VERTICAL_SCROLL_BARS (frame)
+	 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (frame)
+	 : 0);
+
+
+    change_frame_size (frame, h, w, 1, 0);
+    char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
+    ew->core.width = pixel_width;
+    ew->core.height = pixel_height;
+
+
+    /* If a position was specified, assign it to the shell widget.
+       (Else WM won't do anything with it.)
+     */
+    if (flags & (XValue | YValue))
+      {
+	/* the tricky things with the sign is to make sure that
+	   -0 is printed -0. */
+	int len;
+	char *tem;
+	sprintf (shell_position, "=%c%d%c%d",
+		 flags & XNegative ? '-' : '+', x < 0 ? -x : x,
+		 flags & YNegative ? '-' : '+', y < 0 ? -y : y);
+	len = strlen (shell_position) + 1;
+	tem = (char *) xmalloc (len);
+	strncpy (tem, shell_position, len);
+	XtVaSetValues (wmshell, XtNgeometry, tem, 0);
+      }
+    else if (flags & (WidthValue | HeightValue))
+      {
+	int len;
+	char *tem;
+	sprintf (shell_position, "=%dx%d", pixel_width, pixel_height);
+	len = strlen (shell_position) + 1;
+	tem = (char *) xmalloc (len);
+	strncpy (tem, shell_position, len);
+	XtVaSetValues (wmshell, XtNgeometry, tem, 0);
+      }
+
+    /* If the geometry spec we're using has W/H components, mark the size
+       in the WM_SIZE_HINTS as user specified. */
+    if (flags & (WidthValue | HeightValue))
+      mark_shell_size_user_specified (wmshell);
+
+    /* Also assign the iconic status of the frame to the Shell, so that
+       the WM sees it. */
+    XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, 0);
+  }
+}
+
+
+static void
+update_wm_hints (EmacsFrame ew)
+{
+  Widget wmshell = get_wm_shell ((Widget)ew);
+  int cw;
+  int ch;
+  Dimension rounded_width;
+  Dimension rounded_height;
+  int char_width;
+  int char_height;
+  int base_width;
+  int base_height;
+  int min_rows = 0, min_cols = 0;
+
+  check_frame_size (ew->emacs_frame.frame, &min_rows, &min_cols);
+
+  pixel_to_char_size (ew, ew->core.width, ew->core.height,
+		      &char_width, &char_height);
+  char_to_pixel_size (ew, char_width, char_height,
+		      &rounded_width, &rounded_height);
+  get_default_char_pixel_size (ew, &cw, &ch); 
+
+  base_width = (wmshell->core.width - ew->core.width
+		+ (rounded_width - (char_width * cw)));
+  base_height = (wmshell->core.height - ew->core.height
+		+ (rounded_height - (char_height * ch)));
+
+  /* This is kind of sleazy, but I can't see how else to tell it to
+     make it mark the WM_SIZE_HINTS size as user specified.
+   */
+/*  ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
+
+  XtVaSetValues (wmshell,
+		 XtNbaseWidth, base_width,
+		 XtNbaseHeight, base_height,
+		 XtNwidthInc, cw, 
+		 XtNheightInc, ch,
+		 XtNminWidth, base_width + min_cols * cw,
+		 XtNminHeight, base_height + min_rows * ch,
+		 0);
+}
+
+static void
+create_frame_gcs (EmacsFrame ew)
+{
+  struct frame* s = ew->emacs_frame.frame;
+
+  s->display.x->normal_gc =
+    XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)), 0, 0);
+  s->display.x->reverse_gc =
+    XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)), 0, 0);
+  s->display.x->cursor_gc =
+    XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)), 0, 0);
+}
+
+static void
+setup_frame_gcs (EmacsFrame ew)
+{
+  XGCValues gc_values;
+  struct frame* s = ew->emacs_frame.frame;
+  Pixmap blank_stipple, blank_tile;
+
+  static char cursor_bits[] =
+    {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+
+  /* We have to initialize all of our GCs to have a stipple/tile, otherwise
+     XGetGCValues returns uninitialized data when we query the stipple
+     (instead of None or something sensible) and it makes things hard.
+
+     This should be fixed for real by not querying the GCs but instead having
+     some GC-based cache instead of the current face-based cache which doesn't
+     effectively cache all of the GC settings we need to use.
+   */
+
+  blank_stipple = 
+    XCreateBitmapFromData (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
+			   cursor_bits, 2, 2);
+
+  /* use fg = 0, bg = 1 below, but it's irrelevant since this pixmap should
+     never actually get used as a background tile!
+   */
+  blank_tile =
+    XCreatePixmapFromBitmapData (XtDisplay(ew),
+				 RootWindowOfScreen (XtScreen (ew)),
+				 cursor_bits, 2, 2, 0, 1, ew->core.depth);
+
+  /* Normal video */
+  gc_values.font = ew->emacs_frame.font->fid;
+  gc_values.foreground = ew->emacs_frame.foreground_pixel;
+  gc_values.background = ew->core.background_pixel;
+  gc_values.graphics_exposures = False;
+  gc_values.stipple = blank_stipple;
+  gc_values.tile = blank_tile;
+  XChangeGC (XtDisplay (ew), s->display.x->normal_gc,
+	     (GCFont | GCForeground | GCBackground | GCGraphicsExposures
+	      | GCStipple | GCTile),
+	     &gc_values);
+
+  /* Reverse video style. */
+  gc_values.font = ew->emacs_frame.font->fid;
+  gc_values.foreground = ew->core.background_pixel;
+  gc_values.background = ew->emacs_frame.foreground_pixel;
+  gc_values.graphics_exposures = False;
+  gc_values.stipple = blank_stipple;
+  gc_values.tile = blank_tile;
+  XChangeGC (XtDisplay (ew), s->display.x->reverse_gc,
+	     (GCFont | GCForeground | GCBackground | GCGraphicsExposures
+	      | GCStipple | GCTile),
+	     &gc_values);
+
+  /* Cursor has to have an empty stipple. */
+  gc_values.font = ew->emacs_frame.font->fid;
+  gc_values.foreground = ew->core.background_pixel;
+  gc_values.background = ew->emacs_frame.cursor_color;
+  gc_values.graphics_exposures = False;
+  gc_values.tile = blank_tile;
+  gc_values.stipple =
+    XCreateBitmapFromData (XtDisplay (ew),
+			   RootWindowOfScreen (XtScreen (ew)),
+			   cursor_bits, 16, 16);
+  XChangeGC (XtDisplay (ew), s->display.x->cursor_gc,
+	     (GCFont | GCForeground | GCBackground | GCGraphicsExposures
+	      | GCStipple | GCTile),
+	     &gc_values);
+}
+
+static void
+update_various_frame_slots (EmacsFrame ew)
+{
+  struct x_display* x = ew->emacs_frame.frame->display.x;
+  x->pixel_height = ew->core.height;
+  x->pixel_width = ew->core.width;
+  x->internal_border_width = ew->emacs_frame.internal_border_width;
+
+}
+
+static void
+update_from_various_frame_slots (EmacsFrame ew)
+{
+  struct x_display* x = ew->emacs_frame.frame->display.x;
+  ew->core.height = x->pixel_height;
+  ew->core.width = x->pixel_width;
+  ew->core.background_pixel = x->background_pixel;
+  ew->emacs_frame.internal_border_width = x->internal_border_width;
+  ew->emacs_frame.font = x->font;
+  ew->emacs_frame.foreground_pixel = x->foreground_pixel;
+  ew->emacs_frame.cursor_color = x->cursor_pixel;
+  ew->core.border_pixel = x->border_pixel;
+}
+
+static void 
+EmacsFrameInitialize (Widget request, Widget new,
+		       ArgList dum1, Cardinal *dum2)
+{
+  EmacsFrame ew = (EmacsFrame)new;
+
+  if (!ew->emacs_frame.frame)
+    {
+      fprintf (stderr,
+	       "can't create an emacs frame widget without a frame\n");
+      exit (1);
+    }
+
+#if 0 /* done in xfns.c */
+  /* If the "Emacs.EmacsFrame.{default,Face}.{attributeFont,AttributeFont}"
+     resource is set, then it always overrides "Emacs.EmacsFrame.{font,Font}".
+     It's unfortunate that we have to do this, but we need to know the font
+     size for frame-sizing purposes before the faces get initialized.  If
+     the "default.attributeFont" isn't set, then we use the font of this
+     EmacsFrame itself, defaulting to XtDefaultFont.  Up in the lisp code,
+     the "default" face will use the frame's font if its own is not set,
+     so everything stays in sync -- it's not possible for the frame's font
+     and the default face's font to be different.
+   */
+  {
+    XFontStruct *f = 0;
+    XtResource face_res;
+    face_res.resource_name = "attributeFont";
+    face_res.resource_class = "AttributeFont";
+    face_res.resource_type = XtRFontStruct;
+    face_res.resource_size = sizeof (XFontStruct *);
+    face_res.resource_offset = 0;
+    face_res.default_type = XtRImmediate;
+    face_res.default_addr = 0;
+    XtGetSubresources ((Widget) ew, (XtPointer) &f, "default", "Face",
+		       &face_res, 1, NULL, 0);
+      
+    if (f)
+	ew->emacs_frame.font = f;
+    else if (! ew->emacs_frame.font)
+      {
+	fprintf (stderr, "emacs frame widget could not load a font\n");
+	exit (1);
+      }
+  }
+
+/* Update the font field in frame */
+  ew->emacs_frame.frame->display.x->font = ew->emacs_frame.font;
+#endif
+
+  update_from_various_frame_slots (ew);
+  set_frame_size (ew); 
+/*create_frame_gcs (ew);
+  setup_frame_gcs (ew);
+  update_various_frame_slots (ew); */
+}
+
+
+static void
+EmacsFrameRealize (Widget widget, XtValueMask *mask,
+		    XSetWindowAttributes *attrs)
+{
+  EmacsFrame ew = (EmacsFrame)widget;
+
+  attrs->event_mask = (KeyPressMask | ExposureMask | ButtonPressMask |
+		       ButtonReleaseMask | StructureNotifyMask |
+		       FocusChangeMask | PointerMotionHintMask |
+		       PointerMotionMask | LeaveWindowMask | EnterWindowMask |
+		       VisibilityChangeMask | PropertyChangeMask |
+		       StructureNotifyMask | SubstructureNotifyMask |
+		       SubstructureRedirectMask);
+  *mask |= CWEventMask;
+  XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
+		  attrs);
+  update_wm_hints (ew); 
+}
+
+extern void free_frame_faces (struct frame *);
+
+static void
+EmacsFrameDestroy (Widget widget)
+{
+  EmacsFrame ew = (EmacsFrame) widget;
+  struct frame* s = ew->emacs_frame.frame;
+
+  if (! s) abort ();
+  if (! s->display.x) abort ();
+  if (! s->display.x->normal_gc) abort ();
+
+  /* this would be called from Fdelete_frame() but it needs to free some
+     stuff after the widget has been finalized but before the widget has
+     been freed. */
+  free_frame_faces (s);
+
+  /* need to be careful that the face-freeing code doesn't free these too */
+  XFreeGC (XtDisplay (widget), s->display.x->normal_gc);
+  XFreeGC (XtDisplay (widget), s->display.x->reverse_gc);
+  XFreeGC (XtDisplay (widget), s->display.x->cursor_gc);
+}
+
+void
+EmacsFrameResize (Widget widget)
+{
+  EmacsFrame ew = (EmacsFrame)widget;
+  struct frame *f = ew->emacs_frame.frame;
+  int columns;
+  int rows;
+
+  pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows);
+  change_frame_size (f, rows, columns, 1, 0);
+  update_wm_hints (ew); 
+  {
+    Window win, child;
+    int win_x, win_y;
+
+    /* Find the position of the outside upper-left corner of
+       the window, in the root coordinate system.  Don't
+       refer to the parent window here; we may be processing
+       this event after the window manager has changed our
+       parent, but before we have reached the ReparentNotify.  */
+    XTranslateCoordinates (x_current_display,
+			   
+			   /* From-window, to-window.  */
+			   XtWindow(XtParent(ew)),
+			   ROOT_WINDOW,
+			   
+			   /* From-position, to-position.  */
+			   -f->display.x->widget->core.border_width,
+			   -f->display.x->widget->core.border_width,
+			   &win_x, &win_y,
+			   
+			   /* Child of win.  */
+			   &child);
+    f->display.x->widget->core.x = win_x;
+    f->display.x->widget->core.y = win_y;
+  }
+  update_various_frame_slots (ew);
+}
+
+static Boolean
+EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget,
+		      ArgList dum1, Cardinal *dum2)
+{
+  EmacsFrame cur = (EmacsFrame)cur_widget;
+  EmacsFrame new = (EmacsFrame)new_widget;
+
+  Boolean needs_a_refresh = False;
+  Boolean has_to_recompute_size;
+  Boolean has_to_recompute_gcs;
+  Boolean has_to_update_hints;
+
+  int char_width, char_height;
+  Dimension pixel_width;
+  Dimension pixel_height;
+  
+  has_to_recompute_gcs = (cur->emacs_frame.font != new->emacs_frame.font
+			  || (cur->emacs_frame.foreground_pixel
+			      != new->emacs_frame.foreground_pixel)
+			  || (cur->core.background_pixel
+			      != new->core.background_pixel)
+			  );
+  
+  has_to_recompute_size = (cur->emacs_frame.font != new->emacs_frame.font
+			   && cur->core.width == new->core.width
+			   && cur->core.height == new->core.height);
+
+  has_to_update_hints = (cur->emacs_frame.font != new->emacs_frame.font);
+
+  if (has_to_recompute_gcs)
+    {
+      setup_frame_gcs (new);
+      needs_a_refresh = True;
+    }
+			  
+  if (has_to_recompute_size)
+    {
+      pixel_width = new->core.width;
+      pixel_height = new->core.height;
+      pixel_to_char_size (new, pixel_width, pixel_height, &char_width,
+			  &char_height);
+      char_to_pixel_size (new, char_width, char_height, &pixel_width,
+			  &pixel_height);
+      new->core.width = pixel_width;
+      new->core.height = pixel_height;
+
+      change_frame_size (new->emacs_frame.frame, char_height, char_width,
+			  1, 0);
+      needs_a_refresh = True;
+    }
+
+  if (has_to_update_hints)
+    update_wm_hints (new);
+
+  update_various_frame_slots (new);
+
+  /* #### This doesn't work, I haven't been able to find ANY kludge that
+     will let (x-create-frame '((iconic . t))) work.  It seems that changes
+     to wm_shell's iconic slot have no effect after it has been realized,
+     and calling XIconifyWindow doesn't work either (even thought the window
+     has been created.)  Perhaps there is some property we could smash
+     directly, but I'm sick of this for now.  Xt is a steaming pile of shit!
+   */
+  if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
+    {
+      Widget wmshell = get_wm_shell ((Widget) cur);
+      XtVaSetValues (wmshell, XtNiconic, new->emacs_frame.iconic, 0);
+    }
+
+  return needs_a_refresh;
+}
+
+static XtGeometryResult
+EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry* request,
+			  XtWidgetGeometry* result)
+{
+  EmacsFrame ew = (EmacsFrame)widget;
+
+  int mask = request->request_mode;
+  Dimension ok_width, ok_height;
+
+  if (mask & (CWWidth | CWHeight))
+    {
+      round_size_to_char (ew,
+			  (mask & CWWidth) ? request->width : ew->core.width,
+			  ((mask & CWHeight) ? request->height
+			   : ew->core.height),
+			  &ok_width, &ok_height);
+      if ((mask & CWWidth) && (ok_width != request->width))
+	{
+	  result->request_mode |= CWWidth;
+	  result->width = ok_width;
+	}
+      if ((mask & CWHeight) && (ok_height != request->height))
+	{
+	  result->request_mode |= CWHeight;
+	  result->height = ok_height;
+	}
+    }
+  return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
+}
+
+#if 0
+/* I don't know why this is necessary; Matthieu said he had to do
+   it to make the focus handlers work??
+ */
+static void
+key_press (Widget w, XEvent* event, String *params, Cardinal *n_params)
+{
+}
+
+static void
+emacs_frame_focus_handler (Widget w, XEvent *event, String *params,
+			    Cardinal *n_params)
+{
+  emacs_Xt_focus_event_handler (event, 0);
+}
+#endif
+
+/* Special entrypoints */
+void
+EmacsFrameSetCharSize (Widget widget, int columns, int rows)
+{
+  EmacsFrame ew = (EmacsFrame) widget;
+  Dimension pixel_width, pixel_height, granted_width, granted_height;
+  XtGeometryResult result;
+  if (columns < 3) columns = 3;  /* no way buddy */
+  if (rows < 3) rows = 3;
+
+  char_to_pixel_size (ew, columns, rows, &pixel_width, &pixel_height);
+  result = XtMakeResizeRequest ((Widget)ew,
+				pixel_width, pixel_height,
+				&granted_width, &granted_height);
+  if (result == XtGeometryAlmost)
+    XtMakeResizeRequest ((Widget) ew, granted_width, granted_height,
+			 NULL, NULL);
+  /* damn Paned widget won't ever change its width.  Force it. */
+  if (ew->core.width != pixel_width)
+    {
+      XtVaSetValues (XtParent ((Widget) ew), XtNwidth, pixel_width, 0);
+      XtVaSetValues ((Widget) ew, XtNwidth, pixel_width, 0);
+    }
+}