(JSP-5368): Separate JX1-7A24.
[chise/xemacs-chise.git.1] / src / EmacsFrame.c
1 /* The emacs frame widget.
2    Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3    Copyright (C) 1993-1995 Sun Microsystems, Inc.
4    Copyright (C) 1995 Ben Wing.
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 /* Synched up with: Not in FSF. */
24
25 /* #### Note to potential hackers: Don't mess with this unless you're
26    sure you know what you're doing!  Xt is a lot more subtle than
27    you may think. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "console-x.h"
33 #include "glyphs-x.h"
34 #include "objects-x.h"
35 #include <X11/Shell.h>
36 #include "EmacsFrameP.h"
37 #include "EmacsManager.h"       /* for EmacsManagerChangeSize */
38 #include "xmu.h"
39
40 #include "faces.h"
41 #include "frame.h"
42 #include "toolbar.h"
43 #include "window.h"
44
45 static void EmacsFrameClassInitialize (void);
46 static void EmacsFrameInitialize (Widget, Widget, ArgList, Cardinal *);
47 static void EmacsFrameRealize (Widget, XtValueMask*, XSetWindowAttributes*);
48 static void EmacsFrameResize (Widget widget);
49 static Boolean EmacsFrameSetValues (Widget, Widget, Widget,
50                                      ArgList, Cardinal *);
51 static XtGeometryResult EmacsFrameQueryGeometry (Widget, XtWidgetGeometry*,
52                                                   XtWidgetGeometry*);
53
54 extern void
55 emacs_Xt_mapping_action (Widget w, XEvent* event);
56
57 #undef XtOffset
58 #define XtOffset(p_type,field) \
59         ((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
60 #define offset(field) XtOffset (EmacsFrame, emacs_frame.field)
61
62 static XtResource resources[] = {
63   { XtNgeometry, XtCGeometry,
64     XtRString, sizeof (String),
65     offset (geometry), XtRString, (XtPointer) 0 },
66   { XtNiconic, XtCIconic,
67     XtRBoolean, sizeof (Boolean),
68     offset (iconic), XtRImmediate, (XtPointer) False },
69
70   { XtNemacsFrame, XtCEmacsFrame,
71     XtRPointer, sizeof (XtPointer),
72     offset (frame), XtRImmediate, 0 },
73   { XtNmenubar, XtCMenubar,
74     XtRBoolean, sizeof (Boolean),
75     offset (menubar_p), XtRImmediate, (XtPointer) True },
76   { XtNinitiallyUnmapped, XtCInitiallyUnmapped,
77     XtRBoolean, sizeof (Boolean),
78     offset (initially_unmapped), XtRImmediate, (XtPointer) False },
79   { XtNminibuffer, XtCMinibuffer,
80     XtRBoolean, sizeof (Boolean),
81     offset (minibuffer), XtRImmediate, (XtPointer) True },
82   { XtNunsplittable, XtCUnsplittable,
83     XtRBoolean, sizeof (Boolean),
84     offset (unsplittable), XtRImmediate, (XtPointer) False },
85   { XtNinternalBorderWidth, XtCInternalBorderWidth,
86     XtRInt, sizeof (int),
87     offset (internal_border_width), XtRImmediate, (XtPointer)4 },
88 #ifdef HAVE_SCROLLBARS
89   { XtNscrollBarWidth, XtCScrollBarWidth,
90     XtRInt, sizeof (int),
91     offset (scrollbar_width), XtRImmediate, (XtPointer)-1 },
92   { XtNscrollBarHeight, XtCScrollBarHeight,
93     XtRInt, sizeof (int),
94     offset (scrollbar_height), XtRImmediate, (XtPointer)-1 },
95   { XtNscrollBarPlacement, XtCScrollBarPlacement,
96     XtRScrollBarPlacement, sizeof (unsigned char),
97     offset (scrollbar_placement), XtRImmediate,
98 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) || \
99     defined (LWLIB_SCROLLBARS_ATHENA3D)
100     (XtPointer) XtBOTTOM_RIGHT
101 #else
102     (XtPointer) XtBOTTOM_LEFT
103 #endif
104   },
105 #endif /* HAVE_SCROLLBARS */
106
107 #ifdef HAVE_TOOLBARS
108   { XtNtopToolBarHeight, XtCTopToolBarHeight,
109     XtRInt, sizeof (int),
110     offset (top_toolbar_height), XtRImmediate, (XtPointer)-1 },
111   { XtNbottomToolBarHeight, XtCBottomToolBarHeight,
112     XtRInt, sizeof (int),
113     offset (bottom_toolbar_height), XtRImmediate, (XtPointer)-1 },
114   { XtNleftToolBarWidth, XtCLeftToolBarWidth,
115     XtRInt, sizeof (int),
116     offset (left_toolbar_width), XtRImmediate, (XtPointer)-1 },
117   { XtNrightToolBarWidth, XtCRightToolBarWidth,
118     XtRInt, sizeof (int),
119     offset (right_toolbar_width), XtRImmediate, (XtPointer)-1 },
120   { XtNtopToolBarBorderWidth, XtCTopToolBarBorderWidth,
121     XtRInt, sizeof (int),
122     offset (top_toolbar_border_width), XtRImmediate, (XtPointer)-1 },
123   { XtNbottomToolBarBorderWidth, XtCBottomToolBarBorderWidth,
124     XtRInt, sizeof (int),
125     offset (bottom_toolbar_border_width), XtRImmediate, (XtPointer)-1 },
126   { XtNleftToolBarBorderWidth, XtCLeftToolBarBorderWidth,
127     XtRInt, sizeof (int),
128     offset (left_toolbar_border_width), XtRImmediate, (XtPointer)-1 },
129   { XtNrightToolBarBorderWidth, XtCRightToolBarBorderWidth,
130     XtRInt, sizeof (int),
131     offset (right_toolbar_border_width), XtRImmediate, (XtPointer)-1 },
132   { XtNtopToolBarShadowColor, XtCTopToolBarShadowColor,
133     XtRPixel, sizeof (Pixel),
134     offset(top_toolbar_shadow_pixel), XtRString, (XtPointer) "#000000" },
135   { XtNbottomToolBarShadowColor, XtCBottomToolBarShadowColor,
136     XtRPixel, sizeof (Pixel),
137     offset (bottom_toolbar_shadow_pixel), XtRString, (XtPointer) "#000000" },
138   { XtNbackgroundToolBarColor, XtCBackgroundToolBarColor,
139     XtRPixel, sizeof (Pixel),
140     offset (background_toolbar_pixel), XtRImmediate, (XtPointer)-1 },
141   { XtNforegroundToolBarColor, XtCForegroundToolBarColor,
142     XtRPixel, sizeof (Pixel),
143     offset (foreground_toolbar_pixel), XtRImmediate, (XtPointer)-1 },
144   { XtNtopToolBarShadowPixmap, XtCTopToolBarShadowPixmap,
145     XtRPixmap, sizeof (Pixmap),
146     offset (top_toolbar_shadow_pixmap), XtRImmediate, (XtPointer)None },
147   { XtNbottomToolBarShadowPixmap, XtCBottomToolBarShadowPixmap,
148     XtRPixmap, sizeof (Pixmap),
149     offset (bottom_toolbar_shadow_pixmap), XtRImmediate, (XtPointer)None },
150   { XtNtoolBarShadowThickness, XtCToolBarShadowThickness,
151     XtRDimension, sizeof (Dimension),
152     offset (toolbar_shadow_thickness), XtRImmediate, (XtPointer)2 },
153 #endif /* HAVE_TOOLBARS */
154
155   { XtNinterline, XtCInterline,
156     XtRInt, sizeof (int),
157     offset (interline), XtRImmediate, (XtPointer)0 },
158   {
159 #ifdef I18N4
160     XtNfontSet, XtCFontSet,
161     XtRFontSet, sizeof (XFontSet),
162 #else
163     XtNfont, XtCFont,
164     XtRFontStruct, sizeof (XFontStruct *),
165 #endif
166     offset(font), XtRImmediate, (XtPointer)0
167   },
168   { XtNforeground, XtCForeground,
169     XtRPixel, sizeof (Pixel),
170     offset(foreground_pixel), XtRString, (XtPointer) "Black" },
171   { XtNbackground, XtCBackground,
172     XtRPixel, sizeof (Pixel),
173     offset(background_pixel), XtRString, (XtPointer) "Gray80" },
174   { XtNcursorColor, XtCForeground,
175     XtRPixel, sizeof (Pixel),
176     offset(cursor_color), XtRString, (XtPointer) "XtDefaultForeground" },
177   { XtNbarCursor, XtCBarCursor,
178     XtRBoolean, sizeof (Boolean),
179     offset (bar_cursor), XtRImmediate, (XtPointer)0 },
180   { XtNvisualBell, XtCVisualBell,
181     XtRBoolean, sizeof (Boolean),
182     offset (visual_bell), XtRImmediate, (XtPointer)0 },
183   { XtNbellVolume, XtCBellVolume,
184     XtRInt, sizeof (int),
185     offset (bell_volume), XtRImmediate, (XtPointer)0 },
186   { XtNuseBackingStore, XtCUseBackingStore,
187     XtRBoolean, sizeof (Boolean),
188     offset (use_backing_store), XtRImmediate, (XtPointer) NotUseful },
189   { XtNpreferredWidth, XtCPreferredWidth,
190     XtRDimension, sizeof (Dimension),
191     offset (preferred_width), XtRImmediate, (XtPointer)0 },
192   { XtNpreferredHeight, XtCPreferredHeight,
193     XtRDimension, sizeof (Dimension),
194     offset (preferred_height), XtRImmediate, (XtPointer)0 },
195 };
196
197 #undef offset
198
199 /* Xt is stupid and dumb.
200    Xt is stupid and dumb.
201    Xt is stupid and dumb. */
202
203 static XtActionsRec
204 emacsFrameActionsTable [] = {
205   {"mapping",  (XtActionProc) emacs_Xt_mapping_action},
206 };
207
208 static char
209 emacsFrameTranslations [] = "\
210 <Mapping>: mapping()\n\
211 ";
212
213 /* If we're running under Motif, make this widget a subclass
214    of XmPrimitive.  It's not clear this is necessary, but it
215    may make focus behavior work better. */
216
217 EmacsFrameClassRec emacsFrameClassRec = {
218     { /* core fields */
219 #ifdef LWLIB_USES_MOTIF
220     /* superclass               */      (WidgetClass) &xmPrimitiveClassRec,
221 #else
222     /* superclass               */      &widgetClassRec,
223 #endif
224     /* class_name               */      "EmacsFrame",
225     /* widget_size              */      sizeof (EmacsFrameRec),
226     /* class_initialize         */      EmacsFrameClassInitialize,
227     /* class_part_initialize    */      0,
228     /* class_inited             */      FALSE,
229     /* initialize               */      EmacsFrameInitialize,
230     /* initialize_hook          */      0,
231     /* realize                  */      EmacsFrameRealize,
232     /* actions                  */      emacsFrameActionsTable,
233     /* num_actions              */      XtNumber (emacsFrameActionsTable),
234     /* resources                */      resources,
235     /* resource_count           */      XtNumber (resources),
236     /* xrm_class                */      NULLQUARK,
237     /* compress_motion          */      TRUE,
238 #ifdef LWLIB_USES_MOTIF
239     /* compress_exposure        */      TRUE,
240 #else
241     /* compress_exposure        */      XtExposeCompressMaximal | XtExposeNoRegion,
242 #endif
243     /* compress_enterleave      */      TRUE,
244     /* visible_interest         */      FALSE,
245     /* destroy                  */      NULL,
246     /* resize                   */      EmacsFrameResize,
247     /* expose                   */      XtInheritExpose,
248     /* set_values               */      EmacsFrameSetValues,
249     /* set_values_hook          */      0,
250     /* set_values_almost        */      XtInheritSetValuesAlmost,
251     /* get_values_hook          */      0,
252     /* accept_focus             */      XtInheritAcceptFocus,
253     /* version                  */      XtVersion,
254     /* callback_private         */      0,
255     /* tm_table                 */      emacsFrameTranslations,
256     /* query_geometry           */      EmacsFrameQueryGeometry,
257     /* display_accelerator      */      XtInheritDisplayAccelerator,
258     /* extension                */      0
259     },
260 #ifdef LWLIB_USES_MOTIF
261     {   /* XmPrimitiveClassPart
262          */
263       (XtWidgetProc) _XtInherit,        /* border_highlight */
264       (XtWidgetProc) _XtInherit,        /* border_unhighlight */
265       /* Setting the following to NULL causes PrimitiveInitialize()
266          not to add traversal (TAB etc. to switch focus) and
267          focus-in/out (border highlight/unhighlight) translations.
268          If you want those translations, use the value XtInheritTranslations
269          instead.  Doing this, however, will interfere with Emacs
270          focus handling (which highlights/unhighlights the text cursor),
271          and will lead to strange display results around the border of the
272          widget. */
273       NULL,                             /* translations */
274       NULL,                             /* arm_and_activate */
275       NULL,                             /* get resources */
276       0,                                /* num get_resources */
277       NULL,                             /* extension */
278     },
279 #endif /* LWLIB_USES_MOTIF */
280     {
281       0
282     }
283 };
284 WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
285
286 static void
287 update_various_frame_slots (EmacsFrame ew)
288 {
289   ew->emacs_frame.frame->pixheight = ew->core.height;
290   ew->emacs_frame.frame->pixwidth = ew->core.width;
291 }
292
293 static void
294 EmacsFrameInitialize (Widget request, Widget new,
295                        ArgList dum1, Cardinal *dum2)
296 {
297   EmacsFrame ew = (EmacsFrame)new;
298   struct frame *f = ew->emacs_frame.frame;
299
300   if (!f)
301     fatal ("can't create an emacs frame widget without a frame.");
302
303   ew->emacs_frame.frame->internal_border_width =
304     ew->emacs_frame.internal_border_width;
305 }
306
307 void emacs_Xt_event_handler (Widget wid /* unused */,
308                              XtPointer closure /* unused */,
309                              XEvent *event,
310                              Boolean *continue_to_dispatch /* unused */);
311
312 static void
313 EmacsFrameRealize (Widget widget, XtValueMask *mask,
314                    XSetWindowAttributes *attrs)
315 {
316   EmacsFrame ew = (EmacsFrame) widget;
317   struct frame *f = ew->emacs_frame.frame;
318   Widget shell_widget = FRAME_X_SHELL_WIDGET (f);
319
320   attrs->event_mask =
321     ExposureMask           |
322     VisibilityChangeMask   |
323     PropertyChangeMask     |
324     StructureNotifyMask    |
325     SubstructureNotifyMask |
326     /*SubstructureRedirectMask |*/ /* Only for WMs! */
327     KeyPressMask           |
328     KeyReleaseMask         |
329     ButtonPressMask        |
330     ButtonReleaseMask      |
331     FocusChangeMask        |
332     PointerMotionHintMask  |
333     PointerMotionMask      |
334     LeaveWindowMask        |
335     EnterWindowMask;
336
337
338 #ifdef I18N4
339   /* Make sure that events wanted by the input method are selected. */
340   attrs->event_mask |= input_method_event_mask;
341 #endif
342
343   *mask |= CWEventMask;
344
345   if (ew->emacs_frame.use_backing_store)
346     {
347       attrs->backing_store = Always;
348       *mask |= CWBackingStore;
349     }
350   XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
351                   attrs);
352
353   /* snarf the events we want. */
354   XtInsertEventHandler (widget, attrs->event_mask, TRUE,
355                         emacs_Xt_event_handler, NULL, XtListHead);
356   /* some events (e.g. map-notify and WM_DELETE_WINDOW) get sent
357      directly to the shell, and the above event handler won't see
358      them.  So add a handler to get them.  These events don't
359      propagate, so there's no danger of them being seen twice. */
360   XtInsertEventHandler (shell_widget,
361                         EnterWindowMask | LeaveWindowMask |
362                         VisibilityChangeMask | StructureNotifyMask |
363                         KeyPressMask,
364                         TRUE, emacs_Xt_event_handler, NULL, XtListHead);
365
366 #ifdef EXTERNAL_WIDGET
367   /* #### Not sure if this special case is necessary */
368   if (!FRAME_X_EXTERNAL_WINDOW_P (f))
369 #endif
370     /* This is necessary under Motif in order to make it possible to click in
371        a buffer and move focus out of a dialog box or control panel and back
372        into emacs-land; also necessary so that you can still type chars
373        if the cursor is over the menubar or scrollbar. */
374     lw_set_keyboard_focus (shell_widget, FRAME_X_TEXT_WIDGET (f));
375 }
376
377 /* DO NOT CALL THIS FUNCTION!  Only Xt is supposed to do this. */
378
379 static void
380 EmacsFrameResize (Widget widget)
381 {
382   EmacsFrame ew = (EmacsFrame)widget;
383   struct frame *f = ew->emacs_frame.frame;
384   int columns;
385   int rows;
386   XtWidgetGeometry req, repl;
387
388   update_various_frame_slots (ew);
389
390   pixel_to_char_size (f, ew->core.width, ew->core.height, &columns, &rows);
391   change_frame_size (f, rows, columns, 0);
392
393   /* Now we tell the EmacsShell that we've changed the size of the non-fixed
394      portion of the frame.  Note that, if we the resize occurred as a result
395      of EmacsFrameSetCharSize(), this information will be stored twice.
396      This is not a big deal, as storing this information doesn't actually
397      do anything until the next resize. */
398   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
399     x_wm_set_variable_size (FRAME_X_SHELL_WIDGET (f), columns, rows);
400
401   /* Kick the manager so that it knows we've changed size. */
402   req.request_mode = 0;
403   XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl);
404   EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width,
405                           repl.height);
406 }
407
408 static Boolean
409 EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget,
410                       ArgList argv, Cardinal *argc)
411 {
412   EmacsFrame cur = (EmacsFrame) cur_widget;
413   EmacsFrame new = (EmacsFrame) new_widget;
414   struct frame *f = new->emacs_frame.frame;
415   Lisp_Object frame;
416
417   XSETFRAME (frame, f);
418   in_resource_setting++;
419   /* This function does not need to do much.  Pretty much everything
420      interesting will get done in the resize method, which will
421      (if necessary) get called by Xt when this function returns
422      (see below).
423    */
424
425   /* #### This function will not work if it is not called from
426      update_EmacsFrame(), called from SET_FACE_PROPERTY().
427      The code located there should be moved inside of here instead,
428      so that things work if either SET_FACE_PROPERTY() is
429      called or XtSetValues() is called.
430      */
431
432   if (cur->emacs_frame.iconic != new->emacs_frame.iconic &&
433       FRAME_X_TOP_LEVEL_FRAME_P (new->emacs_frame.frame))
434     x_wm_set_shell_iconic_p (FRAME_X_SHELL_WIDGET (new->emacs_frame.frame),
435                              new->emacs_frame.iconic);
436
437       /* If we got here, then we were likely called as a result of
438          the EditRes protocol, so go ahead and change scrollbar-width
439          and scrollbar-height.  Otherwise, we're merely mirroring
440          a change made to scrollbar-width etc. so don't do anything
441          special. */
442   if (cur->emacs_frame.internal_border_width !=
443       new->emacs_frame.internal_border_width)
444     {
445       f->internal_border_width = new->emacs_frame.internal_border_width;
446       MARK_FRAME_SIZE_SLIPPED (f);
447     }
448
449 #ifdef HAVE_SCROLLBARS
450       if (cur->emacs_frame.scrollbar_width !=
451           new->emacs_frame.scrollbar_width)
452         Fadd_spec_to_specifier
453           (Vscrollbar_width,
454            make_int (new->emacs_frame.scrollbar_width),
455            frame, Qnil, Qnil);
456       if (cur->emacs_frame.scrollbar_height !=
457           new->emacs_frame.scrollbar_height)
458         Fadd_spec_to_specifier
459           (Vscrollbar_height,
460            make_int (new->emacs_frame.scrollbar_height),
461            frame, Qnil, Qnil);
462 #endif /* HAVE_SCROLLBARS */
463 #ifdef HAVE_TOOLBARS
464       if (cur->emacs_frame.top_toolbar_height !=
465           new->emacs_frame.top_toolbar_height)
466         Fadd_spec_to_specifier
467           (Vtoolbar_size[TOP_TOOLBAR],
468            make_int (new->emacs_frame.top_toolbar_height),
469            frame, Qnil, Qnil);
470       if (cur->emacs_frame.bottom_toolbar_height !=
471           new->emacs_frame.bottom_toolbar_height)
472         Fadd_spec_to_specifier
473           (Vtoolbar_size[BOTTOM_TOOLBAR],
474            make_int (new->emacs_frame.bottom_toolbar_height),
475            frame, Qnil, Qnil);
476       if (cur->emacs_frame.left_toolbar_width !=
477           new->emacs_frame.left_toolbar_width)
478         Fadd_spec_to_specifier
479           (Vtoolbar_size[LEFT_TOOLBAR],
480            make_int (new->emacs_frame.left_toolbar_width),
481            frame, Qnil, Qnil);
482       if (cur->emacs_frame.right_toolbar_width !=
483           new->emacs_frame.right_toolbar_width)
484         Fadd_spec_to_specifier
485           (Vtoolbar_size[RIGHT_TOOLBAR],
486            make_int (new->emacs_frame.right_toolbar_width),
487            frame, Qnil, Qnil);
488       if (cur->emacs_frame.top_toolbar_border_width !=
489           new->emacs_frame.top_toolbar_border_width)
490         Fadd_spec_to_specifier
491           (Vtoolbar_border_width[TOP_TOOLBAR],
492            make_int (new->emacs_frame.top_toolbar_border_width),
493            frame, Qnil, Qnil);
494       if (cur->emacs_frame.bottom_toolbar_border_width !=
495           new->emacs_frame.bottom_toolbar_border_width)
496         Fadd_spec_to_specifier
497           (Vtoolbar_border_width[BOTTOM_TOOLBAR],
498            make_int (new->emacs_frame.bottom_toolbar_border_width),
499            frame, Qnil, Qnil);
500       if (cur->emacs_frame.left_toolbar_border_width !=
501           new->emacs_frame.left_toolbar_border_width)
502         Fadd_spec_to_specifier
503           (Vtoolbar_border_width[LEFT_TOOLBAR],
504            make_int (new->emacs_frame.left_toolbar_border_width),
505            frame, Qnil, Qnil);
506       if (cur->emacs_frame.right_toolbar_border_width !=
507           new->emacs_frame.right_toolbar_border_width)
508         Fadd_spec_to_specifier
509           (Vtoolbar_border_width[RIGHT_TOOLBAR],
510            make_int (new->emacs_frame.right_toolbar_border_width),
511            frame, Qnil, Qnil);
512 #endif /* HAVE_TOOLBARS */
513
514   in_resource_setting--;
515
516   /* If the request was to resize us, but the size has not changed, Xt
517      will do nothing, and won't call our resize callback. Since such a
518      request might be issued as a result of hiding/showing menubar or
519      changing toolbar placement, where we rely on relayout made by the
520      callback, we go ahead and simulate such a call */
521   if (cur->core.width == new->core.width
522       && cur->core.height == new->core.height)
523     {
524       Cardinal i;
525       for (i=0; i<*argc; i++)
526         if (strcmp (argv[i].name, XtNwidth) == 0
527             || strcmp (argv[i].name, XtNheight) == 0)
528           {
529             EmacsFrameResize (new_widget);
530             break;
531           }
532     }
533
534   return False;
535
536   /* Note that if either (a) we return True, or (b) the width or
537      height has changed, an Expose event will be generated.  The Xt
538      manual says you should not return True if the width or height has
539      changed, because then two Expose events will be generated.
540
541      In any case, there is no need to return True because
542      SET_FACE_PROPERTY(), which does the resource
543      setting, automatically forces a redisplay as necessary. */
544 }
545
546 static XtGeometryResult
547 EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request,
548                          XtWidgetGeometry *result)
549 {
550   EmacsFrame ew = (EmacsFrame) widget;
551   int mask = request->request_mode;
552   Dimension width, height;
553   int ok_width_int, ok_height_int;
554   Dimension ok_width, ok_height;
555
556   /* We have a definite preference for what size we would like
557      to be.
558
559      1) If a preferred size was specified for us, use it.
560         (This is not currently used)
561      2) If a proposed size was given, round it to the nearest
562         multiple of the default char size and return it.
563      3) Otherwise, take our current size and round it to the
564         nearest multiple of the default char size. */
565
566   width = mask & CWWidth ? request->width : ew->core.width;
567   height = mask & CWHeight ? request->height : ew->core.height;
568   round_size_to_char (ew->emacs_frame.frame, width, height,
569                       &ok_width_int, &ok_height_int);
570   ok_width = (Dimension) ok_width_int;
571   ok_height = (Dimension) ok_height_int;
572   if (ew->emacs_frame.preferred_width)
573     ok_width = ew->emacs_frame.preferred_width;
574   if (ew->emacs_frame.preferred_height)
575     ok_height = ew->emacs_frame.preferred_height;
576   result->request_mode |= CWWidth | CWHeight;
577   result->width = ok_width;
578   result->height = ok_height;
579   if (((mask & CWWidth) && ok_width != request->width)
580       || ((mask & CWHeight) && ok_height != request->height))
581     return XtGeometryAlmost;
582   else
583     return XtGeometryYes;
584 }
585
586 /* Xt string-to-scrollbar-placement converter */
587 /* #### Convert this to a `new-style' converter (See XtAddTypeConverter) */
588
589 /* This variable cannot be a stack variable. */
590 static unsigned char cvt_string_scrollbar_placement;
591
592 /* ARGSUSED */
593 static void
594 Xt_StringToScrollBarPlacement (XrmValuePtr args,   /* unused */
595                                  Cardinal *num_args, /* unused */
596                                  XrmValuePtr fromVal,
597                                  XrmValuePtr toVal)
598 {
599   XrmQuark q;
600   char *lowerName = (char *) alloca (strlen ((char *) fromVal->addr) + 1);
601
602   XmuCopyISOLatin1Lowered (lowerName, (char *) fromVal->addr);
603   q = XrmStringToQuark (lowerName);
604
605   toVal->size = sizeof (cvt_string_scrollbar_placement);
606   toVal->addr = (XPointer) &cvt_string_scrollbar_placement;
607
608   if      (q == XrmStringToQuark ("top-left")
609            || q == XrmStringToQuark ("top_left"))
610     cvt_string_scrollbar_placement = XtTOP_LEFT;
611   else if (q == XrmStringToQuark ("bottom-left")
612            || q == XrmStringToQuark ("bottom_left"))
613     cvt_string_scrollbar_placement = XtBOTTOM_LEFT;
614   else if (q == XrmStringToQuark ("top-right")
615            || q == XrmStringToQuark ("top_right"))
616     cvt_string_scrollbar_placement = XtTOP_RIGHT;
617   else if (q == XrmStringToQuark ("bottom-right")
618            || q == XrmStringToQuark ("bottom_right"))
619     cvt_string_scrollbar_placement = XtBOTTOM_RIGHT;
620   else
621     {
622       XtStringConversionWarning (fromVal->addr, "scrollBarPlacement");
623       toVal->addr = NULL;
624       toVal->size = 0;
625     }
626 }
627
628 static void
629 EmacsFrameClassInitialize (void)
630 {
631   XtAddConverter (XtRString, XtRScrollBarPlacement,
632                   Xt_StringToScrollBarPlacement, NULL, 0);
633 }
634
635 /********************* Special entrypoints *******************/
636
637 void
638 EmacsFrameRecomputeCellSize (Widget w)
639 {
640   EmacsFrame ew = (EmacsFrame) w;
641   int cw, ch;
642   struct frame *f = ew->emacs_frame.frame;
643
644   if (! XtIsSubclass (w, emacsFrameClass))
645     ABORT ();
646
647   default_face_height_and_width (make_frame (f), &ch, &cw);
648   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
649     x_wm_set_cell_size (FRAME_X_SHELL_WIDGET (f), cw, ch);
650 }
651
652 /* Set the size of the widget to have the number of rows and columns
653    specified.  This both causes the X window to change and the
654    internal frame structures to get modified to match. */
655
656 void
657 EmacsFrameSetCharSize (Widget widget, int columns, int rows)
658 {
659   EmacsFrame ew = (EmacsFrame) widget;
660   int pixel_width, pixel_height;
661   struct frame *f = ew->emacs_frame.frame;
662
663   if (columns < 3)
664     columns = 3;  /* no way buddy */
665   if (rows < 1)
666     rows = 1;
667
668   char_to_pixel_size (f, columns, rows, &pixel_width, &pixel_height);
669
670   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
671     x_wm_set_variable_size (FRAME_X_SHELL_WIDGET (f), columns, rows);
672
673   {
674     Arg al [2];
675     XtSetArg (al [0], XtNwidth,  pixel_width);
676     XtSetArg (al [1], XtNheight, pixel_height);
677     XtSetValues ((Widget) ew, al, countof (al));
678   }
679 }