widget.c 32.5 KB
Newer Older
Richard M. Stallman's avatar
Richard M. Stallman committed
1
/* The emacs frame widget.
2 3
   Copyright (C) 1992, 1993, 2000, 2001, 2002, 2003, 2004,
                 2005, 2006, 2007  Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
Lute Kamstra's avatar
Lute Kamstra committed
19 20
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
21 22 23

/* Emacs 19 face widget ported by Fred Pierresteguy */

Karl Heuer's avatar
Karl Heuer committed
24 25 26 27 28 29 30 31 32 33
/* This file has been censored by the Communications Decency Act.
   That law was passed under the guise of a ban on pornography, but
   it bans far more than that.  This file did not contain pornography,
   but it was censored nonetheless.

   For information on US government censorship of the Internet, and
   what you can do to bring back freedom of the press, see the web
   site http://www.vtw.org/
   */

34
#include <config.h>
35
#include <stdio.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
36 37 38
#include "lisp.h"
#include "xterm.h"

39
#include "keyboard.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
40
#include "frame.h"
Andreas Schwab's avatar
Andreas Schwab committed
41
#include "window.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
42 43

#include "dispextern.h"
44
#include "blockinput.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
45 46 47 48 49

#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/cursorfont.h>
#include "widgetprv.h"
50
#include <X11/ObjectP.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
51 52
#include <X11/Shell.h>
#include <X11/ShellP.h>
53
#include "../lwlib/lwlib.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
54

55 56 57
#include <signal.h>
#include "syssignal.h"

Richard M. Stallman's avatar
Richard M. Stallman committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
/* This sucks: this is the first default that x-faces.el tries.  This won't
   be used unless neither the "Emacs.EmacsFrame" resource nor the
   "Emacs.EmacsFrame" resource is set; the frame
   may have the wrong default size if this font doesn't exist, but some other
   font that x-faces.el does.  The workaround is to specify some font in the
   resource database; I don't know a solution other than duplicating the font-
   searching code from x-faces.el in this file.

   This also means that if "Emacs.EmacsFrame" is specified as a non-
   existent font, then Xt is going to substitute "XtDefaultFont" for it,
   which is a different size than this one.  The solution for this is to
   make x-faces.el try to use XtDefaultFont.  The problem with that is that
   XtDefaultFont is almost certainly variable-width.

   #### Perhaps we could have this code explicitly set XtDefaultFont to this?
 */
#define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"


77 78 79 80 81 82 83 84
static void EmacsFrameInitialize (/*Widget, Widget, ArgList, Cardinal * */);
static void EmacsFrameDestroy (/* Widget */);
static void EmacsFrameRealize (/* Widget, XtValueMask*, XSetWindowAttributes* */);
void EmacsFrameResize (/* Widget widget */);
static Boolean EmacsFrameSetValues (/* Widget, Widget, Widget,
				     ArgList, Cardinal * */);
static XtGeometryResult EmacsFrameQueryGeometry (/* Widget, XtWidgetGeometry*,
						  XtWidgetGeometry* */);
Richard M. Stallman's avatar
Richard M. Stallman committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180


