1 /* Emacs shell widget -- define the two widgets.
2 Copyright (C) 1994, 1995 Sun Microsystems, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Not in FSF. */
23 /* Written by Ben Wing, May, 1994. */
26 It is rather unfortunate that we have to do this. Blame those
27 short-sighted people who designed the monstrosities known as
32 This widget is not actually Emacs-specific; perhaps there could
33 be a better name than "EmacsShell". What it does is work around
34 a limitation in Xt in correctly dealing with the window-manager
35 size hints with applications that
37 (a) dynamically change their window size
38 (b) have a cell size (width-inc and height-inc) other than 1
42 (c) cannot predict in advance exactly what size their shell will be
43 (This is the more common situation, when you have a number
44 of widgets, each with their own size ideas)
46 This widget assumes that your program contains a fixed "base size"
47 plus some number of cells (e.g. character cells). The WMShell
48 resources "widthInc" and "heightInc" specify the size of a
49 character cell, and the window manager will report the app's
50 size in cells rather than in pixels.
52 If you use this widget, do not use the WMShell resources
53 "baseWidth", "baseHeight", "minWidth", or "minHeight".
54 Instead, use "widthCells" and "heightCells" to specify the
55 current size in cells (you must keep this up-to-date),
56 and "minWidthCells" and "minHeightCells" to specify the
57 minimum size in cells.
59 Every time that the program issues a size command, the
60 "baseWidth", "baseHeight", "minWidth", and "minHeight" fields
61 of the WM_NORMAL_HINTS property will be updated to stay in
62 line with the resource values specified above. The calculations
63 are done once the desired shell size is known but before the
64 window-manager size-change request is issued. (We must do it
65 at this time because before then we don't know what size we
66 will request, and after the request the deed has already
69 After you change the "baseWidth", "baseHeight", "minWidth",
70 or "minHeight" resources, you need to call
71 EmacsShellUpdateSizeHints() to manually update the size
72 hints, except in the following two circumstances:
74 (a) you are about to make a geometry request.
75 (b) you are changing only "baseWidth" and "baseHeight"
76 from within a resize procedure. (In this case,
77 the size hints are already correct.)
85 #include <X11/StringDefs.h>
86 #include "xintrinsicp.h"
87 #include <X11/Shell.h>
88 #include <X11/ShellP.h>
89 #include <X11/Vendor.h>
90 #include <X11/VendorP.h>
91 #include "EmacsShellP.h"
95 #if defined (DEFINE_TOP_LEVEL_EMACS_SHELL)
96 #define EMACS_SHELL_WIDGET TopLevelEmacsShellWidget
97 #define SUPERCLASS_WIDGET_CLASS topLevelShellWidgetClass
98 #define SUPERCLASS_CLASS_REC topLevelShellClassRec
99 #define EMACS_SHELL_REC TopLevelEmacsShellRec
100 #define EMACS_SHELL_CLASS_REC topLevelEmacsShellClassRec
101 #define EMACS_SHELL_CLASS_REC_TYPE TopLevelEmacsShellClassRec
102 #define EMACS_SHELL_CLASS_NAME "TopLevelEmacsShell"
103 #define EMACS_SHELL_WIDGET_CLASS topLevelEmacsShellWidgetClass
104 #define EMACS_SHELL_UPDATE_SIZE_HINTS TopLevelEmacsShellUpdateSizeHints
105 #elif defined (DEFINE_TRANSIENT_EMACS_SHELL)
106 #define EMACS_SHELL_WIDGET TransientEmacsShellWidget
107 #define SUPERCLASS_WIDGET_CLASS transientShellWidgetClass
108 #define SUPERCLASS_CLASS_REC transientShellClassRec
109 #define EMACS_SHELL_REC TransientEmacsShellRec
110 #define EMACS_SHELL_CLASS_REC transientEmacsShellClassRec
111 #define EMACS_SHELL_CLASS_REC_TYPE TransientEmacsShellClassRec
112 #define EMACS_SHELL_CLASS_NAME "TransientEmacsShell"
113 #define EMACS_SHELL_WIDGET_CLASS transientEmacsShellWidgetClass
114 #define EMACS_SHELL_UPDATE_SIZE_HINTS TransientEmacsShellUpdateSizeHints
116 Error. Must define either DEFINE_TOP_LEVEL_EMACS_SHELL or
117 DEFINE_TRANSIENT_EMACS_SHELL.
121 XtPointer next_extension;
122 XrmQuark record_type;
124 Cardinal record_size;
125 } GenericClassExtRec;
127 static XtGeometryResult RootGeometryManager (Widget gw,
128 XtWidgetGeometry *request, XtWidgetGeometry *reply);
129 static void ChangeManaged (Widget w);
131 /* snarfed from Shell.c */
132 #define BIGSIZE ((Dimension)32767)
134 static XtResource resources[] = {
135 #define offset(field) XtOffset(EMACS_SHELL_WIDGET, emacs_shell.field)
136 #define coreoffset(field) XtOffset(EMACS_SHELL_WIDGET, core.field)
137 #ifdef LWLIB_USES_MOTIF
138 /* *** BOGOSITY^10! *** The Motif VendorShell fucks around with
139 the default values for X and Y, for no obvious reason. This
140 causes Shell to indicate that the defaults of (0,0) were
141 program-specified, instead of letting the WM do what it wants. */
143 XtRPosition, sizeof (Position),
144 coreoffset (x), XtRImmediate, (XtPointer)BIGSIZE },
146 XtRPosition, sizeof (Position),
147 coreoffset (y), XtRImmediate, (XtPointer)BIGSIZE },
149 { XtNwidthCells, XtCWidthCells,
150 XtRInt, sizeof (int),
151 offset (width_cells), XtRImmediate, (XtPointer)0 },
152 { XtNheightCells, XtCHeightCells,
153 XtRInt, sizeof (int),
154 offset (height_cells), XtRImmediate, (XtPointer)0 },
155 { XtNminWidthCells, XtCMinWidthCells,
156 XtRInt, sizeof (int),
157 offset (min_width_cells), XtRImmediate, (XtPointer)0 },
158 { XtNminHeightCells, XtCMinHeightCells,
159 XtRInt, sizeof (int),
160 offset (min_height_cells), XtRImmediate, (XtPointer)0 },
163 static CompositeClassExtensionRec compositeClassExtRec = {
166 XtCompositeExtensionVersion,
167 sizeof (CompositeClassExtensionRec),
171 static ShellClassExtensionRec shellClassExtRec = {
174 XtShellExtensionVersion,
175 sizeof (ShellClassExtensionRec),
179 EMACS_SHELL_CLASS_REC_TYPE EMACS_SHELL_CLASS_REC = {
183 /* superclass */ (WidgetClass) &SUPERCLASS_CLASS_REC,
184 /* class_name */ (String) EMACS_SHELL_CLASS_NAME,
185 /* size */ sizeof (EMACS_SHELL_REC),
186 /* Class Initializer */ NULL,
187 /* class_part_initialize*/ NULL, /* XtInheritClassPartInitialize, */
188 /* Class init'ed ? */ FALSE,
189 /* initialize */ NULL,
190 /* initialize_notify */ NULL,
191 /* realize */ XtInheritRealize,
194 /* resources */ resources,
195 /* resource_count */ XtNumber (resources),
196 /* xrm_class */ NULLQUARK,
197 /* compress_motion */ TRUE,
198 /* compress_exposure */ XtExposeCompressMaximal | XtExposeNoRegion,
199 /* compress_enterleave*/ TRUE,
200 /* visible_interest */ TRUE,
202 /* resize */ XtInheritResize,
204 /* set_values */ NULL, /* XtInheritSetValues, */
205 /* set_values_hook */ NULL,
206 /* set_values_almost */ XtInheritSetValuesAlmost,
207 /* get_values_hook */ NULL,
208 /* accept_focus */ NULL,
209 /* intrinsics version */ XtVersion,
210 /* callback offsets */ NULL,
212 /* query_geometry */ NULL,
213 /* display_accelerator*/ NULL,
216 /* geometry_manager */ XtInheritGeometryManager,
217 /* change_managed */ ChangeManaged,
218 /* insert_child */ XtInheritInsertChild,
219 /* delete_child */ XtInheritDeleteChild,
220 /* extension */ (XtPointer)&compositeClassExtRec
222 /* extension */ (XtPointer)&shellClassExtRec
225 },{ /* VendorShell */
227 },{ /* TopLevelShell or TransientShell */
228 /* both have exactly one XtPointer here. */
235 WidgetClass EMACS_SHELL_WIDGET_CLASS = (WidgetClass) &EMACS_SHELL_CLASS_REC;
238 update_size_hints_internal (EMACS_SHELL_WIDGET w,
239 int width, int height)
241 int base_width, base_height;
242 int cell_width, cell_height;
245 /* time to update them thar size hints */
246 cell_width = w->wm.size_hints.width_inc;
247 cell_height = w->wm.size_hints.height_inc;
248 base_width = width - cell_width * w->emacs_shell.width_cells;
249 base_height = height - cell_height * w->emacs_shell.height_cells;
250 #ifdef DEBUG_GEOMETRY_MANAGEMENT
251 /* Very useful info when debugging geometry management problems.
252 When it's guaranteed that no more such problems exist, take
254 printf ("update_size_hints_internal:\n");
255 printf (" actual pixel size: %d %d\n", width, height);
256 printf (" cell size in pixels: %d %d\n", cell_width, cell_height);
257 printf (" text area size in cells: %d %d\n", w->emacs_shell.width_cells,
258 w->emacs_shell.height_cells);
259 printf (" base size set to: %d %d\n", base_width, base_height);
262 XtSetArg(al [0], XtNbaseWidth, base_width);
263 XtSetArg(al [1], XtNbaseHeight, base_height);
264 XtSetArg(al [2], XtNminWidth, base_width +
265 cell_width * w->emacs_shell.min_width_cells);
266 XtSetArg(al [3], XtNminHeight, base_height +
267 cell_height * w->emacs_shell.min_height_cells);
268 XtSetValues ((Widget) w, al, 4);
271 static XtGeometryResult
272 SuperClassRootGeometryManager (Widget gw,
273 XtWidgetGeometry *request,
274 XtWidgetGeometry *reply)
276 ShellWidgetClass swc = (ShellWidgetClass) SUPERCLASS_WIDGET_CLASS;
277 ShellClassExtensionRec *scer;
278 GenericClassExtRec *gcer;
280 /* find the shell extension record that specifies the
281 root geometry manager method */
282 for (gcer = (GenericClassExtRec *) swc->shell_class.extension;
284 gcer = (GenericClassExtRec *) gcer->next_extension)
286 if (gcer->record_type == NULLQUARK)
293 /* call it to actually make the geometry request */
294 scer = (ShellClassExtensionRec *) gcer;
295 return (scer->root_geometry_manager)(gw, request, reply);
298 static XtGeometryResult
299 RootGeometryManager (Widget gw,
300 XtWidgetGeometry *request,
301 XtWidgetGeometry *reply)
303 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) gw;
304 /* OK since this file is not dumped */
305 static int reentrant = 0;
306 XtGeometryResult result;
312 #ifdef DEBUG_GEOMETRY_MANAGEMENT
313 printf ("root_geometry_manager:\n");
314 printf (" current shell size: %d %d\n", w->core.width, w->core.height);
315 if (request->request_mode & CWWidth)
316 printf ("width requested;");
317 if (request->request_mode & CWHeight)
318 printf ("height requested;");
320 printf (" requested shell size: %d %d\n", request->width, request->height);
322 /* update the size hints */
323 update_size_hints_internal (w,
324 request->request_mode & CWWidth ?
325 request->width : w->core.width,
326 request->request_mode & CWHeight ?
327 request->height : w->core.height);
329 result = SuperClassRootGeometryManager (gw, request, reply);
331 #ifdef DEBUG_GEOMETRY_MANAGEMENT
332 printf (" result: %s\n",
333 result == XtGeometryYes ? "XtGeometryYes" :
334 result == XtGeometryNo ? "XtGeometryNo" :
335 result == XtGeometryAlmost ? "XtGeometryAlmost" :
337 if (reply->request_mode & CWWidth)
338 printf ("width returned was %d%s",
340 reply->request_mode & CWHeight ? "; " : ".\n");
341 if (reply->request_mode & CWHeight)
342 printf ("height returned was %d.\n", reply->height);
343 /* #### does this also need to depend on the result?
344 With XtGeometryYes there doesn't seem to be a useful reply object. */
345 printf (" resulting shell size: %d %d\n",
346 reply->request_mode & CWWidth ? reply->width : w->core.width,
347 reply->request_mode & CWHeight ? reply->height : w->core.height);
348 printf ("----------\n");
356 ChangeManaged (Widget wid)
358 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) wid;
360 /* If not realized, then we're being called from XtRealizeWidget().
361 RootGeometryManager() has not yet been called, and thus our
362 base size is incorrect. We need to set it now or the Shell
363 will mess up geometry specifications with negative positional
365 if (!XtIsRealized (wid))
370 /* the managed child indicates what our size is */
371 for (i = 0; i < w->composite.num_children; i++) {
372 if (XtIsManaged(w->composite.children[i])) {
373 child = w->composite.children[i];
374 update_size_hints_internal (w, child->core.width,
381 /* call the real ChangeManaged */
382 (((ShellWidgetClass) SUPERCLASS_WIDGET_CLASS)->
383 composite_class.change_managed)(wid);
387 /******************* external entry points *********************/
390 EMACS_SHELL_UPDATE_SIZE_HINTS (Widget gw)
392 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) gw;
393 update_size_hints_internal (w, w->core.width, w->core.height);