428
+ − 1 /* Emacs shell widget -- define the two widgets.
+ − 2 Copyright (C) 1994, 1995 Sun Microsystems, Inc.
+ − 3
+ − 4 This file is part of XEmacs.
+ − 5
+ − 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
+ − 9 later version.
+ − 10
+ − 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
+ − 14 for more details.
+ − 15
+ − 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. */
+ − 20
+ − 21 /* Synched up with: Not in FSF. */
+ − 22
+ − 23 /* Written by Ben Wing, May, 1994. */
+ − 24
+ − 25 /*
+ − 26 It is rather unfortunate that we have to do this. Blame those
+ − 27 short-sighted people who designed the monstrosities known as
+ − 28 Xt and ICCCM.
+ − 29 */
+ − 30
+ − 31 /*
+ − 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
+ − 36
+ − 37 (a) dynamically change their window size
+ − 38 (b) have a cell size (width-inc and height-inc) other than 1
+ − 39
+ − 40 and
+ − 41
+ − 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)
+ − 45
+ − 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.
+ − 51
+ − 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.
+ − 58
+ − 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
+ − 67 been done.)
+ − 68
+ − 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:
+ − 73
+ − 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.)
+ − 78
+ − 79 */
+ − 80
+ − 81 #include <config.h>
+ − 82
+ − 83 #include <stdio.h>
+ − 84 #include <stdlib.h>
+ − 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"
+ − 92
2500
+ − 93 #define ABORT abort
+ − 94
428
+ − 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
+ − 115 #else
+ − 116 Error. Must define either DEFINE_TOP_LEVEL_EMACS_SHELL or
+ − 117 DEFINE_TRANSIENT_EMACS_SHELL.
+ − 118 #endif
+ − 119
+ − 120 typedef struct {
+ − 121 XtPointer next_extension;
+ − 122 XrmQuark record_type;
+ − 123 long version;
+ − 124 Cardinal record_size;
+ − 125 } GenericClassExtRec;
+ − 126
+ − 127 static XtGeometryResult RootGeometryManager (Widget gw,
+ − 128 XtWidgetGeometry *request, XtWidgetGeometry *reply);
+ − 129 static void ChangeManaged (Widget w);
+ − 130
+ − 131 /* snarfed from Shell.c */
+ − 132 #define BIGSIZE ((Dimension)32767)
+ − 133
+ − 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. */
440
+ − 142 { XtNx, XtCPosition,
+ − 143 XtRPosition, sizeof (Position),
+ − 144 coreoffset (x), XtRImmediate, (XtPointer)BIGSIZE },
+ − 145 { XtNy, XtCPosition,
+ − 146 XtRPosition, sizeof (Position),
+ − 147 coreoffset (y), XtRImmediate, (XtPointer)BIGSIZE },
428
+ − 148 #endif
440
+ − 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 },
428
+ − 161 };
+ − 162
+ − 163 static CompositeClassExtensionRec compositeClassExtRec = {
+ − 164 NULL,
+ − 165 NULLQUARK,
+ − 166 XtCompositeExtensionVersion,
440
+ − 167 sizeof (CompositeClassExtensionRec),
428
+ − 168 TRUE,
+ − 169 };
+ − 170
+ − 171 static ShellClassExtensionRec shellClassExtRec = {
+ − 172 NULL,
+ − 173 NULLQUARK,
+ − 174 XtShellExtensionVersion,
440
+ − 175 sizeof (ShellClassExtensionRec),
428
+ − 176 RootGeometryManager
+ − 177 };
+ − 178
+ − 179 EMACS_SHELL_CLASS_REC_TYPE EMACS_SHELL_CLASS_REC = {
+ − 180 { /*
+ − 181 * core_class fields
+ − 182 */
+ − 183 /* superclass */ (WidgetClass) &SUPERCLASS_CLASS_REC,
+ − 184 /* class_name */ (String) EMACS_SHELL_CLASS_NAME,
440
+ − 185 /* size */ sizeof (EMACS_SHELL_REC),
428
+ − 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,
+ − 192 /* actions */ NULL,
+ − 193 /* num_actions */ 0,
+ − 194 /* resources */ resources,
+ − 195 /* resource_count */ XtNumber (resources),
+ − 196 /* xrm_class */ NULLQUARK,
1294
+ − 197 /* compress_motion */ TRUE,
+ − 198 /* compress_exposure */ XtExposeCompressMaximal | XtExposeNoRegion,
+ − 199 /* compress_enterleave*/ TRUE,
428
+ − 200 /* visible_interest */ TRUE,
+ − 201 /* destroy */ NULL,
+ − 202 /* resize */ XtInheritResize,
+ − 203 /* expose */ NULL,
+ − 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,
+ − 211 /* tm_table */ NULL,
+ − 212 /* query_geometry */ NULL,
+ − 213 /* display_accelerator*/ NULL,
+ − 214 /* extension */ NULL
+ − 215 },{ /* Composite */
+ − 216 /* geometry_manager */ XtInheritGeometryManager,
+ − 217 /* change_managed */ ChangeManaged,
+ − 218 /* insert_child */ XtInheritInsertChild,
+ − 219 /* delete_child */ XtInheritDeleteChild,
+ − 220 /* extension */ (XtPointer)&compositeClassExtRec
+ − 221 },{ /* Shell */
+ − 222 /* extension */ (XtPointer)&shellClassExtRec
+ − 223 },{ /* WMShell */
+ − 224 /* extension */ NULL
+ − 225 },{ /* VendorShell */
+ − 226 /* extension */ NULL
+ − 227 },{ /* TopLevelShell or TransientShell */
+ − 228 /* both have exactly one XtPointer here. */
+ − 229 /* extension */ NULL
+ − 230 },{ /* EmacsShell */
+ − 231 0
+ − 232 }
+ − 233 };
+ − 234
+ − 235 WidgetClass EMACS_SHELL_WIDGET_CLASS = (WidgetClass) &EMACS_SHELL_CLASS_REC;
+ − 236
+ − 237 static void
+ − 238 update_size_hints_internal (EMACS_SHELL_WIDGET w,
+ − 239 int width, int height)
+ − 240 {
+ − 241 int base_width, base_height;
+ − 242 int cell_width, cell_height;
+ − 243 Arg al [10];
+ − 244
+ − 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
+ − 253 this stuff out. */
+ − 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);
+ − 260 fflush (stdout);
+ − 261 #endif
+ − 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);
+ − 269 }
+ − 270
+ − 271 static XtGeometryResult
+ − 272 SuperClassRootGeometryManager (Widget gw,
+ − 273 XtWidgetGeometry *request,
+ − 274 XtWidgetGeometry *reply)
+ − 275 {
+ − 276 ShellWidgetClass swc = (ShellWidgetClass) SUPERCLASS_WIDGET_CLASS;
+ − 277 ShellClassExtensionRec *scer;
+ − 278 GenericClassExtRec *gcer;
+ − 279
+ − 280 /* find the shell extension record that specifies the
3381
+ − 281 root geometry manager method
+ − 282 #### We could use XtGetClassExtension here. */
428
+ − 283 for (gcer = (GenericClassExtRec *) swc->shell_class.extension;
+ − 284 gcer;
+ − 285 gcer = (GenericClassExtRec *) gcer->next_extension)
+ − 286 {
+ − 287 if (gcer->record_type == NULLQUARK)
+ − 288 break;
+ − 289 }
+ − 290
3381
+ − 291 /* #### The R11.6.4 Xt specification says if we don't find NULLQUARK here,
+ − 292 we should assume root_geometry_manager = XtInheritRootGeometryManager.
+ − 293 Is that actually callable? */
428
+ − 294 if (!gcer)
2500
+ − 295 ABORT ();
428
+ − 296
+ − 297 /* call it to actually make the geometry request */
+ − 298 scer = (ShellClassExtensionRec *) gcer;
+ − 299 return (scer->root_geometry_manager)(gw, request, reply);
+ − 300 }
+ − 301
+ − 302 static XtGeometryResult
+ − 303 RootGeometryManager (Widget gw,
+ − 304 XtWidgetGeometry *request,
+ − 305 XtWidgetGeometry *reply)
+ − 306 {
+ − 307 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) gw;
+ − 308 /* OK since this file is not dumped */
+ − 309 static int reentrant = 0;
+ − 310 XtGeometryResult result;
+ − 311
+ − 312 if (reentrant)
2500
+ − 313 ABORT ();
428
+ − 314 reentrant++;
+ − 315
+ − 316 #ifdef DEBUG_GEOMETRY_MANAGEMENT
+ − 317 printf ("root_geometry_manager:\n");
+ − 318 printf (" current shell size: %d %d\n", w->core.width, w->core.height);
+ − 319 if (request->request_mode & CWWidth)
+ − 320 printf ("width requested;");
+ − 321 if (request->request_mode & CWHeight)
+ − 322 printf ("height requested;");
+ − 323 printf ("\n");
+ − 324 printf (" requested shell size: %d %d\n", request->width, request->height);
+ − 325 #endif
+ − 326 /* update the size hints */
+ − 327 update_size_hints_internal (w,
+ − 328 request->request_mode & CWWidth ?
+ − 329 request->width : w->core.width,
+ − 330 request->request_mode & CWHeight ?
+ − 331 request->height : w->core.height);
+ − 332
+ − 333 result = SuperClassRootGeometryManager (gw, request, reply);
+ − 334
+ − 335 #ifdef DEBUG_GEOMETRY_MANAGEMENT
+ − 336 printf (" result: %s\n",
+ − 337 result == XtGeometryYes ? "XtGeometryYes" :
+ − 338 result == XtGeometryNo ? "XtGeometryNo" :
+ − 339 result == XtGeometryAlmost ? "XtGeometryAlmost" :
+ − 340 "XtGeometryDone");
+ − 341 if (reply->request_mode & CWWidth)
3385
+ − 342 printf ("width returned was %d%s",
+ − 343 reply->width,
+ − 344 reply->request_mode & CWHeight ? "; " : ".\n");
428
+ − 345 if (reply->request_mode & CWHeight)
3385
+ − 346 printf ("height returned was %d.\n", reply->height);
+ − 347 /* #### does this also need to depend on the result?
+ − 348 With XtGeometryYes there doesn't seem to be a useful reply object. */
+ − 349 printf (" resulting shell size: %d %d\n",
+ − 350 reply->request_mode & CWWidth ? reply->width : w->core.width,
+ − 351 reply->request_mode & CWHeight ? reply->height : w->core.height);
428
+ − 352 printf ("----------\n");
+ − 353 fflush (stdout);
+ − 354 #endif
+ − 355 reentrant--;
+ − 356 return result;
+ − 357 }
+ − 358
+ − 359 static void
+ − 360 ChangeManaged (Widget wid)
+ − 361 {
+ − 362 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) wid;
+ − 363
+ − 364 /* If not realized, then we're being called from XtRealizeWidget().
+ − 365 RootGeometryManager() has not yet been called, and thus our
+ − 366 base size is incorrect. We need to set it now or the Shell
+ − 367 will mess up geometry specifications with negative positional
+ − 368 offsets. */
+ − 369 if (!XtIsRealized (wid))
+ − 370 {
+ − 371 Widget child = NULL;
+ − 372 Cardinal i;
+ − 373
+ − 374 /* the managed child indicates what our size is */
+ − 375 for (i = 0; i < w->composite.num_children; i++) {
+ − 376 if (XtIsManaged(w->composite.children[i])) {
+ − 377 child = w->composite.children[i];
+ − 378 break;
+ − 379 }
+ − 380 }
+ − 381
+ − 382 update_size_hints_internal (w, child->core.width, child->core.height);
+ − 383 }
+ − 384
+ − 385 /* call the real ChangeManaged */
+ − 386 (((ShellWidgetClass) SUPERCLASS_WIDGET_CLASS)->
+ − 387 composite_class.change_managed)(wid);
+ − 388 }
+ − 389
+ − 390
+ − 391 /******************* external entry points *********************/
+ − 392
+ − 393 void
+ − 394 EMACS_SHELL_UPDATE_SIZE_HINTS (Widget gw)
+ − 395 {
+ − 396 EMACS_SHELL_WIDGET w = (EMACS_SHELL_WIDGET) gw;
+ − 397 update_size_hints_internal (w, w->core.width, w->core.height);
+ − 398 }