window-actor: Move X11-specific code to MetaWindowActorX11
MetaWindowActor handles sending _NET_WM_FRAME_* X atoms to clients - even pure Wayland clients. Now that we have Wayland- and X11-specific implementations of MetaWindowActor, we can delegate this to MetaWindowActorX11, and allow pure Wayland apps to not even connect to MetaSurfaceActor:repaint-scheduled. Do that by moving all the X11-specific code to the X11-specific MetaWindowActorX11 class. Add vfuncs to MetaWindowActorClass that are necessary for the move, namely: * pre_paint() and post_paint() * post_init() * frame_complete() * set_surface_actor() * queue_frame_drawn() https://gitlab.gnome.org/GNOME/mutter/merge_requests/368
This commit is contained in:
parent
ac2f8cad0c
commit
80e3c1de57
@ -12,6 +12,22 @@
|
||||
struct _MetaWindowActorClass
|
||||
{
|
||||
ClutterActorClass parent;
|
||||
|
||||
void (*frame_complete) (MetaWindowActor *actor,
|
||||
ClutterFrameInfo *frame_info,
|
||||
int64_t presentation_time);
|
||||
|
||||
void (*set_surface_actor) (MetaWindowActor *actor,
|
||||
MetaSurfaceActor *surface);
|
||||
|
||||
void (*queue_frame_drawn) (MetaWindowActor *actor,
|
||||
gboolean skip_sync_delay);
|
||||
|
||||
void (*post_init) (MetaWindowActor *actor);
|
||||
|
||||
void (*pre_paint) (MetaWindowActor *actor);
|
||||
void (*post_paint) (MetaWindowActor *actor);
|
||||
void (*queue_destroy) (MetaWindowActor *actor);
|
||||
};
|
||||
|
||||
MetaWindowActor *meta_window_actor_new (MetaWindow *window);
|
||||
|
@ -20,6 +20,7 @@
|
||||
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||
*/
|
||||
|
||||
#include "compositor/meta-surface-actor.h"
|
||||
#include "compositor/meta-window-actor-wayland.h"
|
||||
#include "meta/meta-window-actor.h"
|
||||
|
||||
@ -30,9 +31,61 @@ struct _MetaWindowActorWayland
|
||||
|
||||
G_DEFINE_TYPE (MetaWindowActorWayland, meta_window_actor_wayland, META_TYPE_WINDOW_ACTOR)
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_frame_complete (MetaWindowActor *actor,
|
||||
ClutterFrameInfo *frame_info,
|
||||
int64_t presentation_time)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_set_surface_actor (MetaWindowActor *actor,
|
||||
MetaSurfaceActor *surface)
|
||||
{
|
||||
MetaWindowActorClass *parent_class =
|
||||
META_WINDOW_ACTOR_CLASS (meta_window_actor_wayland_parent_class);
|
||||
|
||||
parent_class->set_surface_actor (actor, surface);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_queue_frame_drawn (MetaWindowActor *actor,
|
||||
gboolean skip_sync_delay)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_post_init (MetaWindowActor *actor)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_pre_paint (MetaWindowActor *actor)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_post_paint (MetaWindowActor *actor)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_queue_destroy (MetaWindowActor *actor)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
|
||||
{
|
||||
MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass);
|
||||
|
||||
window_actor_class->frame_complete = meta_window_actor_wayland_frame_complete;
|
||||
window_actor_class->set_surface_actor = meta_window_actor_wayland_set_surface_actor;
|
||||
window_actor_class->queue_frame_drawn = meta_window_actor_wayland_queue_frame_drawn;
|
||||
window_actor_class->post_init = meta_window_actor_wayland_post_init;
|
||||
window_actor_class->pre_paint = meta_window_actor_wayland_pre_paint;
|
||||
window_actor_class->post_paint = meta_window_actor_wayland_post_paint;
|
||||
window_actor_class->queue_destroy = meta_window_actor_wayland_queue_destroy;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -20,19 +20,518 @@
|
||||
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||
*/
|
||||
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "compositor/compositor-private.h"
|
||||
#include "compositor/meta-surface-actor.h"
|
||||
#include "compositor/meta-window-actor-x11.h"
|
||||
#include "core/window-private.h"
|
||||
#include "meta/compositor.h"
|
||||
#include "meta/meta-window-actor.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
#include "meta/window.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
|
||||
struct _MetaWindowActorX11
|
||||
{
|
||||
MetaWindowActor parent;
|
||||
|
||||
/* List of FrameData for recent frames */
|
||||
GList *frames;
|
||||
|
||||
guint send_frame_messages_timer;
|
||||
int64_t frame_drawn_time;
|
||||
|
||||
guint repaint_scheduled_id;
|
||||
|
||||
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
|
||||
* client message for one or more messages in ->frames */
|
||||
gboolean needs_frame_drawn;
|
||||
gboolean repaint_scheduled;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaWindowActorX11, meta_window_actor_x11, META_TYPE_WINDOW_ACTOR)
|
||||
|
||||
/* Each time the application updates the sync request counter to a new even value
|
||||
* value, we queue a frame into the windows list of frames. Once we're painting
|
||||
* an update "in response" to the window, we fill in frame_counter with the
|
||||
* Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the
|
||||
* frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback.
|
||||
*
|
||||
* As an exception, if a window is completely obscured, we try to throttle drawning
|
||||
* to a slower frame rate. In this case, frame_counter stays -1 until
|
||||
* send_frame_message_timeout() runs, at which point we send both the
|
||||
* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint64_t sync_request_serial;
|
||||
int64_t frame_counter;
|
||||
int64_t frame_drawn_time;
|
||||
} FrameData;
|
||||
|
||||
static void
|
||||
frame_data_free (FrameData *frame)
|
||||
{
|
||||
g_slice_free (FrameData, frame);
|
||||
}
|
||||
|
||||
static void
|
||||
surface_repaint_scheduled (MetaSurfaceActor *actor,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data);
|
||||
|
||||
actor_x11->repaint_scheduled = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_frame_messages_timer (MetaWindowActorX11 *actor_x11)
|
||||
{
|
||||
g_assert (actor_x11->send_frame_messages_timer != 0);
|
||||
|
||||
g_source_remove (actor_x11->send_frame_messages_timer);
|
||||
actor_x11->send_frame_messages_timer = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
do_send_frame_drawn (MetaWindowActorX11 *actor_x11,
|
||||
FrameData *frame)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
|
||||
MetaDisplay *display = meta_window_get_display (window);
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
|
||||
XClientMessageEvent ev = { 0, };
|
||||
|
||||
frame->frame_drawn_time =
|
||||
meta_compositor_monotonic_time_to_server_time (display,
|
||||
g_get_monotonic_time ());
|
||||
actor_x11->frame_drawn_time = frame->frame_drawn_time;
|
||||
|
||||
ev.type = ClientMessage;
|
||||
ev.window = meta_window_get_xwindow (window);
|
||||
ev.message_type = display->x11_display->atom__NET_WM_FRAME_DRAWN;
|
||||
ev.format = 32;
|
||||
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff);
|
||||
ev.data.l[1] = frame->sync_request_serial >> 32;
|
||||
ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT (0xffffffff);
|
||||
ev.data.l[3] = frame->frame_drawn_time >> 32;
|
||||
|
||||
meta_x11_error_trap_push (display->x11_display);
|
||||
XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev);
|
||||
XFlush (xdisplay);
|
||||
meta_x11_error_trap_pop (display->x11_display);
|
||||
}
|
||||
|
||||
static void
|
||||
do_send_frame_timings (MetaWindowActorX11 *actor_x11,
|
||||
FrameData *frame,
|
||||
int refresh_interval,
|
||||
int64_t presentation_time)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
|
||||
MetaDisplay *display = meta_window_get_display (window);
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
|
||||
XClientMessageEvent ev = { 0, };
|
||||
|
||||
ev.type = ClientMessage;
|
||||
ev.window = meta_window_get_xwindow (window);
|
||||
ev.message_type = display->x11_display->atom__NET_WM_FRAME_TIMINGS;
|
||||
ev.format = 32;
|
||||
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff);
|
||||
ev.data.l[1] = frame->sync_request_serial >> 32;
|
||||
|
||||
if (presentation_time != 0)
|
||||
{
|
||||
int64_t presentation_time_server =
|
||||
meta_compositor_monotonic_time_to_server_time (display,
|
||||
presentation_time);
|
||||
int64_t presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
|
||||
if (presentation_time_offset == 0)
|
||||
presentation_time_offset = 1;
|
||||
|
||||
if ((int32_t)presentation_time_offset == presentation_time_offset)
|
||||
ev.data.l[2] = presentation_time_offset;
|
||||
}
|
||||
|
||||
ev.data.l[3] = refresh_interval;
|
||||
ev.data.l[4] = 1000 * META_SYNC_DELAY;
|
||||
|
||||
meta_x11_error_trap_push (display->x11_display);
|
||||
XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev);
|
||||
XFlush (xdisplay);
|
||||
meta_x11_error_trap_pop (display->x11_display);
|
||||
}
|
||||
|
||||
static void
|
||||
send_frame_timings (MetaWindowActorX11 *actor_x11,
|
||||
FrameData *frame,
|
||||
ClutterFrameInfo *frame_info,
|
||||
int64_t presentation_time)
|
||||
{
|
||||
float refresh_rate;
|
||||
int refresh_interval;
|
||||
|
||||
refresh_rate = frame_info->refresh_rate;
|
||||
/* 0.0 is a flag for not known, but sanity-check against other odd numbers */
|
||||
if (refresh_rate >= 1.0)
|
||||
refresh_interval = (int) (0.5 + 1000000 / refresh_rate);
|
||||
else
|
||||
refresh_interval = 0;
|
||||
|
||||
do_send_frame_timings (actor_x11, frame, refresh_interval, presentation_time);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
send_frame_messages_timeout (gpointer data)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (data);
|
||||
GList *l;
|
||||
|
||||
for (l = actor_x11->frames; l;)
|
||||
{
|
||||
GList *l_next = l->next;
|
||||
FrameData *frame = l->data;
|
||||
|
||||
if (frame->frame_counter == -1)
|
||||
{
|
||||
do_send_frame_drawn (actor_x11, frame);
|
||||
do_send_frame_timings (actor_x11, frame, 0, 0);
|
||||
|
||||
actor_x11->frames = g_list_delete_link (actor_x11->frames, l);
|
||||
frame_data_free (frame);
|
||||
}
|
||||
|
||||
l = l_next;
|
||||
}
|
||||
|
||||
actor_x11->needs_frame_drawn = FALSE;
|
||||
actor_x11->send_frame_messages_timer = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
|
||||
MetaDisplay *display = meta_window_get_display (window);
|
||||
MetaLogicalMonitor *logical_monitor;
|
||||
int64_t current_time;
|
||||
float refresh_rate;
|
||||
int interval, offset;
|
||||
|
||||
if (actor_x11->send_frame_messages_timer != 0)
|
||||
return;
|
||||
|
||||
logical_monitor = meta_window_get_main_logical_monitor (window);
|
||||
if (logical_monitor)
|
||||
{
|
||||
GList *monitors = meta_logical_monitor_get_monitors (logical_monitor);
|
||||
MetaMonitor *monitor;
|
||||
MetaMonitorMode *mode;
|
||||
|
||||
monitor = g_list_first (monitors)->data;
|
||||
mode = meta_monitor_get_current_mode (monitor);
|
||||
|
||||
refresh_rate = meta_monitor_mode_get_refresh_rate (mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
refresh_rate = 60.0f;
|
||||
}
|
||||
|
||||
current_time =
|
||||
meta_compositor_monotonic_time_to_server_time (display,
|
||||
g_get_monotonic_time ());
|
||||
interval = (int) (1000000 / refresh_rate) * 6;
|
||||
offset = MAX (0, actor_x11->frame_drawn_time + interval - current_time) / 1000;
|
||||
|
||||
/* The clutter master clock source has already been added with META_PRIORITY_REDRAW,
|
||||
* so the timer will run *after* the clutter frame handling, if a frame is ready
|
||||
* to be drawn when the timer expires.
|
||||
*/
|
||||
actor_x11->send_frame_messages_timer =
|
||||
g_timeout_add_full (META_PRIORITY_REDRAW, offset,
|
||||
send_frame_messages_timeout,
|
||||
actor_x11, NULL);
|
||||
g_source_set_name_by_id (actor_x11->send_frame_messages_timer,
|
||||
"[mutter] send_frame_messages_timeout");
|
||||
}
|
||||
|
||||
static void
|
||||
assign_frame_counter_to_frames (MetaWindowActorX11 *actor_x11)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
|
||||
MetaCompositor *compositor = window->display->compositor;
|
||||
ClutterStage *stage = CLUTTER_STAGE (compositor->stage);
|
||||
GList *l;
|
||||
|
||||
/* If the window is obscured, then we're expecting to deal with sending
|
||||
* frame messages in a timeout, rather than in this paint cycle.
|
||||
*/
|
||||
if (actor_x11->send_frame_messages_timer != 0)
|
||||
return;
|
||||
|
||||
for (l = actor_x11->frames; l; l = l->next)
|
||||
{
|
||||
FrameData *frame = l->data;
|
||||
|
||||
if (frame->frame_counter == -1)
|
||||
frame->frame_counter = clutter_stage_get_frame_counter (stage);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_frame_complete (MetaWindowActor *actor,
|
||||
ClutterFrameInfo *frame_info,
|
||||
int64_t presentation_time)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
GList *l;
|
||||
|
||||
if (meta_window_actor_is_destroyed (actor))
|
||||
return;
|
||||
|
||||
for (l = actor_x11->frames; l;)
|
||||
{
|
||||
GList *l_next = l->next;
|
||||
FrameData *frame = l->data;
|
||||
int64_t frame_counter = frame_info->frame_counter;
|
||||
|
||||
if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (actor);
|
||||
|
||||
if (G_UNLIKELY (frame->frame_drawn_time == 0))
|
||||
g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
|
||||
window->desc);
|
||||
if (G_UNLIKELY (frame->frame_counter < frame_counter))
|
||||
g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
|
||||
window->desc, frame->frame_counter);
|
||||
|
||||
actor_x11->frames = g_list_delete_link (actor_x11->frames, l);
|
||||
send_frame_timings (actor_x11, frame, frame_info, presentation_time);
|
||||
frame_data_free (frame);
|
||||
}
|
||||
|
||||
l = l_next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_set_surface_actor (MetaWindowActor *actor,
|
||||
MetaSurfaceActor *surface)
|
||||
{
|
||||
MetaWindowActorClass *parent_class =
|
||||
META_WINDOW_ACTOR_CLASS (meta_window_actor_x11_parent_class);
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
MetaSurfaceActor *old_surface;
|
||||
|
||||
old_surface = meta_window_actor_get_surface (actor);
|
||||
|
||||
if (old_surface)
|
||||
{
|
||||
g_signal_handler_disconnect (old_surface,
|
||||
actor_x11->repaint_scheduled_id);
|
||||
actor_x11->repaint_scheduled_id = 0;
|
||||
}
|
||||
|
||||
parent_class->set_surface_actor (actor, surface);
|
||||
|
||||
if (surface)
|
||||
{
|
||||
actor_x11->repaint_scheduled_id =
|
||||
g_signal_connect (surface, "repaint-scheduled",
|
||||
G_CALLBACK (surface_repaint_scheduled),
|
||||
actor_x11);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_queue_frame_drawn (MetaWindowActor *actor,
|
||||
gboolean skip_sync_delay)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (actor);
|
||||
FrameData *frame;
|
||||
|
||||
if (meta_window_actor_is_destroyed (actor))
|
||||
return;
|
||||
|
||||
frame = g_slice_new0 (FrameData);
|
||||
frame->frame_counter = -1;
|
||||
frame->sync_request_serial = window->sync_request_serial;
|
||||
|
||||
actor_x11->frames = g_list_prepend (actor_x11->frames, frame);
|
||||
|
||||
actor_x11->needs_frame_drawn = TRUE;
|
||||
|
||||
if (skip_sync_delay)
|
||||
{
|
||||
ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (actor_x11));
|
||||
clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
|
||||
}
|
||||
|
||||
if (!actor_x11->repaint_scheduled)
|
||||
{
|
||||
MetaSurfaceActor *surface;
|
||||
gboolean is_obscured;
|
||||
|
||||
surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11));
|
||||
|
||||
if (surface)
|
||||
is_obscured = meta_surface_actor_is_obscured (surface);
|
||||
else
|
||||
is_obscured = FALSE;
|
||||
|
||||
/* A frame was marked by the client without actually doing any
|
||||
* damage or any unobscured, or while we had the window frozen
|
||||
* (e.g. during an interactive resize.) We need to make sure that the
|
||||
* pre_paint/post_paint functions get called, enabling us to
|
||||
* send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
|
||||
* consistent timing with non-empty frames. If the window
|
||||
* is completely obscured we fire off the send_frame_messages timeout.
|
||||
*/
|
||||
if (is_obscured)
|
||||
{
|
||||
queue_send_frame_messages_timeout (actor_x11);
|
||||
}
|
||||
else if (surface)
|
||||
{
|
||||
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (surface), &clip);
|
||||
actor_x11->repaint_scheduled = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_post_init (MetaWindowActor *actor)
|
||||
{
|
||||
MetaWindow *window = meta_window_actor_get_meta_window (actor);
|
||||
|
||||
/* If a window doesn't start off with updates frozen, we should
|
||||
* we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
|
||||
*/
|
||||
if (window->extended_sync_request_counter &&
|
||||
!meta_window_updates_are_frozen (window))
|
||||
meta_window_actor_queue_frame_drawn (actor, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_pre_paint (MetaWindowActor *actor)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
|
||||
assign_frame_counter_to_frames (actor_x11);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_post_paint (MetaWindowActor *actor)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
|
||||
actor_x11->repaint_scheduled = FALSE;
|
||||
|
||||
if (meta_window_actor_is_destroyed (actor))
|
||||
return;
|
||||
|
||||
/* If the window had damage, but wasn't actually redrawn because
|
||||
* it is obscured, we should wait until timer expiration before
|
||||
* sending _NET_WM_FRAME_* messages.
|
||||
*/
|
||||
if (actor_x11->send_frame_messages_timer == 0 &&
|
||||
actor_x11->needs_frame_drawn)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = actor_x11->frames; l; l = l->next)
|
||||
{
|
||||
FrameData *frame = l->data;
|
||||
|
||||
if (frame->frame_drawn_time == 0)
|
||||
do_send_frame_drawn (actor_x11, frame);
|
||||
}
|
||||
|
||||
actor_x11->needs_frame_drawn = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_queue_destroy (MetaWindowActor *actor)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
|
||||
if (actor_x11->send_frame_messages_timer != 0)
|
||||
remove_frame_messages_timer (actor_x11);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor);
|
||||
|
||||
/* This window got damage when obscured; we set up a timer
|
||||
* to send frame completion events, but since we're drawing
|
||||
* the window now (for some other reason) cancel the timer
|
||||
* and send the completion events normally */
|
||||
if (actor_x11->send_frame_messages_timer != 0)
|
||||
{
|
||||
remove_frame_messages_timer (actor_x11);
|
||||
assign_frame_counter_to_frames (actor_x11);
|
||||
}
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_window_actor_x11_parent_class)->paint (actor);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_dispose (GObject *object)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object);
|
||||
|
||||
if (actor_x11->send_frame_messages_timer != 0)
|
||||
remove_frame_messages_timer (actor_x11);
|
||||
|
||||
G_OBJECT_CLASS (meta_window_actor_x11_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_finalize (GObject *object)
|
||||
{
|
||||
MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object);
|
||||
|
||||
g_list_free_full (actor_x11->frames, (GDestroyNotify) frame_data_free);
|
||||
|
||||
G_OBJECT_CLASS (meta_window_actor_x11_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_x11_class_init (MetaWindowActorX11Class *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass);
|
||||
|
||||
window_actor_class->frame_complete = meta_window_actor_x11_frame_complete;
|
||||
window_actor_class->set_surface_actor = meta_window_actor_x11_set_surface_actor;
|
||||
window_actor_class->queue_frame_drawn = meta_window_actor_x11_queue_frame_drawn;
|
||||
window_actor_class->post_init = meta_window_actor_x11_post_init;
|
||||
window_actor_class->pre_paint = meta_window_actor_x11_pre_paint;
|
||||
window_actor_class->post_paint = meta_window_actor_x11_post_paint;
|
||||
window_actor_class->queue_destroy = meta_window_actor_x11_queue_destroy;
|
||||
|
||||
actor_class->paint = meta_window_actor_x11_paint;
|
||||
|
||||
object_class->dispose = meta_window_actor_x11_dispose;
|
||||
object_class->finalize = meta_window_actor_x11_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -12,9 +12,6 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
#include "backends/meta-screen-cast-window.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
@ -34,9 +31,7 @@
|
||||
#include "meta/meta-enum-types.h"
|
||||
#include "meta/meta-shadow-factory.h"
|
||||
#include "meta/meta-shaped-texture.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
#include "meta/window.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "compositor/meta-surface-actor-wayland.h"
|
||||
@ -83,10 +78,6 @@ typedef struct _MetaWindowActorPrivate
|
||||
|
||||
MetaShadowMode shadow_mode;
|
||||
|
||||
guint send_frame_messages_timer;
|
||||
gint64 frame_drawn_time;
|
||||
|
||||
guint repaint_scheduled_id;
|
||||
guint size_changed_id;
|
||||
|
||||
/*
|
||||
@ -100,18 +91,11 @@ typedef struct _MetaWindowActorPrivate
|
||||
gint map_in_progress;
|
||||
gint destroy_in_progress;
|
||||
|
||||
/* List of FrameData for recent frames */
|
||||
GList *frames;
|
||||
guint freeze_count;
|
||||
|
||||
guint visible : 1;
|
||||
guint disposed : 1;
|
||||
|
||||
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
|
||||
* client message for one or more messages in ->frames */
|
||||
guint needs_frame_drawn : 1;
|
||||
guint repaint_scheduled : 1;
|
||||
|
||||
guint needs_reshape : 1;
|
||||
guint recompute_focused_shadow : 1;
|
||||
guint recompute_unfocused_shadow : 1;
|
||||
@ -122,26 +106,6 @@ typedef struct _MetaWindowActorPrivate
|
||||
guint first_frame_state : 2; /* FirstFrameState */
|
||||
} MetaWindowActorPrivate;
|
||||
|
||||
typedef struct _FrameData FrameData;
|
||||
|
||||
/* Each time the application updates the sync request counter to a new even value
|
||||
* value, we queue a frame into the windows list of frames. Once we're painting
|
||||
* an update "in response" to the window, we fill in frame_counter with the
|
||||
* Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the
|
||||
* frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback.
|
||||
*
|
||||
* As an exception, if a window is completely obscured, we try to throttle drawning
|
||||
* to a slower frame rate. In this case, frame_counter stays -1 until
|
||||
* send_frame_message_timeout() runs, at which point we send both the
|
||||
* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages.
|
||||
*/
|
||||
struct _FrameData
|
||||
{
|
||||
guint64 sync_request_serial;
|
||||
int64_t frame_counter;
|
||||
gint64 frame_drawn_time;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FIRST_FRAME,
|
||||
@ -160,7 +124,6 @@ enum
|
||||
};
|
||||
|
||||
static void meta_window_actor_dispose (GObject *object);
|
||||
static void meta_window_actor_finalize (GObject *object);
|
||||
static void meta_window_actor_constructed (GObject *object);
|
||||
static void meta_window_actor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -175,7 +138,8 @@ static void meta_window_actor_paint (ClutterActor *actor);
|
||||
|
||||
static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
static void set_surface (MetaWindowActor *actor,
|
||||
MetaSurfaceActor *surface);
|
||||
|
||||
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
|
||||
|
||||
@ -183,12 +147,6 @@ static void meta_window_actor_handle_updates (MetaWindowActor *self);
|
||||
|
||||
static void check_needs_reshape (MetaWindowActor *self);
|
||||
|
||||
static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame);
|
||||
static void do_send_frame_timings (MetaWindowActor *self,
|
||||
FrameData *frame,
|
||||
gint refresh_interval,
|
||||
gint64 presentation_time);
|
||||
|
||||
static void cullable_iface_init (MetaCullableInterface *iface);
|
||||
|
||||
static void screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface);
|
||||
@ -199,9 +157,10 @@ G_DEFINE_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init));
|
||||
|
||||
static void
|
||||
frame_data_free (FrameData *frame)
|
||||
meta_window_actor_real_set_surface_actor (MetaWindowActor *actor,
|
||||
MetaSurfaceActor *surface)
|
||||
{
|
||||
g_slice_free (FrameData, frame);
|
||||
set_surface (actor, surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -212,7 +171,6 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
|
||||
GParamSpec *pspec;
|
||||
|
||||
object_class->dispose = meta_window_actor_dispose;
|
||||
object_class->finalize = meta_window_actor_finalize;
|
||||
object_class->set_property = meta_window_actor_set_property;
|
||||
object_class->get_property = meta_window_actor_get_property;
|
||||
object_class->constructed = meta_window_actor_constructed;
|
||||
@ -220,6 +178,8 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
|
||||
actor_class->paint = meta_window_actor_paint;
|
||||
actor_class->get_paint_volume = meta_window_actor_get_paint_volume;
|
||||
|
||||
klass->set_surface_actor = meta_window_actor_real_set_surface_actor;
|
||||
|
||||
/**
|
||||
* MetaWindowActor::first-frame:
|
||||
* @actor: the #MetaWindowActor instance
|
||||
@ -314,17 +274,6 @@ surface_size_changed (MetaSurfaceActor *actor,
|
||||
meta_window_actor_update_shape (self);
|
||||
}
|
||||
|
||||
static void
|
||||
surface_repaint_scheduled (MetaSurfaceActor *actor,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaWindowActor *self = META_WINDOW_ACTOR (user_data);
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_argb32 (MetaWindowActor *self)
|
||||
{
|
||||
@ -421,9 +370,7 @@ set_surface (MetaWindowActor *self,
|
||||
|
||||
if (priv->surface)
|
||||
{
|
||||
g_signal_handler_disconnect (priv->surface, priv->repaint_scheduled_id);
|
||||
g_signal_handler_disconnect (priv->surface, priv->size_changed_id);
|
||||
priv->repaint_scheduled_id = 0;
|
||||
clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
||||
g_object_unref (priv->surface);
|
||||
}
|
||||
@ -433,8 +380,6 @@ set_surface (MetaWindowActor *self,
|
||||
if (priv->surface)
|
||||
{
|
||||
g_object_ref_sink (priv->surface);
|
||||
priv->repaint_scheduled_id = g_signal_connect (priv->surface, "repaint-scheduled",
|
||||
G_CALLBACK (surface_repaint_scheduled), self);
|
||||
priv->size_changed_id = g_signal_connect (priv->surface, "size-changed",
|
||||
G_CALLBACK (surface_size_changed), self);
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
||||
@ -501,12 +446,6 @@ meta_window_actor_dispose (GObject *object)
|
||||
|
||||
priv->disposed = TRUE;
|
||||
|
||||
if (priv->send_frame_messages_timer != 0)
|
||||
{
|
||||
g_source_remove (priv->send_frame_messages_timer);
|
||||
priv->send_frame_messages_timer = 0;
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
||||
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
|
||||
|
||||
@ -524,18 +463,6 @@ meta_window_actor_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_finalize (GObject *object)
|
||||
{
|
||||
MetaWindowActor *self = META_WINDOW_ACTOR (object);
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
|
||||
g_list_free_full (priv->frames, (GDestroyNotify) frame_data_free);
|
||||
|
||||
G_OBJECT_CLASS (meta_window_actor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -706,30 +633,6 @@ clip_shadow_under_window (MetaWindowActor *self)
|
||||
return is_non_opaque (self) && priv->window->frame;
|
||||
}
|
||||
|
||||
static void
|
||||
assign_frame_counter_to_frames (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
MetaCompositor *compositor = priv->compositor;
|
||||
ClutterStage *stage = CLUTTER_STAGE (compositor->stage);
|
||||
GList *l;
|
||||
|
||||
/* If the window is obscured, then we're expecting to deal with sending
|
||||
* frame messages in a timeout, rather than in this paint cycle.
|
||||
*/
|
||||
if (priv->send_frame_messages_timer != 0)
|
||||
return;
|
||||
|
||||
for (l = priv->frames; l; l = l->next)
|
||||
{
|
||||
FrameData *frame = l->data;
|
||||
|
||||
if (frame->frame_counter == -1)
|
||||
frame->frame_counter = clutter_stage_get_frame_counter (stage);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_paint (ClutterActor *actor)
|
||||
{
|
||||
@ -742,18 +645,6 @@ meta_window_actor_paint (ClutterActor *actor)
|
||||
|
||||
shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
|
||||
|
||||
/* This window got damage when obscured; we set up a timer
|
||||
* to send frame completion events, but since we're drawing
|
||||
* the window now (for some other reason) cancel the timer
|
||||
* and send the completion events normally */
|
||||
if (priv->send_frame_messages_timer != 0)
|
||||
{
|
||||
g_source_remove (priv->send_frame_messages_timer);
|
||||
priv->send_frame_messages_timer = 0;
|
||||
|
||||
assign_frame_counter_to_frames (self);
|
||||
}
|
||||
|
||||
if (shadow != NULL)
|
||||
{
|
||||
MetaShadowParams params;
|
||||
@ -968,140 +859,12 @@ meta_window_actor_is_destroyed (MetaWindowActor *self)
|
||||
return priv->disposed || priv->needs_destroy;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
send_frame_messages_timeout (gpointer data)
|
||||
{
|
||||
MetaWindowActor *self = (MetaWindowActor *) data;
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
GList *l;
|
||||
|
||||
for (l = priv->frames; l;)
|
||||
{
|
||||
GList *l_next = l->next;
|
||||
FrameData *frame = l->data;
|
||||
|
||||
if (frame->frame_counter == -1)
|
||||
{
|
||||
do_send_frame_drawn (self, frame);
|
||||
do_send_frame_timings (self, frame, 0, 0);
|
||||
|
||||
priv->frames = g_list_delete_link (priv->frames, l);
|
||||
frame_data_free (frame);
|
||||
}
|
||||
|
||||
l = l_next;
|
||||
}
|
||||
|
||||
priv->needs_frame_drawn = FALSE;
|
||||
priv->send_frame_messages_timer = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
queue_send_frame_messages_timeout (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
MetaWindow *window = priv->window;
|
||||
MetaDisplay *display = meta_window_get_display (priv->window);
|
||||
MetaLogicalMonitor *logical_monitor;
|
||||
int64_t current_time;
|
||||
float refresh_rate;
|
||||
int interval, offset;
|
||||
|
||||
if (priv->send_frame_messages_timer != 0)
|
||||
return;
|
||||
|
||||
logical_monitor = meta_window_get_main_logical_monitor (window);
|
||||
if (logical_monitor)
|
||||
{
|
||||
GList *monitors = meta_logical_monitor_get_monitors (logical_monitor);
|
||||
MetaMonitor *monitor;
|
||||
MetaMonitorMode *mode;
|
||||
|
||||
monitor = g_list_first (monitors)->data;
|
||||
mode = meta_monitor_get_current_mode (monitor);
|
||||
|
||||
refresh_rate = meta_monitor_mode_get_refresh_rate (mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
refresh_rate = 60.0f;
|
||||
}
|
||||
|
||||
current_time =
|
||||
meta_compositor_monotonic_time_to_server_time (display,
|
||||
g_get_monotonic_time ());
|
||||
interval = (int)(1000000 / refresh_rate) * 6;
|
||||
offset = MAX (0, priv->frame_drawn_time + interval - current_time) / 1000;
|
||||
|
||||
/* The clutter master clock source has already been added with META_PRIORITY_REDRAW,
|
||||
* so the timer will run *after* the clutter frame handling, if a frame is ready
|
||||
* to be drawn when the timer expires.
|
||||
*/
|
||||
priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL);
|
||||
g_source_set_name_by_id (priv->send_frame_messages_timer, "[mutter] send_frame_messages_timeout");
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
gboolean no_delay_frame)
|
||||
{
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
FrameData *frame;
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
frame = g_slice_new0 (FrameData);
|
||||
frame->frame_counter = -1;
|
||||
|
||||
priv->needs_frame_drawn = TRUE;
|
||||
|
||||
frame->sync_request_serial = priv->window->sync_request_serial;
|
||||
|
||||
priv->frames = g_list_prepend (priv->frames, frame);
|
||||
|
||||
if (no_delay_frame)
|
||||
{
|
||||
ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
|
||||
clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
|
||||
}
|
||||
|
||||
if (!priv->repaint_scheduled)
|
||||
{
|
||||
gboolean is_obscured;
|
||||
|
||||
if (priv->surface)
|
||||
is_obscured = meta_surface_actor_is_obscured (priv->surface);
|
||||
else
|
||||
is_obscured = FALSE;
|
||||
|
||||
/* A frame was marked by the client without actually doing any
|
||||
* damage or any unobscured, or while we had the window frozen
|
||||
* (e.g. during an interactive resize.) We need to make sure that the
|
||||
* pre_paint/post_paint functions get called, enabling us to
|
||||
* send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
|
||||
* consistent timing with non-empty frames. If the window
|
||||
* is completely obscured we fire off the send_frame_messages timeout.
|
||||
*/
|
||||
if (is_obscured)
|
||||
{
|
||||
queue_send_frame_messages_timeout (self);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->surface)
|
||||
{
|
||||
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip);
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->queue_frame_drawn (self,
|
||||
no_delay_frame);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -1317,11 +1080,7 @@ meta_window_actor_queue_destroy (MetaWindowActor *self)
|
||||
|
||||
meta_window_set_compositor_private (window, NULL);
|
||||
|
||||
if (priv->send_frame_messages_timer != 0)
|
||||
{
|
||||
g_source_remove (priv->send_frame_messages_timer);
|
||||
priv->send_frame_messages_timer = 0;
|
||||
}
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->queue_destroy (self);
|
||||
|
||||
if (window_type == META_WINDOW_DROPDOWN_MENU ||
|
||||
window_type == META_WINDOW_POPUP_MENU ||
|
||||
@ -1507,11 +1266,7 @@ meta_window_actor_new (MetaWindow *window)
|
||||
else
|
||||
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
||||
|
||||
/* If a window doesn't start off with updates frozen, we should
|
||||
* we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
|
||||
*/
|
||||
if (priv->window->extended_sync_request_counter && !priv->updates_frozen)
|
||||
meta_window_actor_queue_frame_drawn (self, FALSE);
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->post_init (self);
|
||||
|
||||
meta_window_actor_sync_actor_geometry (self, priv->window->placed);
|
||||
|
||||
@ -2043,36 +1798,7 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
|
||||
|
||||
meta_window_actor_handle_updates (self);
|
||||
|
||||
assign_frame_counter_to_frames (self);
|
||||
}
|
||||
|
||||
static void
|
||||
do_send_frame_drawn (MetaWindowActor *self, FrameData *frame)
|
||||
{
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
MetaDisplay *display = meta_window_get_display (priv->window);
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
|
||||
XClientMessageEvent ev = { 0, };
|
||||
|
||||
frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display,
|
||||
g_get_monotonic_time ());
|
||||
priv->frame_drawn_time = frame->frame_drawn_time;
|
||||
|
||||
ev.type = ClientMessage;
|
||||
ev.window = meta_window_get_xwindow (priv->window);
|
||||
ev.message_type = display->x11_display->atom__NET_WM_FRAME_DRAWN;
|
||||
ev.format = 32;
|
||||
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
|
||||
ev.data.l[1] = frame->sync_request_serial >> 32;
|
||||
ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT(0xffffffff);
|
||||
ev.data.l[3] = frame->frame_drawn_time >> 32;
|
||||
|
||||
meta_x11_error_trap_push (display->x11_display);
|
||||
XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
|
||||
XFlush (xdisplay);
|
||||
meta_x11_error_trap_pop (display->x11_display);
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->pre_paint (self);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2081,31 +1807,11 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
|
||||
priv->repaint_scheduled = FALSE;
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->post_paint (self);
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
/* If the window had damage, but wasn't actually redrawn because
|
||||
* it is obscured, we should wait until timer expiration before
|
||||
* sending _NET_WM_FRAME_* messages.
|
||||
*/
|
||||
if (priv->send_frame_messages_timer == 0 &&
|
||||
priv->needs_frame_drawn)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = priv->frames; l; l = l->next)
|
||||
{
|
||||
FrameData *frame = l->data;
|
||||
|
||||
if (frame->frame_drawn_time == 0)
|
||||
do_send_frame_drawn (self, frame);
|
||||
}
|
||||
|
||||
priv->needs_frame_drawn = FALSE;
|
||||
}
|
||||
|
||||
if (priv->first_frame_state == DRAWING_FIRST_FRAME)
|
||||
{
|
||||
priv->first_frame_state = EMITTED_FIRST_FRAME;
|
||||
@ -2113,100 +1819,14 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_send_frame_timings (MetaWindowActor *self,
|
||||
FrameData *frame,
|
||||
gint refresh_interval,
|
||||
gint64 presentation_time)
|
||||
{
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
MetaDisplay *display = meta_window_get_display (priv->window);
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
|
||||
XClientMessageEvent ev = { 0, };
|
||||
|
||||
ev.type = ClientMessage;
|
||||
ev.window = meta_window_get_xwindow (priv->window);
|
||||
ev.message_type = display->x11_display->atom__NET_WM_FRAME_TIMINGS;
|
||||
ev.format = 32;
|
||||
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
|
||||
ev.data.l[1] = frame->sync_request_serial >> 32;
|
||||
|
||||
if (presentation_time != 0)
|
||||
{
|
||||
gint64 presentation_time_server = meta_compositor_monotonic_time_to_server_time (display,
|
||||
presentation_time);
|
||||
gint64 presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
|
||||
if (presentation_time_offset == 0)
|
||||
presentation_time_offset = 1;
|
||||
|
||||
if ((gint32)presentation_time_offset == presentation_time_offset)
|
||||
ev.data.l[2] = presentation_time_offset;
|
||||
}
|
||||
|
||||
ev.data.l[3] = refresh_interval;
|
||||
ev.data.l[4] = 1000 * META_SYNC_DELAY;
|
||||
|
||||
meta_x11_error_trap_push (display->x11_display);
|
||||
XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
|
||||
XFlush (xdisplay);
|
||||
meta_x11_error_trap_pop (display->x11_display);
|
||||
}
|
||||
|
||||
static void
|
||||
send_frame_timings (MetaWindowActor *self,
|
||||
FrameData *frame,
|
||||
ClutterFrameInfo *frame_info,
|
||||
gint64 presentation_time)
|
||||
{
|
||||
float refresh_rate;
|
||||
int refresh_interval;
|
||||
|
||||
refresh_rate = frame_info->refresh_rate;
|
||||
/* 0.0 is a flag for not known, but sanity-check against other odd numbers */
|
||||
if (refresh_rate >= 1.0)
|
||||
refresh_interval = (int) (0.5 + 1000000 / refresh_rate);
|
||||
else
|
||||
refresh_interval = 0;
|
||||
|
||||
do_send_frame_timings (self, frame, refresh_interval, presentation_time);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_frame_complete (MetaWindowActor *self,
|
||||
ClutterFrameInfo *frame_info,
|
||||
gint64 presentation_time)
|
||||
{
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (self);
|
||||
GList *l;
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
for (l = priv->frames; l;)
|
||||
{
|
||||
GList *l_next = l->next;
|
||||
FrameData *frame = l->data;
|
||||
gint64 frame_counter = frame_info->frame_counter;
|
||||
|
||||
if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
|
||||
{
|
||||
if (G_UNLIKELY (frame->frame_drawn_time == 0))
|
||||
g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
|
||||
priv->window->desc);
|
||||
if (G_UNLIKELY (frame->frame_counter < frame_counter))
|
||||
g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
|
||||
priv->window->desc, frame->frame_counter);
|
||||
|
||||
priv->frames = g_list_delete_link (priv->frames, l);
|
||||
send_frame_timings (self, frame, frame_info, presentation_time);
|
||||
frame_data_free (frame);
|
||||
}
|
||||
|
||||
l = l_next;
|
||||
}
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->frame_complete (self,
|
||||
frame_info,
|
||||
presentation_time);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user