Rewrite Haiku frame geometry code to handle decorator frames

* doc/lispref/frames.texi (Frame Layout): Document changes to
Haiku frame layout.

* src/haiku_support.cc (class EmacsWindow, MoveToIncludingFrame)
(EmacsMoveTo, MakeFullscreen): Move to an offset including the
decorator frames.
(be_get_window_decorator_dimensions):
(be_get_window_decorator_frame): New functions.

* src/haiku_support.h: Update prototypes.

* src/haikufns.c (haiku_update_after_decoration_change): New
function.
(haiku_create_frame, haiku_set_undecorated)
(haiku_set_override_redirect): Call that function.
(frame_geometry): Actually calculate frame geometry based on
decorator and frame sizes.

* src/haikuterm.c (haiku_coords_from_parent): Use frame width
instead.
(haiku_read_socket): Set left and top positions based on
decorator width and height.
* src/haikuterm.h (struct haiku_output): New field `frame_x' and
`frame_y'.
This commit is contained in:
Po Lu 2022-05-17 09:40:57 +00:00
parent dc239872cc
commit e9ad64ef92
6 changed files with 205 additions and 103 deletions

View file

@ -683,9 +683,9 @@ The position of the top left corner of the native frame specifies the
indicate that position for the various builds:
@itemize @w{}
@item (1) non-toolkit and terminal frames
@item (1) non-toolkit, Haiku, and terminal frames
@item (2) Lucid, Motif, MS-Windows, and Haiku frames
@item (2) Lucid, Motif, and MS-Windows frames
@item (3) GTK+ and NS frames
@end itemize

View file

@ -795,12 +795,24 @@ class EmacsWindow : public BWindow
subset_windows = f;
}
void
MoveToIncludingFrame (int x, int y)
{
BRect decorator, frame;
decorator = DecoratorFrame ();
frame = Frame ();
MoveTo (x + frame.left - decorator.left,
y + frame.top - decorator.top);
}
void
DoMove (struct child_frame *f)
{
BRect frame = this->Frame ();
f->window->MoveTo (frame.left + f->xoff,
frame.top + f->yoff);
f->window->MoveToIncludingFrame (frame.left + f->xoff,
frame.top + f->yoff);
}
void
@ -1062,7 +1074,7 @@ class EmacsWindow : public BWindow
gui_abort ("Failed to lock child frame state lock");
if (!this->parent)
this->MoveTo (x, y);
this->MoveToIncludingFrame (x, y);
else
this->parent->MoveChild (this, x, y, 0);
child_frame_lock.Unlock ();
@ -1172,30 +1184,6 @@ class EmacsWindow : public BWindow
BWindow::Zoom ();
}
void
GetParentWidthHeight (int *width, int *height)
{
if (!child_frame_lock.Lock ())
gui_abort ("Failed to lock child frame state lock");
if (parent)
{
BRect frame = parent->Frame ();
*width = BE_RECT_WIDTH (frame);
*height = BE_RECT_HEIGHT (frame);
}
else
{
BScreen s (this);
BRect frame = s.Frame ();
*width = BE_RECT_WIDTH (frame);
*height = BE_RECT_HEIGHT (frame);
}
child_frame_lock.Unlock ();
}
void
OffsetChildRect (BRect *r, EmacsWindow *c)
{
@ -1221,17 +1209,21 @@ class EmacsWindow : public BWindow
MakeFullscreen (int make_fullscreen_p)
{
BScreen screen (this);
uint32 flags;
BRect screen_frame;
if (!screen.IsValid ())
gui_abort ("Trying to make a window fullscreen without a screen");
screen_frame = screen.Frame ();
UnZoom ();
if (make_fullscreen_p == fullscreen_p)
return;
fullscreen_p = make_fullscreen_p;
uint32 flags = Flags ();
flags = Flags ();
if (fullscreen_p)
{
if (zoomed_p)
@ -1240,24 +1232,18 @@ class EmacsWindow : public BWindow
flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE;
pre_fullscreen_rect = Frame ();
if (!child_frame_lock.Lock ())
gui_abort ("Failed to lock child frame state lock");
if (parent)
parent->OffsetChildRect (&pre_fullscreen_rect, this);
child_frame_lock.Unlock ();
int w, h;
EmacsMoveTo (0, 0);
GetParentWidthHeight (&w, &h);
ResizeTo (w - 1, h - 1);
MoveTo (0, 0);
ResizeTo (BE_RECT_WIDTH (screen_frame) - 1,
BE_RECT_HEIGHT (screen_frame) - 1);
}
else
{
flags &= ~(B_NOT_MOVABLE | B_NOT_ZOOMABLE);
EmacsMoveTo (pre_fullscreen_rect.left,
pre_fullscreen_rect.top);
/* Use MoveTo directly since pre_fullscreen_rect isn't
adjusted for decorator sizes. */
MoveTo (pre_fullscreen_rect.left,
pre_fullscreen_rect.top);
ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1,
BE_RECT_HEIGHT (pre_fullscreen_rect) - 1);
}
@ -5097,3 +5083,55 @@ be_create_pixmap_cursor (void *bitmap, int x, int y)
return cursor;
}
void
be_get_window_decorator_dimensions (void *window, int *left, int *top,
int *right, int *bottom)
{
BWindow *wnd;
BRect frame, window_frame;
wnd = (BWindow *) window;
if (!wnd->LockLooper ())
gui_abort ("Failed to lock window looper frame");
frame = wnd->DecoratorFrame ();
window_frame = wnd->Frame ();
if (left)
*left = window_frame.left - frame.left;
if (top)
*top = window_frame.top - frame.top;
if (right)
*right = frame.right - window_frame.right;
if (bottom)
*bottom = frame.bottom - window_frame.bottom;
wnd->UnlockLooper ();
}
void
be_get_window_decorator_frame (void *window, int *left, int *top,
int *width, int *height)
{
BWindow *wnd;
BRect frame;
wnd = (BWindow *) window;
if (!wnd->LockLooper ())
gui_abort ("Failed to lock window looper frame");
frame = wnd->DecoratorFrame ();
*left = frame.left;
*top = frame.top;
*width = BE_RECT_WIDTH (frame);
*height = BE_RECT_HEIGHT (frame);
wnd->UnlockLooper ();
}

