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