Redisplay "invisible" frames that are actually visible on modern X

* etc/NEWS: Document that "invisible" frames are now redisplayed
if the compositing manager is still displaying it as part of a
thumbnail out of Emacs's control.

* src/dispnew.c (Fredraw_display): Use FRAME_REDISPLAY_P.
* src/frame.h (FRAME_REDISPLAY_P): New macro.

* src/xdisp.c (clear_garbaged_frames, echo_area_display)
(prepare_menu_bars, redisplay_internal, display_and_set_cursor)
(gui_clear_cursor): Use FRAME_REDISPLAY_P to determine whether
or not a frame should be redisplayed.
* src/xfns.c (Fx_create_frame): Set visibility state initially.
* src/xterm.c (handle_one_xevent): Likewise.
* src/xterm.h (struct x_output): New field `visibility_state'.
This commit is contained in:
Po Lu
2022-12-26 15:57:06 +08:00
parent 419ca81809
commit cc29fab3a6
7 changed files with 47 additions and 16 deletions

View File

@@ -35,6 +35,12 @@ This means it should be less necessary to disable the likes of
`select-active-regions' when Emacs is running over a slow network
connection.
** Emacs will now redisplay frames that are made visible by a compositor.
This means even if `frame-visible-p' returns nil or `icon', the frame
will be redisplayed if it is being displayed to the user by the
compositing manager, which can happenas part of a preview for
iconified windows.
* Editing Changes in Emacs 30.1

View File

@@ -3188,7 +3188,7 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
if (FRAME_VISIBLE_P (XFRAME (frame)))
if (FRAME_REDISPLAY_P (XFRAME (frame)))
redraw_frame (XFRAME (frame));
return Qnil;

View File

@@ -1010,6 +1010,20 @@ default_pixels_per_inch_y (void)
/* True if frame F is currently visible. */
#define FRAME_VISIBLE_P(f) (f)->visible
/* True if frame F should be redisplayed. This is normally the same
as FRAME_VISIBLE_P (f). Under X, frames can continue to be
displayed to the user by the compositing manager even if they are
invisible, so this also checks whether or not the frame is reported
visible by the X server. */
#ifndef HAVE_X_WINDOWS
#define FRAME_REDISPLAY_P(f) (FRAME_VISIBLE_P (f))
#else
#define FRAME_REDISPLAY_P(f) (FRAME_VISIBLE_P (f) \
|| (FRAME_X_P (f) \
&& FRAME_X_VISIBLE (f)))
#endif
/* True if frame F is currently visible but hidden. */
#define FRAME_OBSCURED_P(f) ((f)->visible > 1)

View File

