#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 <signal.h>
#include "syssignal.h"
#define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"
static void EmacsFrameInitialize ();
static void EmacsFrameDestroy ();
static void EmacsFrameRealize ();
void EmacsFrameResize ();
static Boolean EmacsFrameSetValues ();
static XtGeometryResult EmacsFrameQueryGeometry ();
#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
EmacsFrameClassRec emacsFrameClassRec = {
{
&widgetClassRec,
"EmacsFrame",
sizeof(EmacsFrameRec),
0,
0,
FALSE,
EmacsFrameInitialize,
0,
EmacsFrameRealize,
0,
0,
resources,
XtNumber(resources),
NULLQUARK,
TRUE,
TRUE,
TRUE,
FALSE,
EmacsFrameDestroy,
EmacsFrameResize,
XtInheritExpose,
EmacsFrameSetValues,
0,
XtInheritSetValuesAlmost,
0,
XtInheritAcceptFocus,
XtVersion,
0,
0,
EmacsFrameQueryGeometry,
XtInheritDisplayAccelerator,
0
}
};
WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
static void
get_default_char_pixel_size (ew, pixel_width, pixel_height)
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 (ew, pixel_width, pixel_height, char_width, char_height)
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 (ew, char_width, char_height, pixel_width, pixel_height)
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 (ew, in_width, in_height, out_width, out_height)
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 (w)
Widget w;
{
Widget wmshell;
for (wmshell = XtParent (w);
wmshell && !XtIsWMShell (wmshell);
wmshell = XtParent (wmshell));
return wmshell;
}
#if 0
static void
mark_shell_size_user_specified (wmshell)
Widget wmshell;
{
if (! XtIsWMShell (wmshell)) abort ();
((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
}
#endif
#if 0
static Boolean first_frame_p = True;
#endif
static void
set_frame_size (ew)
EmacsFrame ew;
{
unsigned int w = FRAME_COLS (ew->emacs_frame.frame);
unsigned int h = FRAME_LINES (ew->emacs_frame.frame);
Widget wmshell = get_wm_shell ((Widget) ew);
if (! XtIsSubclass (wmshell, shellWidgetClass)) abort ();
#if 0
if (ew->emacs_frame.geometry == 0)
XtVaGetValues (wmshell, XtNgeometry, &ew->emacs_frame.geometry, NULL);
if (!ew->emacs_frame.iconic)
XtVaGetValues (wmshell, XtNiconic, &ew->emacs_frame.iconic, NULL);
{
char *geom = 0;
XtVaGetValues (app_shell, XtNgeometry, &geom, NULL);
if (geom)
app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
}
if (ew->emacs_frame.geometry)
frame_flags = XParseGeometry (ew->emacs_frame.geometry,
&frame_x, &frame_y,
&frame_w, &frame_h);
if (first_frame_p)
{
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 (!ew->emacs_frame.iconic)
XtVaGetValues (app_shell, XtNiconic, &ew->emacs_frame.iconic, NULL);
first_frame_p = False;
}
else
{
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));
}
}
#endif
{
struct frame *f = ew->emacs_frame.frame;
Dimension pixel_width, pixel_height;
f->scroll_bar_actual_width
= FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
compute_fringe_widths (f, 0);
#if 0
change_frame_size (f, h, w, 1, 0, 0);
#endif
char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
ew->core.width = pixel_width;
ew->core.height = pixel_height;
#if 0
if (flags & (XValue | YValue))
{
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);
XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
}
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);
XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
}
if (flags & (WidthValue | HeightValue))
mark_shell_size_user_specified (wmshell);
XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, NULL);
#endif
}
}
int update_hints_inhibit;
static void
update_wm_hints (ew)
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;
if (update_hints_inhibit)
return;
#if 0
check_frame_size (ew->emacs_frame.frame, &min_rows, &min_cols);
#endif
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)));
XtVaSetValues (wmshell,
XtNbaseWidth, (XtArgVal) base_width,
XtNbaseHeight, (XtArgVal) base_height,
XtNwidthInc, (XtArgVal) cw,
XtNheightInc, (XtArgVal) ch,
XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
NULL);
}
#if 0
static void
create_frame_gcs (ew)
EmacsFrame ew;
{
struct frame *s = ew->emacs_frame.frame;
s->output_data.x->normal_gc
= XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
(unsigned long)0, (XGCValues *)0);
s->output_data.x->reverse_gc
= XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
(unsigned long)0, (XGCValues *)0);
s->output_data.x->cursor_gc
= XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
(unsigned long)0, (XGCValues *)0);
s->output_data.x->black_relief.gc = 0;
s->output_data.x->white_relief.gc = 0;
}
#endif
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
};
static void
setup_frame_gcs (ew)
EmacsFrame ew;
{
XGCValues gc_values;
struct frame* s = ew->emacs_frame.frame;
Pixmap blank_stipple, blank_tile;
blank_stipple
= XCreateBitmapFromData (XtDisplay (ew),
RootWindowOfScreen (XtScreen (ew)),
setup_frame_cursor_bits, 2, 2);
blank_tile
= XCreatePixmapFromBitmapData (XtDisplay(ew),
RootWindowOfScreen (XtScreen (ew)),
setup_frame_cursor_bits, 2, 2,
(unsigned long)0, (unsigned long)1,
ew->core.depth);
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;
XChangeGC (XtDisplay (ew), s->output_data.x->normal_gc,
(GCFont | GCForeground | GCBackground | GCGraphicsExposures
| GCStipple | GCTile),
&gc_values);
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;
XChangeGC (XtDisplay (ew), s->output_data.x->reverse_gc,
(GCFont | GCForeground | GCBackground | GCGraphicsExposures
| GCStipple | GCTile),
&gc_values);
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;
gc_values.stipple
= XCreateBitmapFromData (XtDisplay (ew),
RootWindowOfScreen (XtScreen (ew)),
setup_frame_cursor_bits, 16, 16);
XChangeGC (XtDisplay (ew), s->output_data.x->cursor_gc,
(GCFont | GCForeground | GCBackground | GCGraphicsExposures
| GCStipple | GCTile),
&gc_values);
}
static void
update_various_frame_slots (ew)
EmacsFrame ew;
{
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;
}
static void
update_from_various_frame_slots (ew)
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 = x->background_pixel;
ew->emacs_frame.internal_border_width = f->internal_border_width;
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;
}
static void
EmacsFrameInitialize (request, new, dum1, dum2)
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);
}
#if 0
{
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);
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);
}
}
FRAME_FONT (ew->emacs_frame.frame) = ew->emacs_frame.font;
#endif
update_from_various_frame_slots (ew);
set_frame_size (ew);
}
static void
EmacsFrameRealize (widget, mask, attrs)
Widget widget;
XtValueMask *mask;
XSetWindowAttributes *attrs;
{
EmacsFrame ew = (EmacsFrame)widget;
attrs->event_mask = (STANDARD_EVENT_SET
| PropertyChangeMask
| SubstructureNotifyMask);
*mask |= CWEventMask;
XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
attrs);
update_wm_hints (ew);
}
extern void free_frame_faces ();
static void
EmacsFrameDestroy (widget)
Widget widget;
{
EmacsFrame ew = (EmacsFrame) widget;
struct frame* s = ew->emacs_frame.frame;
if (! s) abort ();
if (! s->output_data.x) abort ();
BLOCK_INPUT;
x_free_gcs (s);
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);
UNBLOCK_INPUT;
}
void
EmacsFrameResize (widget)
Widget widget;
{
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);
change_frame_size (f, rows, columns, 0, 1, 0);
update_wm_hints (ew);
update_various_frame_slots (ew);
cancel_mouse_face (f);
}
static Boolean
EmacsFrameSetValues (cur_widget, req_widget, new_widget, dum1, dum2)
Widget cur_widget;
Widget req_widget;
Widget new_widget;
ArgList dum1;
Cardinal *dum2;
{
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;
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)
);
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;
}
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,
1, 0, 0);
needs_a_refresh = True;
}
if (has_to_update_hints)
update_wm_hints (new);
update_various_frame_slots (new);
if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
{
Widget wmshell = get_wm_shell ((Widget) cur);
XtVaSetValues (wmshell, XtNiconic,
(XtArgVal) new->emacs_frame.iconic, NULL);
}
return needs_a_refresh;
}
static XtGeometryResult
EmacsFrameQueryGeometry (widget, request, result)
Widget widget;
XtWidgetGeometry* request;
XtWidgetGeometry* result;
{
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;
}
void
EmacsFrameSetCharSize (widget, columns, rows)
Widget widget;
int columns;
int rows;
{
EmacsFrame ew = (EmacsFrame) widget;
Dimension pixel_width, pixel_height;
struct frame *f = ew->emacs_frame.frame;
if (columns < 3) columns = 3;
check_frame_size (f, &rows, &columns);
f->scroll_bar_actual_width
= FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
compute_fringe_widths (f, 0);
char_to_pixel_size (ew, columns, rows, &pixel_width, &pixel_height);
#if 0
XtVaGetValues (widget, XtNborderWidth, &border_width, NULL);
pixel_height += 2 * border_width;
pixel_width += 2 * border_width;
#endif
if (ew->core.width != pixel_width
|| ew->core.height != pixel_height)
{
int hdelta = pixel_height - ew->core.height;
int wdelta = pixel_width - ew->core.width;
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;
lw_refigure_widget (f->output_data.x->column_widget, False);
update_hints_inhibit = 1;
x_catch_errors (FRAME_X_DISPLAY (f));
XtVaSetValues (f->output_data.x->widget,
XtNwaitForWm, (XtArgVal) f->output_data.x->wait_for_wm,
NULL);
x_uncatch_errors ();
turn_on_atimers (0);
#ifdef SIGIO
sigblock (sigmask (SIGIO));
#endif
x_catch_errors (FRAME_X_DISPLAY (f));
XtVaSetValues (f->output_data.x->widget,
XtNheight, (XtArgVal) (outer_widget_height + hdelta),
XtNwidth, (XtArgVal) (outer_widget_width + wdelta),
NULL);
XtVaSetValues (f->output_data.x->column_widget,
XtNheight, (XtArgVal) (column_widget_height + hdelta),
XtNwidth, (XtArgVal) column_widget_width + wdelta,
NULL);
XtVaSetValues ((Widget) ew,
XtNheight, (XtArgVal) pixel_height,
XtNwidth, (XtArgVal) pixel_width,
NULL);
x_uncatch_errors ();
#ifdef SIGIO
sigunblock (sigmask (SIGIO));
#endif
turn_on_atimers (1);
lw_refigure_widget (f->output_data.x->column_widget, True);
update_hints_inhibit = 0;
update_wm_hints (ew);
f->output_data.x->widget->core.x = old_left;
f->output_data.x->widget->core.y = old_top;
}
SET_FRAME_GARBAGED (f);
}
void
widget_store_internal_border (widget)
Widget widget;
{
EmacsFrame ew = (EmacsFrame) widget;
FRAME_PTR f = ew->emacs_frame.frame;
ew->emacs_frame.internal_border_width = f->internal_border_width;
}