View file

@ -686,6 +686,9 @@ extern bool be_select_font (void (*) (void), bool (*) (void),
extern int be_find_font_indices (struct haiku_font_pattern *, int *, int *);
extern status_t be_roster_launch (const char *, const char *, char **,
ptrdiff_t, void *, team_id *);
extern void be_get_window_decorator_dimensions (void *, int *, int *, int *, int *);
extern void be_get_window_decorator_frame (void *, int *, int *, int *, int *);
#ifdef __cplusplus
}

View file

@ -104,6 +104,29 @@ get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
return parms;
}
/* Update the left and top offsets of F after its decorators
change. */
static void
haiku_update_after_decoration_change (struct frame *f)
{
int x, y, width, height;
struct frame *parent;
be_get_window_decorator_frame (FRAME_HAIKU_WINDOW (f),
&x, &y, &width, &height);
parent = FRAME_PARENT_FRAME (f);
if (parent)
{
x = x - FRAME_OUTPUT_DATA (f)->frame_x;
y = y - FRAME_OUTPUT_DATA (f)->frame_x;
}
f->left_pos = x;
f->top_pos = y;
}
void
haiku_change_tool_bar_height (struct frame *f, int height)
{
@ -827,10 +850,7 @@ haiku_create_frame (Lisp_Object parms)
f->terminal->reference_count++;
block_input ();
FRAME_OUTPUT_DATA (f)->window
= BWindow_new (&FRAME_OUTPUT_DATA (f)->view);
unblock_input ();
FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view);
if (!FRAME_OUTPUT_DATA (f)->window)
xsignal1 (Qerror, build_unibyte_string ("Could not create window"));
@ -842,7 +862,8 @@ haiku_create_frame (Lisp_Object parms)
Vframe_list = Fcons (frame, Vframe_list);
Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms,
Qparent_frame, NULL, NULL,
RES_TYPE_SYMBOL);
if (EQ (parent_frame, Qunbound)
@ -1315,6 +1336,8 @@ haiku_set_undecorated (struct frame *f, Lisp_Object new_value,
FRAME_UNDECORATED (f) = !NILP (new_value);
BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value));
unblock_input ();
haiku_update_after_decoration_change (f);
}
static void
@ -1329,6 +1352,8 @@ haiku_set_override_redirect (struct frame *f, Lisp_Object new_value,
!NILP (new_value));
FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value);
unblock_input ();
haiku_update_after_decoration_change (f);
}
static void
@ -1375,47 +1400,74 @@ haiku_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval
static Lisp_Object
frame_geometry (Lisp_Object frame, Lisp_Object attribute)
{
struct frame *f = decode_live_frame (frame);
check_window_system (f);
struct frame *f, *parent;
int outer_x, outer_y, outer_width, outer_height;
int right_off, bottom_off, top_off;
int native_x, native_y;
f = decode_window_system_frame (frame);
parent = FRAME_PARENT_FRAME (f);
be_get_window_decorator_frame (FRAME_HAIKU_WINDOW (f), &outer_x,
&outer_y, &outer_width, &outer_height);
be_get_window_decorator_dimensions (FRAME_HAIKU_WINDOW (f), NULL,
&top_off, &right_off, &bottom_off);
native_x = FRAME_OUTPUT_DATA (f)->frame_x;
native_y = FRAME_OUTPUT_DATA (f)->frame_y;
if (parent)
{
/* Adjust all the coordinates by the coordinates of the parent
frame. */
outer_x -= FRAME_OUTPUT_DATA (parent)->frame_x;
outer_y -= FRAME_OUTPUT_DATA (parent)->frame_y;
native_x -= FRAME_OUTPUT_DATA (parent)->frame_x;
native_y -= FRAME_OUTPUT_DATA (parent)->frame_y;
}
if (EQ (attribute, Qouter_edges))
return list4i (f->left_pos, f->top_pos,
f->left_pos, f->top_pos);
return list4i (outer_x, outer_y,
outer_x + outer_width,
outer_y + outer_height);
else if (EQ (attribute, Qnative_edges))
return list4i (f->left_pos, f->top_pos,
f->left_pos + FRAME_PIXEL_WIDTH (f),
f->top_pos + FRAME_PIXEL_HEIGHT (f));
return list4i (native_x, native_y,
native_x + FRAME_PIXEL_WIDTH (f),
native_y + FRAME_PIXEL_HEIGHT (f));
else if (EQ (attribute, Qinner_edges))
return list4i (f->left_pos + FRAME_INTERNAL_BORDER_WIDTH (f),
f->top_pos + FRAME_INTERNAL_BORDER_WIDTH (f) +
FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
f->left_pos - FRAME_INTERNAL_BORDER_WIDTH (f) +
FRAME_PIXEL_WIDTH (f),
f->top_pos + FRAME_PIXEL_HEIGHT (f) -
FRAME_INTERNAL_BORDER_WIDTH (f));
return list4i (native_x + FRAME_INTERNAL_BORDER_WIDTH (f),
native_y + FRAME_INTERNAL_BORDER_WIDTH (f)
+ FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
native_x - FRAME_INTERNAL_BORDER_WIDTH (f)
+ FRAME_PIXEL_WIDTH (f),
native_y + FRAME_PIXEL_HEIGHT (f)
- FRAME_INTERNAL_BORDER_WIDTH (f));
else
return
list (Fcons (Qouter_position,
Fcons (make_fixnum (f->left_pos),
make_fixnum (f->top_pos))),
Fcons (Qouter_size,
Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
make_fixnum (FRAME_PIXEL_HEIGHT (f)))),
Fcons (Qexternal_border_size,
Fcons (make_fixnum (0), make_fixnum (0))),
Fcons (Qtitle_bar_size,
Fcons (make_fixnum (0), make_fixnum (0))),
Fcons (Qmenu_bar_external, Qnil),
Fcons (Qmenu_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
(FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
Fcons (Qtool_bar_external, Qnil),
Fcons (Qtool_bar_position, Qtop),
Fcons (Qtool_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
(FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
Fcons (Qinternal_border_width, make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
return list (Fcons (Qouter_position,
Fcons (make_fixnum (outer_x),
make_fixnum (outer_y))),
Fcons (Qouter_size,
Fcons (make_fixnum (outer_width),
make_fixnum (outer_height))),
Fcons (Qexternal_border_size,
Fcons (make_fixnum (right_off),
make_fixnum (bottom_off))),
Fcons (Qtitle_bar_size,
Fcons (make_fixnum (outer_width),
make_fixnum (top_off))),
Fcons (Qmenu_bar_external, Qnil),
Fcons (Qmenu_bar_size,
Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)
- (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
Fcons (Qtool_bar_external, Qnil),
Fcons (Qtool_bar_position, Qtop),
Fcons (Qtool_bar_size,
Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)
- (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
Fcons (Qinternal_border_width,
make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
}
void

View file

@ -96,14 +96,9 @@ 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;
}
*x -= FRAME_OUTPUT_DATA (p)->frame_x;
*y -= FRAME_OUTPUT_DATA (p)->frame_y;
}
static void
@ -3535,7 +3530,6 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
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. */
@ -3559,30 +3553,40 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
{
struct haiku_move_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
int decorator_width, decorator_height, top, left;
struct frame *p;
if (!f)
continue;
FRAME_OUTPUT_DATA (f)->frame_x = b->x;
FRAME_OUTPUT_DATA (f)->frame_y = b->y;
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)
be_get_window_decorator_dimensions (b->window, &decorator_width,
&decorator_height, NULL,
NULL);
left = b->x - decorator_width;
top = b->y - decorator_height;
if (left != f->left_pos || top != f->top_pos)
{
inev.kind = MOVE_FRAME_EVENT;
XSETINT (inev.x, b->x);
XSETINT (inev.y, b->y);
XSETINT (inev.x, left);
XSETINT (inev.y, top);
f->left_pos = b->x;
f->top_pos = b->y;
f->left_pos = left;
f->top_pos = top;
struct frame *p;
p = FRAME_PARENT_FRAME (f);
if ((p = FRAME_PARENT_FRAME (f)))
{
void *window = FRAME_HAIKU_WINDOW (p);
EmacsWindow_move_weak_child (window, b->window, b->x, b->y);
}
if (p)
EmacsWindow_move_weak_child (FRAME_HAIKU_WINDOW (p),
b->window, left, top);
XSETFRAME (inev.frame_or_window, f);
}

View file

@ -196,6 +196,11 @@ struct haiku_output
They are changed only when a different background is involved.
-1 means no color has been computed. */
long relief_background;
/* The absolute position of this frame. This differs from left_pos
and top_pos in that the decorator and parent frames are not taken
into account. */
int frame_x, frame_y;
};
struct x_output