#undef XtOffset
#define XtOffset(p_type,field) \
	((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
#define offset(field) XtOffset(EmacsFrame, emacs_frame.field)

static XtResource resources[] = {
  {XtNgeometry, XtCGeometry, XtRString, sizeof(String),
     offset (geometry), XtRString, (XtPointer) 0},
  {XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean),
     offset (iconic), XtRImmediate, (XtPointer) False},

  {XtNemacsFrame, XtCEmacsFrame, XtRPointer, sizeof (XtPointer),
     offset (frame), XtRImmediate, 0},

  {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
     offset (minibuffer), XtRImmediate, (XtPointer)0},
  {XtNunsplittable, XtCUnsplittable, XtRBoolean, sizeof (Boolean),
     offset (unsplittable), XtRImmediate, (XtPointer)0},
  {XtNinternalBorderWidth, XtCInternalBorderWidth, XtRInt, sizeof (int),
     offset (internal_border_width), XtRImmediate, (XtPointer)4},
  {XtNinterline, XtCInterline, XtRInt, sizeof (int),
     offset (interline), XtRImmediate, (XtPointer)0},
  {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
     offset(font),XtRString, DEFAULT_FACE_FONT},
  {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
     offset(foreground_pixel), XtRString, "XtDefaultForeground"},
  {XtNcursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
     offset(cursor_color), XtRString, "XtDefaultForeground"},
  {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
     offset (bar_cursor), XtRImmediate, (XtPointer)0},
  {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
     offset (visual_bell), XtRImmediate, (XtPointer)0},
  {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
     offset (bell_volume), XtRImmediate, (XtPointer)0},
};

#undef offset

/*
static XtActionsRec
emacsFrameActionsTable [] = {
  {"keypress",  key_press},
  {"focus_in",  emacs_frame_focus_handler},
  {"focus_out", emacs_frame_focus_handler},
};

static char
emacsFrameTranslations [] = "\
<KeyPress>: keypress()\n\
<FocusIn>:  focus_in()\n\
<FocusOut>: focus_out()\n\
";
*/

EmacsFrameClassRec emacsFrameClassRec = {
    { /* core fields */
    /* superclass		*/	&widgetClassRec,
    /* class_name		*/	"EmacsFrame",
    /* widget_size		*/	sizeof(EmacsFrameRec),
    /* class_initialize		*/	0,
    /* class_part_initialize	*/	0,
    /* class_inited		*/	FALSE,
    /* initialize		*/	EmacsFrameInitialize,
    /* initialize_hook		*/	0,
    /* realize			*/	EmacsFrameRealize,
    /* actions			*/	0, /*emacsFrameActionsTable*/
    /* num_actions		*/	0, /*XtNumber (emacsFrameActionsTable)*/
    /* resources		*/	resources,
    /* resource_count		*/	XtNumber(resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	EmacsFrameDestroy,
    /* resize			*/	EmacsFrameResize,
    /* expose			*/	XtInheritExpose,
    /* set_values		*/	EmacsFrameSetValues,
    /* set_values_hook		*/	0,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	0,
    /* accept_focus		*/	XtInheritAcceptFocus,
    /* version			*/	XtVersion,
    /* callback_private		*/	0,
    /* tm_table			*/	0, /*emacsFrameTranslations*/
    /* query_geometry		*/	EmacsFrameQueryGeometry,
    /* display_accelerator	*/	XtInheritDisplayAccelerator,
    /* extension		*/	0
    }
};

WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;

static void
181 182 183 184
get_default_char_pixel_size (ew, pixel_width, pixel_height)
     EmacsFrame ew;
     int* pixel_width;
     int* pixel_height;
Richard M. Stallman's avatar
Richard M. Stallman committed
185 186
{
  struct frame* f = ew->emacs_frame.frame;
187 188
  *pixel_width = FRAME_COLUMN_WIDTH (f);
  *pixel_height = FRAME_LINE_HEIGHT (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
189 190 191
}

static void
192 193 194 195 196 197
pixel_to_char_size (ew, pixel_width, pixel_height, char_width, char_height)
     EmacsFrame ew;
     Dimension pixel_width;
     Dimension pixel_height;
     int* char_width;
     int* char_height;
Richard M. Stallman's avatar
Richard M. Stallman committed
198 199
{
  struct frame* f = ew->emacs_frame.frame;
200 201
  *char_width = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, (int) pixel_width);
  *char_height = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (int) pixel_height);
Richard M. Stallman's avatar
Richard M. Stallman committed
202 203 204
}

static void
205 206 207 208 209 210
char_to_pixel_size (ew, char_width, char_height, pixel_width, pixel_height)
     EmacsFrame ew;
     int char_width;
     int char_height;
     Dimension* pixel_width;
     Dimension* pixel_height;
Richard M. Stallman's avatar
Richard M. Stallman committed
211 212
{
  struct frame* f = ew->emacs_frame.frame;
213 214
  *pixel_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, char_width);
  *pixel_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, char_height);
Richard M. Stallman's avatar
Richard M. Stallman committed
215 216 217
}

static void
218 219 220 221 222 223
round_size_to_char (ew, in_width, in_height, out_width, out_height)
     EmacsFrame ew;
     Dimension in_width;
     Dimension in_height;
     Dimension* out_width;
     Dimension* out_height;
Richard M. Stallman's avatar
Richard M. Stallman committed
224 225 226 227 228 229 230 231
{
  int char_width;
  int char_height;
  pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
  char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
}

static Widget
232 233
get_wm_shell (w)
     Widget w;
Richard M. Stallman's avatar
Richard M. Stallman committed
234 235 236 237 238 239 240 241 242 243
{
  Widget wmshell;

  for (wmshell = XtParent (w);
       wmshell && !XtIsWMShell (wmshell);
       wmshell = XtParent (wmshell));

  return wmshell;
}

244 245
#if 0 /* Currently not used.  */

Richard M. Stallman's avatar
Richard M. Stallman committed
246
static void
247 248
mark_shell_size_user_specified (wmshell)
     Widget wmshell;
Richard M. Stallman's avatar
Richard M. Stallman committed
249 250 251 252 253 254 255
{
  if (! XtIsWMShell (wmshell)) abort ();
  /* This is kind of sleazy, but I can't see how else to tell it to make it
     mark the WM_SIZE_HINTS size as user specified when appropriate. */
  ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
}

256 257
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
258 259 260 261 262 263 264

/* Can't have static frame locals because of some broken compilers.
   Normally, initializing a variable like this doesn't work in emacs,
   but it's ok in this file because it must come after lastfile (and
   thus have its data not go into text space) because Xt needs to
   write to initialized data objects too.
 */
265
#if 0
Richard M. Stallman's avatar
Richard M. Stallman committed
266
static Boolean first_frame_p = True;
267
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
268 269

static void
270 271
set_frame_size (ew)
     EmacsFrame ew;
