From 4dfaefcffc987400a317b5ccf0c9bf00f7c84134 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 19 May 2022 03:43:39 +0000 Subject: [PATCH] Fix race conditions processing frame fullscreen state on Haiku * doc/lispref/frames.texi (Size Parameters): Remove note saying Haiku doesn't support `fullwidth' and `fullboth'. * src/haiku_support.cc (subset_windows, class EmacsWindow) (Unparent, ParentTo): Stop calling old fullscreen functions. (ClearFullscreen, FullscreenRectForMode, SetFullscreen): New functions. Completely rewrite old zoom and fullscreen handling code. (Zoom): Send a ZOOM_EVENT and don't actually zoom. (BWindow_zoom, EmacsWindow_make_fullscreen, EmacsWindow_unzoom): Delete functions. (be_set_window_fullscreen_mode): New function. * src/haiku_support.h (struct haiku_zoom_event): Remove `zoomed_p' parameter. (enum haiku_fullscreen_mode): New enum. Update prototypes. * src/haikufns.c (Fx_display_pixel_height): Return height instead of width. * src/haikuterm.c (haiku_make_fullscreen_consistent) (haiku_read_socket, haiku_fullscreen): Adjust to always set zoom and fullscreen in the main thread instead of the UI threads. * src/haikuterm.h (struct haiku_output): Remove flag `zoomed_p' and add field `fullscreen_mode'. --- doc/lispref/frames.texi | 14 +-- src/haiku_support.cc | 242 ++++++++++++++++++++-------------------- src/haiku_support.h | 14 ++- src/haikufns.c | 2 +- src/haikuterm.c | 47 +++++--- src/haikuterm.h | 11 +- 6 files changed, 183 insertions(+), 147 deletions(-) diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 5853c45b79e..5ea060871f4 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -1734,16 +1734,14 @@ fit will be clipped by the window manager. @item fullscreen This parameter specifies whether to maximize the frame's width, height or both. Its value can be @code{fullwidth}, @code{fullheight}, -@code{fullboth}, or @code{maximized}.@footnote{On Haiku, setting -@code{fullscreen} to @code{fullwidth} or @code{fullheight} has no -effect.} A @dfn{fullwidth} frame is as +@code{fullboth}, or @code{maximized}. A @dfn{fullwidth} frame is as wide as possible, a @dfn{fullheight} frame is as tall as possible, and a @dfn{fullboth} frame is both as wide and as tall as possible. A -@dfn{maximized} frame is like a ``fullboth'' frame, except that it usually -keeps its title bar and the buttons for resizing -and closing the frame. Also, maximized frames typically avoid hiding -any task bar or panels displayed on the desktop. A ``fullboth'' frame, -on the other hand, usually omits the title bar and occupies the entire +@dfn{maximized} frame is like a ``fullboth'' frame, except that it +usually keeps its title bar and the buttons for resizing and closing +the frame. Also, maximized frames typically avoid hiding any task bar +or panels displayed on the desktop. A ``fullboth'' frame, on the +other hand, usually omits the title bar and occupies the entire available screen space. Full-height and full-width frames are more similar to maximized diff --git a/src/haiku_support.cc b/src/haiku_support.cc index 0c126dab3d6..0b3ab4cf4ae 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include +#include #include #include @@ -518,33 +519,42 @@ public: struct child_frame *next; int xoff, yoff; EmacsWindow *window; - } *subset_windows = NULL; + } *subset_windows; - EmacsWindow *parent = NULL; + EmacsWindow *parent; BRect pre_fullscreen_rect; BRect pre_zoom_rect; - int x_before_zoom = INT_MIN; - int y_before_zoom = INT_MIN; - bool fullscreen_p = false; - bool zoomed_p = false; - bool shown_flag = false; - volatile int was_shown_p = 0; - bool menu_bar_active_p = false; - bool override_redirect_p = false; + int x_before_zoom; + int y_before_zoom; + bool shown_flag; + volatile bool was_shown_p; + bool menu_bar_active_p; + bool override_redirect_p; window_look pre_override_redirect_look; window_feel pre_override_redirect_feel; uint32 pre_override_redirect_workspaces; int window_id; - bool *menus_begun = NULL; + bool *menus_begun; enum haiku_z_group z_group; - bool tooltip_p = false; + bool tooltip_p; + enum haiku_fullscreen_mode fullscreen_mode; EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK, - B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS) + B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS), + subset_windows (NULL), + parent (NULL), + x_before_zoom (INT_MIN), + y_before_zoom (INT_MIN), + shown_flag (false), + was_shown_p (false), + menu_bar_active_p (false), + override_redirect_p (false), + window_id (current_window_id), + menus_begun (NULL), + z_group (Z_GROUP_NONE), + tooltip_p (false), + fullscreen_mode (FULLSCREEN_MODE_NONE) { - window_id = current_window_id++; - z_group = Z_GROUP_NONE; - /* This pulse rate is used by scroll bars for repeating a button action while a button is held down. */ SetPulseRate (30000); @@ -711,12 +721,6 @@ public: RecomputeFeel (); UpwardsUnSubsetChildren (parent); this->RemoveFromSubset (this); - - if (fullscreen_p) - { - fullscreen_p = 0; - MakeFullscreen (1); - } child_frame_lock.Unlock (); } @@ -766,11 +770,6 @@ public: this->AddToSubset (this); if (!IsHidden () && this->parent) UpwardsSubsetChildren (parent); - if (fullscreen_p) - { - fullscreen_p = 0; - MakeFullscreen (1); - } window->LinkChild (this); child_frame_lock.Unlock (); @@ -1161,41 +1160,103 @@ public: } void - Zoom (BPoint o, float w, float h) + ClearFullscreen (void) { - struct haiku_zoom_event rq; - BRect rect; - rq.window = this; + switch (fullscreen_mode) + { + case FULLSCREEN_MODE_MAXIMIZED: + BWindow::Zoom (pre_zoom_rect.LeftTop (), + BE_RECT_WIDTH (pre_zoom_rect) - 1, + BE_RECT_HEIGHT (pre_zoom_rect) - 1); + break; - if (fullscreen_p) - MakeFullscreen (0); + case FULLSCREEN_MODE_BOTH: + case FULLSCREEN_MODE_HEIGHT: + case FULLSCREEN_MODE_WIDTH: + MoveTo (pre_fullscreen_rect.LeftTop ()); + ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1, + BE_RECT_HEIGHT (pre_fullscreen_rect) - 1); - if (!zoomed_p) - { - pre_zoom_rect = Frame (); - zoomed_p = true; - rect = CalculateZoomRect (); - } - else - { - zoomed_p = false; - rect = pre_zoom_rect; + SetFlags (Flags () & ~(B_NOT_MOVABLE + | B_NOT_ZOOMABLE + | B_NOT_RESIZABLE)); + break; + + case FULLSCREEN_MODE_NONE: + break; } - rq.zoomed = zoomed_p; - haiku_write (ZOOM_EVENT, &rq); + fullscreen_mode = FULLSCREEN_MODE_NONE; + } - BWindow::Zoom (rect.LeftTop (), BE_RECT_WIDTH (rect) - 1, - BE_RECT_HEIGHT (rect) - 1); + BRect + FullscreenRectForMode (enum haiku_fullscreen_mode mode) + { + BScreen screen (this); + BRect frame; + + if (!screen.IsValid ()) + return BRect (0, 0, 0, 0); + + frame = screen.Frame (); + + if (mode == FULLSCREEN_MODE_HEIGHT) + frame.right -= BE_RECT_WIDTH (frame) / 2; + else if (mode == FULLSCREEN_MODE_WIDTH) + frame.bottom -= BE_RECT_HEIGHT (frame) / 2; + + return frame; } void - UnZoom (void) + SetFullscreen (enum haiku_fullscreen_mode mode) { - if (!zoomed_p) + BRect zoom_rect; + + if (fullscreen_mode == mode) return; - BWindow::Zoom (); + ClearFullscreen (); + + switch (mode) + { + case FULLSCREEN_MODE_MAXIMIZED: + pre_zoom_rect = Frame (); + zoom_rect = CalculateZoomRect (); + BWindow::Zoom (zoom_rect.LeftTop (), + BE_RECT_WIDTH (zoom_rect) - 1, + BE_RECT_HEIGHT (zoom_rect) - 1); + break; + + case FULLSCREEN_MODE_BOTH: + SetFlags (Flags () | B_NOT_MOVABLE); + FALLTHROUGH; + + case FULLSCREEN_MODE_HEIGHT: + case FULLSCREEN_MODE_WIDTH: + SetFlags (Flags () | B_NOT_ZOOMABLE | B_NOT_RESIZABLE); + pre_fullscreen_rect = Frame (); + zoom_rect = FullscreenRectForMode (mode); + ResizeTo (BE_RECT_WIDTH (zoom_rect) - 1, + BE_RECT_HEIGHT (zoom_rect) - 1); + MoveTo (zoom_rect.left, zoom_rect.top); + + break; + + case FULLSCREEN_MODE_NONE: + break; + } + + fullscreen_mode = mode; + } + + void + Zoom (BPoint o, float w, float h) + { + struct haiku_zoom_event rq; + + rq.window = this; + haiku_write (ZOOM_EVENT, &rq); } void @@ -1218,51 +1279,6 @@ public: child_frame_lock.Lock (); gui_abort ("Trying to calculate offsets for a child frame that doesn't exist"); } - - void - 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; - flags = Flags (); - - if (fullscreen_p) - { - if (zoomed_p) - UnZoom (); - - flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE; - pre_fullscreen_rect = Frame (); - - MoveTo (0, 0); - ResizeTo (BE_RECT_WIDTH (screen_frame) - 1, - BE_RECT_HEIGHT (screen_frame) - 1); - } - else - { - flags &= ~(B_NOT_MOVABLE | B_NOT_ZOOMABLE); - - /* 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); - } - SetFlags (flags); - } }; class EmacsMenuBar : public BMenuBar @@ -4486,30 +4502,6 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p, return file_name; } -/* Zoom WINDOW. */ -void -BWindow_zoom (void *window) -{ - BWindow *w = (BWindow *) window; - w->Zoom (); -} - -/* Make WINDOW fullscreen if FULLSCREEN_P. */ -void -EmacsWindow_make_fullscreen (void *window, int fullscreen_p) -{ - EmacsWindow *w = (EmacsWindow *) window; - w->MakeFullscreen (fullscreen_p); -} - -/* Unzoom (maximize) WINDOW. */ -void -EmacsWindow_unzoom (void *window) -{ - EmacsWindow *w = (EmacsWindow *) window; - w->UnZoom (); -} - /* Move the pointer into MBAR and start tracking. Return whether the menu bar was opened correctly. */ bool @@ -5180,3 +5172,15 @@ be_unlock_window (void *window) wnd->UnlockLooper (); } + +void +be_set_window_fullscreen_mode (void *window, enum haiku_fullscreen_mode mode) +{ + EmacsWindow *w = (EmacsWindow *) window; + + if (!w->LockLooper ()) + gui_abort ("Failed to lock window to set fullscreen mode"); + + w->SetFullscreen (mode); + w->UnlockLooper (); +} diff --git a/src/haiku_support.h b/src/haiku_support.h index 14dd36e275a..0bfd027c0d3 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h @@ -249,7 +249,6 @@ struct haiku_menu_bar_help_event struct haiku_zoom_event { void *window; - bool zoomed; }; enum haiku_font_specification @@ -316,6 +315,15 @@ enum haiku_font_weight HAIKU_MEDIUM = 2000, }; +enum haiku_fullscreen_mode + { + FULLSCREEN_MODE_NONE, + FULLSCREEN_MODE_WIDTH, + FULLSCREEN_MODE_HEIGHT, + FULLSCREEN_MODE_BOTH, + FULLSCREEN_MODE_MAXIMIZED, + }; + struct haiku_font_pattern { /* Bitmask indicating which fields are set. */ @@ -495,7 +503,6 @@ extern void BWindow_center_on_screen (void *); extern void BWindow_change_decoration (void *, int); extern void BWindow_set_tooltip_decoration (void *); extern void BWindow_set_avoid_focus (void *, int); -extern void BWindow_zoom (void *); extern void BWindow_set_size_alignment (void *, int, int); extern void BWindow_sync (void *); extern void BWindow_send_behind (void *, void *); @@ -623,8 +630,6 @@ extern void BAlert_delete (void *); extern void EmacsWindow_parent_to (void *, void *); extern void EmacsWindow_unparent (void *); extern void EmacsWindow_move_weak_child (void *, void *, int, int); -extern void EmacsWindow_make_fullscreen (void *, int); -extern void EmacsWindow_unzoom (void *); extern void be_get_version_string (char *, int); extern int be_get_display_planes (void); @@ -690,6 +695,7 @@ extern status_t be_roster_launch (const char *, const char *, char **, extern void be_get_window_decorator_dimensions (void *, int *, int *, int *, int *); extern void be_get_window_decorator_frame (void *, int *, int *, int *, int *); extern void be_send_move_frame_event (void *); +extern void be_set_window_fullscreen_mode (void *, enum haiku_fullscreen_mode); extern void be_lock_window (void *); extern void be_unlock_window (void *); diff --git a/src/haikufns.c b/src/haikufns.c index 76a8569970a..314152008b0 100644 --- a/src/haikufns.c +++ b/src/haikufns.c @@ -2281,7 +2281,7 @@ DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_heigh check_haiku_display_info (terminal); be_get_screen_dimensions (&width, &height); - return make_fixnum (width); + return make_fixnum (height); } DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, diff --git a/src/haikuterm.c b/src/haikuterm.c index 2db1e352ffb..731afd9d394 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -3018,11 +3018,20 @@ static struct redisplay_interface haiku_redisplay_interface = 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) + Lisp_Object lval; + struct haiku_output *output; + + output = FRAME_OUTPUT_DATA (f); + + if (output->fullscreen_mode == FULLSCREEN_MODE_BOTH) + lval = Qfullboth; + else if (output->fullscreen_mode == FULLSCREEN_MODE_WIDTH) + lval = Qfullwidth; + else if (output->fullscreen_mode == FULLSCREEN_MODE_HEIGHT) + lval = Qfullheight; + else if (output->fullscreen_mode == FULLSCREEN_MODE_MAXIMIZED) lval = Qmaximized; - else if (EQ (lval, Qmaximized) && !FRAME_OUTPUT_DATA (f)->zoomed_p) + else lval = Qnil; store_frame_param (f, Qfullscreen, lval); @@ -3857,14 +3866,20 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) case ZOOM_EVENT: { struct haiku_zoom_event *b = buf; - struct frame *f = haiku_window_to_frame (b->window); + struct haiku_output *output; if (!f) continue; - FRAME_OUTPUT_DATA (f)->zoomed_p = b->zoomed; - haiku_make_fullscreen_consistent (f); + output = FRAME_OUTPUT_DATA (f); + + if (output->fullscreen_mode == FULLSCREEN_MAXIMIZED) + f->want_fullscreen = FULLSCREEN_NONE; + else + f->want_fullscreen = FULLSCREEN_MAXIMIZED; + + FRAME_TERMINAL (f)->fullscreen_hook (f); break; } case DRAG_AND_DROP_EVENT: @@ -4096,6 +4111,8 @@ haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p) static void haiku_fullscreen (struct frame *f) { + enum haiku_fullscreen_mode mode; + /* When FRAME_OUTPUT_DATA (f)->configury_done is false, the frame is being created, and its regular width and height have not yet been set. This function will be called again by haiku_create_frame, @@ -4104,18 +4121,22 @@ haiku_fullscreen (struct frame *f) return; if (f->want_fullscreen == FULLSCREEN_MAXIMIZED) - BWindow_zoom (FRAME_HAIKU_WINDOW (f)); + mode = FULLSCREEN_MODE_MAXIMIZED; else if (f->want_fullscreen == FULLSCREEN_BOTH) - EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 1); + mode = FULLSCREEN_MODE_BOTH; + else if (f->want_fullscreen == FULLSCREEN_WIDTH) + mode = FULLSCREEN_MODE_WIDTH; + else if (f->want_fullscreen == FULLSCREEN_HEIGHT) + mode = FULLSCREEN_MODE_HEIGHT; else - { - EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0); - EmacsWindow_unzoom (FRAME_HAIKU_WINDOW (f)); - } + mode = FULLSCREEN_MODE_NONE; f->want_fullscreen = FULLSCREEN_NONE; + be_set_window_fullscreen_mode (FRAME_HAIKU_WINDOW (f), mode); + FRAME_OUTPUT_DATA (f)->fullscreen_mode = mode; haiku_update_size_hints (f); + haiku_make_fullscreen_consistent (f); } static struct terminal * diff --git a/src/haikuterm.h b/src/haikuterm.h index 068be826871..41b1a85b000 100644 --- a/src/haikuterm.h +++ b/src/haikuterm.h @@ -160,13 +160,16 @@ struct haiku_output int fontset; int baseline_offset; - bool_bf zoomed_p : 1; + /* Whether or not the hourglass cursor is currently being + displayed. */ bool_bf hourglass_p : 1; + + /* Whether or not the menu bar is open. */ bool_bf menu_bar_open_p : 1; /* Whether or not there is data in a back buffer that hasn't been displayed yet. */ - bool dirty_p; + bool_bf dirty_p : 1; struct font *font; @@ -201,6 +204,10 @@ struct haiku_output and top_pos in that the decorator and parent frames are not taken into account. */ int frame_x, frame_y; + + /* The current fullscreen mode of this frame. This should be `enum + haiku_fullscreen_mode', but that isn't available here. */ + int fullscreen_mode; }; struct x_output -- 2.39.2