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