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