emacs/src/widget.c
Martin Rudalics d4fe840df0 Allow setting frame pixel sizes from frame parameters (Bug#21415)
Also fix some misfeatures in frame (re-)sizing code, add more
debugging information and remove some dead code.

* lisp/frame.el (frame-notice-user-settings, make-frame): Change
parameter names when setting `frame-size-history'.
(frame--size-history): New function.

* src/frame.c (frame_inhibit_resize): If frame has not been made
yet, return t if inhibit_horizontal_resize or
inhibit_vertical_resize bit have been set.
(adjust_frame_size): Simplify.
(make_frame): Initialize inhibit_horizontal_resize,
inhibit_vertical_resize, tool_bar_redisplayed, tool_bar_resized.
(Fframe_after_make_frame): Reset inhibit_horizontal_resize and
inhibit_vertical_resize slots.
(x_set_frame_parameters): Handle `text-pixels' specification for
width and height parameters.  Don't consider new_height or
new_width changes.  Call adjust_frame_size instead of
Fset_frame_size.
(x_figure_window_size): Two new arguments x_width and y_width
returning frame's figures width and height.  Calculate tool bar
height before frame sizes so SET_FRAME_HEIGHT can pick it up.
Handle `text-pixels' specification for width and height
parameters.
(Qtext_pixels, Qx_set_frame_parameters, Qset_frame_size)
(Qx_set_window_size_1, Qx_set_window_size_2)
(Qx_set_window_size_3, Qx_set_menu_bar_lines)
(Qupdate_frame_menubar, Qfree_frame_menubar_1)
(Qfree_frame_menubar_2): New symbols.
* src/frame.h (structure frame): New booleans
tool_bar_redisplayed, tool_bar_resized,
inhibit_horizontal_resize, inhibit_vertical_resize.
(x_figure_window_size): Update external declaration.
* src/gtkutil.c (xg_frame_set_char_size): Set size hints before
calling gtk_window_resize.
(update_frame_tool_bar): Make inhibiting of frame resizing more
discriminative.  Set tool_bar_resized bit.
* src/nsfns.m (x_set_tool_bar_lines): Make inhibiting of frame
resizing more discriminative.  Call adjust_frame_size instead of
x_set_window_size.
(Fx_create_frame): Handle x_width and x_height if
set by x_figure_window_size.
* src/nsterm.m (x_set_window_size): For GNUSTEP build don't
subtract 3 from tool bar height.
(x_set_window_size): Add frame_size_history_add call.
(x_new_font): Call adjust_frame_size instead of
x_set_window_size.
* src/w32fns.c (x_change_tool_bar_height): Reset
tool_bar_redisplayed and tool_bar_resized bits when adding tool
bar.  Make inhibiting of frame resizing more discriminative.
(w32_wnd_proc): Remove dead code in WM_WINDOWPOSCHANGING case.
(Fx_create_frame): Handle x_width and x_height if set by
x_figure_window_size.  Set size hints before adjusting frame size.
(x_create_tip_frame): Adjust x_figure_window_size call.
* src/w32term.c (x_set_window_size): Add frame_size_history_add
call.
* src/widget.c (set_frame_size): Remove dead code.  Add
frame_size_history_add call.  When frame_resize_pixelwise is t
use FRAME_PIXEL_WIDTH and FRAME_PIXEL_HEIGHT instead of
pixel_width and pixel_height.
(update_various_frame_slots): Remove dead code.
(EmacsFrameResize): Add more information in
frame_size_history_add call.
(EmacsFrameQueryGeometry): Round only when frame_resize_pixelwise
is not set.
* src/xdisp.c (redisplay_tool_bar): Set tool_bar_redisplayed bits.
* src/xfns.c (x_set_menu_bar_lines): Change argument name.
(x_change_tool_bar_height): Reset tool_bar_redisplayed and
tool_bar_resized bits when adding tool bar.  Make inhibiting of
frame resizing more discriminative.
(Fx_create_frame): Handle x_width and x_height if set by
x_figure_window_size.  Set size hints before adjusting frame size.
(x_create_tip_frame): Adjust x_figure_window_size call.
* src/xmenu.c (update_frame_menubar): Don't handle Lucid specially.
(set_frame_menubar): On Lucid never add core-border-width to
avoid that adding XtNinternalBorderWidth adds it again.
(free_frame_menubar): Handle frame_inhibit_resize true for Motif.
* src/xterm.c (x_new_font): In non-toolkit case handle size
change of menu bar.
(x_set_window_size_1): Fix calls to frame_size_history_add.
(x_wm_set_size_hint): Remove dead code.  Set
size_hints.min_width and size_hints.min_height to base_width and
base_height.
2015-10-13 12:11:43 +02:00

492 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* The emacs frame widget.
Copyright (C) 1992-1993, 2000-2015 Free Software Foundation, Inc.
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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>. */
/* Emacs 19 face widget ported by Fred Pierresteguy */
/* 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/
*/
#include <config.h>
#include <stdio.h>
#include "lisp.h"
#include "xterm.h"
#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "dispextern.h"
#include "blockinput.h"
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/cursorfont.h>
#include "widgetprv.h"
#include <X11/ObjectP.h>
#include <X11/Shell.h>
#include <X11/ShellP.h>
#include "../lwlib/lwlib.h"
#include "character.h"
#include "font.h"
static void EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2);
static void EmacsFrameDestroy (Widget widget);
static void EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs);
static void EmacsFrameResize (Widget widget);
static XtGeometryResult EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result);
#define offset(field) offsetof (EmacsFrameRec, 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},
{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\
";
*/
static 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,
/* Emacs never does XtSetvalues on this widget, so we have no code
for it. */
/* set_values */ 0, /* Not supported */
/* 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
get_default_char_pixel_size (EmacsFrame ew, int *pixel_width, int *pixel_height)
{
struct frame* f = ew->emacs_frame.frame;
*pixel_width = FRAME_COLUMN_WIDTH (f);
*pixel_height = FRAME_LINE_HEIGHT (f);
}
static void
pixel_to_char_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *char_width, int *char_height)
{
struct frame* f = ew->emacs_frame.frame;
*char_width = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, (int) pixel_width);
*char_height = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (int) pixel_height);
}
static void
pixel_to_text_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *text_width, int *text_height)
{
struct frame* f = ew->emacs_frame.frame;
*text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, (int) pixel_width);
*text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, (int) pixel_height);
}
static void
char_to_pixel_size (EmacsFrame ew, int char_width, int char_height, Dimension *pixel_width, Dimension *pixel_height)
{
struct frame* f = ew->emacs_frame.frame;
*pixel_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, char_width);
*pixel_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, char_height);
}
static void
round_size_to_char (EmacsFrame ew, Dimension in_width, Dimension in_height, Dimension *out_width, Dimension *out_height)
{
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
get_wm_shell (Widget w)
{
Widget wmshell;
for (wmshell = XtParent (w);
wmshell && !XtIsWMShell (wmshell);
wmshell = XtParent (wmshell));
return wmshell;
}
#if 0 /* Currently not used. */
static void
mark_shell_size_user_specified (Widget wmshell)
{
if (! XtIsWMShell (wmshell)) emacs_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;
}
#endif
/* 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.
*/
#if 0
static Boolean first_frame_p = True;
#endif
static void
set_frame_size (EmacsFrame ew)
{
/* 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.)
The EmacsShell widget is simply a replacement for the Shell widget
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 */
struct frame *f = ew->emacs_frame.frame;
int w = FRAME_COLS (f);
int h = FRAME_LINES (f);
Widget wmshell = get_wm_shell ((Widget) ew);
Dimension pixel_width, pixel_height;
/* Each Emacs shell is now independent and top-level. */
if (! XtIsSubclass (wmshell, shellWidgetClass)) emacs_abort ();
char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
ew->core.width = (frame_resize_pixelwise
? FRAME_PIXEL_WIDTH (f)
: pixel_width);
ew->core.height = (frame_resize_pixelwise
? FRAME_PIXEL_HEIGHT (f)
: pixel_height);
frame_size_history_add
(f, Qset_frame_size, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
list2 (make_number (ew->core.width), make_number (ew->core.height)));
}
static void
update_wm_hints (EmacsFrame ew)
{
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;
/* This happens when the frame is just created. */
if (! wmshell) return;
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);
get_default_char_pixel_size (ew, &cw, &ch);
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,
XtNbaseWidth, (XtArgVal) base_width,
XtNbaseHeight, (XtArgVal) base_height,
XtNwidthInc, (XtArgVal) (frame_resize_pixelwise ? 1 : cw),
XtNheightInc, (XtArgVal) (frame_resize_pixelwise ? 1 : ch),
XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
NULL);
}
void
widget_update_wm_size_hints (Widget widget)
{
EmacsFrame ew = (EmacsFrame) widget;
update_wm_hints (ew);
}
static void
update_various_frame_slots (EmacsFrame ew)
{
struct frame *f = ew->emacs_frame.frame;
f->internal_border_width = ew->emacs_frame.internal_border_width;
}
static void
update_from_various_frame_slots (EmacsFrame ew)
{
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);
ew->core.background_pixel = FRAME_BACKGROUND_PIXEL (f);
ew->emacs_frame.internal_border_width = f->internal_border_width;
ew->emacs_frame.foreground_pixel = FRAME_FOREGROUND_PIXEL (f);
ew->emacs_frame.cursor_color = x->cursor_pixel;
ew->core.border_pixel = x->border_pixel;
}
static void
EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2)
{
EmacsFrame ew = (EmacsFrame) new;
if (!ew->emacs_frame.frame)
{
fprintf (stderr,
"can't create an emacs frame widget without a frame\n");
exit (1);
}
update_from_various_frame_slots (ew);
set_frame_size (ew);
}
static void
resize_cb (Widget widget,
XtPointer closure,
XEvent* event,
Boolean* continue_to_dispatch)
{
EmacsFrameResize (widget);
}
static void
EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs)
{
EmacsFrame ew = (EmacsFrame) widget;
/* This used to contain SubstructureRedirectMask, but this turns out
to be a problem with XIM on Solaris, and events from that mask
don't seem to be used. Let's check that. */
attrs->event_mask = (STANDARD_EVENT_SET
| PropertyChangeMask
| SubstructureNotifyMask);
*mask |= CWEventMask;
XtCreateWindow (widget, InputOutput, (Visual *) CopyFromParent, *mask,
attrs);
/* Some ConfigureNotify events does not end up in EmacsFrameResize so
make sure we get them all. Seen with xfcwm4 for example. */
XtAddRawEventHandler (widget, StructureNotifyMask, False, resize_cb, NULL);
update_wm_hints (ew);
}
static void
EmacsFrameDestroy (Widget widget)
{
/* All GCs are now freed in x_free_frame_resources. */
}
static void
EmacsFrameResize (Widget widget)
{
EmacsFrame ew = (EmacsFrame) widget;
struct frame *f = ew->emacs_frame.frame;
int width, height;
pixel_to_text_size (ew, ew->core.width, ew->core.height, &width, &height);
frame_size_history_add
(f, QEmacsFrameResize, width, height,
list5 (make_number (ew->core.width), make_number (ew->core.height),
make_number (FRAME_TOP_MARGIN_HEIGHT (f)),
make_number (FRAME_SCROLL_BAR_AREA_HEIGHT (f)),
make_number (2 * FRAME_INTERNAL_BORDER_WIDTH (f))));
change_frame_size (f, width, height, 0, 1, 0, 1);
update_wm_hints (ew);
update_various_frame_slots (ew);
cancel_mouse_face (f);
}
static XtGeometryResult
EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result)
{
EmacsFrame ew = (EmacsFrame) widget;
int mask = request->request_mode;
Dimension ok_width, ok_height;
if (mask & (CWWidth | CWHeight))
{
if (!frame_resize_pixelwise)
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 entry points */
void
EmacsFrameSetCharSize (Widget widget, int columns, int rows)
{
EmacsFrame ew = (EmacsFrame) widget;
struct frame *f = ew->emacs_frame.frame;
if (!frame_inhibit_resize (f, 0, Qfont)
&& !frame_inhibit_resize (f, 1, Qfont))
x_set_window_size (f, 0, columns, rows, 0);
}
void
widget_store_internal_border (Widget widget)
{
EmacsFrame ew = (EmacsFrame) widget;
struct frame *f = ew->emacs_frame.frame;
ew->emacs_frame.internal_border_width = f->internal_border_width;
}