Subject: Re: bug#18136: 24.4.50; crash in redisplay when calling load-theme

From: martin rudalics <[email-masked]>
Date: Thu, 31 Jul 2014 10:49:11 +0200

> I thought we agreed that TTY frames should include the menu bar in
 > their height, and therefore change_frame_size should not have its 3rd
 > argument decreased by FRAME_MENU_BAR_LINES for TTY frames.

I'm afraid that doing so might run into problems in adjust_frame_size.
Basically, the flow of things for turning on/off menubars should be as
follows where "outer frame" stands for what Windows calls the client
area and what on a TTY would stand for the screen space within a
terminal window allotted to Emacs.

(1) The user decides to enable/disable the menubar.  The request is
     passed to adjust_frame_size.

(2) adjust_frame_size (or better, frame_inhibit_resize) decides that
     we're on TTY and therefore the outer frame should _not_ be resized.
     Thus inhibit_horizontal and inhibit_vertical should be both true
     after frame_inhibit_resize has been called.  This means that
     removing the menu bar must be handled internally by calling
     resize_frame_windows to either enlarge or shrink the root window by
     the menubar line.

But I don't really understand about `set-frame-height' and friends on a
TTY and what they are supposed to do.  Should these be allowed to change
the frame size?  If not we should assure that inhibit_horizontal and
inhibit_vertical are always true (regardless of the INHIBIT argument) on
TTYs.

Now about the

     change_frame_size (XFRAME (selected_frame),
                        FrameCols (t->display_info.tty),
                        FrameRows (t->display_info.tty)
		       - FRAME_MENU_BAR_LINES (f), 0, 0, 1, 0);

call in init_display.  What precisely is this supposed to accomplish?
Note one thing: change_frame_size is just a relay to detect whether
applying (Emacs-)window changes and running Lisp is safe in the current
state.  If it is not, it simply waits.  Otherwise, it passes all
information to adjust_frame_size with INHIBIT set to 5 which means that
the size of the outer frame has been set already and adjust_frame_size
should only care about how to handle these sizes internally by resizing
(Emacs-)windows appropriately.

Now what does init_display?  IIUC it just gets the height and width
values from t->display_info.tty and passes them on to change_frame_size.
That is, the outer frame sizes are set and adjust_frame_size has only to
deal with resizing the (Emacs-)windows corectly.  This is done by
setting the new height of these windows from the height of the outer
frame via

   new_windows_height = (new_pixel_height
			- FRAME_TOP_MARGIN_HEIGHT (f)
			- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));

where new_pixel_height was earlier calculated from new_text_height as

   new_pixel_height = ((inhibit_vertical && (inhibit < 5))
		      ? old_pixel_height
		      : max (FRAME_TEXT_TO_PIXEL_HEIGHT (f, new_text_height),
			     min_windows_height
			     + FRAME_TOP_MARGIN_HEIGHT (f)
			     + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)));

where new_text_height is the normalized value passed to
adjust_frame_size via the HEIGHT argument.  This sounds contrived (why
don't I call adjust_frame_size directly with the size of the outer
frame?) but note that adjust_frame_size is more often called from inside
Emacs and there we don't care about the outer frame (on GTK we certainly
don't).

Back to init_display and the question I asked earlier: Why should the
subsequent adjust_frame_size call do

       if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f))
	FrameRows (FRAME_TTY (f)) = new_lines;

here?  IIUC this _has_ already been set correctly when calling
change_frame_size and so should not be set here any more.  Agreed?

Now please tell me one thing: Which calls of change_frame_size or
adjust_frame_size _should_ set FrameRows or FrameCols and how can
I distinguish them?

martin