This commit was generated by cvs2svn to compensate for changes in r5209,
[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)0 },
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     /* compress_exposure        */      TRUE,
239     /* compress_enterleave      */      TRUE,
240     /* visible_interest         */      FALSE,
241     /* destroy                  */      NULL,
242     /* resize                   */      EmacsFrameResize,
243     /* expose                   */      XtInheritExpose,
244     /* set_values               */      EmacsFrameSetValues,
245     /* set_values_hook          */      0,
246     /* set_values_almost        */      XtInheritSetValuesAlmost,
247     /* get_values_hook          */      0,
248     /* accept_focus             */      XtInheritAcceptFocus,
249     /* version                  */      XtVersion,
250     /* callback_private         */      0,
251     /* tm_table                 */      emacsFrameTranslations,
252     /* query_geometry           */      EmacsFrameQueryGeometry,
253     /* display_accelerator      */      XtInheritDisplayAccelerator,
254     /* extension                */      0
255     },
256 #ifdef LWLIB_USES_MOTIF
257     {   /* XmPrimitiveClassPart
258          */
259       (XtWidgetProc) _XtInherit,        /* border_highlight */
260       (XtWidgetProc) _XtInherit,        /* border_unhighlight */
261       /* Setting the following to NULL causes PrimitiveInitialize()
262          not to add traversal (TAB etc. to switch focus) and
263          focus-in/out (border highlight/unhighlight) translations.
264          If you want those translations, use the value XtInheritTranslations
265          instead.  Doing this, however, will interfere with Emacs
266          focus handling (which highlights/unhighlights the text cursor),
267          and will lead to strange display results around the border of the
268          widget. */
269       NULL,                             /* translations */
270       NULL,                             /* arm_and_activate */
271       NULL,                             /* get resources */
272       0,                                /* num get_resources */
273       NULL,                             /* extension */
274     },
275 #endif /* LWLIB_USES_MOTIF */
276     {
277       0
278     }
279 };
280 WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
281
282 static void
283 update_various_frame_slots (EmacsFrame ew)
284 {
285   ew->emacs_frame.frame->pixheight = ew->core.height;
286   ew->emacs_frame.frame->pixwidth = ew->core.width;
287 }
288
289 static void
290 EmacsFrameInitialize (Widget request, Widget new,
291                        ArgList dum1, Cardinal *dum2)
292 {
293   EmacsFrame ew = (EmacsFrame)new;
294   struct frame *f = ew->emacs_frame.frame;
295
296   if (!f)
297     fatal ("can't create an emacs frame widget without a frame.");
298
299   ew->emacs_frame.frame->internal_border_width =
300     ew->emacs_frame.internal_border_width;
301 }
302
303 void emacs_Xt_event_handler (Widget wid /* unused */,
304                              XtPointer closure /* unused */,
305                              XEvent *event,
306                              Boolean *continue_to_dispatch /* unused */);
307
308 static void
309 EmacsFrameRealize (Widget widget, XtValueMask *mask,
310                    XSetWindowAttributes *attrs)
311 {
312   EmacsFrame ew = (EmacsFrame) widget;
313   struct frame *f = ew->emacs_frame.frame;
314   Widget shell_widget = FRAME_X_SHELL_WIDGET (f);
315
316   attrs->event_mask =
317     ExposureMask           |
318     VisibilityChangeMask   |
319     PropertyChangeMask     |
320     StructureNotifyMask    |
321     SubstructureNotifyMask |
322     /*SubstructureRedirectMask |*/ /* Only for WMs! */
323     KeyPressMask           |
324     KeyReleaseMask         |
325     ButtonPressMask        |
326     ButtonReleaseMask      |
327     FocusChangeMask        |
328     PointerMotionHintMask  |
329     PointerMotionMask      |
330     LeaveWindowMask        |
331     EnterWindowMask;
332
333
334 #ifdef I18N4
335   /* Make sure that events wanted by the input method are selected. */
336   attrs->event_mask |= input_method_event_mask;
337 #endif
338
339   *mask |= CWEventMask;
340
341   if (ew->emacs_frame.use_backing_store)
342     {
343       attrs->backing_store = Always;
344       *mask |= CWBackingStore;
345     }
346   XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
347                   attrs);
348
349   /* snarf the events we want. */
350   XtInsertEventHandler (widget, attrs->event_mask, TRUE,
351                         emacs_Xt_event_handler, NULL, XtListHead);
352   /* some events (e.g. map-notify and WM_DELETE_WINDOW) get sent
353      directly to the shell, and the above event handler won't see
354      them.  So add a handler to get them.  These events don't
355      propagate, so there's no danger of them being seen twice. */
356   XtInsertEventHandler (shell_widget,
357                         EnterWindowMask | LeaveWindowMask |
358                         VisibilityChangeMask | StructureNotifyMask |
359                         KeyPressMask,
360                         TRUE, emacs_Xt_event_handler, NULL, XtListHead);
361
362 #ifdef EXTERNAL_WIDGET
363   /* #### Not sure if this special case is necessary */
364   if (!FRAME_X_EXTERNAL_WINDOW_P (f))
365 #endif
366     /* This is necessary under Motif in order to make it possible to click in
367        a buffer and move focus out of a dialog box or control panel and back
368        into emacs-land; also necessary so that you can still type chars
369        if the cursor is over the menubar or scrollbar. */
370     lw_set_keyboard_focus (shell_widget, FRAME_X_TEXT_WIDGET (f));
371 }
372
373 /* DO NOT CALL THIS FUNCTION!  Only Xt is supposed to do this. */
374
375 static void
376 EmacsFrameResize (Widget widget)
377 {
378   EmacsFrame ew = (EmacsFrame)widget;
379   struct frame *f = ew->emacs_frame.frame;
380   int columns;
381   int rows;
382   XtWidgetGeometry req, repl;
383
384   update_various_frame_slots (ew);
385
386   pixel_to_char_size (f, ew->core.width, ew->core.height, &columns, &rows);
387   change_frame_size (f, rows, columns, 0);
388
389   /* Now we tell the EmacsShell that we've changed the size of the non-fixed
390      portion of the frame.  Note that, if we the resize occurred as a result
391      of EmacsFrameSetCharSize(), this information will be stored twice.
392      This is not a big deal, as storing this information doesn't actually
393      do anything until the next resize. */
394   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
395     x_wm_set_variable_size (FRAME_X_SHELL_WIDGET (f), columns, rows);
396
397   /* Kick the manager so that it knows we've changed size. */
398   req.request_mode = 0;
399   XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl);
400   EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width,
401                           repl.height);
402 }
403
404 static Boolean
405 EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget,
406                       ArgList argv, Cardinal *argc)
407 {
408   EmacsFrame cur = (EmacsFrame) cur_widget;
409   EmacsFrame new = (EmacsFrame) new_widget;
410   struct frame *f = new->emacs_frame.frame;
411   Lisp_Object frame;
412
413   XSETFRAME (frame, f);
414   in_resource_setting++;
415   /* This function does not need to do much.  Pretty much everything
416      interesting will get done in the resize method, which will
417      (if necessary) get called by Xt when this function returns
418      (see below).
419    */
420
421   /* #### This function will not work if it is not called from
422      update_EmacsFrame(), called from SET_FACE_PROPERTY().
423      The code located there should be moved inside of here instead,
424      so that things work if either SET_FACE_PROPERTY() is
425      called or XtSetValues() is called.
426      */
427
428   if (cur->emacs_frame.iconic != new->emacs_frame.iconic &&
429       FRAME_X_TOP_LEVEL_FRAME_P (new->emacs_frame.frame))
430     x_wm_set_shell_iconic_p (FRAME_X_SHELL_WIDGET (new->emacs_frame.frame),
431                              new->emacs_frame.iconic);
432
433       /* If we got here, then we were likely called as a result of
434          the EditRes protocol, so go ahead and change scrollbar-width
435          and scrollbar-height.  Otherwise, we're merely mirroring
436          a change made to scrollbar-width etc. so don't do anything
437          special. */
438   if (cur->emacs_frame.internal_border_width !=
439       new->emacs_frame.internal_border_width)
440     {
441       f->internal_border_width = new->emacs_frame.internal_border_width;
442       MARK_FRAME_SIZE_SLIPPED (f);
443     }
444
445 #ifdef HAVE_SCROLLBARS
446       if (cur->emacs_frame.scrollbar_width !=
447           new->emacs_frame.scrollbar_width)
448         Fadd_spec_to_specifier
449           (Vscrollbar_width,
450            make_int (new->emacs_frame.scrollbar_width),
451            frame, Qnil, Qnil);
452       if (cur->emacs_frame.scrollbar_height !=
453           new->emacs_frame.scrollbar_height)
454         Fadd_spec_to_specifier
455           (Vscrollbar_height,
456            make_int (new->emacs_frame.scrollbar_height),
457            frame, Qnil, Qnil);
458 #endif /* HAVE_SCROLLBARS */
459 #ifdef HAVE_TOOLBARS
460       if (cur->emacs_frame.top_toolbar_height !=
461           new->emacs_frame.top_toolbar_height)
462         Fadd_spec_to_specifier
463           (Vtoolbar_size[TOP_TOOLBAR],
464            make_int (new->emacs_frame.top_toolbar_height),
465            frame, Qnil, Qnil);
466       if (cur->emacs_frame.bottom_toolbar_height !=
467           new->emacs_frame.bottom_toolbar_height)
468         Fadd_spec_to_specifier
469           (Vtoolbar_size[BOTTOM_TOOLBAR],
470            make_int (new->emacs_frame.bottom_toolbar_height),
471            frame, Qnil, Qnil);
472       if (cur->emacs_frame.left_toolbar_width !=
473           new->emacs_frame.left_toolbar_width)
474         Fadd_spec_to_specifier
475           (Vtoolbar_size[LEFT_TOOLBAR],
476            make_int (new->emacs_frame.left_toolbar_width),
477            frame, Qnil, Qnil);
478       if (cur->emacs_frame.right_toolbar_width !=
479           new->emacs_frame.right_toolbar_width)
480         Fadd_spec_to_specifier
481           (Vtoolbar_size[RIGHT_TOOLBAR],
482            make_int (new->emacs_frame.right_toolbar_width),
483            frame, Qnil, Qnil);
484       if (cur->emacs_frame.top_toolbar_border_width !=
485           new->emacs_frame.top_toolbar_border_width)
486         Fadd_spec_to_specifier
487           (Vtoolbar_border_width[TOP_TOOLBAR],
488            make_int (new->emacs_frame.top_toolbar_border_width),
489            frame, Qnil, Qnil);
490       if (cur->emacs_frame.bottom_toolbar_border_width !=
491           new->emacs_frame.bottom_toolbar_border_width)
492         Fadd_spec_to_specifier
493           (Vtoolbar_border_width[BOTTOM_TOOLBAR],
494            make_int (new->emacs_frame.bottom_toolbar_border_width),
495            frame, Qnil, Qnil);
496       if (cur->emacs_frame.left_toolbar_border_width !=
497           new->emacs_frame.left_toolbar_border_width)
498         Fadd_spec_to_specifier
499           (Vtoolbar_border_width[LEFT_TOOLBAR],
500            make_int (new->emacs_frame.left_toolbar_border_width),
501            frame, Qnil, Qnil);
502       if (cur->emacs_frame.right_toolbar_border_width !=
503           new->emacs_frame.right_toolbar_border_width)
504         Fadd_spec_to_specifier
505           (Vtoolbar_border_width[RIGHT_TOOLBAR],
506            make_int (new->emacs_frame.right_toolbar_border_width),
507            frame, Qnil, Qnil);
508 #endif /* HAVE_TOOLBARS */
509
510   in_resource_setting--;
511
512   /* If the request was to resize us, but the size has not changed, Xt
513      will do nothing, and won't call our resize callback. Since such a
514      request might be issued as a result of hiding/showing menubar or
515      changing toolbar placement, where we rely on relayout made by the
516      callback, we go ahead and simulate such a call */
517   if (cur->core.width == new->core.width
518       && cur->core.height == new->core.height)
519     {
520       Cardinal i;
521       for (i=0; i<*argc; i++)
522         if (strcmp (argv[i].name, XtNwidth) == 0
523             || strcmp (argv[i].name, XtNheight) == 0)
524           {
525             EmacsFrameResize (new_widget);
526             break;
527           }
528     }
529
530   return False;
531
532   /* Note that if either (a) we return True, or (b) the width or
533      height has changed, an Expose event will be generated.  The Xt
534      manual says you should not return True if the width or height has
535      changed, because then two Expose events will be generated.
536
537      In any case, there is no need to return True because
538      SET_FACE_PROPERTY(), which does the resource
539      setting, automatically forces a redisplay as necessary. */
540 }
541
542 static XtGeometryResult
543 EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request,
544                          XtWidgetGeometry *result)
545 {
546   EmacsFrame ew = (EmacsFrame) widget;
547   int mask = request->request_mode;
548   Dimension width, height;
549   int ok_width_int, ok_height_int;
550   Dimension ok_width, ok_height;
551
552   /* We have a definite preference for what size we would like
553      to be.
554
555      1) If a preferred size was specified for us, use it.
556         (This is not currently used)
557      2) If a proposed size was given, round it to the nearest
558         multiple of the default char size and return it.
559      3) Otherwise, take our current size and round it to the
560         nearest multiple of the default char size. */
561
562   width = mask & CWWidth ? request->width : ew->core.width;
563   height = mask & CWHeight ? request->height : ew->core.height;
564   round_size_to_char (ew->emacs_frame.frame, width, height,
565                       &ok_width_int, &ok_height_int);
566   ok_width = (Dimension) ok_width_int;
567   ok_height = (Dimension) ok_height_int;
568   if (ew->emacs_frame.preferred_width)
569     ok_width = ew->emacs_frame.preferred_width;
570   if (ew->emacs_frame.preferred_height)
571     ok_height = ew->emacs_frame.preferred_height;
572   result->request_mode |= CWWidth | CWHeight;
573   result->width = ok_width;
574   result->height = ok_height;
575   if (((mask & CWWidth) && ok_width != request->width)
576       || ((mask & CWHeight) && ok_height != request->height))
577     return XtGeometryAlmost;
578   else
579     return XtGeometryYes;
580 }
581
582 /* Xt string-to-scrollbar-placement converter */
583 /* #### Convert this to a `new-style' converter (See XtAddTypeConverter) */
584
585 /* This variable cannot be a stack variable. */
586 static unsigned char cvt_string_scrollbar_placement;
587
588 /* ARGSUSED */
589 static void
590 Xt_StringToScrollBarPlacement (XrmValuePtr args,   /* unused */
591                                  Cardinal *num_args, /* unused */
592                                  XrmValuePtr fromVal,
593                                  XrmValuePtr toVal)
594 {
595   XrmQuark q;
596   char *lowerName = (char *) alloca (strlen ((char *) fromVal->addr) + 1);
597
598   XmuCopyISOLatin1Lowered (lowerName, (char *) fromVal->addr);
599   q = XrmStringToQuark (lowerName);
600
601   toVal->size = sizeof (cvt_string_scrollbar_placement);
602   toVal->addr = (XPointer) &cvt_string_scrollbar_placement;
603
604   if      (q == XrmStringToQuark ("top-left")
605            || q == XrmStringToQuark ("top_left"))
606     cvt_string_scrollbar_placement = XtTOP_LEFT;
607   else if (q == XrmStringToQuark ("bottom-left")
608            || q == XrmStringToQuark ("bottom_left"))
609     cvt_string_scrollbar_placement = XtBOTTOM_LEFT;
610   else if (q == XrmStringToQuark ("top-right")
611            || q == XrmStringToQuark ("top_right"))
612     cvt_string_scrollbar_placement = XtTOP_RIGHT;
613   else if (q == XrmStringToQuark ("bottom-right")
614            || q == XrmStringToQuark ("bottom_right"))
615     cvt_string_scrollbar_placement = XtBOTTOM_RIGHT;
616   else
617     {
618       XtStringConversionWarning (fromVal->addr, "scrollBarPlacement");
619       toVal->addr = NULL;
620       toVal->size = 0;
621     }
622 }
623
624 static void
625 EmacsFrameClassInitialize (void)
626 {
627   XtAddConverter (XtRString, XtRScrollBarPlacement,
628                   Xt_StringToScrollBarPlacement, NULL, 0);
629 }
630
631 /********************* Special entrypoints *******************/
632
633 void
634 EmacsFrameRecomputeCellSize (Widget w)
635 {
636   EmacsFrame ew = (EmacsFrame) w;
637   int cw, ch;
638   struct frame *f = ew->emacs_frame.frame;
639
640   if (! XtIsSubclass (w, emacsFrameClass))
641     abort ();
642
643   default_face_height_and_width (make_frame (f), &ch, &cw);
644   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
645     x_wm_set_cell_size (FRAME_X_SHELL_WIDGET (f), cw, ch);
646 }
647
648 /* Set the size of the widget to have the number of rows and columns
649    specified.  This both causes the X window to change and the
650    internal frame structures to get modified to match. */
651
652 void
653 EmacsFrameSetCharSize (Widget widget, int columns, int rows)
654 {
655   EmacsFrame ew = (EmacsFrame) widget;
656   int pixel_width, pixel_height;
657   struct frame *f = ew->emacs_frame.frame;
658
659   if (columns < 3)
660     columns = 3;  /* no way buddy */
661   if (rows < 1)
662     rows = 1;
663
664   char_to_pixel_size (f, columns, rows, &pixel_width, &pixel_height);
665
666   if (FRAME_X_TOP_LEVEL_FRAME_P (f))
667     x_wm_set_variable_size (FRAME_X_SHELL_WIDGET (f), columns, rows);
668
669   {
670     Arg al [2];
671     XtSetArg (al [0], XtNwidth,  pixel_width);
672     XtSetArg (al [1], XtNheight, pixel_height);
673     XtSetValues ((Widget) ew, al, countof (al));
674   }
675 }