mirror of
https://github.com/brl/mutter.git
synced 2024-12-01 12:20:47 -05:00
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
|
struct _MetaWindowActorClass
|
||||||
{
|
{
|
||||||
ClutterActorClass parent;
|
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);
|
MetaWindowActor *meta_window_actor_new (MetaWindow *window);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "compositor/meta-surface-actor.h"
|
||||||
#include "compositor/meta-window-actor-wayland.h"
|
#include "compositor/meta-window-actor-wayland.h"
|
||||||
#include "meta/meta-window-actor.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)
|
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
|
static void
|
||||||
meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
|
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
|
static void
|
||||||
|
@ -20,19 +20,518 @@
|
|||||||
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
* 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 "compositor/meta-window-actor-x11.h"
|
||||||
|
#include "core/window-private.h"
|
||||||
|
#include "meta/compositor.h"
|
||||||
#include "meta/meta-window-actor.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
|
struct _MetaWindowActorX11
|
||||||
{
|
{
|
||||||
MetaWindowActor parent;
|
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)
|
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
|
static void
|
||||||
meta_window_actor_x11_class_init (MetaWindowActorX11Class *klass)
|
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
|
static void
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.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 "backends/meta-screen-cast-window.h"
|
||||||
#include "clutter/clutter-mutter.h"
|
#include "clutter/clutter-mutter.h"
|
||||||
#include "clutter/x11/clutter-x11.h"
|
#include "clutter/x11/clutter-x11.h"
|
||||||
@ -34,9 +31,7 @@
|
|||||||
#include "meta/meta-enum-types.h"
|
#include "meta/meta-enum-types.h"
|
||||||
#include "meta/meta-shadow-factory.h"
|
#include "meta/meta-shadow-factory.h"
|
||||||
#include "meta/meta-shaped-texture.h"
|
#include "meta/meta-shaped-texture.h"
|
||||||
#include "meta/meta-x11-errors.h"
|
|
||||||
#include "meta/window.h"
|
#include "meta/window.h"
|
||||||
#include "x11/meta-x11-display-private.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
#ifdef HAVE_WAYLAND
|
||||||
#include "compositor/meta-surface-actor-wayland.h"
|
#include "compositor/meta-surface-actor-wayland.h"
|
||||||
@ -83,10 +78,6 @@ typedef struct _MetaWindowActorPrivate
|
|||||||
|
|
||||||
MetaShadowMode shadow_mode;
|
MetaShadowMode shadow_mode;
|
||||||
|
|
||||||
guint send_frame_messages_timer;
|
|
||||||
gint64 frame_drawn_time;
|
|
||||||
|
|
||||||
guint repaint_scheduled_id;
|
|
||||||
guint size_changed_id;
|
guint size_changed_id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -100,18 +91,11 @@ typedef struct _MetaWindowActorPrivate
|
|||||||
gint map_in_progress;
|
gint map_in_progress;
|
||||||
gint destroy_in_progress;
|
gint destroy_in_progress;
|
||||||
|
|
||||||
/* List of FrameData for recent frames */
|
|
||||||
GList *frames;
|
|
||||||
guint freeze_count;
|
guint freeze_count;
|
||||||
|
|
||||||
guint visible : 1;
|
guint visible : 1;
|
||||||
guint disposed : 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 needs_reshape : 1;
|
||||||
guint recompute_focused_shadow : 1;
|
guint recompute_focused_shadow : 1;
|
||||||
guint recompute_unfocused_shadow : 1;
|
guint recompute_unfocused_shadow : 1;
|
||||||
@ -122,26 +106,6 @@ typedef struct _MetaWindowActorPrivate
|
|||||||
guint first_frame_state : 2; /* FirstFrameState */
|
guint first_frame_state : 2; /* FirstFrameState */
|
||||||
} MetaWindowActorPrivate;
|
} 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
|
enum
|
||||||
{
|
{
|
||||||
FIRST_FRAME,
|
FIRST_FRAME,
|
||||||
@ -160,7 +124,6 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void meta_window_actor_dispose (GObject *object);
|
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_constructed (GObject *object);
|
||||||
static void meta_window_actor_set_property (GObject *object,
|
static void meta_window_actor_set_property (GObject *object,
|
||||||
guint prop_id,
|
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,
|
static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
|
||||||
ClutterPaintVolume *volume);
|
ClutterPaintVolume *volume);
|
||||||
|
static void set_surface (MetaWindowActor *actor,
|
||||||
|
MetaSurfaceActor *surface);
|
||||||
|
|
||||||
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
|
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 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 cullable_iface_init (MetaCullableInterface *iface);
|
||||||
|
|
||||||
static void screen_cast_window_iface_init (MetaScreenCastWindowInterface *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));
|
G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init));
|
||||||
|
|
||||||
static void
|
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
|
static void
|
||||||
@ -212,7 +171,6 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
|
|||||||
GParamSpec *pspec;
|
GParamSpec *pspec;
|
||||||
|
|
||||||
object_class->dispose = meta_window_actor_dispose;
|
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->set_property = meta_window_actor_set_property;
|
||||||
object_class->get_property = meta_window_actor_get_property;
|
object_class->get_property = meta_window_actor_get_property;
|
||||||
object_class->constructed = meta_window_actor_constructed;
|
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->paint = meta_window_actor_paint;
|
||||||
actor_class->get_paint_volume = meta_window_actor_get_paint_volume;
|
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:
|
* MetaWindowActor::first-frame:
|
||||||
* @actor: the #MetaWindowActor instance
|
* @actor: the #MetaWindowActor instance
|
||||||
@ -314,17 +274,6 @@ surface_size_changed (MetaSurfaceActor *actor,
|
|||||||
meta_window_actor_update_shape (self);
|
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
|
static gboolean
|
||||||
is_argb32 (MetaWindowActor *self)
|
is_argb32 (MetaWindowActor *self)
|
||||||
{
|
{
|
||||||
@ -421,9 +370,7 @@ set_surface (MetaWindowActor *self,
|
|||||||
|
|
||||||
if (priv->surface)
|
if (priv->surface)
|
||||||
{
|
{
|
||||||
g_signal_handler_disconnect (priv->surface, priv->repaint_scheduled_id);
|
|
||||||
g_signal_handler_disconnect (priv->surface, priv->size_changed_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));
|
clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
||||||
g_object_unref (priv->surface);
|
g_object_unref (priv->surface);
|
||||||
}
|
}
|
||||||
@ -433,8 +380,6 @@ set_surface (MetaWindowActor *self,
|
|||||||
if (priv->surface)
|
if (priv->surface)
|
||||||
{
|
{
|
||||||
g_object_ref_sink (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",
|
priv->size_changed_id = g_signal_connect (priv->surface, "size-changed",
|
||||||
G_CALLBACK (surface_size_changed), self);
|
G_CALLBACK (surface_size_changed), self);
|
||||||
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
||||||
@ -501,12 +446,6 @@ meta_window_actor_dispose (GObject *object)
|
|||||||
|
|
||||||
priv->disposed = TRUE;
|
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->shape_region, cairo_region_destroy);
|
||||||
g_clear_pointer (&priv->shadow_clip, 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);
|
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
|
static void
|
||||||
meta_window_actor_set_property (GObject *object,
|
meta_window_actor_set_property (GObject *object,
|
||||||
guint prop_id,
|
guint prop_id,
|
||||||
@ -706,30 +633,6 @@ clip_shadow_under_window (MetaWindowActor *self)
|
|||||||
return is_non_opaque (self) && priv->window->frame;
|
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
|
static void
|
||||||
meta_window_actor_paint (ClutterActor *actor)
|
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;
|
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)
|
if (shadow != NULL)
|
||||||
{
|
{
|
||||||
MetaShadowParams params;
|
MetaShadowParams params;
|
||||||
@ -968,140 +859,12 @@ meta_window_actor_is_destroyed (MetaWindowActor *self)
|
|||||||
return priv->disposed || priv->needs_destroy;
|
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
|
void
|
||||||
meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||||
gboolean no_delay_frame)
|
gboolean no_delay_frame)
|
||||||
{
|
{
|
||||||
MetaWindowActorPrivate *priv =
|
META_WINDOW_ACTOR_GET_CLASS (self)->queue_frame_drawn (self,
|
||||||
meta_window_actor_get_instance_private (self);
|
no_delay_frame);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@ -1317,11 +1080,7 @@ meta_window_actor_queue_destroy (MetaWindowActor *self)
|
|||||||
|
|
||||||
meta_window_set_compositor_private (window, NULL);
|
meta_window_set_compositor_private (window, NULL);
|
||||||
|
|
||||||
if (priv->send_frame_messages_timer != 0)
|
META_WINDOW_ACTOR_GET_CLASS (self)->queue_destroy (self);
|
||||||
{
|
|
||||||
g_source_remove (priv->send_frame_messages_timer);
|
|
||||||
priv->send_frame_messages_timer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window_type == META_WINDOW_DROPDOWN_MENU ||
|
if (window_type == META_WINDOW_DROPDOWN_MENU ||
|
||||||
window_type == META_WINDOW_POPUP_MENU ||
|
window_type == META_WINDOW_POPUP_MENU ||
|
||||||
@ -1507,11 +1266,7 @@ meta_window_actor_new (MetaWindow *window)
|
|||||||
else
|
else
|
||||||
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
||||||
|
|
||||||
/* If a window doesn't start off with updates frozen, we should
|
META_WINDOW_ACTOR_GET_CLASS (self)->post_init (self);
|
||||||
* 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_sync_actor_geometry (self, priv->window->placed);
|
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);
|
meta_window_actor_handle_updates (self);
|
||||||
|
|
||||||
assign_frame_counter_to_frames (self);
|
META_WINDOW_ACTOR_GET_CLASS (self)->pre_paint (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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2081,31 +1807,11 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
|||||||
MetaWindowActorPrivate *priv =
|
MetaWindowActorPrivate *priv =
|
||||||
meta_window_actor_get_instance_private (self);
|
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))
|
if (meta_window_actor_is_destroyed (self))
|
||||||
return;
|
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)
|
if (priv->first_frame_state == DRAWING_FIRST_FRAME)
|
||||||
{
|
{
|
||||||
priv->first_frame_state = EMITTED_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
|
void
|
||||||
meta_window_actor_frame_complete (MetaWindowActor *self,
|
meta_window_actor_frame_complete (MetaWindowActor *self,
|
||||||
ClutterFrameInfo *frame_info,
|
ClutterFrameInfo *frame_info,
|
||||||
gint64 presentation_time)
|
gint64 presentation_time)
|
||||||
{
|
{
|
||||||
MetaWindowActorPrivate *priv =
|
META_WINDOW_ACTOR_GET_CLASS (self)->frame_complete (self,
|
||||||
meta_window_actor_get_instance_private (self);
|
frame_info,
|
||||||
GList *l;
|
presentation_time);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
Reference in New Issue
Block a user