@@ -12938,7 +12938,7 @@ clear_garbaged_frames (void)
{
struct frame *f = XFRAME (frame);
if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
if (FRAME_REDISPLAY_P (f) && FRAME_GARBAGED_P (f))
{
if (f->resized_p
/* It makes no sense to redraw a non-selected TTY
@@ -12987,7 +12987,7 @@ echo_area_display (bool update_frame_p)
f = XFRAME (WINDOW_FRAME (w));
/* Don't display if frame is invisible or not yet initialized. */
if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p)
if (!FRAME_REDISPLAY_P (f) || !f->glyphs_initialized_p)
return;
#ifdef HAVE_WINDOW_SYSTEM
@@ -13543,7 +13543,7 @@ prepare_menu_bars (void)
TTY frames to be completely redrawn, when there
are more than one of them, even though nothing
should be changed on display. */
|| (FRAME_VISIBLE_P (f) == 2 && FRAME_WINDOW_P (f))))
|| (FRAME_REDISPLAY_P (f) && FRAME_WINDOW_P (f))))
gui_consider_frame_title (frame);
}
}
@@ -16430,7 +16430,7 @@ redisplay_internal (void)
{
struct frame *f = XFRAME (frame);
if (FRAME_VISIBLE_P (f))
if (FRAME_REDISPLAY_P (f))
{
++number_of_visible_frames;
/* Adjust matrices for visible frames only. */
@@ -16572,7 +16572,7 @@ redisplay_internal (void)
&& !w->update_mode_line
&& !current_buffer->clip_changed
&& !current_buffer->prevent_redisplay_optimizations_p
&& FRAME_VISIBLE_P (XFRAME (w->frame))
&& FRAME_REDISPLAY_P (XFRAME (w->frame))
&& !FRAME_OBSCURED_P (XFRAME (w->frame))
&& !XFRAME (w->frame)->cursor_type_changed
&& !XFRAME (w->frame)->face_change
@@ -16850,7 +16850,7 @@ redisplay_internal (void)
if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f))
{
/* Don't allow freeing images and faces for this
frame as long as the frame's update wasn't
@@ -16876,7 +16876,7 @@ redisplay_internal (void)
if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook)
FRAME_TERMINAL (f)->judge_scroll_bars_hook (f);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f))
{
/* If fonts changed on visible frame, display again. */
if (f->fonts_changed)
@@ -16982,7 +16982,7 @@ redisplay_internal (void)
}
}
}
else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
else if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf))
{
sf->inhibit_clear_image_cache = true;
displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents);
@@ -17033,7 +17033,7 @@ redisplay_internal (void)
unrequest_sigio ();
STOP_POLLING;
if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf))
{
if (hscroll_retries <= MAX_HSCROLL_RETRIES
&& hscroll_windows (selected_window))
@@ -17132,7 +17132,7 @@ redisplay_internal (void)
FOR_EACH_FRAME (tail, frame)
{
if (XFRAME (frame)->visible)
if (FRAME_REDISPLAY_P (XFRAME (frame)))
new_count++;
}
@@ -33256,7 +33256,7 @@ display_and_set_cursor (struct window *w, bool on,
windows and frames; in the latter case, the frame or window may
be in the midst of changing its size, and x and y may be off the
window. */
if (! FRAME_VISIBLE_P (f)
if (! FRAME_REDISPLAY_P (f)
|| vpos >= w->current_matrix->nrows
|| hpos >= w->current_matrix->matrix_w)
return;
@@ -33417,7 +33417,7 @@ gui_update_cursor (struct frame *f, bool on_p)
void
gui_clear_cursor (struct window *w)
{
if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
if (FRAME_REDISPLAY_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
update_window_cursor (w, false);
}

View File

@@ -4741,6 +4741,7 @@ This function is an internal primitive--use `make-frame' instead. */)
#endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */
f->output_data.x->white_relief.pixel = -1;
f->output_data.x->black_relief.pixel = -1;
f->output_data.x->visibility_state = VisibilityFullyObscured;
fset_icon_name (f, gui_display_get_arg (dpyinfo,
parms,

View File

@@ -21743,9 +21743,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
case VisibilityNotify:
f = x_top_window_to_frame (dpyinfo, event->xvisibility.window);
if (f && (event->xvisibility.state == VisibilityUnobscured
|| event->xvisibility.state == VisibilityPartiallyObscured))
SET_FRAME_VISIBLE (f, 1);
if (f)
FRAME_X_OUTPUT (f)->visibility_state = event->xvisibility.state;
goto OTHER;

View File

@@ -1290,6 +1290,11 @@ struct x_output
strictly an optimization to avoid extraneous synchronizing in
some cases. */
int root_x, root_y;
/* The frame visibility state. This starts out
VisibilityFullyObscured, but is set to something else in
handle_one_xevent. */
int visibility_state;
};
enum
@@ -1408,6 +1413,11 @@ extern void x_mark_frame_dirty (struct frame *f);
/* And its corresponding visual info. */
#define FRAME_X_VISUAL_INFO(f) (&FRAME_DISPLAY_INFO (f)->visual_info)
/* Whether or not the frame is visible. Do not test this alone.
Instead, use FRAME_REDISPLAY_P. */
#define FRAME_X_VISIBLE(f) (FRAME_X_OUTPUT (f)->visibility_state \
!= VisibilityFullyObscured)
#ifdef HAVE_XRENDER
#define FRAME_X_PICTURE_FORMAT(f) FRAME_DISPLAY_INFO (f)->pict_format
#define FRAME_X_PICTURE(f) ((f)->output_data.x->picture)