/* * Copyright (C) 2020 Alberts Muktupāvels * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include "meta-compositor-xpresent.h" #include #include "display-private.h" #include "errors.h" #include "screen-private.h" #define NUM_BUFFER 2 struct _MetaCompositorXPresent { MetaCompositorXRender parent; int major_opcode; int event_base; int error_base; Picture root_buffers[NUM_BUFFER]; Pixmap root_pixmaps[NUM_BUFFER]; int root_current; gboolean present_pending; }; G_DEFINE_TYPE (MetaCompositorXPresent, meta_compositor_xpresent, META_TYPE_COMPOSITOR_XRENDER) static gboolean meta_compositor_xpresent_manage (MetaCompositor *compositor, GError **error) { MetaCompositorClass *compositor_class; MetaCompositorXPresent *self; MetaDisplay *display; Display *xdisplay; compositor_class = META_COMPOSITOR_CLASS (meta_compositor_xpresent_parent_class); if (!compositor_class->manage (compositor, error)) return FALSE; self = META_COMPOSITOR_XPRESENT (compositor); display = meta_compositor_get_display (compositor); xdisplay = meta_display_get_xdisplay (display); if (!XPresentQueryExtension (xdisplay, &self->major_opcode, &self->event_base, &self->error_base)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Missing present extension required for compositing"); return FALSE; } XPresentSelectInput (xdisplay, meta_compositor_get_overlay_window (compositor), PresentCompleteNotifyMask); return TRUE; } static void meta_compositor_xpresent_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window) { MetaCompositorXPresent *self; MetaCompositorClass *compositor_class; self = META_COMPOSITOR_XPRESENT (compositor); if (event->type == GenericEvent) { XGenericEvent *generic_event; XGenericEventCookie *generic_event_cookie; MetaDisplay *display; Display *xdisplay; generic_event = (XGenericEvent *) event; generic_event_cookie = (XGenericEventCookie *) generic_event; display = meta_compositor_get_display (compositor); xdisplay = meta_display_get_xdisplay (display); if (generic_event_cookie->extension == self->major_opcode) { XGetEventData (xdisplay, generic_event_cookie); if (generic_event_cookie->evtype == PresentCompleteNotify) { meta_compositor_queue_redraw (compositor); self->present_pending = FALSE; } XFreeEventData (xdisplay, generic_event_cookie); } } compositor_class = META_COMPOSITOR_CLASS (meta_compositor_xpresent_parent_class); compositor_class->process_event (compositor, event, window); } static gboolean meta_compositor_xpresent_ready_to_redraw (MetaCompositor *compositor) { MetaCompositorXPresent *self; self = META_COMPOSITOR_XPRESENT (compositor); return !self->present_pending; } static void meta_compositor_xpresent_redraw (MetaCompositor *compositor, XserverRegion all_damage) { MetaCompositorXPresent *self; MetaDisplay *display; Display *xdisplay; int result; self = META_COMPOSITOR_XPRESENT (compositor); display = meta_compositor_get_display (META_COMPOSITOR (self)); xdisplay = meta_display_get_xdisplay (display); meta_compositor_xrender_draw (META_COMPOSITOR_XRENDER (compositor), self->root_buffers[self->root_current], all_damage); meta_error_trap_push (display); XPresentPixmap (xdisplay, meta_compositor_get_overlay_window (compositor), self->root_pixmaps[self->root_current], 0, all_damage, all_damage, 0, 0, None, None, None, PresentOptionNone, 0, 1, 0, NULL, 0); result = meta_error_trap_pop_with_return (display); if (result != Success) { char error_text[64]; XGetErrorText (xdisplay, result, error_text, 63); g_warning ("XPresentPixmap failed with error %i (%s)", result, error_text); g_unsetenv ("META_COMPOSITOR"); meta_display_update_compositor (display); return; } self->root_current = !self->root_current; self->present_pending = TRUE; } static void meta_compositor_xpresent_ensure_root_buffers (MetaCompositorXRender *xrender) { MetaCompositorXPresent *self; int i; self = META_COMPOSITOR_XPRESENT (xrender); for (i = 0; i < NUM_BUFFER; i++) { if (self->root_buffers[i] == None && self->root_pixmaps[i] == None) { meta_compositor_xrender_create_root_buffer (xrender, &self->root_pixmaps[i], &self->root_buffers[i]); } } } static void meta_compositor_xpresent_free_root_buffers (MetaCompositorXRender *xrender) { MetaCompositorXPresent *self; MetaDisplay *display; Display *xdisplay; int i; self = META_COMPOSITOR_XPRESENT (xrender); display = meta_compositor_get_display (META_COMPOSITOR (self)); xdisplay = meta_display_get_xdisplay (display); for (i = 0; i < NUM_BUFFER; i++) { if (self->root_buffers[i] != None) { XRenderFreePicture (xdisplay, self->root_buffers[i]); self->root_buffers[i] = None; } if (self->root_pixmaps[i] != None) { XFreePixmap (xdisplay, self->root_pixmaps[i]); self->root_pixmaps[i] = None; } } } static void meta_compositor_xpresent_class_init (MetaCompositorXPresentClass *self_class) { MetaCompositorClass *compositor_class; MetaCompositorXRenderClass *xrender_class; compositor_class = META_COMPOSITOR_CLASS (self_class); xrender_class = META_COMPOSITOR_XRENDER_CLASS (self_class); compositor_class->manage = meta_compositor_xpresent_manage; compositor_class->process_event = meta_compositor_xpresent_process_event; compositor_class->ready_to_redraw = meta_compositor_xpresent_ready_to_redraw; compositor_class->redraw = meta_compositor_xpresent_redraw; xrender_class->ensure_root_buffers = meta_compositor_xpresent_ensure_root_buffers; xrender_class->free_root_buffers = meta_compositor_xpresent_free_root_buffers; } static void meta_compositor_xpresent_init (MetaCompositorXPresent *self) { int i; for (i = 0; i < NUM_BUFFER; i++) { self->root_buffers[i] = None; self->root_pixmaps[i] = None; } } MetaCompositor * meta_compositor_xpresent_new (MetaDisplay *display, GError **error) { return g_initable_new (META_TYPE_COMPOSITOR_XPRESENT, NULL, error, "display", display, NULL); }