/* Haiku window system support
Copyright (C) 2021 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 . */
#include
#include "dispextern.h"
#include "frame.h"
#include "lisp.h"
#include "haikugui.h"
#include "keyboard.h"
#include "haikuterm.h"
#include "blockinput.h"
#include "termchar.h"
#include "termhooks.h"
#include "menu.h"
#include "buffer.h"
#include "haiku_support.h"
#include "thread.h"
#include "window.h"
#include
#include
#ifdef USE_BE_CAIRO
#include
#endif
struct haiku_display_info *x_display_list = NULL;
extern frame_parm_handler haiku_frame_parm_handlers[];
static void **fringe_bmps;
static int fringe_bitmap_fillptr = 0;
static Lisp_Object rdb;
struct unhandled_event
{
struct unhandled_event *next;
enum haiku_event_type type;
uint8_t buffer[200];
};
char *
get_keysym_name (int keysym)
{
static char value[16];
sprintf (value, "%d", keysym);
return value;
}
static struct frame *
haiku_window_to_frame (void *window)
{
Lisp_Object tail, tem;
struct frame *f;
FOR_EACH_FRAME (tail, tem)
{
f = XFRAME (tem);
if (!FRAME_HAIKU_P (f))
continue;
eassert (FRAME_DISPLAY_INFO (f) == x_display_list);
if (FRAME_HAIKU_WINDOW (f) == window)
return f;
}
return 0;
}
static void
haiku_coords_from_parent (struct frame *f, int *x, int *y)
{
struct frame *p = FRAME_PARENT_FRAME (f);
eassert (p);
for (struct frame *parent = p; parent;
parent = FRAME_PARENT_FRAME (parent))
{
*x -= parent->left_pos;
*y -= parent->top_pos;
}
}
static void
haiku_delete_terminal (struct terminal *terminal)
{
emacs_abort ();
}
static const char *
get_string_resource (void *ignored, const char *name, const char *class)
{
if (!name)
return NULL;
Lisp_Object lval = assoc_no_quit (build_string (name), rdb);
if (!NILP (lval))
return SSDATA (XCDR (lval));
return NULL;
}
static void
haiku_update_size_hints (struct frame *f)
{
int base_width, base_height;
eassert (FRAME_HAIKU_P (f) && FRAME_HAIKU_WINDOW (f));
base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
block_input ();
BWindow_set_size_alignment (FRAME_HAIKU_WINDOW (f),
frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f),
frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f));
BWindow_set_min_size (FRAME_HAIKU_WINDOW (f), base_width,
base_height
+ FRAME_TOOL_BAR_HEIGHT (f)
+ FRAME_MENU_BAR_HEIGHT (f));
unblock_input ();
}
static void
haiku_clip_to_string (struct glyph_string *s)
{
struct haiku_rect r[2];
int n = get_glyph_string_clip_rects (s, (struct haiku_rect *) &r, 2);
if (n)
BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[0].x, r[0].y,
r[0].width, r[0].height);
if (n > 1)
{
BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[1].x, r[1].y,
r[1].width, r[1].height);
}
s->num_clips = n;
}
static void
haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst)
{
BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y,
s->width, s->height);
dst->num_clips = 1;
}
static void
haiku_flip_buffers (struct frame *f)
{
void *view = FRAME_OUTPUT_DATA (f)->view;
block_input ();
BView_draw_lock (view);
FRAME_DIRTY_P (f) = 0;
EmacsView_flip_and_blit (view);
BView_draw_unlock (view);
unblock_input ();
}
static void
haiku_frame_up_to_date (struct frame *f)
{
block_input ();
FRAME_MOUSE_UPDATE (f);
if (FRAME_DIRTY_P (f) && !buffer_flipping_blocked_p ())
haiku_flip_buffers (f);
unblock_input ();
}
static void
haiku_buffer_flipping_unblocked_hook (struct frame *f)
{
if (FRAME_DIRTY_P (f))
haiku_flip_buffers (f);
}
static void
haiku_clear_frame_area (struct frame *f, int x, int y,
int width, int height)
{
void *vw = FRAME_HAIKU_VIEW (f);
block_input ();
BView_draw_lock (vw);
BView_StartClip (vw);
BView_ClipToRect (vw, x, y, width, height);
BView_SetHighColor (vw, FRAME_BACKGROUND_PIXEL (f));
BView_FillRectangle (vw, x, y, width, height);
BView_EndClip (vw);
BView_draw_unlock (vw);
unblock_input ();
}
static void
haiku_clear_frame (struct frame *f)
{
void *view = FRAME_HAIKU_VIEW (f);
block_input ();
BView_draw_lock (view);
BView_StartClip (view);
BView_ClipToRect (view, 0, 0, FRAME_PIXEL_WIDTH (f) + 1,
FRAME_PIXEL_HEIGHT (f) + 1);
BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f));
BView_FillRectangle (view, 0, 0, FRAME_PIXEL_WIDTH (f) + 1,
FRAME_PIXEL_HEIGHT (f) + 1);
BView_EndClip (view);
BView_draw_unlock (view);
unblock_input ();
}
/* Give frame F the font FONT-OBJECT as its default font. The return
value is FONT-OBJECT. FONTSET is an ID of the fontset for the
frame. If it is negative, generate a new fontset from
FONT-OBJECT. */
static Lisp_Object
haiku_new_font (struct frame *f, Lisp_Object font_object, int fontset)
{
struct font *font = XFONT_OBJECT (font_object);
if (fontset < 0)
fontset = fontset_from_font (font_object);
FRAME_FONTSET (f) = fontset;
if (FRAME_FONT (f) == font)
return font_object;
FRAME_FONT (f) = font;
FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
FRAME_COLUMN_WIDTH (f) = font->average_width;
int ascent, descent;
get_font_ascent_descent (font, &ascent, &descent);
FRAME_LINE_HEIGHT (f) = ascent + descent;
FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
int unit = FRAME_COLUMN_WIDTH (f);
if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
FRAME_CONFIG_SCROLL_BAR_COLS (f)
= (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
else
FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
if (FRAME_HAIKU_WINDOW (f))
{
adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
FRAME_LINES (f) * FRAME_LINE_HEIGHT (f),
3, false, Qfont);
haiku_clear_under_internal_border (f);
}
return font_object;
}
static int
haiku_valid_modifier_p (Lisp_Object sym)
{
return EQ (sym, Qcommand) || EQ (sym, Qshift)
|| EQ (sym, Qcontrol) || EQ (sym, Qoption);
}
#define MODIFIER_OR(obj, def) (haiku_valid_modifier_p (obj) ? obj : def)
static void
haiku_add_modifier (int modifier, int toput, Lisp_Object qtem, int *modifiers)
{
if ((modifier & HAIKU_MODIFIER_ALT && EQ (qtem, Qcommand))
|| (modifier & HAIKU_MODIFIER_SHIFT && EQ (qtem, Qshift))
|| (modifier & HAIKU_MODIFIER_CTRL && EQ (qtem, Qcontrol))
|| (modifier & HAIKU_MODIFIER_SUPER && EQ (qtem, Qoption)))
*modifiers |= toput;
}
static int
haiku_modifiers_to_emacs (int haiku_key)
{
int modifiers = 0;
haiku_add_modifier (haiku_key, shift_modifier,
MODIFIER_OR (Vhaiku_shift_keysym, Qshift), &modifiers);
haiku_add_modifier (haiku_key, super_modifier,
MODIFIER_OR (Vhaiku_super_keysym, Qoption), &modifiers);
haiku_add_modifier (haiku_key, meta_modifier,
MODIFIER_OR (Vhaiku_meta_keysym, Qcommand), &modifiers);
haiku_add_modifier (haiku_key, ctrl_modifier,
MODIFIER_OR (Vhaiku_control_keysym, Qcontrol), &modifiers);
return modifiers;
}
#undef MODIFIER_OR
static void
haiku_rehighlight (void)
{
eassert (x_display_list && !x_display_list->next);
block_input ();
struct frame *old_hl = x_display_list->highlight_frame;
if (x_display_list->focused_frame)
{
x_display_list->highlight_frame
= ((FRAMEP (FRAME_FOCUS_FRAME (x_display_list->focused_frame)))
? XFRAME (FRAME_FOCUS_FRAME (x_display_list->focused_frame))
: x_display_list->focused_frame);
if (!FRAME_LIVE_P (x_display_list->highlight_frame))
{
fset_focus_frame (x_display_list->focused_frame, Qnil);
x_display_list->highlight_frame = x_display_list->focused_frame;
}
}
else
x_display_list->highlight_frame = 0;
if (old_hl)
gui_update_cursor (old_hl, true);
if (x_display_list->highlight_frame)
gui_update_cursor (x_display_list->highlight_frame, true);
unblock_input ();
}
static void
haiku_frame_raise_lower (struct frame *f, bool raise_p)
{
if (raise_p)
{
block_input ();
BWindow_activate (FRAME_HAIKU_WINDOW (f));
flush_frame (f);
unblock_input ();
}
}
/* Unfortunately, NOACTIVATE is not implementable on Haiku. */
static void
haiku_focus_frame (struct frame *frame, bool noactivate)
{
if (x_display_list->focused_frame != frame)
haiku_frame_raise_lower (frame, 1);
}
static void
haiku_new_focus_frame (struct frame *frame)
{
eassert (x_display_list && !x_display_list->next);
block_input ();
if (frame != x_display_list->focused_frame)
{
if (x_display_list->focused_frame &&
x_display_list->focused_frame->auto_lower)
haiku_frame_raise_lower (x_display_list->focused_frame, 0);
x_display_list->focused_frame = frame;
if (frame && frame->auto_raise)
haiku_frame_raise_lower (frame, 1);
}
unblock_input ();
haiku_rehighlight ();
}
static void
haiku_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
haiku_set_name (f, arg, 0);
}
static void
haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor)
{
haiku_query_color (FRAME_BACKGROUND_PIXEL (f), bgcolor);
}
static bool
haiku_defined_color (struct frame *f,
const char *name,
Emacs_Color *color,
bool alloc,
bool make_index)
{
return !haiku_get_color (name, color);
}
/* Adapted from xterm `x_draw_box_rect'. */
static void
haiku_draw_box_rect (struct glyph_string *s,
int left_x, int top_y, int right_x, int bottom_y, int hwidth,
int vwidth, bool left_p, bool right_p, struct haiku_rect *clip_rect)
{
void *view = FRAME_HAIKU_VIEW (s->f);
struct face *face = s->face;
BView_StartClip (view);
BView_SetHighColor (view, face->box_color);
if (clip_rect)
BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
clip_rect->height);
BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
if (left_p)
BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
BView_FillRectangle (view, left_x, bottom_y - hwidth + 1,
right_x - left_x + 1, hwidth);
if (right_p)
BView_FillRectangle (view, right_x - vwidth + 1,
top_y, vwidth, bottom_y - top_y + 1);
BView_EndClip (view);
}
static void
haiku_calculate_relief_colors (struct glyph_string *s,
uint32_t *rgbout_w, uint32_t *rgbout_b,
uint32_t *rgbout_c)
{
struct face *face = s->face;
prepare_face_for_display (s->f, s->face);
uint32_t rgbin = face->use_box_color_for_shadows_p
? face->box_color : face->background;
if (s->hl == DRAW_CURSOR)
rgbin = FRAME_CURSOR_COLOR (s->f).pixel;
double h, cs, l;
rgb_color_hsl (rgbin, &h, &cs, &l);
hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 0.6), rgbout_b);
hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 1.2), rgbout_w);
hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 1.8), rgbout_c);
}
static void
haiku_draw_relief_rect (struct glyph_string *s,
int left_x, int top_y, int right_x, int bottom_y,
int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p,
bool left_p, bool right_p,
struct haiku_rect *clip_rect, bool fancy_p)
{
uint32_t color_white;
uint32_t color_black;
uint32_t color_corner;
haiku_calculate_relief_colors (s, &color_white, &color_black,
&color_corner);
void *view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
BView_SetHighColor (view, raised_p ? color_white : color_black);
if (clip_rect)
BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
clip_rect->height);
if (top_p)
BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
if (left_p)
BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
BView_SetHighColor (view, !raised_p ? color_white : color_black);
if (bot_p)
BView_FillRectangle (view, left_x, bottom_y - hwidth + 1,
right_x - left_x + 1, hwidth);
if (right_p)
BView_FillRectangle (view, right_x - vwidth + 1, top_y,
vwidth, bottom_y - top_y + 1);
/* Draw the triangle for the bottom-left corner. */
if (bot_p && left_p)
{
BView_SetHighColor (view, raised_p ? color_white : color_black);
BView_FillTriangle (view, left_x, bottom_y - hwidth, left_x + vwidth,
bottom_y - hwidth, left_x, bottom_y);
}
/* Now draw the triangle for the top-right corner. */
if (top_p && right_p)
{
BView_SetHighColor (view, raised_p ? color_white : color_black);
BView_FillTriangle (view, right_x - vwidth, top_y,
right_x, top_y,
right_x - vwidth, top_y + hwidth);
}
/* If (h/v)width is > 1, we draw the outer-most line on each side in the
black relief color. */
BView_SetHighColor (view, color_black);
if (hwidth > 1 && top_p)
BView_StrokeLine (view, left_x, top_y, right_x, top_y);
if (hwidth > 1 && bot_p)
BView_StrokeLine (view, left_x, bottom_y, right_x, bottom_y);
if (vwidth > 1 && left_p)
BView_StrokeLine (view, left_x, top_y, left_x, bottom_y);
if (vwidth > 1 && right_p)
BView_StrokeLine (view, right_x, top_y, right_x, bottom_y);
BView_SetHighColor (view, color_corner);
/* Omit corner pixels. */
if (hwidth > 1 || vwidth > 1)
{
if (left_p && top_p)
BView_FillRectangle (view, left_x, top_y, 1, 1);
if (left_p && bot_p)
BView_FillRectangle (view, left_x, bottom_y, 1, 1);
if (right_p && top_p)
BView_FillRectangle (view, right_x, top_y, 1, 1);
if (right_p && bot_p)
BView_FillRectangle (view, right_x, bottom_y, 1, 1);
}
BView_EndClip (view);
}
static void
haiku_draw_underwave (struct glyph_string *s, int width, int x)
{
int wave_height = 3, wave_length = 2;
int y, dx, dy, odd, xmax;
dx = wave_length;
dy = wave_height - 1;
y = s->ybase - wave_height + 3;
float ax, ay, bx, by;
xmax = x + width;
void *view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
BView_ClipToRect (view, x, y, width, wave_height);
ax = x - ((int) (x) % dx) + (float) 0.5;
bx = ax + dx;
odd = (int) (ax / dx) % 2;
ay = by = y + 0.5;
if (odd)
ay += dy;
else
by += dy;
while (ax <= xmax)
{
BView_StrokeLine (view, ax, ay, bx, by);
ax = bx, ay = by;
bx += dx, by = y + 0.5 + odd * dy;
odd = !odd;
}
BView_EndClip (view);
}
static void
haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
uint8_t dcol, int width, int x)
{
if (s->for_overlaps)
return;
void *view = FRAME_HAIKU_VIEW (s->f);
BView_draw_lock (view);
BView_StartClip (view);
if (face->underline)
{
if (s->hl == DRAW_CURSOR)
BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
else if (!face->underline_defaulted_p)
BView_SetHighColor (view, face->underline_color);
else
BView_SetHighColor (view, dcol);
if (face->underline == FACE_UNDER_WAVE)
haiku_draw_underwave (s, width, x);
else if (face->underline == FACE_UNDER_LINE)
{
unsigned long thickness, position;
int y;
if (s->prev && s->prev && s->prev->hl == DRAW_MOUSE_FACE)
{
struct face *prev_face = s->prev->face;
if (prev_face && prev_face->underline == FACE_UNDER_LINE)
{
/* We use the same underline style as the previous one. */
thickness = s->prev->underline_thickness;
position = s->prev->underline_position;
}
else
goto calculate_underline_metrics;
}
else
{
calculate_underline_metrics:;
struct font *font = font_for_underline_metrics (s);
unsigned long minimum_offset;
bool underline_at_descent_line;
bool use_underline_position_properties;
Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE
(Qunderline_minimum_offset, s->w));
if (FIXNUMP (val))
minimum_offset = max (0, XFIXNUM (val));
else
minimum_offset = 1;
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
= !(NILP (val) || EQ (val, Qunbound));
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
use_underline_position_properties
= !(NILP (val) || EQ (val, Qunbound));
/* Get the underline thickness. Default is 1 pixel. */
if (font && font->underline_thickness > 0)
thickness = font->underline_thickness;
else
thickness = 1;
if (underline_at_descent_line)
position = (s->height - thickness) - (s->ybase - s->y);
else
{
/* Get the underline position. This is the
recommended vertical offset in pixels from
the baseline to the top of the underline.
This is a signed value according to the
specs, and its default is
ROUND ((maximum descent) / 2), with
ROUND(x) = floor (x + 0.5) */
if (use_underline_position_properties
&& font && font->underline_position >= 0)
position = font->underline_position;
else if (font)
position = (font->descent + 1) / 2;
else
position = minimum_offset;
}
position = max (position, minimum_offset);
}
/* Check the sanity of thickness and position. We should
avoid drawing underline out of the current line area. */
if (s->y + s->height <= s->ybase + position)
position = (s->height - 1) - (s->ybase - s->y);
if (s->y + s->height < s->ybase + position + thickness)
thickness = (s->y + s->height) - (s->ybase + position);
s->underline_thickness = thickness;
s->underline_position = position;
y = s->ybase + position;
BView_FillRectangle (view, s->x, y, s->width, thickness);
}
}
if (face->overline_p)
{
unsigned long dy = 0, h = 1;
if (s->hl == DRAW_CURSOR)
BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
else if (!face->overline_color_defaulted_p)
BView_SetHighColor (view, face->overline_color);
else
BView_SetHighColor (view, dcol);
BView_FillRectangle (view, s->x, s->y + dy, s->width, h);
}
if (face->strike_through_p)
{
/* Y-coordinate and height of the glyph string's first
glyph. We cannot use s->y and s->height because those
could be larger if there are taller display elements
(e.g., characters displayed with a larger font) in the
same glyph row. */
int glyph_y = s->ybase - s->first_glyph->ascent;
int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
/* Strike-through width and offset from the glyph string's
top edge. */
unsigned long h = 1;
unsigned long dy = (glyph_height - h) / 2;
if (s->hl == DRAW_CURSOR)
BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
else if (!face->strike_through_color_defaulted_p)
BView_SetHighColor (view, face->strike_through_color);
else
BView_SetHighColor (view, dcol);
BView_FillRectangle (view, s->x, glyph_y + dy, s->width, h);
}
BView_EndClip (view);
BView_draw_unlock (view);
}
static void
haiku_draw_string_box (struct glyph_string *s, int clip_p)
{
int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x;
bool raised_p, left_p, right_p;
struct glyph *last_glyph;
struct haiku_rect clip_rect;
struct face *face = s->face;
last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
? WINDOW_RIGHT_EDGE_X (s->w)
: window_box_right (s->w, s->area));
/* The glyph that may have a right box line. For static
compositions and images, the right-box flag is on the first glyph
of the glyph string; for other types it's on the last glyph. */
if (s->cmp || s->img)
last_glyph = s->first_glyph;
else if (s->first_glyph->type == COMPOSITE_GLYPH
&& s->first_glyph->u.cmp.automatic)
{
/* For automatic compositions, we need to look up the last glyph
in the composition. */
struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area];
struct glyph *g = s->first_glyph;
for (last_glyph = g++;
g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id
&& g->slice.cmp.to < s->cmp_to;
last_glyph = g++)
;
}
else
last_glyph = s->first_glyph + s->nchars - 1;
vwidth = eabs (face->box_vertical_line_width);
hwidth = eabs (face->box_horizontal_line_width);
raised_p = face->box == FACE_RAISED_BOX;
left_x = s->x;
right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
? last_x - 1
: min (last_x, s->x + s->background_width) - 1);
top_y = s->y;
bottom_y = top_y + s->height - 1;
left_p = (s->first_glyph->left_box_line_p
|| (s->hl == DRAW_MOUSE_FACE
&& (s->prev == NULL
|| s->prev->hl != s->hl)));
right_p = (last_glyph->right_box_line_p
|| (s->hl == DRAW_MOUSE_FACE
&& (s->next == NULL
|| s->next->hl != s->hl)));
get_glyph_string_clip_rect (s, &clip_rect);
if (face->box == FACE_SIMPLE_BOX)
haiku_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
vwidth, left_p, right_p, &clip_rect);
else
haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
vwidth, raised_p, true, true, left_p, right_p,
&clip_rect, 1);
if (clip_p)
{
void *view = FRAME_HAIKU_VIEW (s->f);
haiku_draw_text_decoration (s, face, face->foreground, s->width, s->x);
BView_ClipToInverseRect (view, left_x, top_y, right_x - left_x + 1, hwidth);
if (left_p)
BView_ClipToInverseRect (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
BView_ClipToInverseRect (view, left_x, bottom_y - hwidth + 1,
right_x - left_x + 1, hwidth);
if (right_p)
BView_ClipToInverseRect (view, right_x - vwidth + 1,
top_y, vwidth, bottom_y - top_y + 1);
}
}
static void
haiku_draw_plain_background (struct glyph_string *s, struct face *face,
int box_line_hwidth, int box_line_vwidth)
{
void *view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
if (s->hl == DRAW_CURSOR)
BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
else
BView_SetHighColor (view, face->background_defaulted_p ?
FRAME_BACKGROUND_PIXEL (s->f) :
face->background);
BView_FillRectangle (view, s->x,
s->y + box_line_hwidth,
s->background_width,
s->height - 2 * box_line_hwidth);
BView_EndClip (view);
}
static void
haiku_draw_stipple_background (struct glyph_string *s, struct face *face,
int box_line_hwidth, int box_line_vwidth)
{
}
static void
haiku_maybe_draw_background (struct glyph_string *s, int force_p)
{
if ((s->first_glyph->type != IMAGE_GLYPH) && !s->background_filled_p)
{
struct face *face = s->face;
int box_line_width = max (face->box_horizontal_line_width, 0);
int box_vline_width = max (face->box_vertical_line_width, 0);
if (FONT_HEIGHT (s->font) < s->height - 2 * box_vline_width
|| FONT_TOO_HIGH (s->font)
|| s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
{
if (!face->stipple)
haiku_draw_plain_background (s, face, box_line_width,
box_vline_width);
else
haiku_draw_stipple_background (s, face, box_line_width,
box_vline_width);
s->background_filled_p = 1;
}
}
}
static void
haiku_mouse_face_colors (struct glyph_string *s, uint32_t *fg,
uint32_t *bg)
{
int face_id;
struct face *face;
/* What face has to be used last for the mouse face? */
face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
face = FACE_FROM_ID_OR_NULL (s->f, face_id);
if (face == NULL)
face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
if (s->first_glyph->type == CHAR_GLYPH)
face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
else
face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
face = FACE_FROM_ID (s->f, face_id);
prepare_face_for_display (s->f, s->face);
if (fg)
*fg = face->foreground;
if (bg)
*bg = face->background;
}
static void
haiku_draw_glyph_string_foreground (struct glyph_string *s)
{
struct face *face = s->face;
int i, x;
if (face->box != FACE_NO_BOX
&& s->first_glyph->left_box_line_p)
x = s->x + max (face->box_vertical_line_width, 0);
else
x = s->x;
void *view = FRAME_HAIKU_VIEW (s->f);
if (s->font_not_found_p)
{
BView_StartClip (view);
if (s->hl == DRAW_CURSOR)
BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
else
BView_SetHighColor (view, face->foreground);
for (i = 0; i < s->nchars; ++i)
{
struct glyph *g = s->first_glyph + i;
BView_StrokeRectangle (view, x, s->y, g->pixel_width,
s->height);
x += g->pixel_width;
}
BView_EndClip (view);
}
else
{
struct font *ft = s->font;
int off = ft->baseline_offset;
int y;
if (ft->vertical_centering)
off = VCENTER_BASELINE_OFFSET (ft, s->f) - off;
y = s->ybase - off;
if (s->for_overlaps || (s->background_filled_p && s->hl != DRAW_CURSOR))
ft->driver->draw (s, 0, s->nchars, x, y, false);
else
ft->driver->draw (s, 0, s->nchars, x, y, true);
if (face->overstrike)
ft->driver->draw (s, 0, s->nchars, x + 1, y, false);
}
}
static void
haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
{
struct glyph *glyph = s->first_glyph;
unsigned char2b[8];
int x, i, j;
struct face *face = s->face;
/* If first glyph of S has a left box line, start drawing the text
of S to the right of that box line. */
if (face && face->box != FACE_NO_BOX
&& s->first_glyph->left_box_line_p)
x = s->x + max (face->box_vertical_line_width, 0);
else
x = s->x;
s->char2b = char2b;
for (i = 0; i < s->nchars; i++, glyph++)
{
#ifdef GCC_LINT
enum { PACIFY_GCC_BUG_81401 = 1 };
#else
enum { PACIFY_GCC_BUG_81401 = 0 };
#endif
char buf[7 + PACIFY_GCC_BUG_81401];
char *str = NULL;
int len = glyph->u.glyphless.len;
if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
{
if (len > 0
&& CHAR_TABLE_P (Vglyphless_char_display)
&& (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
>= 1))
{
Lisp_Object acronym
= (! glyph->u.glyphless.for_no_font
? CHAR_TABLE_REF (Vglyphless_char_display,
glyph->u.glyphless.ch)
: XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
if (STRINGP (acronym))
str = SSDATA (acronym);
}
}
else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
{
unsigned int ch = glyph->u.glyphless.ch;
eassume (ch <= MAX_CHAR);
sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch);
str = buf;
}
if (str)
{
int upper_len = (len + 1) / 2;
/* It is assured that all LEN characters in STR is ASCII. */
for (j = 0; j < len; j++)
char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF;
s->font->driver->draw (s, 0, upper_len,
x + glyph->slice.glyphless.upper_xoff,
s->ybase + glyph->slice.glyphless.upper_yoff,
false);
s->font->driver->draw (s, upper_len, len,
x + glyph->slice.glyphless.lower_xoff,
s->ybase + glyph->slice.glyphless.lower_yoff,
false);
}
BView_StartClip (FRAME_HAIKU_VIEW (s->f));
if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
BView_FillRectangle (FRAME_HAIKU_VIEW (s->f),
x, s->ybase - glyph->ascent,
glyph->pixel_width - 1,
glyph->ascent + glyph->descent - 1);
BView_EndClip (FRAME_HAIKU_VIEW (s->f));
x += glyph->pixel_width;
}
}
static void
haiku_draw_stretch_glyph_string (struct glyph_string *s)
{
eassert (s->first_glyph->type == STRETCH_GLYPH);
struct face *face = s->face;
if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
{
int width, background_width = s->background_width;
int x = s->x;
if (!s->row->reversed_p)
{
int left_x = window_box_left_offset (s->w, TEXT_AREA);
if (x < left_x)
{
background_width -= left_x - x;
x = left_x;
}
}
else
{
/* In R2L rows, draw the cursor on the right edge of the
stretch glyph. */
int right_x = window_box_right (s->w, TEXT_AREA);
if (x + background_width > right_x)
background_width -= x - right_x;
x += background_width;
}
width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
if (s->row->reversed_p)
x -= width;
void *view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
BView_FillRectangle (view, x, s->y, width, s->height);
BView_EndClip (view);
if (width < background_width)
{
if (!s->row->reversed_p)
x += width;
else
x = s->x;
int y = s->y;
int w = background_width - width, h = s->height;
if (!face->stipple)
{
uint32_t bkg;
if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR
&& s->row->mouse_face_p
&& cursor_in_mouse_face_p (s->w)))
haiku_mouse_face_colors (s, NULL, &bkg);
else
bkg = face->background;
BView_StartClip (view);
BView_SetHighColor (view, bkg);
BView_FillRectangle (view, x, y, w, h);
BView_EndClip (view);
}
}
}
else if (!s->background_filled_p)
{
int background_width = s->background_width;
int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
/* Don't draw into left fringe or scrollbar area except for
header line and mode line. */
if (s->area == TEXT_AREA
&& x < text_left_x && !s->row->mode_line_p)
{
background_width -= text_left_x - x;
x = text_left_x;
}
if (background_width > 0)
{
void *view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
uint32_t bkg;
if (s->hl == DRAW_MOUSE_FACE)
haiku_mouse_face_colors (s, NULL, &bkg);
else if (s->hl == DRAW_CURSOR)
bkg = FRAME_CURSOR_COLOR (s->f).pixel;
else
bkg = s->face->background;
BView_SetHighColor (view, bkg);
BView_FillRectangle (view, x, s->y, background_width, s->height);
BView_EndClip (view);
}
}
s->background_filled_p = 1;
}
static void
haiku_start_clip (struct glyph_string *s)
{
void *view = FRAME_HAIKU_VIEW (s->f);
BView_draw_lock (view);
BView_StartClip (view);
}
static void
haiku_end_clip (struct glyph_string *s)
{
void *view = FRAME_HAIKU_VIEW (s->f);
BView_EndClip (view);
BView_draw_unlock (view);
}
static void
haiku_clip_to_row (struct window *w, struct glyph_row *row,
enum glyph_row_area area)
{
struct frame *f = WINDOW_XFRAME (w);
int window_x, window_y, window_width;
int x, y, width, height;
window_box (w, area, &window_x, &window_y, &window_width, 0);
x = window_x;
y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
y = max (y, window_y);
width = window_width;
height = row->visible_height;
BView_ClipToRect (FRAME_HAIKU_VIEW (f), x, y, width, height);
}
static void
haiku_update_begin (struct frame *f)
{
}
static void
haiku_update_end (struct frame *f)
{
MOUSE_HL_INFO (f)->mouse_face_defer = false;
flush_frame (f);
}
static void
haiku_draw_composite_glyph_string_foreground (struct glyph_string *s)
{
int i, j, x;
struct font *font = s->font;
void *view = FRAME_HAIKU_VIEW (s->f);
struct face *face = s->face;
/* If first glyph of S has a left box line, start drawing the text
of S to the right of that box line. */
if (face && face->box != FACE_NO_BOX
&& s->first_glyph->left_box_line_p)
x = s->x + max (face->box_vertical_line_width, 0);
else
x = s->x;
/* S is a glyph string for a composition. S->cmp_from is the index
of the first character drawn for glyphs of this composition.
S->cmp_from == 0 means we are drawing the very first character of
this composition. */
/* Draw a rectangle for the composition if the font for the very
first character of the composition could not be loaded. */
if (s->font_not_found_p && !s->cmp_from)
{
BView_StartClip (view);
if (s->hl == DRAW_CURSOR)
BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
else
BView_SetHighColor (view, s->face->foreground);
BView_StrokeRectangle (view, s->x, s->y, s->width - 1, s->height - 1);
BView_EndClip (view);
}
else if (!s->first_glyph->u.cmp.automatic)
{
int y = s->ybase;
for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
/* TAB in a composition means display glyphs with padding
space on the left or right. */
if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
{
int xx = x + s->cmp->offsets[j * 2];
int yy = y - s->cmp->offsets[j * 2 + 1];
font->driver->draw (s, j, j + 1, xx, yy, false);
if (face->overstrike)
font->driver->draw (s, j, j + 1, xx + 1, yy, false);
}
}
else
{
Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
Lisp_Object glyph;
int y = s->ybase;
int width = 0;
for (i = j = s->cmp_from; i < s->cmp_to; i++)
{
glyph = LGSTRING_GLYPH (gstring, i);
if (NILP (LGLYPH_ADJUSTMENT (glyph)))
width += LGLYPH_WIDTH (glyph);
else
{
int xoff, yoff, wadjust;
if (j < i)
{
font->driver->draw (s, j, i, x, y, false);
if (s->face->overstrike)
font->driver->draw (s, j, i, x + 1, y, false);
x += width;
}
xoff = LGLYPH_XOFF (glyph);
yoff = LGLYPH_YOFF (glyph);
wadjust = LGLYPH_WADJUST (glyph);
font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
if (face->overstrike)
font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
false);
x += wadjust;
j = i + 1;
width = 0;
}
}
if (j < i)
{
font->driver->draw (s, j, i, x, y, false);
if (face->overstrike)
font->driver->draw (s, j, i, x + 1, y, false);
}
}
}
static void
haiku_draw_image_relief (struct glyph_string *s)
{
int x1, y1, thick;
bool raised_p, top_p, bot_p, left_p, right_p;
int extra_x, extra_y;
struct haiku_rect r;
int x = s->x;
int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
struct face *face = s->face;
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
if (face->box != FACE_NO_BOX
&& s->first_glyph->left_box_line_p
&& s->slice.x == 0)
x += max (face->box_vertical_line_width, 0);
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
if (s->slice.x == 0)
x += s->img->hmargin;
if (s->slice.y == 0)
y += s->img->vmargin;
if (s->hl == DRAW_IMAGE_SUNKEN
|| s->hl == DRAW_IMAGE_RAISED)
{
if (s->face->id == TAB_BAR_FACE_ID)
thick = (tab_bar_button_relief < 0
? DEFAULT_TAB_BAR_BUTTON_RELIEF
: min (tab_bar_button_relief, 1000000));
else
thick = (tool_bar_button_relief < 0
? DEFAULT_TOOL_BAR_BUTTON_RELIEF
: min (tool_bar_button_relief, 1000000));
raised_p = s->hl == DRAW_IMAGE_RAISED;
}
else
{
thick = eabs (s->img->relief);
raised_p = s->img->relief > 0;
}
x1 = x + s->slice.width - 1;
y1 = y + s->slice.height - 1;
extra_x = extra_y = 0;
if (s->face->id == TAB_BAR_FACE_ID)
{
if (CONSP (Vtab_bar_button_margin)
&& FIXNUMP (XCAR (Vtab_bar_button_margin))
&& FIXNUMP (XCDR (Vtab_bar_button_margin)))
{
extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
}
else if (FIXNUMP (Vtab_bar_button_margin))
extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
}
if (s->face->id == TOOL_BAR_FACE_ID)
{
if (CONSP (Vtool_bar_button_margin)
&& FIXNUMP (XCAR (Vtool_bar_button_margin))
&& FIXNUMP (XCDR (Vtool_bar_button_margin)))
{
extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
}
else if (FIXNUMP (Vtool_bar_button_margin))
extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
}
top_p = bot_p = left_p = right_p = 0;
if (s->slice.x == 0)
x -= thick + extra_x, left_p = 1;
if (s->slice.y == 0)
y -= thick + extra_y, top_p = 1;
if (s->slice.x + s->slice.width == s->img->width)
x1 += thick + extra_x, right_p = 1;
if (s->slice.y + s->slice.height == s->img->height)
y1 += thick + extra_y, bot_p = 1;
get_glyph_string_clip_rect (s, &r);
haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p,
top_p, bot_p, left_p, right_p, &r, 0);
}
static void
haiku_draw_image_glyph_string (struct glyph_string *s)
{
struct face *face = s->face;
int box_line_hwidth = max (face->box_vertical_line_width, 0);
int box_line_vwidth = max (face->box_horizontal_line_width, 0);
int x, y;
int height, width;
height = s->height;
if (s->slice.y == 0)
height -= box_line_vwidth;
if (s->slice.y + s->slice.height >= s->img->height)
height -= box_line_vwidth;
width = s->background_width;
x = s->x;
if (s->first_glyph->left_box_line_p
&& s->slice.x == 0)
{
x += box_line_hwidth;
width -= box_line_hwidth;
}
y = s->y;
if (s->slice.y == 0)
y += box_line_vwidth;
void *view = FRAME_HAIKU_VIEW (s->f);
void *bitmap = s->img->pixmap;
s->stippled_p = face->stipple != 0;
BView_draw_lock (view);
BView_StartClip (view);
BView_SetHighColor (view, face->background);
BView_FillRectangle (view, x, y, width, height);
BView_EndClip (view);
BView_draw_unlock (view);
if (bitmap)
{
struct haiku_rect nr;
Emacs_Rectangle cr, ir, r;
get_glyph_string_clip_rect (s, &nr);
CONVERT_TO_EMACS_RECT (cr, nr);
x = s->x;
y = s->ybase - image_ascent (s->img, face, &s->slice);
if (s->slice.x == 0)
x += s->img->hmargin;
if (s->slice.y == 0)
y += s->img->vmargin;
if (face->box != FACE_NO_BOX
&& s->first_glyph->left_box_line_p
&& s->slice.x == 0)
x += max (face->box_vertical_line_width, 0);
ir.x = x;
ir.y = y;
ir.width = s->slice.width;
ir.height = s->slice.height;
r = ir;
void *mask = s->img->mask;
if (gui_intersect_rectangles (&cr, &ir, &r))
{
BView_draw_lock (view);
BView_StartClip (view);
haiku_clip_to_string (s);
if (s->img->have_be_transforms_p)
{
bitmap = BBitmap_transform_bitmap (bitmap,
s->img->mask,
face->background,
s->img->be_rotate,
s->img->width,
s->img->height);
mask = NULL;
}
BView_DrawBitmap (view, bitmap,
s->slice.x + r.x - x,
s->slice.y + r.y - y,
r.width, r.height,
r.x, r.y, r.width, r.height);
if (mask)
{
BView_DrawMask (mask, view,
s->slice.x + r.x - x,
s->slice.y + r.y - y,
r.width, r.height,
r.x, r.y, r.width, r.height,
face->background);
}
if (s->img->have_be_transforms_p)
BBitmap_free (bitmap);
BView_EndClip (view);
BView_draw_unlock (view);
}
if (s->hl == DRAW_CURSOR)
{
BView_draw_lock (view);
BView_StartClip (view);
BView_SetPenSize (view, 1);
BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
BView_StrokeRectangle (view, r.x, r.y, r.width, r.height);
BView_EndClip (view);
BView_draw_unlock (view);
}
}
if (s->img->relief
|| s->hl == DRAW_IMAGE_RAISED
|| s->hl == DRAW_IMAGE_SUNKEN)
haiku_draw_image_relief (s);
}
static void
haiku_draw_glyph_string (struct glyph_string *s)
{
block_input ();
prepare_face_for_display (s->f, s->face);
struct face *face = s->face;
if (face != s->face)
prepare_face_for_display (s->f, face);
if (s->next && s->right_overhang && !s->for_overlaps)
{
int width;
struct glyph_string *next;
for (width = 0, next = s->next;
next && width < s->right_overhang;
width += next->width, next = next->next)
if (next->first_glyph->type != IMAGE_GLYPH)
{
prepare_face_for_display (s->f, s->next->face);
haiku_start_clip (s->next);
haiku_clip_to_string (s->next);
if (next->first_glyph->type != STRETCH_GLYPH)
haiku_maybe_draw_background (s->next, 1);
else
haiku_draw_stretch_glyph_string (s->next);
next->num_clips = 0;
haiku_end_clip (s);
}
}
haiku_start_clip (s);
int box_filled_p = 0;
if (!s->for_overlaps && face->box != FACE_NO_BOX
&& (s->first_glyph->type == CHAR_GLYPH
|| s->first_glyph->type == COMPOSITE_GLYPH))
{
haiku_clip_to_string (s);
haiku_maybe_draw_background (s, 1);
box_filled_p = 1;
haiku_draw_string_box (s, 0);
}
else if (!s->clip_head && !s->clip_tail &&
((s->prev && s->left_overhang && s->prev->hl != s->hl) ||
(s->next && s->right_overhang && s->next->hl != s->hl)))
haiku_clip_to_string_exactly (s, s);
else
haiku_clip_to_string (s);
if (s->for_overlaps)
s->background_filled_p = 1;
switch (s->first_glyph->type)
{
case COMPOSITE_GLYPH:
if (s->for_overlaps || (s->cmp_from > 0
&& ! s->first_glyph->u.cmp.automatic))
s->background_filled_p = 1;
else
haiku_maybe_draw_background (s, 1);
haiku_draw_composite_glyph_string_foreground (s);
break;
case CHAR_GLYPH:
if (s->for_overlaps)
s->background_filled_p = 1;
else
haiku_maybe_draw_background (s, 0);
haiku_draw_glyph_string_foreground (s);
break;
case STRETCH_GLYPH:
haiku_draw_stretch_glyph_string (s);
break;
case IMAGE_GLYPH:
haiku_draw_image_glyph_string (s);
break;
case GLYPHLESS_GLYPH:
if (s->for_overlaps)
s->background_filled_p = 1;
else
haiku_maybe_draw_background (s, 1);
haiku_draw_glyphless_glyph_string_foreground (s);
break;
}
if (!box_filled_p && face->box != FACE_NO_BOX)
haiku_draw_string_box (s, 1);
else
haiku_draw_text_decoration (s, face, face->foreground, s->width, s->x);
if (!s->for_overlaps)
{
if (s->prev)
{
struct glyph_string *prev;
for (prev = s->prev; prev; prev = prev->prev)
if (prev->hl != s->hl
&& prev->x + prev->width + prev->right_overhang > s->x)
{
/* As prev was drawn while clipped to its own area, we
must draw the right_overhang part using s->hl now. */
enum draw_glyphs_face save = prev->hl;
struct face *save_face = prev->face;
prev->hl = s->hl;
prev->face = s->face;
haiku_start_clip (s);
haiku_clip_to_string_exactly (s, prev);
if (prev->first_glyph->type == CHAR_GLYPH)
haiku_draw_glyph_string_foreground (prev);
else
haiku_draw_composite_glyph_string_foreground (prev);
haiku_end_clip (s);
prev->hl = save;
prev->face = save_face;
prev->num_clips = 0;
}
}
if (s->next)
{
struct glyph_string *next;
for (next = s->next; next; next = next->next)
if (next->hl != s->hl
&& next->x - next->left_overhang < s->x + s->width)
{
/* As next will be drawn while clipped to its own area,
we must draw the left_overhang part using s->hl now. */
enum draw_glyphs_face save = next->hl;
struct face *save_face = next->face;
next->hl = s->hl;
next->face = s->face;
haiku_start_clip (s);
haiku_clip_to_string_exactly (s, next);
if (next->first_glyph->type == CHAR_GLYPH)
haiku_draw_glyph_string_foreground (next);
else
haiku_draw_composite_glyph_string_foreground (next);
haiku_end_clip (s);
next->background_filled_p = 0;
next->hl = save;
next->face = save_face;
next->clip_head = next;
next->num_clips = 0;
}
}
}
s->num_clips = 0;
haiku_end_clip (s);
unblock_input ();
}
static void
haiku_after_update_window_line (struct window *w,
struct glyph_row *desired_row)
{
eassert (w);
struct frame *f;
int width, height;
if (!desired_row->mode_line_p && !w->pseudo_window_p)
desired_row->redraw_fringe_bitmaps_p = true;
if (windows_or_buffers_changed
&& desired_row->full_width_p
&& (f = XFRAME (w->frame),
width = FRAME_INTERNAL_BORDER_WIDTH (f),
width != 0)
&& (height = desired_row->visible_height,
height > 0))
{
int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
int face_id =
!NILP (Vface_remapping_alist)
? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
: INTERNAL_BORDER_FACE_ID;
struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
block_input ();
if (face)
{
void *view = FRAME_HAIKU_VIEW (f);
BView_draw_lock (view);
BView_StartClip (view);
BView_SetHighColor (view, face->background_defaulted_p ?
FRAME_BACKGROUND_PIXEL (f) : face->background);
BView_FillRectangle (view, 0, y, width, height);
BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
y, width, height);
BView_EndClip (view);
BView_draw_unlock (view);
}
else
{
haiku_clear_frame_area (f, 0, y, width, height);
haiku_clear_frame_area (f, FRAME_PIXEL_WIDTH (f) - width,
y, width, height);
}
unblock_input ();
}
}
static void
haiku_set_window_size (struct frame *f, bool change_gravity,
int width, int height)
{
haiku_update_size_hints (f);
if (FRAME_HAIKU_WINDOW (f))
{
block_input ();
BWindow_resize (FRAME_HAIKU_WINDOW (f), width, height);
unblock_input ();
}
}
static void
haiku_draw_window_cursor (struct window *w,
struct glyph_row *glyph_row,
int x, int y,
enum text_cursor_kinds cursor_type,
int cursor_width, bool on_p, bool active_p)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct glyph *phys_cursor_glyph;
struct glyph *cursor_glyph;
void *view = FRAME_HAIKU_VIEW (f);
int fx, fy, h, cursor_height;
if (!on_p)
return;
if (cursor_type == NO_CURSOR)
{
w->phys_cursor_width = 0;
return;
}
w->phys_cursor_on_p = true;
w->phys_cursor_type = cursor_type;
phys_cursor_glyph = get_phys_cursor_glyph (w);
if (!phys_cursor_glyph)
{
if (glyph_row->exact_window_width_line_p
&& w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
{
glyph_row->cursor_in_fringe_p = 1;
draw_fringe_bitmap (w, glyph_row, 0);
}
return;
}
get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
if (cursor_type == BAR_CURSOR)
{
if (cursor_width < 1)
cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
if (cursor_width < w->phys_cursor_width)
w->phys_cursor_width = cursor_width;
}
else if (cursor_type == HBAR_CURSOR)
{
cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
if (cursor_height > glyph_row->height)
cursor_height = glyph_row->height;
if (h > cursor_height)
fy += h - cursor_height;
h = cursor_height;
}
BView_draw_lock (view);
BView_StartClip (view);
BView_SetHighColor (view, FRAME_CURSOR_COLOR (f).pixel);
haiku_clip_to_row (w, glyph_row, TEXT_AREA);
switch (cursor_type)
{
default:
case DEFAULT_CURSOR:
case NO_CURSOR:
break;
case HBAR_CURSOR:
BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
break;
case BAR_CURSOR:
cursor_glyph = get_phys_cursor_glyph (w);
if (cursor_glyph->resolved_level & 1)
BView_FillRectangle (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width,
fy, w->phys_cursor_width, h);
else
BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
break;
case HOLLOW_BOX_CURSOR:
if (phys_cursor_glyph->type != IMAGE_GLYPH)
{
BView_SetPenSize (view, 1);
BView_StrokeRectangle (view, fx, fy, w->phys_cursor_width, h);
}
else
draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
break;
case FILLED_BOX_CURSOR:
draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
}
BView_EndClip (view);
BView_draw_unlock (view);
}
static void
haiku_show_hourglass (struct frame *f)
{
if (FRAME_OUTPUT_DATA (f)->hourglass_p)
return;
block_input ();
FRAME_OUTPUT_DATA (f)->hourglass_p = 1;
if (FRAME_HAIKU_VIEW (f))
BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
FRAME_OUTPUT_DATA (f)->hourglass_cursor);
unblock_input ();
}
static void
haiku_hide_hourglass (struct frame *f)
{
if (!FRAME_OUTPUT_DATA (f)->hourglass_p)
return;
block_input ();
FRAME_OUTPUT_DATA (f)->hourglass_p = 0;
if (FRAME_HAIKU_VIEW (f))
BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
FRAME_OUTPUT_DATA (f)->current_cursor);
unblock_input ();
}
static void
haiku_compute_glyph_string_overhangs (struct glyph_string *s)
{
if (s->cmp == NULL
&& (s->first_glyph->type == CHAR_GLYPH
|| s->first_glyph->type == COMPOSITE_GLYPH))
{
struct font_metrics metrics;
if (s->first_glyph->type == CHAR_GLYPH)
{
struct font *font = s->font;
font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
}
else
{
Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
}
s->right_overhang = (metrics.rbearing > metrics.width
? metrics.rbearing - metrics.width : 0);
s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
}
else if (s->cmp)
{
s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
s->left_overhang = - s->cmp->lbearing;
}
}
static void
haiku_draw_vertical_window_border (struct window *w,
int x, int y_0, int y_1)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct face *face;
face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
void *view = FRAME_HAIKU_VIEW (f);
BView_draw_lock (view);
BView_StartClip (view);
if (face)
BView_SetHighColor (view, face->foreground);
BView_StrokeLine (view, x, y_0, x, y_1);
BView_EndClip (view);
BView_draw_unlock (view);
}
static void
haiku_set_scroll_bar_default_width (struct frame *f)
{
int unit = FRAME_COLUMN_WIDTH (f);
FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1;
FRAME_CONFIG_SCROLL_BAR_COLS (f) =
(FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
}
static void
haiku_set_scroll_bar_default_height (struct frame *f)
{
int height = FRAME_LINE_HEIGHT (f);
FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1;
FRAME_CONFIG_SCROLL_BAR_LINES (f) =
(FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
}
static void
haiku_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
struct face *face_first
= FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
struct face *face_last
= FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
unsigned long color_first = (face_first
? face_first->foreground
: FRAME_FOREGROUND_PIXEL (f));
unsigned long color_last = (face_last
? face_last->foreground
: FRAME_FOREGROUND_PIXEL (f));
void *view = FRAME_HAIKU_VIEW (f);
BView_draw_lock (view);
BView_StartClip (view);
if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
/* A vertical divider, at least three pixels wide: Draw first and
last pixels differently. */
{
BView_SetHighColor (view, color_first);
BView_StrokeLine (view, x0, y0, x0, y1 - 1);
BView_SetHighColor (view, color);
BView_FillRectangle (view, x0 + 1, y0, x1 - x0 - 2, y1 - y0);
BView_SetHighColor (view, color_last);
BView_StrokeLine (view, x1 - 1, y0, x1 - 1, y1 - 1);
}
else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
/* A horizontal divider, at least three pixels high: Draw first and
last pixels differently. */
{
BView_SetHighColor (view, color_first);
BView_StrokeLine (f, x0, y0, x1 - 1, y0);
BView_SetHighColor (view, color);
BView_FillRectangle (view, x0, y0 + 1, x1 - x0, y1 - y0 - 2);
BView_SetHighColor (view, color_last);
BView_StrokeLine (view, x0, y1, x1 - 1, y1);
}
else
{
BView_SetHighColor (view, color);
BView_FillRectangleAbs (view, x0, y0, x1, y1);
}
BView_EndClip (view);
BView_draw_unlock (view);
}
static void
haiku_condemn_scroll_bars (struct frame *frame)
{
if (!NILP (FRAME_SCROLL_BARS (frame)))
{
if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
{
/* Prepend scrollbars to already condemned ones. */
Lisp_Object last = FRAME_SCROLL_BARS (frame);
while (!NILP (XSCROLL_BAR (last)->next))
last = XSCROLL_BAR (last)->next;
XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
}
fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
fset_scroll_bars (frame, Qnil);
}
}
static void
haiku_redeem_scroll_bar (struct window *w)
{
struct scroll_bar *bar;
Lisp_Object barobj;
struct frame *f;
if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
{
bar = XSCROLL_BAR (w->vertical_scroll_bar);
/* Unlink it from the condemned list. */
f = XFRAME (WINDOW_FRAME (w));
if (NILP (bar->prev))
{
/* If the prev pointer is nil, it must be the first in one of
the lists. */
if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
/* It's not condemned. Everything's fine. */
goto horizontal;
else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
w->vertical_scroll_bar))
fset_condemned_scroll_bars (f, bar->next);
else
/* If its prev pointer is nil, it must be at the front of
one or the other! */
emacs_abort ();
}
else
XSCROLL_BAR (bar->prev)->next = bar->next;
if (! NILP (bar->next))
XSCROLL_BAR (bar->next)->prev = bar->prev;
bar->next = FRAME_SCROLL_BARS (f);
bar->prev = Qnil;
XSETVECTOR (barobj, bar);
fset_scroll_bars (f, barobj);
if (! NILP (bar->next))
XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
}
horizontal:
if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
{
bar = XSCROLL_BAR (w->horizontal_scroll_bar);
/* Unlink it from the condemned list. */
f = XFRAME (WINDOW_FRAME (w));
if (NILP (bar->prev))
{
/* If the prev pointer is nil, it must be the first in one of
the lists. */
if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
/* It's not condemned. Everything's fine. */
return;
else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
w->horizontal_scroll_bar))
fset_condemned_scroll_bars (f, bar->next);
else
/* If its prev pointer is nil, it must be at the front of
one or the other! */
emacs_abort ();
}
else
XSCROLL_BAR (bar->prev)->next = bar->next;
if (! NILP (bar->next))
XSCROLL_BAR (bar->next)->prev = bar->prev;
bar->next = FRAME_SCROLL_BARS (f);
bar->prev = Qnil;
XSETVECTOR (barobj, bar);
fset_scroll_bars (f, barobj);
if (! NILP (bar->next))
XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
}
}
static void
haiku_judge_scroll_bars (struct frame *f)
{
Lisp_Object bar, next;
bar = FRAME_CONDEMNED_SCROLL_BARS (f);
/* Clear out the condemned list now so we won't try to process any
more events on the hapless scroll bars. */
fset_condemned_scroll_bars (f, Qnil);
for (; ! NILP (bar); bar = next)
{
struct scroll_bar *b = XSCROLL_BAR (bar);
haiku_scroll_bar_remove (b);
next = b->next;
b->next = b->prev = Qnil;
}
/* Now there should be no references to the condemned scroll bars,
and they should get garbage-collected. */
}
static struct scroll_bar *
haiku_scroll_bar_create (struct window *w, int left, int top,
int width, int height, bool horizontal_p)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
Lisp_Object barobj;
void *sb = NULL;
void *vw = FRAME_HAIKU_VIEW (f);
block_input ();
struct scroll_bar *bar
= ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
XSETWINDOW (bar->window, w);
bar->top = top;
bar->left = left;
bar->width = width;
bar->height = height;
bar->position = 0;
bar->total = 0;
bar->dragging = 0;
bar->update = -1;
bar->horizontal = horizontal_p;
sb = BScrollBar_make_for_view (vw, horizontal_p,
left, top, left + width - 1,
top + height - 1, bar);
BView_publish_scroll_bar (vw, left, top, width, height);
bar->next = FRAME_SCROLL_BARS (f);
bar->prev = Qnil;
bar->scroll_bar = sb;
XSETVECTOR (barobj, bar);
fset_scroll_bars (f, barobj);
if (!NILP (bar->next))
XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
unblock_input ();
return bar;
}
static void
haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
{
eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
Lisp_Object barobj;
struct scroll_bar *bar;
int top, height, left, width;
int window_x, window_width;
/* Get window dimensions. */
window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
left = window_x;
width = window_width;
top = WINDOW_SCROLL_BAR_AREA_Y (w);
height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
block_input ();
if (NILP (w->horizontal_scroll_bar))
{
bar = haiku_scroll_bar_create (w, left, top, width, height, true);
BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
bar->update = position;
bar->position = position;
bar->total = whole;
}
else
{
bar = XSCROLL_BAR (w->horizontal_scroll_bar);
if (bar->left != left || bar->top != top ||
bar->width != width || bar->height != height)
{
void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
BView_forget_scroll_bar (view, bar->left, bar->top,
bar->width, bar->height);
BView_move_frame (bar->scroll_bar, left, top,
left + width - 1, top + height - 1);
BView_publish_scroll_bar (view, left, top, width, height);
bar->left = left;
bar->top = top;
bar->width = width;
bar->height = height;
}
if (!bar->dragging)
{
BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
BView_invalidate (bar->scroll_bar);
}
}
bar->position = position;
bar->total = whole;
XSETVECTOR (barobj, bar);
wset_horizontal_scroll_bar (w, barobj);
unblock_input ();
}
static void
haiku_set_vertical_scroll_bar (struct window *w,
int portion, int whole, int position)
{
eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
Lisp_Object barobj;
struct scroll_bar *bar;
int top, height, left, width;
int window_y, window_height;
/* Get window dimensions. */
window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
top = window_y;
height = window_height;
/* Compute the left edge and the width of the scroll bar area. */
left = WINDOW_SCROLL_BAR_AREA_X (w);
width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
block_input ();
if (NILP (w->vertical_scroll_bar))
{
bar = haiku_scroll_bar_create (w, left, top, width, height, false);
BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
bar->position = position;
bar->total = whole;
}
else
{
bar = XSCROLL_BAR (w->vertical_scroll_bar);
if (bar->left != left || bar->top != top ||
bar->width != width || bar->height != height)
{
void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
BView_forget_scroll_bar (view, bar->left, bar->top,
bar->width, bar->height);
BView_move_frame (bar->scroll_bar, left, top,
left + width - 1, top + height - 1);
flush_frame (WINDOW_XFRAME (w));
BView_publish_scroll_bar (view, left, top, width, height);
bar->left = left;
bar->top = top;
bar->width = width;
bar->height = height;
}
if (!bar->dragging)
{
BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
bar->update = position;
BView_invalidate (bar->scroll_bar);
}
}
bar->position = position;
bar->total = whole;
XSETVECTOR (barobj, bar);
wset_vertical_scroll_bar (w, barobj);
unblock_input ();
}
static void
haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
struct draw_fringe_bitmap_params *p)
{
void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w)));
struct face *face = p->face;
BView_draw_lock (view);
BView_StartClip (view);
haiku_clip_to_row (w, row, ANY_AREA);
if (p->bx >= 0 && !p->overlay_p)
{
BView_SetHighColor (view, face->background);
BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
}
if (p->which && p->which < fringe_bitmap_fillptr)
{
void *bitmap = fringe_bmps[p->which];
uint32_t col;
if (!p->cursor_p)
col = face->foreground;
else if (p->overlay_p)
col = face->background;
else
col = FRAME_CURSOR_COLOR (XFRAME (WINDOW_FRAME (w))).pixel;
if (!p->overlay_p)
{
BView_SetHighColor (view, face->background);
BView_FillRectangle (view, p->x, p->y, p->wd, p->h);
}
BView_SetLowColor (view, col);
BView_DrawBitmapWithEraseOp (view, bitmap, p->x, p->y, p->wd, p->h);
}
BView_EndClip (view);
BView_draw_unlock (view);
}
static void
haiku_define_fringe_bitmap (int which, unsigned short *bits,
int h, int wd)
{
if (which >= fringe_bitmap_fillptr)
{
int i = fringe_bitmap_fillptr;
fringe_bitmap_fillptr = which + 20;
fringe_bmps = !i ? xmalloc (fringe_bitmap_fillptr * sizeof (void *)) :
xrealloc (fringe_bmps, fringe_bitmap_fillptr * sizeof (void *));
while (i < fringe_bitmap_fillptr)
fringe_bmps[i++] = NULL;
}
fringe_bmps[which] = BBitmap_new (wd, h, 1);
BBitmap_import_mono_bits (fringe_bmps[which], bits, wd, h);
}
static void
haiku_destroy_fringe_bitmap (int which)
{
if (which >= fringe_bitmap_fillptr)
return;
if (fringe_bmps[which])
BBitmap_free (fringe_bmps[which]);
fringe_bmps[which] = NULL;
}
static void
haiku_scroll_run (struct window *w, struct run *run)
{
struct frame *f = XFRAME (w->frame);
void *view = FRAME_HAIKU_VIEW (f);
int x, y, width, height, from_y, to_y, bottom_y;
window_box (w, ANY_AREA, &x, &y, &width, &height);
from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
bottom_y = y + height;
if (to_y < from_y)
{
/* Scrolling up. Make sure we don't copy part of the mode
line at the bottom. */
if (from_y + run->height > bottom_y)
height = bottom_y - from_y;
else
height = run->height;
}
else
{
/* Scrolling down. Make sure we don't copy over the mode line.
at the bottom. */
if (to_y + run->height > bottom_y)
height = bottom_y - to_y;
else
height = run->height;
}
if (!height)
return;
block_input ();
gui_clear_cursor (w);
BView_draw_lock (view);
#ifdef USE_BE_CAIRO
if (EmacsView_double_buffered_p (view))
{
#endif
BView_StartClip (view);
BView_CopyBits (view, x, from_y, width, height,
x, to_y, width, height);
BView_EndClip (view);
#ifdef USE_BE_CAIRO
}
else
{
EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f));
cairo_surface_t *surface = FRAME_CR_SURFACE (f);
cairo_surface_t *s
= cairo_surface_create_similar (surface,
cairo_surface_get_content (surface),
width, height);
cairo_t *cr = cairo_create (s);
if (surface)
{
cairo_set_source_surface (cr, surface, -x, -from_y);
cairo_paint (cr);
cairo_destroy (cr);
cr = haiku_begin_cr_clip (f, NULL);
cairo_save (cr);
cairo_set_source_surface (cr, s, x, to_y);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle (cr, x, to_y, width, height);
cairo_fill (cr);
cairo_restore (cr);
cairo_surface_destroy (s);
haiku_end_cr_clip (cr);
}
EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
}
#endif
BView_draw_unlock (view);
unblock_input ();
}
static void
haiku_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
Time *timestamp)
{
if (!fp)
return;
block_input ();
Lisp_Object frame, tail;
struct frame *f1 = NULL;
FOR_EACH_FRAME (tail, frame)
XFRAME (frame)->mouse_moved = false;
if (gui_mouse_grabbed (x_display_list) && !EQ (track_mouse, Qdropping))
f1 = x_display_list->last_mouse_frame;
if (!f1 || FRAME_TOOLTIP_P (f1))
f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (x_display_list))
? x_display_list->last_mouse_frame
: NULL);
if (!f1 && insist > 0)
f1 = SELECTED_FRAME ();
if (!f1 || (!FRAME_HAIKU_P (f1) && (insist > 0)))
FOR_EACH_FRAME (tail, frame)
if (FRAME_HAIKU_P (XFRAME (frame)) &&
!FRAME_TOOLTIP_P (XFRAME (frame)))
f1 = XFRAME (frame);
if (FRAME_TOOLTIP_P (f1))
f1 = NULL;
if (f1 && FRAME_HAIKU_P (f1))
{
int sx, sy;
void *view = FRAME_HAIKU_VIEW (f1);
if (view)
{
BView_get_mouse (view, &sx, &sy);
remember_mouse_glyph (f1, sx, sy, &x_display_list->last_mouse_glyph);
x_display_list->last_mouse_glyph_frame = f1;
*bar_window = Qnil;
*part = scroll_bar_above_handle;
*fp = f1;
*timestamp = x_display_list->last_mouse_movement_time;
XSETINT (*x, sx);
XSETINT (*y, sy);
}
}
unblock_input ();
}
static void
haiku_flush (struct frame *f)
{
if (FRAME_VISIBLE_P (f))
BWindow_Flush (FRAME_HAIKU_WINDOW (f));
}
static void
haiku_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
{
if (f->tooltip)
return;
block_input ();
if (!f->pointer_invisible && FRAME_HAIKU_VIEW (f)
&& !FRAME_OUTPUT_DATA (f)->hourglass_p)
BView_set_view_cursor (FRAME_HAIKU_VIEW (f), cursor);
unblock_input ();
FRAME_OUTPUT_DATA (f)->current_cursor = cursor;
}
static void
haiku_update_window_end (struct window *w, bool cursor_on_p,
bool mouse_face_overwritten_p)
{
}
static void
haiku_default_font_parameter (struct frame *f, Lisp_Object parms)
{
struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
RES_TYPE_STRING);
Lisp_Object font = Qnil;
if (EQ (font_param, Qunbound))
font_param = Qnil;
if (NILP (font_param))
{
/* System font should take precedence over X resources. We suggest this
regardless of font-use-system-font because .emacs may not have been
read yet. */
struct haiku_font_pattern ptn;
ptn.specified = 0;
if (f->tooltip)
BFont_populate_plain_family (&ptn);
else
BFont_populate_fixed_family (&ptn);
if (ptn.specified & FSPEC_FAMILY)
font = font_open_by_name (f, build_unibyte_string (ptn.family));
}
if (NILP (font))
font = !NILP (font_param) ? font_param
: gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font",
RES_TYPE_STRING);
if (! FONTP (font) && ! STRINGP (font))
{
const char **names = (const char *[]) { "monospace-12",
"Noto Sans Mono-12",
"Source Code Pro-12",
NULL };
int i;
for (i = 0; names[i]; i++)
{
font
= font_open_by_name (f, build_unibyte_string (names[i]));
if (!NILP (font))
break;
}
if (NILP (font))
error ("No suitable font was found");
}
else if (!NILP (font_param))
{
/* Remember the explicit font parameter, so we can re-apply it
after we've applied the `default' face settings. */
AUTO_FRAME_ARG (arg, Qfont_parameter, font_param);
gui_set_frame_parameters (f, arg);
}
gui_default_parameter (f, parms, Qfont, font, "font", "Font",
RES_TYPE_STRING);
}
static struct redisplay_interface haiku_redisplay_interface =
{
haiku_frame_parm_handlers,
gui_produce_glyphs,
gui_write_glyphs,
gui_insert_glyphs,
gui_clear_end_of_line,
haiku_scroll_run,
haiku_after_update_window_line,
NULL,
haiku_update_window_end,
haiku_flush,
gui_clear_window_mouse_face,
gui_get_glyph_overhangs,
gui_fix_overlapping_area,
haiku_draw_fringe_bitmap,
haiku_define_fringe_bitmap,
haiku_destroy_fringe_bitmap,
haiku_compute_glyph_string_overhangs,
haiku_draw_glyph_string,
haiku_define_frame_cursor,
haiku_clear_frame_area,
haiku_clear_under_internal_border,
haiku_draw_window_cursor,
haiku_draw_vertical_window_border,
haiku_draw_window_divider,
0, /* shift glyphs for insert */
haiku_show_hourglass,
haiku_hide_hourglass,
haiku_default_font_parameter,
};
static void
haiku_make_fullscreen_consistent (struct frame *f)
{
Lisp_Object lval = get_frame_param (f, Qfullscreen);
if (!EQ (lval, Qmaximized) && FRAME_OUTPUT_DATA (f)->zoomed_p)
lval = Qmaximized;
else if (EQ (lval, Qmaximized) && !FRAME_OUTPUT_DATA (f)->zoomed_p)
lval = Qnil;
store_frame_param (f, Qfullscreen, lval);
}
static void
flush_dirty_back_buffers (void)
{
block_input ();
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_LIVE_P (f) &&
FRAME_HAIKU_P (f) &&
FRAME_HAIKU_WINDOW (f) &&
!FRAME_GARBAGED_P (f) &&
!buffer_flipping_blocked_p () &&
FRAME_DIRTY_P (f))
haiku_flip_buffers (f);
}
unblock_input ();
}
static int
haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
{
block_input ();
int message_count = 0;
static void *buf = NULL;
ssize_t b_size;
struct unhandled_event *unhandled_events = NULL;
int button_or_motion_p;
int need_flush = 0;
if (!buf)
buf = xmalloc (200);
haiku_read_size (&b_size);
while (b_size >= 0)
{
enum haiku_event_type type;
struct input_event inev, inev2;
if (b_size > 200)
emacs_abort ();
EVENT_INIT (inev);
EVENT_INIT (inev2);
inev.kind = NO_EVENT;
inev2.kind = NO_EVENT;
inev.arg = Qnil;
inev2.arg = Qnil;
button_or_motion_p = 0;
haiku_read (&type, buf, b_size);
switch (type)
{
case QUIT_REQUESTED:
{
struct haiku_quit_requested_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
inev.kind = DELETE_WINDOW_EVENT;
XSETFRAME (inev.frame_or_window, f);
break;
}
case FRAME_RESIZED:
{
struct haiku_resize_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
int width = lrint (b->px_widthf);
int height = lrint (b->px_heightf);
BView_draw_lock (FRAME_HAIKU_VIEW (f));
BView_resize_to (FRAME_HAIKU_VIEW (f), width, height);
BView_draw_unlock (FRAME_HAIKU_VIEW (f));
if (width != FRAME_PIXEL_WIDTH (f)
|| height != FRAME_PIXEL_HEIGHT (f)
|| (f->new_size_p
&& ((f->new_width >= 0 && width != f->new_width)
|| (f->new_height >= 0 && height != f->new_height))))
{
change_frame_size (f, width, height, false, true, false);
SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
haiku_clear_under_internal_border (f);
}
if (FRAME_OUTPUT_DATA (f)->pending_zoom_width != width ||
FRAME_OUTPUT_DATA (f)->pending_zoom_height != height)
{
FRAME_OUTPUT_DATA (f)->zoomed_p = 0;
haiku_make_fullscreen_consistent (f);
}
else
{
FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
FRAME_OUTPUT_DATA (f)->pending_zoom_width = INT_MIN;
FRAME_OUTPUT_DATA (f)->pending_zoom_height = INT_MIN;
}
break;
}
case FRAME_EXPOSED:
{
struct haiku_expose_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
expose_frame (f, b->x, b->y, b->width, b->height);
haiku_clear_under_internal_border (f);
break;
}
case KEY_DOWN:
{
struct haiku_key_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
int non_ascii_p;
if (!f)
continue;
inev.code = b->unraw_mb_char;
BMapKey (b->kc, &non_ascii_p, &inev.code);
if (non_ascii_p)
inev.kind = NON_ASCII_KEYSTROKE_EVENT;
else
inev.kind = inev.code > 127 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT :
ASCII_KEYSTROKE_EVENT;
inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
XSETFRAME (inev.frame_or_window, f);
break;
}
case ACTIVATION:
{
struct haiku_activation_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
if ((x_display_list->focus_event_frame != f && b->activated_p) ||
(x_display_list->focus_event_frame == f && !b->activated_p))
{
haiku_new_focus_frame (b->activated_p ? f : NULL);
if (b->activated_p)
x_display_list->focus_event_frame = f;
else
x_display_list->focus_event_frame = NULL;
inev.kind = b->activated_p ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
XSETFRAME (inev.frame_or_window, f);
}
break;
}
case MOUSE_MOTION:
{
struct haiku_mouse_motion_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
Lisp_Object frame;
XSETFRAME (frame, f);
x_display_list->last_mouse_movement_time = time (NULL);
button_or_motion_p = 1;
if (b->just_exited_p)
{
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
if (f == hlinfo->mouse_face_mouse_frame)
{
/* If we move outside the frame, then we're
certainly no longer on any text in the frame. */
clear_mouse_face (hlinfo);
hlinfo->mouse_face_mouse_frame = 0;
}
haiku_new_focus_frame (x_display_list->focused_frame);
help_echo_string = Qnil;
gen_help_event (Qnil, frame, Qnil, Qnil, 0);
}
else
{
struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
struct haiku_rect r = dpyinfo->last_mouse_glyph;
dpyinfo->last_mouse_motion_x = b->x;
dpyinfo->last_mouse_motion_y = b->y;
dpyinfo->last_mouse_motion_frame = f;
previous_help_echo_string = help_echo_string;
help_echo_string = Qnil;
if (f != dpyinfo->last_mouse_glyph_frame
|| b->x < r.x || b->x >= r.x + r.width
|| b->y < r.y || b->y >= r.y + r.height)
{
f->mouse_moved = true;
dpyinfo->last_mouse_scroll_bar = NULL;
note_mouse_highlight (f, b->x, b->y);
remember_mouse_glyph (f, b->x, b->y,
&FRAME_DISPLAY_INFO (f)->last_mouse_glyph);
dpyinfo->last_mouse_glyph_frame = f;
gen_help_event (help_echo_string, frame, help_echo_window,
help_echo_object, help_echo_pos);
}
if (MOUSE_HL_INFO (f)->mouse_face_hidden)
{
MOUSE_HL_INFO (f)->mouse_face_hidden = 0;
clear_mouse_face (MOUSE_HL_INFO (f));
}
if (!NILP (Vmouse_autoselect_window))
{
static Lisp_Object last_mouse_window;
Lisp_Object window = window_from_coordinates (f, b->x, b->y, 0, 0, 0);
if (WINDOWP (window)
&& !EQ (window, last_mouse_window)
&& !EQ (window, selected_window)
&& (!NILP (focus_follows_mouse)
|| (EQ (XWINDOW (window)->frame,
XWINDOW (selected_window)->frame))))
{
inev.kind = SELECT_WINDOW_EVENT;
inev.frame_or_window = window;
}
last_mouse_window = window;
}
}
break;
}
case BUTTON_UP:
case BUTTON_DOWN:
{
struct haiku_button_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
Lisp_Object tab_bar_arg = Qnil;
int tab_bar_p = 0, tool_bar_p = 0;
if (!f)
continue;
struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
x_display_list->last_mouse_glyph_frame = 0;
x_display_list->last_mouse_movement_time = time (NULL);
button_or_motion_p = 1;
/* Is this in the tab-bar? */
if (WINDOWP (f->tab_bar_window)
&& WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
{
Lisp_Object window;
int x = b->x;
int y = b->y;
window = window_from_coordinates (f, x, y, 0, true, true);
tab_bar_p = EQ (window, f->tab_bar_window);
if (tab_bar_p)
{
tab_bar_arg = handle_tab_bar_click
(f, x, y, type == BUTTON_DOWN, inev.modifiers);
need_flush = 1;
}
}
if (WINDOWP (f->tool_bar_window)
&& WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
{
Lisp_Object window;
int x = b->x;
int y = b->y;
window = window_from_coordinates (f, x, y, 0, true, true);
tool_bar_p = EQ (window, f->tool_bar_window);
if (tool_bar_p)
{
handle_tool_bar_click
(f, x, y, type == BUTTON_DOWN, inev.modifiers);
need_flush = 1;
}
}
if (type == BUTTON_UP)
{
inev.modifiers |= up_modifier;
dpyinfo->grabbed &= ~(1 << b->btn_no);
}
else
{
inev.modifiers |= down_modifier;
dpyinfo->last_mouse_frame = f;
dpyinfo->grabbed |= (1 << b->btn_no);
if (f && !tab_bar_p)
f->last_tab_bar_item = -1;
if (f && !tool_bar_p)
f->last_tool_bar_item = -1;
}
if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
inev.kind = MOUSE_CLICK_EVENT;
inev.arg = tab_bar_arg;
inev.code = b->btn_no;
f->mouse_moved = false;
XSETINT (inev.x, b->x);
XSETINT (inev.y, b->y);
XSETFRAME (inev.frame_or_window, f);
break;
}
case ICONIFICATION:
{
struct haiku_iconification_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
if (!b->iconified_p)
{
SET_FRAME_VISIBLE (f, 1);
SET_FRAME_ICONIFIED (f, 0);
inev.kind = DEICONIFY_EVENT;
/* Haiku doesn't expose frames on deiconification, but
if we are double-buffered, the previous screen
contents should have been preserved. */
if (!EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)))
{
SET_FRAME_GARBAGED (f);
expose_frame (f, 0, 0, 0, 0);
}
}
else
{
SET_FRAME_VISIBLE (f, 0);
SET_FRAME_ICONIFIED (f, 1);
inev.kind = ICONIFY_EVENT;
}
XSETFRAME (inev.frame_or_window, f);
break;
}
case MOVE_EVENT:
{
struct haiku_move_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
if (FRAME_OUTPUT_DATA (f)->pending_zoom_x != b->x ||
FRAME_OUTPUT_DATA (f)->pending_zoom_y != b->y)
FRAME_OUTPUT_DATA (f)->zoomed_p = 0;
else
{
FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
FRAME_OUTPUT_DATA (f)->pending_zoom_x = INT_MIN;
FRAME_OUTPUT_DATA (f)->pending_zoom_y = INT_MIN;
}
if (FRAME_PARENT_FRAME (f))
haiku_coords_from_parent (f, &b->x, &b->y);
if (b->x != f->left_pos || b->y != f->top_pos)
{
inev.kind = MOVE_FRAME_EVENT;
XSETINT (inev.x, b->x);
XSETINT (inev.y, b->y);
f->left_pos = b->x;
f->top_pos = b->y;
struct frame *p;
if ((p = FRAME_PARENT_FRAME (f)))
{
void *window = FRAME_HAIKU_WINDOW (p);
EmacsWindow_move_weak_child (window, b->window, b->x, b->y);
}
XSETFRAME (inev.frame_or_window, f);
}
haiku_make_fullscreen_consistent (f);
break;
}
case SCROLL_BAR_VALUE_EVENT:
{
struct haiku_scroll_bar_value_event *b = buf;
struct scroll_bar *bar = b->scroll_bar;
struct window *w = XWINDOW (bar->window);
if (bar->update != -1)
{
bar->update = -1;
break;
}
if (bar->position != b->position)
{
inev.kind = bar->horizontal ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT :
SCROLL_BAR_CLICK_EVENT;
inev.part = bar->horizontal ?
scroll_bar_horizontal_handle : scroll_bar_handle;
XSETINT (inev.x, b->position);
XSETINT (inev.y, bar->total);
XSETWINDOW (inev.frame_or_window, w);
}
break;
}
case SCROLL_BAR_DRAG_EVENT:
{
struct haiku_scroll_bar_drag_event *b = buf;
struct scroll_bar *bar = b->scroll_bar;
bar->dragging = b->dragging_p;
if (!b->dragging_p && bar->horizontal)
set_horizontal_scroll_bar (XWINDOW (bar->window));
else if (!b->dragging_p)
set_vertical_scroll_bar (XWINDOW (bar->window));
break;
}
case WHEEL_MOVE_EVENT:
{
struct haiku_wheel_move_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
int x, y;
static float px = 0.0f, py = 0.0f;
if (!f)
continue;
BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y);
inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
inev2.modifiers = inev.modifiers;
if (signbit (px) != signbit (b->delta_x))
px = 0;
if (signbit (py) != signbit (b->delta_y))
py = 0;
px += (b->delta_x
* powf (FRAME_PIXEL_HEIGHT (f), 2.0f / 3.0f));
py += (b->delta_y
* powf (FRAME_PIXEL_HEIGHT (f), 2.0f / 3.0f));
if (fabsf (py) >= FRAME_LINE_HEIGHT (f)
|| fabsf (px) >= FRAME_COLUMN_WIDTH (f)
|| !mwheel_coalesce_scroll_events)
{
inev.kind = (fabsf (px) > fabsf (py)
? HORIZ_WHEEL_EVENT
: WHEEL_EVENT);
inev.code = 0;
XSETINT (inev.x, x);
XSETINT (inev.y, y);
inev.arg = list3 (Qnil, make_float (-px),
make_float (-py));
XSETFRAME (inev.frame_or_window, f);
inev.modifiers |= (signbit (inev.kind == HORIZ_WHEEL_EVENT
? px : py)
? up_modifier
: down_modifier);
py = 0.0f;
px = 0.0f;
}
break;
}
case MENU_BAR_RESIZE:
{
struct haiku_menu_bar_resize_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
continue;
int old_height = FRAME_MENU_BAR_HEIGHT (f);
FRAME_MENU_BAR_HEIGHT (f) = b->height + 1;
FRAME_MENU_BAR_LINES (f) =
(b->height + FRAME_LINE_HEIGHT (f)) / FRAME_LINE_HEIGHT (f);
if (old_height != b->height)
{
adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines);
haiku_clear_under_internal_border (f);
}
break;
}
case MENU_BAR_OPEN:
case MENU_BAR_CLOSE:
{
struct haiku_menu_bar_state_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
continue;
if (type == MENU_BAR_OPEN)
{
if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
{
BView_draw_lock (FRAME_HAIKU_VIEW (f));
/* This shouldn't be here, but nsmenu does it, so
it should probably be safe. */
int was_waiting_for_input_p = waiting_for_input;
if (waiting_for_input)
waiting_for_input = 0;
set_frame_menubar (f, 1);
waiting_for_input = was_waiting_for_input_p;
BView_draw_unlock (FRAME_HAIKU_VIEW (f));
}
FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
popup_activated_p += 1;
}
else
{
if (!popup_activated_p)
emacs_abort ();
if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
{
FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0;
popup_activated_p -= 1;
}
}
break;
}
case MENU_BAR_SELECT_EVENT:
{
struct haiku_menu_bar_select_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
continue;
if (FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
find_and_call_menu_selection (f, f->menu_bar_items_used,
f->menu_bar_vector, b->ptr);
break;
}
case FILE_PANEL_EVENT:
{
if (!popup_activated_p)
continue;
struct unhandled_event *ev = xmalloc (sizeof *ev);
ev->next = unhandled_events;
ev->type = type;
memcpy (&ev->buffer, buf, 200);
unhandled_events = ev;
break;
}
case MENU_BAR_HELP_EVENT:
{
struct haiku_menu_bar_help_event *b = buf;
if (!popup_activated_p)
continue;
struct frame *f = haiku_window_to_frame (b->window);
if (!f || !FRAME_EXTERNAL_MENU_BAR (f) ||
!FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
continue;
run_menu_bar_help_event (f, b->mb_idx);
break;
}
case ZOOM_EVENT:
{
struct haiku_zoom_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
FRAME_OUTPUT_DATA (f)->pending_zoom_height = b->height;
FRAME_OUTPUT_DATA (f)->pending_zoom_width = b->width;
FRAME_OUTPUT_DATA (f)->pending_zoom_x = b->x;
FRAME_OUTPUT_DATA (f)->pending_zoom_y = b->y;
FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
haiku_make_fullscreen_consistent (f);
break;
}
case REFS_EVENT:
{
struct haiku_refs_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
inev.kind = DRAG_N_DROP_EVENT;
inev.arg = build_string_from_utf8 (b->ref);
XSETINT (inev.x, b->x);
XSETINT (inev.y, b->y);
XSETFRAME (inev.frame_or_window, f);
/* There should be no problem with calling free here.
free on Haiku is thread-safe. */
free (b->ref);
break;
}
case APP_QUIT_REQUESTED_EVENT:
case KEY_UP:
default:
break;
}
haiku_read_size (&b_size);
if (inev.kind != NO_EVENT)
{
if (inev.kind != HELP_EVENT)
inev.timestamp = (button_or_motion_p
? x_display_list->last_mouse_movement_time
: time (NULL));
kbd_buffer_store_event_hold (&inev, hold_quit);
++message_count;
}
if (inev2.kind != NO_EVENT)
{
if (inev2.kind != HELP_EVENT)
inev2.timestamp = (button_or_motion_p
? x_display_list->last_mouse_movement_time
: time (NULL));
kbd_buffer_store_event_hold (&inev2, hold_quit);
++message_count;
}
}
for (struct unhandled_event *ev = unhandled_events; ev;)
{
haiku_write_without_signal (ev->type, &ev->buffer);
struct unhandled_event *old = ev;
ev = old->next;
xfree (old);
}
if (need_flush)
flush_dirty_back_buffers ();
unblock_input ();
return message_count;
}
static void
haiku_frame_rehighlight (struct frame *frame)
{
haiku_rehighlight ();
}
static void
haiku_delete_window (struct frame *f)
{
check_window_system (f);
haiku_free_frame_resources (f);
}
static void
haiku_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
{
BBitmap_free (pixmap);
}
static void
haiku_beep (struct frame *f)
{
if (visible_bell)
{
void *view = FRAME_HAIKU_VIEW (f);
if (view)
{
block_input ();
BView_draw_lock (view);
if (!EmacsView_double_buffered_p (view))
{
BView_SetHighColorForVisibleBell (view, FRAME_FOREGROUND_PIXEL (f));
BView_FillRectangleForVisibleBell (view, 0, 0, FRAME_PIXEL_WIDTH (f),
FRAME_PIXEL_HEIGHT (f));
SET_FRAME_GARBAGED (f);
expose_frame (f, 0, 0, 0, 0);
}
else
{
EmacsView_do_visible_bell (view, FRAME_FOREGROUND_PIXEL (f));
haiku_flip_buffers (f);
}
BView_draw_unlock (view);
unblock_input ();
}
}
else
haiku_ring_bell ();
}
static void
haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p)
{
void *view = FRAME_HAIKU_VIEW (f);
if (view)
{
block_input ();
BView_set_view_cursor (view, invisible_p ?
FRAME_OUTPUT_DATA (f)->no_cursor :
FRAME_OUTPUT_DATA (f)->current_cursor);
f->pointer_invisible = invisible_p;
unblock_input ();
}
}
static void
haiku_fullscreen (struct frame *f)
{
if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
{
EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
BWindow_zoom (FRAME_HAIKU_WINDOW (f));
}
else if (f->want_fullscreen == FULLSCREEN_BOTH)
EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 1);
else if (f->want_fullscreen == FULLSCREEN_NONE)
{
EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
EmacsWindow_unzoom (FRAME_HAIKU_WINDOW (f));
}
f->want_fullscreen = FULLSCREEN_NONE;
haiku_update_size_hints (f);
}
static struct terminal *
haiku_create_terminal (struct haiku_display_info *dpyinfo)
{
struct terminal *terminal;
terminal = create_terminal (output_haiku, &haiku_redisplay_interface);
terminal->display_info.haiku = dpyinfo;
dpyinfo->terminal = terminal;
terminal->kboard = allocate_kboard (Qhaiku);
terminal->iconify_frame_hook = haiku_iconify_frame;
terminal->focus_frame_hook = haiku_focus_frame;
terminal->ring_bell_hook = haiku_beep;
terminal->popup_dialog_hook = haiku_popup_dialog;
terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible;
terminal->set_frame_offset_hook = haiku_set_offset;
terminal->delete_terminal_hook = haiku_delete_terminal;
terminal->get_string_resource_hook = get_string_resource;
terminal->set_new_font_hook = haiku_new_font;
terminal->defined_color_hook = haiku_defined_color;
terminal->set_window_size_hook = haiku_set_window_size;
terminal->read_socket_hook = haiku_read_socket;
terminal->implicit_set_name_hook = haiku_implicitly_set_name;
terminal->mouse_position_hook = haiku_mouse_position;
terminal->delete_frame_hook = haiku_delete_window;
terminal->frame_up_to_date_hook = haiku_frame_up_to_date;
terminal->buffer_flipping_unblocked_hook = haiku_buffer_flipping_unblocked_hook;
terminal->clear_frame_hook = haiku_clear_frame;
terminal->change_tab_bar_height_hook = haiku_change_tab_bar_height;
terminal->change_tool_bar_height_hook = haiku_change_tool_bar_height;
terminal->set_vertical_scroll_bar_hook = haiku_set_vertical_scroll_bar;
terminal->set_horizontal_scroll_bar_hook = haiku_set_horizontal_scroll_bar;
terminal->set_scroll_bar_default_height_hook = haiku_set_scroll_bar_default_height;
terminal->set_scroll_bar_default_width_hook = haiku_set_scroll_bar_default_width;
terminal->judge_scroll_bars_hook = haiku_judge_scroll_bars;
terminal->condemn_scroll_bars_hook = haiku_condemn_scroll_bars;
terminal->redeem_scroll_bar_hook = haiku_redeem_scroll_bar;
terminal->update_begin_hook = haiku_update_begin;
terminal->update_end_hook = haiku_update_end;
terminal->frame_rehighlight_hook = haiku_frame_rehighlight;
terminal->query_frame_background_color = haiku_query_frame_background_color;
terminal->free_pixmap = haiku_free_pixmap;
terminal->frame_raise_lower_hook = haiku_frame_raise_lower;
terminal->menu_show_hook = haiku_menu_show;
terminal->toggle_invisible_pointer_hook = haiku_toggle_invisible_pointer;
terminal->fullscreen_hook = haiku_fullscreen;
return terminal;
}
struct haiku_display_info *
haiku_term_init (void)
{
struct haiku_display_info *dpyinfo;
struct terminal *terminal;
Lisp_Object color_file, color_map;
block_input ();
Fset_input_interrupt_mode (Qnil);
baud_rate = 19200;
dpyinfo = xzalloc (sizeof *dpyinfo);
haiku_io_init ();
if (port_application_to_emacs < B_OK)
emacs_abort ();
color_file = Fexpand_file_name (build_string ("rgb.txt"),
Fsymbol_value (intern ("data-directory")));
color_map = Fx_load_color_file (color_file);
if (NILP (color_map))
fatal ("Could not read %s.\n", SDATA (color_file));
dpyinfo->color_map = color_map;
dpyinfo->display = BApplication_setup ();
BScreen_res (&dpyinfo->resx, &dpyinfo->resy);
dpyinfo->next = x_display_list;
dpyinfo->n_planes = be_get_display_planes ();
x_display_list = dpyinfo;
terminal = haiku_create_terminal (dpyinfo);
if (current_kboard == initial_kboard)
current_kboard = terminal->kboard;
terminal->kboard->reference_count++;
/* Never delete haiku displays -- there can only ever be one,
anyhow. */
terminal->reference_count++;
terminal->name = xstrdup ("be");
dpyinfo->name_list_element = Fcons (build_string ("be"), Qnil);
dpyinfo->smallest_font_height = 1;
dpyinfo->smallest_char_width = 1;
gui_init_fringe (terminal->rif);
unblock_input ();
return dpyinfo;
}
void
put_xrm_resource (Lisp_Object name, Lisp_Object val)
{
eassert (STRINGP (name));
eassert (STRINGP (val) || NILP (val));
Lisp_Object lval = assoc_no_quit (name, rdb);
if (!NILP (lval))
Fsetcdr (lval, val);
else
rdb = Fcons (Fcons (name, val), rdb);
}
void
haiku_clear_under_internal_border (struct frame *f)
{
if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
int border = FRAME_INTERNAL_BORDER_WIDTH (f);
int width = FRAME_PIXEL_WIDTH (f);
int height = FRAME_PIXEL_HEIGHT (f);
int margin = FRAME_TOP_MARGIN_HEIGHT (f);
int face_id =
(FRAME_PARENT_FRAME (f)
? (!NILP (Vface_remapping_alist)
? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID)
: CHILD_FRAME_BORDER_FACE_ID)
: (!NILP (Vface_remapping_alist)
? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
: INTERNAL_BORDER_FACE_ID));
struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
void *view = FRAME_HAIKU_VIEW (f);
block_input ();
BView_draw_lock (view);
BView_StartClip (view);
BView_ClipToRect (view, 0, 0, FRAME_PIXEL_WIDTH (f),
FRAME_PIXEL_HEIGHT (f));
if (face)
BView_SetHighColor (view, face->background);
else
BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f));
BView_FillRectangle (view, 0, margin, width, border);
BView_FillRectangle (view, 0, 0, border, height);
BView_FillRectangle (view, 0, margin, width, border);
BView_FillRectangle (view, width - border, 0, border, height);
BView_FillRectangle (view, 0, height - border, width, border);
BView_EndClip (view);
BView_draw_unlock (view);
unblock_input ();
}
}
void
mark_haiku_display (void)
{
if (x_display_list)
mark_object (x_display_list->color_map);
}
void
haiku_scroll_bar_remove (struct scroll_bar *bar)
{
block_input ();
void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window)));
BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height);
BScrollBar_delete (bar->scroll_bar);
expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)),
bar->left, bar->top, bar->width, bar->height);
if (bar->horizontal)
wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
else
wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
unblock_input ();
};
void
haiku_set_offset (struct frame *frame, int x, int y,
int change_gravity)
{
if (change_gravity > 0)
{
frame->top_pos = y;
frame->left_pos = x;
frame->size_hint_flags &= ~ (XNegative | YNegative);
if (x < 0)
frame->size_hint_flags |= XNegative;
if (y < 0)
frame->size_hint_flags |= YNegative;
frame->win_gravity = NorthWestGravity;
}
haiku_update_size_hints (frame);
block_input ();
if (change_gravity)
BWindow_set_offset (FRAME_HAIKU_WINDOW (frame), x, y);
unblock_input ();
}
#ifdef USE_BE_CAIRO
cairo_t *
haiku_begin_cr_clip (struct frame *f, struct glyph_string *s)
{
cairo_surface_t *surface = FRAME_CR_SURFACE (f);
if (!surface)
return NULL;
cairo_t *context = cairo_create (surface);
return context;
}
void
haiku_end_cr_clip (cairo_t *cr)
{
cairo_destroy (cr);
}
#endif
void
syms_of_haikuterm (void)
{
DEFVAR_BOOL ("haiku-initialized", haiku_initialized,
doc: /* Non-nil if the Haiku terminal backend has been initialized. */);
DEFVAR_BOOL ("x-use-underline-position-properties",
x_use_underline_position_properties,
doc: /* SKIP: real doc in xterm.c. */);
x_use_underline_position_properties = 1;
DEFVAR_BOOL ("x-underline-at-descent-line",
x_underline_at_descent_line,
doc: /* SKIP: real doc in xterm.c. */);
x_underline_at_descent_line = 0;
DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
doc: /* SKIP: real doc in xterm.c. */);
Vx_toolkit_scroll_bars = Qt;
DEFVAR_BOOL ("haiku-debug-on-fatal-error", haiku_debug_on_fatal_error,
doc: /* If non-nil, Emacs will launch the system debugger upon a fatal error. */);
haiku_debug_on_fatal_error = 1;
DEFSYM (Qshift, "shift");
DEFSYM (Qcontrol, "control");
DEFSYM (Qoption, "option");
DEFSYM (Qcommand, "command");
DEFVAR_LISP ("haiku-meta-keysym", Vhaiku_meta_keysym,
doc: /* Which key Emacs uses as the meta modifier.
This is either one of the symbols `shift', `control', `command', and
`option', or nil, in which case it is treated as `command'.
Setting it to any other value is equivalent to `command'. */);
Vhaiku_meta_keysym = Qnil;
DEFVAR_LISP ("haiku-control-keysym", Vhaiku_control_keysym,
doc: /* Which key Emacs uses as the control modifier.
This is either one of the symbols `shift', `control', `command', and
`option', or nil, in which case it is treated as `control'.
Setting it to any other value is equivalent to `control'. */);
Vhaiku_control_keysym = Qnil;
DEFVAR_LISP ("haiku-super-keysym", Vhaiku_super_keysym,
doc: /* Which key Emacs uses as the super modifier.
This is either one of the symbols `shift', `control', `command', and
`option', or nil, in which case it is treated as `option'.
Setting it to any other value is equivalent to `option'. */);
Vhaiku_super_keysym = Qnil;
DEFVAR_LISP ("haiku-shift-keysym", Vhaiku_shift_keysym,
doc: /* Which key Emacs uses as the shift modifier.
This is either one of the symbols `shift', `control', `command', and
`option', or nil, in which case it is treated as `shift'.
Setting it to any other value is equivalent to `shift'. */);
Vhaiku_shift_keysym = Qnil;
DEFSYM (Qx_use_underline_position_properties,
"x-use-underline-position-properties");
DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
rdb = Qnil;
staticpro (&rdb);
Fprovide (Qhaiku, Qnil);
#ifdef USE_BE_CAIRO
Fprovide (intern_c_string ("cairo"), Qnil);
#endif
}