1 /* Emacs shell widget -- define the two widgets.
2 Copyright (C) 1994, 1995 Sun Microsystems, Inc.
4 This file is part of SXEmacs
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* Synched up with: Not in FSF. */
22 /* Written by Ben Wing, May, 1994. */
25 It is rather unfortunate that we have to do this. Blame those
26 short-sighted people who designed the monstrosities known as
31 This widget is not actually Emacs-specific; perhaps there could
32 be a better name than "EmacsShell". What it does is work around
33 a limitation in Xt in correctly dealing with the window-manager
34 size hints with applications that
36 (a) dynamically change their window size
37 (b) have a cell size (width-inc and height-inc) other than 1
41 (c) cannot predict in advance exactly what size their shell will be
42 (This is the more common situation, when you have a number
43 of widgets, each with their own size ideas)
45 This widget assumes that your program contains a fixed "base size"
46 plus some number of cells (e.g. character cells). The WMShell
47 resources "widthInc" and "heightInc" specify the size of a
48 character cell, and the window manager will report the app's
49 size in cells rather than in pixels.
51 If you use this widget, do not use the WMShell resources
52 "baseWidth", "baseHeight", "minWidth", or "minHeight".
53 Instead, use "widthCells" and "heightCells" to specify the
54 current size in cells (you must keep this up-to-date),
55 and "minWidthCells" and "minHeightCells" to specify the
56 minimum size in cells.
58 Every time that the program issues a size command, the
59 "baseWidth", "baseHeight", "minWidth", and "minHeight" fields
60 of the WM_NORMAL_HINTS property will be updated to stay in
61 line with the resource values specified above. The calculations
62 are done once the desired shell size is known but before the
63 window-manager size-change request is issued. (We must do it
64 at this time because before then we don't know what size we
65 will request, and after the request the deed has already
68 After you change the "baseWidth", "baseHeight", "minWidth",
69 or "minHeight" resources, you need to call
70 EmacsShellUpdateSizeHints() to manually update the size
71 hints, except in the following two circumstances:
73 (a) you are about to make a geometry request.
74 (b) you are changing only "baseWidth" and "baseHeight"
75 from within a resize procedure. (In this case,
76 the size hints are already correct.)
84 #include <X11/StringDefs.h>
85 #include "xintrinsicp.h"
86 #include <X11/Shell.h>
87 #include <X11/ShellP.h>
88 #include <X11/Vendor.h>
89 #include <X11/VendorP.h>
90 #include "EmacsShellP.h"
92 #if defined (DEFINE_TOP_LEVEL_EMACS_SHELL)
93 #define EMACS_SHELL_WIDGET TopLevelEmacsShellWidget
94 #define SUPERCLASS_WIDGET_CLASS topLevelShellWidgetClass
95 #define SUPERCLASS_CLASS_REC topLevelShellClassRec
96 #define EMACS_SHELL_REC TopLevelEmacsShellRec
97 #define EMACS_SHELL_CLASS_REC topLevelEmacsShellClassRec
98 #define EMACS_SHELL_CLASS_REC_TYPE TopLevelEmacsShellClassRec
99 #define EMACS_SHELL_CLASS_NAME "TopLevelEmacsShell"
100 #define EMACS_SHELL_WIDGET_CLASS topLevelEmacsShellWidgetClass
101 #define EMACS_SHELL_UPDATE_SIZE_HINTS TopLevelEmacsShellUpdateSizeHints
102 #elif defined (DEFINE_TRANSIENT_EMACS_SHELL)
103 #define EMACS_SHELL_WIDGET TransientEmacsShellWidget
104 #define SUPERCLASS_WIDGET_CLASS transientShellWidgetClass
105 #define SUPERCLASS_CLASS_REC transientShellClassRec
106 #define EMACS_SHELL_REC TransientEmacsShellRec
107 #define EMACS_SHELL_CLASS_REC transientEmacsShellClassRec
108 #define EMACS_SHELL_CLASS_REC_TYPE TransientEmacsShellClassRec
109 #define EMACS_SHELL_CLASS_NAME "TransientEmacsShell"
110 #define EMACS_SHELL_WIDGET_CLASS transientEmacsShellWidgetClass
111 #define EMACS_SHELL_UPDATE_SIZE_HINTS TransientEmacsShellUpdateSizeHints
113 Error.Must define either DEFINE_TOP_LEVEL_EMACS_SHELL or
114 DEFINE_TRANSIENT_EMACS_SHELL.
117 XtPointer next_extension;
118 XrmQuark record_type;
120 Cardinal record_size;
121 } GenericClassExtRec;
123 static XtGeometryResult RootGeometryManager(Widget gw,
124 XtWidgetGeometry * request,
125 XtWidgetGeometry * reply);
126 static void ChangeManaged(Widget w);
128 /* snarfed from Shell.c */
129 #define BIGSIZE ((Dimension)32767)
131 static XtResource resources[] = {
132 #define offset(field) XtOffset(EMACS_SHELL_WIDGET, emacs_shell.field)
133 #define coreoffset(field) XtOffset(EMACS_SHELL_WIDGET, core.field)
134 #ifdef LWLIB_USES_MOTIF
135 /* *** BOGOSITY^10! *** The Motif VendorShell fucks around with
136 the default values for X and Y, for no obvious reason. This
137 causes Shell to indicate that the defaults of (0,0) were
138 program-specified, instead of letting the WM do what it wants. */
140 XtRPosition, sizeof(Position),
141 coreoffset(x), XtRImmediate, (XtPointer) BIGSIZE}
144 XtRPosition, sizeof(Position),
145 coreoffset(y), XtRImmediate, (XtPointer) BIGSIZE}
148 {XtNwidthCells, XtCWidthCells,
150 offset(width_cells), XtRImmediate, (XtPointer) 0},
151 {XtNheightCells, XtCHeightCells,
153 offset(height_cells), XtRImmediate, (XtPointer) 0},
154 {XtNminWidthCells, XtCMinWidthCells,
156 offset(min_width_cells), XtRImmediate, (XtPointer) 0},
157 {XtNminHeightCells, XtCMinHeightCells,
159 offset(min_height_cells), XtRImmediate, (XtPointer) 0},
162 static CompositeClassExtensionRec compositeClassExtRec = {
165 XtCompositeExtensionVersion,
166 sizeof(CompositeClassExtensionRec),
170 static ShellClassExtensionRec shellClassExtRec = {
173 XtShellExtensionVersion,
174 sizeof(ShellClassExtensionRec),
178 EMACS_SHELL_CLASS_REC_TYPE EMACS_SHELL_CLASS_REC = {
182 /* superclass */ (WidgetClass) & SUPERCLASS_CLASS_REC,
183 /* class_name */ (String) EMACS_SHELL_CLASS_NAME,
184 /* size */ sizeof(EMACS_SHELL_REC),
185 /* Class Initializer */ NULL,
186 /* class_part_initialize */ NULL,
187 /* 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,
205 /* XtInheritSetValues, */
206 /* set_values_hook */ NULL,
207 /* set_values_almost */ XtInheritSetValuesAlmost,
208 /* get_values_hook */ NULL,
209 /* accept_focus */ NULL,
210 /* intrinsics version */ XtVersion,
211 /* callback offsets */ NULL,
213 /* query_geometry */ NULL,
214 /* display_accelerator */ NULL,
218 /* geometry_manager */ XtInheritGeometryManager,
219 /* change_managed */ ChangeManaged,
220 /* insert_child */ XtInheritInsertChild,
221 /* delete_child */ XtInheritDeleteChild,
222 /* extension */ (XtPointer) & compositeClassExtRec
225 /* extension */ (XtPointer) & shellClassExtRec
230 , { /* VendorShell */
233 , { /* TopLevelShell or TransientShell */
234 /* both have exactly one XtPointer here. */
241 WidgetClass EMACS_SHELL_WIDGET_CLASS = (WidgetClass) & EMACS_SHELL_CLASS_REC;
244 update_size_hints_internal(EMACS_SHELL_WIDGET w, int width, int height)
246 int base_width, base_height;
247 int cell_width, cell_height;
250 /* time to update them thar size hints */
251 cell_width = w->wm.size_hints.width_inc;
252 cell_height = w->wm.size_hints.height_inc;
253 base_width = width - cell_width * w->emacs_shell.width_cells;
254 base_height = height - cell_height * w->emacs_shell.height_cells;
255 #ifdef DEBUG_GEOMETRY_MANAGEMENT
256 /* Very useful info when debugging geometry management problems.
257 When it's guaranteed that no more such problems exist, take
259 printf("update_size_hints_internal:\n");
260 printf(" actual pixel size: %d %d\n", width, height);
261 printf(" cell size in pixels: %d %d\n", cell_width, cell_height);
262 printf(" text area size in cells: %d %d\n", w->emacs_shell.width_cells,
263 w->emacs_shell.height_cells);
264 printf(" base size set to: %d %d\n", base_width, base_height);
267 XtSetArg(al[0], XtNbaseWidth, base_width);
268 XtSetArg(al[1], XtNbaseHeight, base_height);
269 XtSetArg(al[2], XtNminWidth, base_width +
270 cell_width * w->emacs_shell.min_width_cells);
271 XtSetArg(al[3], XtNminHeight, base_height +
272 cell_height * w->emacs_shell.min_height_cells);
273 XtSetValues((Widget) w, al, 4);
276 static XtGeometryResult
277 SuperClassRootGeometryManager(Widget gw,
278 XtWidgetGeometry * request,
279 XtWidgetGeometry * reply)
281 ShellWidgetClass swc = (ShellWidgetClass) SUPERCLASS_WIDGET_CLASS;
282 ShellClassExtensionRec *scer;
283 GenericClassExtRec *gcer;
285 /* find the shell extension record that specifies the
286 root geometry manager method */
287 for (gcer = (GenericClassExtRec *) swc->shell_class.extension;
288 gcer; gcer = (GenericClassExtRec *) gcer->next_extension) {
289 if (gcer->record_type == NULLQUARK)
296 /* call it to actually make the geometry request */
297 scer = (ShellClassExtensionRec *) gcer;
298 return (scer->root_geometry_manager) (gw, request, reply);
301 static XtGeometryResult
302 RootGeometryManager(Widget gw,
303 XtWidgetGeometry * request, XtWidgetGeometry * reply)
305 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) gw;
306 /* OK since this file is not dumped */
307 static int reentrant = 0;
308 XtGeometryResult result;
314 #ifdef DEBUG_GEOMETRY_MANAGEMENT
315 printf("root_geometry_manager:\n");
316 printf(" current shell size: %d %d\n", w->core.width, w->core.height);
317 if (request->request_mode & CWWidth)
318 printf("width requested;");
319 if (request->request_mode & CWHeight)
320 printf("height requested;");
322 printf(" requested shell size: %d %d\n", request->width,
325 /* update the size hints */
326 update_size_hints_internal(w,
327 request->request_mode & CWWidth ?
328 request->width : w->core.width,
329 request->request_mode & CWHeight ?
330 request->height : w->core.height);
332 result = SuperClassRootGeometryManager(gw, request, reply);
334 #ifdef DEBUG_GEOMETRY_MANAGEMENT
335 printf(" result: %s\n",
336 result == XtGeometryYes ? "XtGeometryYes" :
337 result == XtGeometryNo ? "XtGeometryNo" :
338 result == XtGeometryAlmost ? "XtGeometryAlmost" :
340 if (reply->request_mode & CWWidth)
341 printf("width returned;");
342 if (reply->request_mode & CWHeight)
343 printf("height returned;");
345 printf(" resulting shell size: %d %d\n", reply->width, reply->height);
346 printf("----------\n");
353 static void ChangeManaged(Widget wid)
355 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) wid;
357 /* If not realized, then we're being called from XtRealizeWidget().
358 RootGeometryManager() has not yet been called, and thus our
359 base size is incorrect. We need to set it now or the Shell
360 will mess up geometry specifications with negative positional
362 if (!XtIsRealized(wid)) {
366 /* the managed child indicates what our size is */
367 for (i = 0; i < w->composite.num_children; i++) {
368 if (XtIsManaged(w->composite.children[i])) {
369 child = w->composite.children[i];
370 update_size_hints_internal(w, child->core.width,
378 /* call the real ChangeManaged */
379 (((ShellWidgetClass) SUPERCLASS_WIDGET_CLASS)->
380 composite_class.change_managed) (wid);
383 /******************* external entry points *********************/
385 void EMACS_SHELL_UPDATE_SIZE_HINTS(Widget gw)
387 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) gw;
388 update_size_hints_internal(w, w->core.width, w->core.height);