/* The emacs frame widget.
Copyright (C) 1992-1993, 2000-2022 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 . */
/* 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. */
#include
#include "widget.h"
#include
#include "lisp.h"
#include "sysstdio.h"
#include "xterm.h"
#include "frame.h"
#include
#include
#include
#include "widgetprv.h"
#include
#include
#include
#include "../lwlib/lwlib.h"
static void EmacsFrameInitialize (Widget, Widget, ArgList, Cardinal *);
static void EmacsFrameDestroy (Widget);
static void EmacsFrameRealize (Widget, XtValueMask *, XSetWindowAttributes *);
static void EmacsFrameResize (Widget);
static void EmacsFrameExpose (Widget, XEvent *, Region);
static XtGeometryResult EmacsFrameQueryGeometry (Widget, XtWidgetGeometry *,
XtWidgetGeometry *);
#define offset(field) offsetof (EmacsFrameRec, emacs_frame.field)
static XtResource resources[] = {
{(char *) XtNgeometry, (char *) XtCGeometry, XtRString, sizeof (String),
offset (geometry), XtRString, (XtPointer) 0},
{XtNiconic, XtCIconic, XtRBoolean, sizeof (Boolean),
offset (iconic), XtRImmediate, (XtPointer) False},
{(char *) XtNemacsFrame, (char *) XtCEmacsFrame,
XtRPointer, sizeof (XtPointer),
offset (frame), XtRImmediate, 0},
{(char *) XtNminibuffer, (char *) XtCMinibuffer, XtRInt, sizeof (int),
offset (minibuffer), XtRImmediate, (XtPointer)0},
{(char *) XtNunsplittable, (char *) XtCUnsplittable,
XtRBoolean, sizeof (Boolean),
offset (unsplittable), XtRImmediate, (XtPointer)0},
{(char *) XtNinternalBorderWidth, (char *) XtCInternalBorderWidth,
XtRInt, sizeof (int),
offset (internal_border_width), XtRImmediate, (XtPointer)4},
{(char *) XtNinterline, (char *) XtCInterline, XtRInt, sizeof (int),
offset (interline), XtRImmediate, (XtPointer)0},
{(char *) XtNforeground, (char *) XtCForeground, XtRPixel, sizeof (Pixel),
offset (foreground_pixel), XtRString, (char *) "XtDefaultForeground"},
{(char *) XtNcursorColor, (char *) XtCForeground, XtRPixel, sizeof (Pixel),
offset (cursor_color), XtRString, (char *) "XtDefaultForeground"},
{(char *) XtNbarCursor, (char *) XtCBarCursor, XtRBoolean, sizeof (Boolean),
offset (bar_cursor), XtRImmediate, (XtPointer)0},
{(char *) XtNvisualBell, (char *) XtCVisualBell, XtRBoolean, sizeof (Boolean),
offset (visual_bell), XtRImmediate, (XtPointer)0},
{(char *) XtNbellVolume, (char *) 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()\n\
: focus_in()\n\
: focus_out()\n\
";
*/
static EmacsFrameClassRec emacsFrameClassRec = {
{ /* core fields */
/* superclass */ 0, /* filled in by emacsFrameClass */
/* class_name */ (char *) "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 */ XtExposeNoCompress,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ EmacsFrameDestroy,
/* resize */ EmacsFrameResize,
/* expose */ EmacsFrameExpose,
/* 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 (void)
{
/* Set the superclass here rather than relying on static
initialization, to work around an unexelf.c bug on x86 platforms
that use the GNU Gold linker (Bug#27248). */
emacsFrameClassRec.core_class.superclass = &widgetClassRec;
return (WidgetClass) &emacsFrameClassRec;
}
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
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 WMShellWidget
get_wm_shell (Widget w)
{
Widget wmshell;
for (wmshell = XtParent (w);
wmshell && !XtIsWMShell (wmshell);
wmshell = XtParent (wmshell));
return (WMShellWidget) wmshell;
}
static void
set_frame_size (EmacsFrame ew)
{
struct frame *f = ew->emacs_frame.frame;
ew->core.width = FRAME_PIXEL_WIDTH (f);
ew->core.height = FRAME_PIXEL_HEIGHT (f);
CALLN (Ffuncall, Qfoo_it, build_string ("set_frame_size"),
build_string ("native pixels"),
Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
make_fixnum (FRAME_PIXEL_HEIGHT (f))));
}
static bool
update_wm_hints (WMShellWidget wmshell, EmacsFrame ew, int width, int height)
{
struct frame *f = ew->emacs_frame.frame;
int char_width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
int char_height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
int base_width
= (FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 1)
+ (((width < 0) ? FRAME_TEXT_WIDTH (f) : width) % char_width));
int base_height
= (FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1)
+ FRAME_MENUBAR_HEIGHT (f)
+ (((height < 0) ? FRAME_TEXT_HEIGHT (f) : height) % char_height));
int min_width = base_width;
int min_height = base_height;
char buffer[sizeof wmshell->wm.size_hints];
char *hints_ptr;
int value;
XtVaSetValues ((Widget) wmshell,
XtNbaseWidth, (XtArgVal) base_width,
XtNbaseHeight, (XtArgVal) base_height,
XtNwidthInc, (XtArgVal) char_width,
XtNheightInc, (XtArgVal) char_height,
XtNminWidth, (XtArgVal) min_width,
XtNminHeight, (XtArgVal) min_height,
NULL);
/* Return if size hints really changed. If they did not, then Xt
probably didn't set them either (or take the flags into
account.) */
hints_ptr = (char *) &wmshell->wm.size_hints;
/* Skip flags, which is unsigned long. */
value = memcmp (hints_ptr + sizeof (long), buffer + sizeof (long),
sizeof wmshell->wm.wm_hints - sizeof (long));
if (value != 0)
{
CALLN (Ffuncall, Qfoo_it, build_string ("update_wm_hints"),
build_string ("char width"), make_fixnum (FRAME_COLUMN_WIDTH (f)),
build_string ("vscroll"), make_fixnum (FRAME_SCROLL_BAR_AREA_WIDTH (f)),
build_string ("fringes"), make_fixnum (FRAME_TOTAL_FRINGE_WIDTH (f)),
build_string ("borders"), make_fixnum (2 * FRAME_INTERNAL_BORDER_WIDTH (f)),
build_string ("base width"), make_fixnum (base_width),
build_string ("min width"), make_fixnum (min_width));
CALLN (Ffuncall, Qfoo_it, build_string (" "),
build_string ("char height"), make_fixnum (FRAME_LINE_HEIGHT (f)),
build_string ("menubar"), make_fixnum (FRAME_MENUBAR_HEIGHT (f)),
build_string ("hscroll"), make_fixnum (FRAME_SCROLL_BAR_AREA_HEIGHT (f)),
build_string ("borders"), make_fixnum (2 * FRAME_INTERNAL_BORDER_WIDTH (f)),
build_string ("base height"), make_fixnum (base_height),
build_string ("min height"), make_fixnum (min_height));
}
return value;
}
bool
widget_update_wm_size_hints (Widget widget, Widget frame, int width, int height)
{
return update_wm_hints ((WMShellWidget) widget, (EmacsFrame) frame,
width, height);
}
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;
CALLN (Ffuncall, Qfoo_it,
build_string ("update_from_various_frame_slots"),
build_string ("native pixels"),
(Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
make_fixnum (FRAME_PIXEL_HEIGHT (f)))));
}
static void
EmacsFrameInitialize (Widget request, Widget new,
ArgList dum1, Cardinal *dum2)
{
EmacsFrame ew = (EmacsFrame) new;
if (!ew->emacs_frame.frame)
{
fputs ("can't create an emacs frame widget without a frame\n", stderr);
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);
if (get_wm_shell (widget))
update_wm_hints (get_wm_shell (widget), ew, -1, -1);
}
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;
CALLN (Ffuncall, Qfoo_it, build_string ("EmacsFrameResize"),
build_string ("old native pixels"),
Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
make_fixnum (FRAME_PIXEL_HEIGHT (f))),
build_string ("new native pixels"),
Fcons (make_fixnum (ew->core.width),
make_fixnum (ew->core.height)));
change_frame_size (f, ew->core.width, ew->core.height,
false, true, false);
if (get_wm_shell (widget))
update_wm_hints (get_wm_shell (widget), ew,
FRAME_PIXEL_TO_TEXT_WIDTH (f, ew->core.width),
FRAME_PIXEL_TO_TEXT_HEIGHT (f, ew->core.height));
update_various_frame_slots (ew);
cancel_mouse_face (f);
}
static XtGeometryResult
EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request,
XtWidgetGeometry *result)
{
int mask = request->request_mode;
if (mask & (CWWidth | CWHeight) && !frame_resize_pixelwise)
{
EmacsFrame ew = (EmacsFrame) widget;
Dimension ok_width, ok_height;
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 * FRAME_COLUMN_WIDTH (f),
rows * FRAME_LINE_HEIGHT (f));
}
static void
EmacsFrameExpose (Widget widget, XEvent *event, Region region)
{
EmacsFrame ew = (EmacsFrame) widget;
struct frame *f = ew->emacs_frame.frame;
expose_frame (f, event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
flush_frame (f);
}
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;
}