Richard M. Stallman's avatar
Richard M. Stallman committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
{
  /* The widget hierarchy is

	argv[0]			emacsShell	pane	Frame-NAME
	ApplicationShell	EmacsShell	Paned	EmacsFrame

     We accept geometry specs in this order:

	*Frame-NAME.geometry
	*EmacsFrame.geometry
	Emacs.geometry

     Other possibilities for widget hierarchies might be

	argv[0]			frame		pane	Frame-NAME
	ApplicationShell	EmacsShell	Paned	EmacsFrame
     or
	argv[0]			Frame-NAME	pane	Frame-NAME
	ApplicationShell	EmacsShell	Paned	EmacsFrame
     or
	argv[0]			Frame-NAME	pane	emacsTextPane
	ApplicationShell	EmacsFrame	Paned	EmacsTextPane

     With the current setup, the text-display-area is the part which is
     an emacs "frame", since that's the only part managed by emacs proper
     (the menubar and the parent of the menubar and all that sort of thing
     are managed by lwlib.)

300
     The EmacsShell widget is simply a replacement for the Shell widget
Richard M. Stallman's avatar
Richard M. Stallman committed
301 302 303 304 305 306 307 308
     which is able to deal with using an externally-supplied window instead
     of always creating its own.  It is not actually emacs specific, and
     should possibly have class "Shell" instead of "EmacsShell" to simplify
     the resources.

   */

  /* Hairily merged geometry */
309 310
  unsigned int w = FRAME_COLS (ew->emacs_frame.frame);
  unsigned int h = FRAME_LINES (ew->emacs_frame.frame);
311

Richard M. Stallman's avatar
Richard M. Stallman committed
312
  Widget wmshell = get_wm_shell ((Widget) ew);
313
  /* Each Emacs shell is now independent and top-level.  */
314

Richard M. Stallman's avatar
Richard M. Stallman committed
315 316
  if (! XtIsSubclass (wmshell, shellWidgetClass)) abort ();

317
  /* We don't need this for the moment. The geometry is computed in
318 319
     xfns.c.  */
#if 0
Richard M. Stallman's avatar
Richard M. Stallman committed
320 321 322 323
  /* If the EmacsFrame doesn't have a geometry but the shell does,
     treat that as the geometry of the frame.  (Is this bogus?
     I'm not sure.) */
  if (ew->emacs_frame.geometry == 0)
324
    XtVaGetValues (wmshell, XtNgeometry, &ew->emacs_frame.geometry, NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
325 326 327 328

  /* If the Shell is iconic, then the EmacsFrame is iconic.  (Is
     this bogus? I'm not sure.) */
  if (!ew->emacs_frame.iconic)
329
    XtVaGetValues (wmshell, XtNiconic, &ew->emacs_frame.iconic, NULL);
330 331


Richard M. Stallman's avatar
Richard M. Stallman committed
332 333
  {
    char *geom = 0;
334
    XtVaGetValues (app_shell, XtNgeometry, &geom, NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
335 336 337
    if (geom)
      app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
  }
338

Richard M. Stallman's avatar
Richard M. Stallman committed
339 340 341 342
  if (ew->emacs_frame.geometry)
    frame_flags = XParseGeometry (ew->emacs_frame.geometry,
				   &frame_x, &frame_y,
				   &frame_w, &frame_h);
343

Richard M. Stallman's avatar
Richard M. Stallman committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
  if (first_frame_p)
    {
      /* If this is the first frame created:
         ====================================

         - Use the ApplicationShell's size/position, if specified.
           (This is "Emacs.geometry", or the "-geometry" command line arg.)
         - Else use the EmacsFrame's size/position.
           (This is "*Frame-NAME.geometry")

	 - If the AppShell is iconic, the frame should be iconic.

	 AppShell comes first so that -geometry always applies to the first
	 frame created, even if there is an "every frame" entry in the
	 resource database.
       */
      if (app_flags & (XValue | YValue))
	{
	  x = app_x; y = app_y;
	  flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
	}
      else if (frame_flags & (XValue | YValue))
	{
	  x = frame_x; y = frame_y;
	  flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
	}

      if (app_flags & (WidthValue | HeightValue))
	{
	  w = app_w; h = app_h;
	  flags |= (app_flags & (WidthValue | HeightValue));
	}
      else if (frame_flags & (WidthValue | HeightValue))
	{
	  w = frame_w; h = frame_h;
	  flags |= (frame_flags & (WidthValue | HeightValue));
	}

      /* If the AppShell is iconic, then the EmacsFrame is iconic. */
      if (!ew->emacs_frame.iconic)
384
	XtVaGetValues (app_shell, XtNiconic, &ew->emacs_frame.iconic, NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

      first_frame_p = False;
    }
  else
    {
      /* If this is not the first frame created:
         ========================================

         - use the EmacsFrame's size/position if specified
         - Otherwise, use the ApplicationShell's size, but not position.

         So that means that one can specify the position of the first frame
         with "Emacs.geometry" or `-geometry'; but can only specify the
	 position of subsequent frames with "*Frame-NAME.geometry".

	 AppShell comes second so that -geometry does not apply to subsequent
	 frames when there is an "every frame" entry in the resource db,
	 but does apply to the first frame.
       */
      if (frame_flags & (XValue | YValue))
	{
	  x = frame_x; y = frame_y;
	  flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
	}

      if (frame_flags & (WidthValue | HeightValue))
	{
	  w = frame_w; h = frame_h;
	  flags |= (frame_flags & (WidthValue | HeightValue));
	}
      else if (app_flags & (WidthValue | HeightValue))
	{
	  w = app_w;
	  h = app_h;
	  flags |= (app_flags & (WidthValue | HeightValue));
	}
    }
422
#endif /* 0 */
Richard M. Stallman's avatar
Richard M. Stallman committed
423
  {
424
    struct frame *f = ew->emacs_frame.frame;
Richard M. Stallman's avatar
Richard M. Stallman committed
425 426
    Dimension pixel_width, pixel_height;

427 428 429 430 431
    /* Take into account the size of the scrollbar.  Always use the
       number of columns occupied by the scroll bar here otherwise we
       might end up with a frame width that is not a multiple of the
       frame's character width which is bad for vertically split
       windows.  */
432 433
    f->scroll_bar_actual_width
      = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
434

435
    compute_fringe_widths (f, 0);
436

437 438 439
#if 0 /* This can run Lisp code, and it is dangerous to give
	 out the frame to Lisp code before it officially exists.
	 This is handled in Fx_create_frame so not needed here.  */
440
    change_frame_size (f, h, w, 1, 0, 0);
441
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
442 443 444 445
    char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
    ew->core.width = pixel_width;
    ew->core.height = pixel_height;

446
#if 0 /* xfns.c takes care of this now.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    /* If a position was specified, assign it to the shell widget.
       (Else WM won't do anything with it.)
     */
    if (flags & (XValue | YValue))
      {
	/* the tricky things with the sign is to make sure that
	   -0 is printed -0. */
	int len;
	char *tem;
	sprintf (shell_position, "=%c%d%c%d",
		 flags & XNegative ? '-' : '+', x < 0 ? -x : x,
		 flags & YNegative ? '-' : '+', y < 0 ? -y : y);
	len = strlen (shell_position) + 1;
	tem = (char *) xmalloc (len);
	strncpy (tem, shell_position, len);
462
	XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
463 464 465 466 467 468 469 470 471
      }
    else if (flags & (WidthValue | HeightValue))
      {
	int len;
	char *tem;
	sprintf (shell_position, "=%dx%d", pixel_width, pixel_height);
	len = strlen (shell_position) + 1;
	tem = (char *) xmalloc (len);
	strncpy (tem, shell_position, len);
472
	XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
473 474 475 476 477 478 479 480 481
      }

    /* If the geometry spec we're using has W/H components, mark the size
       in the WM_SIZE_HINTS as user specified. */
    if (flags & (WidthValue | HeightValue))
      mark_shell_size_user_specified (wmshell);

    /* Also assign the iconic status of the frame to the Shell, so that
       the WM sees it. */
482
    XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, NULL);
483
#endif /* 0 */
Richard M. Stallman's avatar
Richard M. Stallman committed
484 485 486
  }
}

487 488 489
/* Nonzero tells update_wm_hints not to do anything
   (the caller should call update_wm_hints explicitly later.)  */
int update_hints_inhibit;
Richard M. Stallman's avatar
Richard M. Stallman committed
490 491

static void
492 493
update_wm_hints (ew)
     EmacsFrame ew;
Richard M. Stallman's avatar
Richard M. Stallman committed
494 495 496 497 498 499 500 501 502 503 504 505
{
  Widget wmshell = get_wm_shell ((Widget)ew);
  int cw;
  int ch;
  Dimension rounded_width;
  Dimension rounded_height;
  int char_width;
  int char_height;
  int base_width;
  int base_height;
  int min_rows = 0, min_cols = 0;

506 507 508 509
  if (update_hints_inhibit)
    return;

#if 0
Richard M. Stallman's avatar
Richard M. Stallman committed
510
  check_frame_size (ew->emacs_frame.frame, &min_rows, &min_cols);
511
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
512 513 514 515 516

  pixel_to_char_size (ew, ew->core.width, ew->core.height,
		      &char_width, &char_height);
  char_to_pixel_size (ew, char_width, char_height,
		      &rounded_width, &rounded_height);
517
  get_default_char_pixel_size (ew, &cw, &ch);
Richard M. Stallman's avatar
Richard M. Stallman committed
518 519 520 521 522 523 524 525 526 527 528 529

  base_width = (wmshell->core.width - ew->core.width
		+ (rounded_width - (char_width * cw)));
  base_height = (wmshell->core.height - ew->core.height
		+ (rounded_height - (char_height * ch)));

  /* This is kind of sleazy, but I can't see how else to tell it to
     make it mark the WM_SIZE_HINTS size as user specified.
   */
/*  ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/

  XtVaSetValues (wmshell,
530 531
		 XtNbaseWidth, (XtArgVal) base_width,
		 XtNbaseHeight, (XtArgVal) base_height,
532
		 XtNwidthInc, (XtArgVal) cw,
533 534 535
		 XtNheightInc, (XtArgVal) ch,
		 XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
		 XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
536
		 NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
537 538
}

539 540
#if 0

Richard M. Stallman's avatar
Richard M. Stallman committed
541
static void
542 543
create_frame_gcs (ew)
     EmacsFrame ew;
Richard M. Stallman's avatar
Richard M. Stallman committed
544
{
545
  struct frame *s = ew->emacs_frame.frame;
Richard M. Stallman's avatar
Richard M. Stallman committed
546

Karl Heuer's avatar
Karl Heuer committed
547
  s->output_data.x->normal_gc
548 549
    = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
		 (unsigned long)0, (XGCValues *)0);
Karl Heuer's avatar
Karl Heuer committed
550
  s->output_data.x->reverse_gc
551 552
    = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
		 (unsigned long)0, (XGCValues *)0);
Karl Heuer's avatar
Karl Heuer committed
553
  s->output_data.x->cursor_gc
554 555
    = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
		 (unsigned long)0, (XGCValues *)0);
556 557
  s->output_data.x->black_relief.gc = 0;
  s->output_data.x->white_relief.gc = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
558 559
}

560 561
#endif /* 0 */

562 563 564 565 566 567 568 569
static char setup_frame_cursor_bits[] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

Richard M. Stallman's avatar
Richard M. Stallman committed
570
static void
571 572
setup_frame_gcs (ew)
     EmacsFrame ew;
Richard M. Stallman's avatar
Richard M. Stallman committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586
{
  XGCValues gc_values;
  struct frame* s = ew->emacs_frame.frame;
  Pixmap blank_stipple, blank_tile;

  /* We have to initialize all of our GCs to have a stipple/tile, otherwise
     XGetGCValues returns uninitialized data when we query the stipple
     (instead of None or something sensible) and it makes things hard.

     This should be fixed for real by not querying the GCs but instead having
     some GC-based cache instead of the current face-based cache which doesn't
     effectively cache all of the GC settings we need to use.
   */

587 588 589 590
  blank_stipple
    = XCreateBitmapFromData (XtDisplay (ew),
			     RootWindowOfScreen (XtScreen (ew)),
			     setup_frame_cursor_bits, 2, 2);
Richard M. Stallman's avatar
Richard M. Stallman committed
591 592 593 594

  /* use fg = 0, bg = 1 below, but it's irrelevant since this pixmap should
     never actually get used as a background tile!
   */
595 596 597 598 599 600
  blank_tile
    = XCreatePixmapFromBitmapData (XtDisplay(ew),
				   RootWindowOfScreen (XtScreen (ew)),
				   setup_frame_cursor_bits, 2, 2,
				   (unsigned long)0, (unsigned long)1,
				   ew->core.depth);
Richard M. Stallman's avatar
Richard M. Stallman committed
601 602 603 604 605 606 607 608

  /* Normal video */
  gc_values.font = ew->emacs_frame.font->fid;
  gc_values.foreground = ew->emacs_frame.foreground_pixel;
  gc_values.background = ew->core.background_pixel;
  gc_values.graphics_exposures = False;
  gc_values.stipple = blank_stipple;
  gc_values.tile = blank_tile;
Karl Heuer's avatar
Karl Heuer committed
609
  XChangeGC (XtDisplay (ew), s->output_data.x->normal_gc,
Richard M. Stallman's avatar
Richard M. Stallman committed
610 611 612 613 614 615 616 617 618 619 620
	     (GCFont | GCForeground | GCBackground | GCGraphicsExposures
	      | GCStipple | GCTile),
	     &gc_values);

  /* Reverse video style. */
  gc_values.font = ew->emacs_frame.font->fid;
  gc_values.foreground = ew->core.background_pixel;
  gc_values.background = ew->emacs_frame.foreground_pixel;
  gc_values.graphics_exposures = False;
  gc_values.stipple = blank_stipple;
  gc_values.tile = blank_tile;
Karl Heuer's avatar
Karl Heuer committed
621
  XChangeGC (XtDisplay (ew), s->output_data.x->reverse_gc,
Richard M. Stallman's avatar
Richard M. Stallman committed
622 623 624 625 626 627 628 629 630 631
	     (GCFont | GCForeground | GCBackground | GCGraphicsExposures
	      | GCStipple | GCTile),
	     &gc_values);

  /* Cursor has to have an empty stipple. */
  gc_values.font = ew->emacs_frame.font->fid;
  gc_values.foreground = ew->core.background_pixel;
  gc_values.background = ew->emacs_frame.cursor_color;
  gc_values.graphics_exposures = False;
  gc_values.tile = blank_tile;
632 633 634 635
  gc_values.stipple
    = XCreateBitmapFromData (XtDisplay (ew),
			     RootWindowOfScreen (XtScreen (ew)),
			     setup_frame_cursor_bits, 16, 16);
Karl Heuer's avatar
Karl Heuer committed
636
  XChangeGC (XtDisplay (ew), s->output_data.x->cursor_gc,
Richard M. Stallman's avatar
Richard M. Stallman committed
637 638 639 640 641 642
	     (GCFont | GCForeground | GCBackground | GCGraphicsExposures
	      | GCStipple | GCTile),
	     &gc_values);
}

static void
643 644
update_various_frame_slots (ew)
     EmacsFrame ew;
Richard M. Stallman's avatar
Richard M. Stallman committed
645
{
646 647 648 649 650
  struct frame *f = ew->emacs_frame.frame;
  struct x_output *x = f->output_data.x;
  FRAME_PIXEL_HEIGHT (f) = ew->core.height + x->menubar_height;
  FRAME_PIXEL_WIDTH (f) = ew->core.width;
  f->internal_border_width = ew->emacs_frame.internal_border_width;
Richard M. Stallman's avatar
Richard M. Stallman committed
651 652 653 654

}

static void
655 656
update_from_various_frame_slots (ew)
     EmacsFrame ew;
Richard M. Stallman's avatar
Richard M. Stallman committed
657
{
658 659 660 661
  struct frame *f = ew->emacs_frame.frame;
  struct x_output *x = f->output_data.x;
  ew->core.height = FRAME_PIXEL_HEIGHT (f) - x->menubar_height;
  ew->core.width = FRAME_PIXEL_WIDTH (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
662
  ew->core.background_pixel = x->background_pixel;
663
  ew->emacs_frame.internal_border_width = f->internal_border_width;
Richard M. Stallman's avatar
Richard M. Stallman committed
664 665 666 667 668 669
  ew->emacs_frame.font = x->font;
  ew->emacs_frame.foreground_pixel = x->foreground_pixel;
  ew->emacs_frame.cursor_color = x->cursor_pixel;
  ew->core.border_pixel = x->border_pixel;
}

670
static void
671 672 673 674 675
EmacsFrameInitialize (request, new, dum1, dum2)
     Widget request;
     Widget new;
     ArgList dum1;
     Cardinal *dum2;
Richard M. Stallman's avatar
Richard M. Stallman committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
{
  EmacsFrame ew = (EmacsFrame)new;

  if (!ew->emacs_frame.frame)
    {
      fprintf (stderr,
	       "can't create an emacs frame widget without a frame\n");
      exit (1);
    }

#if 0 /* done in xfns.c */
  /* If the "Emacs.EmacsFrame.{default,Face}.{attributeFont,AttributeFont}"
     resource is set, then it always overrides "Emacs.EmacsFrame.{font,Font}".
     It's unfortunate that we have to do this, but we need to know the font
     size for frame-sizing purposes before the faces get initialized.  If
     the "default.attributeFont" isn't set, then we use the font of this
     EmacsFrame itself, defaulting to XtDefaultFont.  Up in the lisp code,
     the "default" face will use the frame's font if its own is not set,
     so everything stays in sync -- it's not possible for the frame's font
     and the default face's font to be different.
   */
  {
    XFontStruct *f = 0;
    XtResource face_res;
    face_res.resource_name = "attributeFont";
    face_res.resource_class = "AttributeFont";
    face_res.resource_type = XtRFontStruct;
    face_res.resource_size = sizeof (XFontStruct *);
    face_res.resource_offset = 0;
    face_res.default_type = XtRImmediate;
    face_res.default_addr = 0;
    XtGetSubresources ((Widget) ew, (XtPointer) &f, "default", "Face",
		       &face_res, 1, NULL, 0);
709

Richard M. Stallman's avatar
Richard M. Stallman committed
710 711 712 713 714 715 716 717 718 719
    if (f)
	ew->emacs_frame.font = f;
    else if (! ew->emacs_frame.font)
      {
	fprintf (stderr, "emacs frame widget could not load a font\n");
	exit (1);
      }
  }

/* Update the font field in frame */
720
  FRAME_FONT (ew->emacs_frame.frame) = ew->emacs_frame.font;
Richard M. Stallman's avatar
Richard M. Stallman committed
721 722 723
#endif

  update_from_various_frame_slots (ew);
724
  set_frame_size (ew);
Richard M. Stallman's avatar
Richard M. Stallman committed
725 726 727 728 729 730 731
/*create_frame_gcs (ew);
  setup_frame_gcs (ew);
  update_various_frame_slots (ew); */
}


static void
732 733 734 735
EmacsFrameRealize (widget, mask, attrs)
     Widget widget;
     XtValueMask *mask;
     XSetWindowAttributes *attrs;
Richard M. Stallman's avatar
Richard M. Stallman committed
736 737 738
{
  EmacsFrame ew = (EmacsFrame)widget;

739 740
  /* This used to contain SubstructureRedirectMask, but this turns out
     to be a problem with XIM on Solaris, and events from that mask
741
     don't seem to be used.  Let's check that.  */
742 743 744
  attrs->event_mask = (STANDARD_EVENT_SET
		       | PropertyChangeMask
		       | SubstructureNotifyMask);
Richard M. Stallman's avatar
Richard M. Stallman committed
745 746 747
  *mask |= CWEventMask;
  XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
		  attrs);
748
  update_wm_hints (ew);
Richard M. Stallman's avatar
Richard M. Stallman committed
749 750
}

751
extern void free_frame_faces (/* struct frame * */);
Richard M. Stallman's avatar
Richard M. Stallman committed
752 753

static void
754 755
EmacsFrameDestroy (widget)
     Widget widget;
Richard M. Stallman's avatar
Richard M. Stallman committed
756 757 758 759 760
{
  EmacsFrame ew = (EmacsFrame) widget;
  struct frame* s = ew->emacs_frame.frame;

  if (! s) abort ();
Karl Heuer's avatar
Karl Heuer committed
761
  if (! s->output_data.x) abort ();
Richard M. Stallman's avatar
Richard M. Stallman committed
762

763
  BLOCK_INPUT;
764
  x_free_gcs (s);
765 766 767 768
  if (s->output_data.x->white_relief.gc)
    XFreeGC (XtDisplay (widget), s->output_data.x->white_relief.gc);
  if (s->output_data.x->black_relief.gc)
    XFreeGC (XtDisplay (widget), s->output_data.x->black_relief.gc);
769
  UNBLOCK_INPUT;
Richard M. Stallman's avatar
Richard M. Stallman committed
770 771 772
}

void
773 774
EmacsFrameResize (widget)
     Widget widget;
Richard M. Stallman's avatar
Richard M. Stallman committed
775 776 777 778 779 780 781
{
  EmacsFrame ew = (EmacsFrame)widget;
  struct frame *f = ew->emacs_frame.frame;
  int columns;
  int rows;

  pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows);
782
  change_frame_size (f, rows, columns, 0, 1, 0);
783
  update_wm_hints (ew);
Richard M. Stallman's avatar
Richard M. Stallman committed
784
  update_various_frame_slots (ew);
785 786

  cancel_mouse_face (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
787 788 789
}

static Boolean
790 791 792 793 794 795
EmacsFrameSetValues (cur_widget, req_widget, new_widget, dum1, dum2)
     Widget cur_widget;
     Widget req_widget;
     Widget new_widget;
     ArgList dum1;
     Cardinal *dum2;
Richard M. Stallman's avatar
Richard M. Stallman committed
796 797 798 799 800 801 802 803 804 805 806 807
{
  EmacsFrame cur = (EmacsFrame)cur_widget;
  EmacsFrame new = (EmacsFrame)new_widget;

  Boolean needs_a_refresh = False;
  Boolean has_to_recompute_size;
  Boolean has_to_recompute_gcs;
  Boolean has_to_update_hints;

  int char_width, char_height;
  Dimension pixel_width;
  Dimension pixel_height;
808

Richard M. Stallman's avatar
Richard M. Stallman committed
809 810 811 812 813 814
  has_to_recompute_gcs = (cur->emacs_frame.font != new->emacs_frame.font
			  || (cur->emacs_frame.foreground_pixel
			      != new->emacs_frame.foreground_pixel)
			  || (cur->core.background_pixel
			      != new->core.background_pixel)
			  );
815

Richard M. Stallman's avatar
Richard M. Stallman committed
816 817 818 819 820 821 822 823 824 825 826
  has_to_recompute_size = (cur->emacs_frame.font != new->emacs_frame.font
			   && cur->core.width == new->core.width
			   && cur->core.height == new->core.height);

  has_to_update_hints = (cur->emacs_frame.font != new->emacs_frame.font);

  if (has_to_recompute_gcs)
    {
      setup_frame_gcs (new);
      needs_a_refresh = True;
    }
827

Richard M. Stallman's avatar
Richard M. Stallman committed
828 829 830 831 832 833 834 835 836 837 838 839
  if (has_to_recompute_size)
    {
      pixel_width = new->core.width;
      pixel_height = new->core.height;
      pixel_to_char_size (new, pixel_width, pixel_height, &char_width,
			  &char_height);
      char_to_pixel_size (new, char_width, char_height, &pixel_width,
			  &pixel_height);
      new->core.width = pixel_width;
      new->core.height = pixel_height;

      change_frame_size (new->emacs_frame.frame, char_height, char_width,
840
			  1, 0, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
841 842 843 844 845 846 847 848 849 850 851
      needs_a_refresh = True;
    }

  if (has_to_update_hints)
    update_wm_hints (new);

  update_various_frame_slots (new);

  /* #### This doesn't work, I haven't been able to find ANY kludge that
     will let (x-create-frame '((iconic . t))) work.  It seems that changes
     to wm_shell's iconic slot have no effect after it has been realized,
Karl Heuer's avatar
Karl Heuer committed
852
     and calling XIconifyWindow doesn't work either (even though the window
Richard M. Stallman's avatar
Richard M. Stallman committed
853
     has been created.)  Perhaps there is some property we could smash
Karl Heuer's avatar
Karl Heuer committed
854
     directly, but I'm sick of this for now.
Richard M. Stallman's avatar
Richard M. Stallman committed
855 856 857 858
   */
  if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
    {
      Widget wmshell = get_wm_shell ((Widget) cur);
859 860
      XtVaSetValues (wmshell, XtNiconic,
		     (XtArgVal) new->emacs_frame.iconic, NULL);
Richard M. Stallman's avatar
Richard M. Stallman committed
861 862 863 864 865 866
    }

  return needs_a_refresh;
}

static XtGeometryResult
867 868 869 870
EmacsFrameQueryGeometry (widget, request, result)
     Widget widget;
     XtWidgetGeometry* request;
     XtWidgetGeometry* result;
Richard M. Stallman's avatar
Richard M. Stallman committed
871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
{
  EmacsFrame ew = (EmacsFrame)widget;

  int mask = request->request_mode;
  Dimension ok_width, ok_height;

  if (mask & (CWWidth | CWHeight))
    {
      round_size_to_char (ew,
			  (mask & CWWidth) ? request->width : ew->core.width,
			  ((mask & CWHeight) ? request->height
			   : ew->core.height),
			  &ok_width, &ok_height);
      if ((mask & CWWidth) && (ok_width != request->width))
	{
	  result->request_mode |= CWWidth;
	  result->width = ok_width;
	}
      if ((mask & CWHeight) && (ok_height != request->height))
	{
	  result->request_mode |= CWHeight;
	  result->height = ok_height;
	}
    }
  return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
}

/* Special entrypoints */
void
900 901 902 903
EmacsFrameSetCharSize (widget, columns, rows)
     Widget widget;
     int columns;
     int rows;
Richard M. Stallman's avatar
Richard M. Stallman committed
904 905
{
  EmacsFrame ew = (EmacsFrame) widget;
906
  Dimension pixel_width, pixel_height;
907
  struct frame *f = ew->emacs_frame.frame;
908

Richard M. Stallman's avatar
Richard M. Stallman committed
909 910
  if (columns < 3) columns = 3;  /* no way buddy */

911
  check_frame_size (f, &rows, &columns);
912 913
  f->scroll_bar_actual_width
    = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
914

915
  compute_fringe_widths (f, 0);
916

917 918 919
  char_to_pixel_size (ew, columns, rows, &pixel_width, &pixel_height);

#if 0  /* This doesn't seem to be right.  The frame gets too wide. --gerd.  */
920 921 922
  /* Something is really strange here wrt to the border width:
     Apparently, XtNwidth and XtNheight include the border, so we have
     to add it here.  But the XtNborderWidth set for the widgets has
923
     no similarity to what f->border_width is set to.  */
924 925 926
  XtVaGetValues (widget, XtNborderWidth, &border_width, NULL);
  pixel_height += 2 * border_width;
  pixel_width += 2 * border_width;
927 928
#endif

929 930
  /* Manually change the height and width of all our widgets,
     adjusting each widget by the same increments.  */
931 932
  if (ew->core.width != pixel_width
      || ew->core.height != pixel_height)
Richard M. Stallman's avatar
Richard M. Stallman committed
933
    {
934
      int hdelta = pixel_height - ew->core.height;
935
      int wdelta = pixel_width - ew->core.width;
Karl Heuer's avatar
Karl Heuer committed
936 937 938 939 940 941 942
      int column_widget_height = f->output_data.x->column_widget->core.height;
      int column_widget_width = f->output_data.x->column_widget->core.width;
      int outer_widget_height = f->output_data.x->widget->core.height;
      int outer_widget_width = f->output_data.x->widget->core.width;
      int old_left = f->output_data.x->widget->core.x;
      int old_top = f->output_data.x->widget->core.y;

943 944 945
      /* Input is blocked here, and Xt waits for some event to
         occur.  */

Karl Heuer's avatar
Karl Heuer committed
946
      lw_refigure_widget (f->output_data.x->column_widget, False);
947 948
      update_hints_inhibit = 1;

949 950 951 952 953 954 955
      /* Xt waits for a ConfigureNotify event from the window manager
	 in EmacsFrameSetCharSize when the shell widget is resized.
	 For some window managers like fvwm2 2.2.5 and KDE 2.1 this
	 event doesn't arrive for an unknown reason and Emacs hangs in
	 Xt when the default font is changed.  Tell Xt not to wait,
	 depending on the value of the frame parameter
	 `wait-for-wm'.  */
956
      x_catch_errors (FRAME_X_DISPLAY (f));
957 958 959
      XtVaSetValues (f->output_data.x->widget,
		     XtNwaitForWm, (XtArgVal) f->output_data.x->wait_for_wm,
		     NULL);
960
      x_uncatch_errors ();
961 962 963 964 965 966 967 968 969

      /* Workaround: When a SIGIO or SIGALRM occurs while Xt is
	 waiting for a ConfigureNotify event (see above), this leads
	 to Xt waiting indefinitely instead of using its default
	 timeout (5 seconds).  */
      turn_on_atimers (0);
#ifdef SIGIO
      sigblock (sigmask (SIGIO));
#endif
970

971 972 973 974
      /* Do parents first, otherwise LessTif's geometry management
	 enters an infinite loop (as of 2000-01-15).  This is fixed in
	 later versions of LessTif (as of 2001-03-13); I'll leave it
	 as is because I think it can't do any harm.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
975 976
      /* In April 2002, simon.marshall@misys.com reports the problem
	 seems not to occur any longer.  */
977
      x_catch_errors (FRAME_X_DISPLAY (f));
978
      XtVaSetValues (f->output_data.x->widget,
979 980 981
      		     XtNheight, (XtArgVal) (outer_widget_height + hdelta),
		     XtNwidth, (XtArgVal) (outer_widget_width + wdelta),
		     NULL);
982
      XtVaSetValues (f->output_data.x->column_widget,
983 984 985
      		     XtNheight, (XtArgVal) (column_widget_height + hdelta),
      		     XtNwidth, (XtArgVal) column_widget_width + wdelta,
		     NULL);
986
      XtVaSetValues ((Widget) ew,
987 988 989
                     XtNheight, (XtArgVal) pixel_height,
      		     XtNwidth, (XtArgVal) pixel_width,
		     NULL);
990 991
      x_uncatch_errors ();

992 993 994 995
#ifdef SIGIO
      sigunblock (sigmask (SIGIO));
#endif
      turn_on_atimers (1);
996

Karl Heuer's avatar
Karl Heuer committed
997
      lw_refigure_widget (f->output_data.x->column_widget, True);
998

999 1000 1001
      update_hints_inhibit = 0;
      update_wm_hints (ew);

1002
      /* These seem to get clobbered.  I don't know why. - rms.  */
Karl Heuer's avatar
Karl Heuer committed
1003 1004
      f->output_data.x->widget->core.x = old_left;
      f->output_data.x->widget->core.y = old_top;
Richard M. Stallman's avatar
Richard M. Stallman committed
1005
    }
1006 1007 1008 1009 1010 1011

  /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
     receive in the ConfigureNotify event; if we get what we asked
     for, then the event won't cause the screen to become garbaged, so
     we have to make sure to do it here.  */
  SET_FRAME_GARBAGED (f);
Richard M. Stallman's avatar
Richard M. Stallman committed
1012
}
1013

1014

Andreas Schwab's avatar
Andreas Schwab committed
1015
void
1016 1017 1018 1019 1020 1021
widget_store_internal_border (widget)
     Widget widget;
{
  EmacsFrame ew = (EmacsFrame) widget;
  FRAME_PTR f = ew->emacs_frame.frame;

1022
  ew->emacs_frame.internal_border_width = f->internal_border_width;
1023
}
Miles Bader's avatar
Miles Bader committed
1024 1025 1026

/* arch-tag: 931d28e5-0d59-405a-8325-7d475d0a13d9
   (do not change this comment) */