static EGLBoolean dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, EGLint numRects, const EGLint *rects) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); EGLBoolean ret; xcb_xfixes_region_t region; xcb_rectangle_t rectangles[16]; int i; if (numRects > (int)ARRAY_SIZE(rectangles)) return dri2_copy_region(drv, disp, draw, dri2_surf->region); for (i = 0; i < numRects; i++) { rectangles[i].x = rects[i * 4]; rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3]; rectangles[i].width = rects[i * 4 + 2]; rectangles[i].height = rects[i * 4 + 3]; } region = xcb_generate_id(dri2_dpy->conn); xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles); ret = dri2_copy_region(drv, disp, draw, region); xcb_xfixes_destroy_region(dri2_dpy->conn, region); return ret; }
void QDri2Context::swapBuffers() { Q_D(QDri2Context); xcb_rectangle_t rectangle; rectangle.x = 0; rectangle.y = 0; rectangle.width = d->qXcbWindow->widget()->geometry().width(); rectangle.height = d->qXcbWindow->widget()->geometry().height(); xcb_xfixes_region_t xfixesRegion = xcb_generate_id(d->xcbConnection()); xcb_xfixes_create_region(d->xcbConnection(), xfixesRegion, 1, &rectangle); xcb_dri2_copy_region_cookie_t cookie = xcb_dri2_copy_region_unchecked(d->xcbConnection(), d->qXcbWindow->window(), xfixesRegion, XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT); xcb_dri2_copy_region_reply_t *reply = xcb_dri2_copy_region_reply(d->xcbConnection(),cookie,NULL); //cleanup delete reply; xcb_xfixes_destroy_region(d->xcbConnection(), xfixesRegion); }
static void vl_dri3_flush_frontbuffer(struct pipe_screen *screen, struct pipe_resource *resource, unsigned level, unsigned layer, void *context_private, struct pipe_box *sub_box) { struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)context_private; uint32_t options = XCB_PRESENT_OPTION_NONE; struct vl_dri3_buffer *back; struct pipe_box src_box; xcb_xfixes_region_t region; xcb_rectangle_t rectangle; back = scrn->back_buffers[scrn->cur_back]; if (!back) return; while (scrn->special_event && scrn->recv_sbc < scrn->send_sbc) if (!dri3_wait_present_events(scrn)) return; rectangle.x = 0; rectangle.y = 0; rectangle.width = (scrn->output_texture) ? scrn->clip_width : scrn->width; rectangle.height = (scrn->output_texture) ? scrn->clip_height : scrn->height; region = xcb_generate_id(scrn->conn); xcb_xfixes_create_region(scrn->conn, region, 2, &rectangle); if (scrn->is_different_gpu) { u_box_origin_2d(back->width, back->height, &src_box); scrn->pipe->resource_copy_region(scrn->pipe, back->linear_texture, 0, 0, 0, 0, back->texture, 0, &src_box); scrn->pipe->flush(scrn->pipe, NULL, 0); } xshmfence_reset(back->shm_fence); back->busy = true; xcb_present_pixmap(scrn->conn, scrn->drawable, back->pixmap, (uint32_t)(++scrn->send_sbc), 0, region, 0, 0, None, None, back->sync_fence, options, scrn->next_msc, 0, 0, 0, NULL); xcb_flush(scrn->conn); return; }
/** Add the given Region to the damaged Region by either copying it if * the global Damaged is currently empty or adding it otherwise * * @todo: Perhaps the copy of the region could be avoided if it * really impacts on performances, but for now this does not * seem to be an issue * * \param region Damaged Region to be added to the global one */ void display_add_damaged_region(xcb_xfixes_region_t *region, bool do_destroy_region) { if(!*region) return; if(globalconf.damaged) { xcb_xfixes_union_region(globalconf.connection, globalconf.damaged, *region, globalconf.damaged); debug("Added %x to damaged region %x", *region, globalconf.damaged); if(do_destroy_region) xcb_xfixes_destroy_region(globalconf.connection, *region); } else { /* If the region should not be destroyed, then copy the given Region as it is generally the Window Region and can still be used later on whereas the damaged Region is cleared at each painting iteration */ if(!do_destroy_region) { globalconf.damaged = xcb_generate_id(globalconf.connection); xcb_xfixes_create_region(globalconf.connection, globalconf.damaged, 0, NULL); xcb_xfixes_copy_region(globalconf.connection, *region, globalconf.damaged); } else globalconf.damaged = *region; debug("Initialized damaged region to %x (copied: %d)", globalconf.damaged, !do_destroy_region); } if(do_destroy_region) *region = XCB_NONE; }
/** * Process list of buffer received from the server * * Processes the list of buffers received in a reply from the server to either * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. */ static void dri2_process_buffers(struct dri2_egl_surface *dri2_surf, xcb_dri2_dri2_buffer_t *buffers, unsigned count) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); xcb_rectangle_t rectangle; unsigned i; dri2_surf->buffer_count = count; dri2_surf->have_fake_front = 0; /* This assumes the DRI2 buffer attachment tokens matches the * __DRIbuffer tokens. */ for (i = 0; i < count; i++) { dri2_surf->buffers[i].attachment = buffers[i].attachment; dri2_surf->buffers[i].name = buffers[i].name; dri2_surf->buffers[i].pitch = buffers[i].pitch; dri2_surf->buffers[i].cpp = buffers[i].cpp; dri2_surf->buffers[i].flags = buffers[i].flags; /* We only use the DRI drivers single buffer configs. This * means that if we try to render to a window, DRI2 will give us * the fake front buffer, which we'll use as a back buffer. * Note that EGL doesn't require that several clients rendering * to the same window must see the same aux buffers. */ if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) dri2_surf->have_fake_front = 1; } if (dri2_surf->region != XCB_NONE) xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region); rectangle.x = 0; rectangle.y = 0; rectangle.width = dri2_surf->base.Width; rectangle.height = dri2_surf->base.Height; dri2_surf->region = xcb_generate_id(dri2_dpy->conn); xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle); }
/** * Create a region from rectangles. * @param rects The rectangles used to initialize the region. * @param num The number of rectangles. * @return The newly created region. * * Create a region initialized to the specified list of rectangles * @p rects. The rectangles may be specified in any order, their union * becomes the region. * @ingroup Ecore_X_Fixes_Group */ EAPI Ecore_X_Region ecore_x_region_new(Ecore_X_Rectangle *rects, int num) { Ecore_X_Region region = 0; #ifdef ECORE_XCB_XFIXES xcb_rectangle_t *xrects; #endif LOGFN(__FILE__, __LINE__, __FUNCTION__); CHECK_XCB_CONN; if (!_xfixes_avail) return 0; #ifdef ECORE_XCB_XFIXES xrects = _ecore_xcb_rect_to_xcb(rects, num); region = xcb_generate_id(_ecore_xcb_conn); xcb_xfixes_create_region(_ecore_xcb_conn, region, num, xrects); free(xrects); // ecore_x_flush(); #endif return region; }
void * run_event_loop(void *thread_arg_struct) { _connection_data *conn_data; xcwm_context_t *context; xcb_connection_t *event_conn; xcb_generic_event_t *evt; xcwm_event_t return_evt; xcwm_event_cb_t callback_ptr; conn_data = thread_arg_struct; context = conn_data->context; event_conn = context->conn; callback_ptr = conn_data->callback; free(thread_arg_struct); _xcwm_windows_adopt(context, callback_ptr); /* Start the event loop, and flush if first */ xcb_flush(event_conn); while ((evt = xcb_wait_for_event(event_conn))) { uint8_t response_type = evt->response_type & ~0x80; if (response_type == context->damage_event_mask) { xcb_damage_notify_event_t *dmgevnt = (xcb_damage_notify_event_t *)evt; /* printf("damage %d,%d @ %d,%d reported against window 0x%08x\n", */ /* dmgevnt->area.width, dmgevnt->area.height, dmgevnt->area.x, dmgevnt->area.y, */ /* dmgevnt->drawable); */ xcwm_window_t *window = _xcwm_get_window_node_by_window_id(dmgevnt->drawable); return_evt.event_type = XCWM_EVENT_WINDOW_DAMAGE; return_evt.window = window; if (!window) { printf("damage reported against unknown window 0x%08x\n", dmgevnt->drawable); continue; } /* Increase the damaged area of window if new damage is * larger than current. */ xcwm_event_get_thread_lock(); /* Initial damage events for override-redirect windows are * reported relative to the root window, subsequent events * are relative to the window itself. We also catch cases * where the damage area is larger than the bounds of the * window. */ if (window->initial_damage == 1 || (dmgevnt->area.width > window->bounds.width) || (dmgevnt->area.height > window->bounds.height) ) { xcb_xfixes_region_t region = xcb_generate_id(window->context->conn); xcb_rectangle_t rect; /* printf("initial damage on window 0x%08x\n", dmgevnt->drawable); */ /* Remove the damage */ xcb_xfixes_create_region(window->context->conn, region, 1, &dmgevnt->area); xcb_damage_subtract(window->context->conn, window->damage, region, XCB_NONE); /* Add new damage area for entire window */ rect.x = 0; rect.y = 0; rect.width = window->bounds.width; rect.height = window->bounds.height; xcb_xfixes_set_region(window->context->conn, region, 1, &rect); xcb_damage_add(window->context->conn, window->window_id, region); window->initial_damage = 0; xcb_xfixes_destroy_region(window->context->conn, region); xcwm_event_release_thread_lock(); continue; } window->dmg_bounds.x = dmgevnt->area.x; window->dmg_bounds.y = dmgevnt->area.y; window->dmg_bounds.width = dmgevnt->area.width; window->dmg_bounds.height = dmgevnt->area.height; xcwm_event_release_thread_lock(); callback_ptr(&return_evt); } else if (response_type == context->shape_event) { xcb_shape_notify_event_t *shapeevnt = (xcb_shape_notify_event_t *)evt; if (shapeevnt->shape_kind == XCB_SHAPE_SK_BOUNDING) { xcwm_window_t *window = _xcwm_get_window_node_by_window_id(shapeevnt->affected_window); _xcwm_window_set_shape(window, shapeevnt->shaped); return_evt.event_type = XCWM_EVENT_WINDOW_SHAPE; return_evt.window = window; callback_ptr(&return_evt); } } else if (response_type == context->fixes_event_base + XCB_XFIXES_CURSOR_NOTIFY) { /* xcb_xfixes_cursor_notify_event_t *cursorevnt = */ /* (xcb_xfixes_cursor_notify_event_t *)evt; */ return_evt.event_type = XCWM_EVENT_CURSOR; return_evt.window = NULL; callback_ptr(&return_evt); } else { switch (response_type) { case 0: { /* Error case. Something very bad has happened. Spit * out some hopefully useful information and then * die. * FIXME: Decide under what circumstances we should * acutally kill the application. */ xcb_generic_error_t *err = (xcb_generic_error_t *)evt; fprintf(stderr, "Error received in event loop.\n" "Error code: %i\n", err->error_code); if ((err->error_code >= XCB_VALUE) && (err->error_code <= XCB_FONT)) { xcb_value_error_t *val_err = (xcb_value_error_t *)evt; fprintf(stderr, "Bad value: %i\n" "Major opcode: %i\n" "Minor opcode: %i\n", val_err->bad_value, val_err->major_opcode, val_err->minor_opcode); } break; } case XCB_EXPOSE: { xcb_expose_event_t *exevnt = (xcb_expose_event_t *)evt; printf( "Window %u exposed. Region to be redrawn at location (%d, %d), ", exevnt->window, exevnt->x, exevnt->y); printf("with dimensions (%d, %d).\n", exevnt->width, exevnt->height); return_evt.event_type = XCWM_EVENT_WINDOW_EXPOSE; callback_ptr(&return_evt); break; } case XCB_CREATE_NOTIFY: { /* We don't actually allow our client to create its * window here, wait until the XCB_MAP_REQUEST */ break; } case XCB_DESTROY_NOTIFY: { // Window destroyed in root window xcb_destroy_notify_event_t *notify = (xcb_destroy_notify_event_t *)evt; xcwm_window_t *window = _xcwm_window_remove(event_conn, notify->window); if (!window) { /* Not a window in the list, don't try and destroy */ break; } return_evt.event_type = XCWM_EVENT_WINDOW_DESTROY; return_evt.window = window; callback_ptr(&return_evt); // Release memory for the window _xcwm_window_release(window); break; } case XCB_MAP_NOTIFY: { xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)evt; /* notify->event holds parent of the window */ xcwm_window_t *window = _xcwm_get_window_node_by_window_id(notify->window); if (!window) { /* No MAP_REQUEST for override-redirect windows, so need to create the xcwm_window_t for it now */ /* printf("MAP_NOTIFY without MAP_REQUEST\n"); */ window = _xcwm_window_create(context, notify->window, notify->event); if (window) { _xcwm_window_composite_pixmap_update(window); return_evt.window = window; return_evt.event_type = XCWM_EVENT_WINDOW_CREATE; callback_ptr(&return_evt); } } else { _xcwm_window_composite_pixmap_update(window); } break; } case XCB_MAP_REQUEST: { xcb_map_request_event_t *request = (xcb_map_request_event_t *)evt; /* Map the window */ xcb_map_window(context->conn, request->window); xcb_flush(context->conn); return_evt.window = _xcwm_window_create(context, request->window, request->parent); if (!return_evt.window) { break; } return_evt.event_type = XCWM_EVENT_WINDOW_CREATE; callback_ptr(&return_evt); break; } case XCB_UNMAP_NOTIFY: { xcb_unmap_notify_event_t *notify = (xcb_unmap_notify_event_t *)evt; xcwm_window_t *window = _xcwm_window_remove(event_conn, notify->window); if (!window) { /* Not a window in the list, don't try and destroy */ break; } return_evt.event_type = XCWM_EVENT_WINDOW_DESTROY; return_evt.window = window; callback_ptr(&return_evt); _xcwm_window_composite_pixmap_release(window); // Release memory for the window _xcwm_window_release(window); break; } case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t *request = (xcb_configure_notify_event_t *)evt; printf("CONFIGURE_NOTIFY: XID 0x%08x %dx%d @ %d,%d\n", request->window, request->width, request->height, request->x, request->y); xcwm_window_t *window = _xcwm_get_window_node_by_window_id(request->window); if (window) _xcwm_window_composite_pixmap_update(window); break; } case XCB_CONFIGURE_REQUEST: { xcb_configure_request_event_t *request = (xcb_configure_request_event_t *)evt; printf("CONFIGURE_REQUEST: XID 0x%08x %dx%d @ %d,%d mask 0x%04x\n", request->window, request->width, request->height, request->x, request->y, request->value_mask); /* relying on the server's idea of the current values of values not in value_mask is a bad idea, we might have a configure request of our own on this window in flight */ if (request->value_mask & (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT)) _xcwm_resize_window(event_conn, request->window, request->x, request->y, request->width, request->height); /* Ignore requests to change stacking ? */ break; } case XCB_PROPERTY_NOTIFY: { xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)evt; xcwm_window_t *window = _xcwm_get_window_node_by_window_id(notify->window); if (!window) { break; } /* If this is WM_PROTOCOLS, do not send event, just * handle internally */ if (notify->atom == window->context->atoms.ewmh_conn.WM_PROTOCOLS) { _xcwm_atoms_set_wm_delete(window); break; } xcwm_event_type_t event; if (_xcwm_atom_change_to_event(notify->atom, window, &event)) { /* Send the appropriate event */ return_evt.event_type = event; return_evt.window = window; callback_ptr(&return_evt); } else { printf("PROPERTY_NOTIFY for ignored property atom %d\n", notify->atom); /* We need a mechanism to forward properties we don't know about to WM, otherwise everything needs to be in libXcwm ...? */ } break; } case XCB_MAPPING_NOTIFY: break; default: { printf("UNKNOWN EVENT: %i\n", (evt->response_type & ~0x80)); break; } } } /* Free the event */ free(evt); } return NULL; }
static void PRESENTForceReleases(PRESENTpriv *present_priv) { PRESENTPixmapPriv *current = NULL; if (!present_priv->window) return; /* There should be no other thread listening for events here. * This can happen when hDestWindowOverride changes without reset. * This case should never happen, but can happen in theory.*/ if (present_priv->xcb_wait) { xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0); xcb_flush(present_priv->xcb_connection); pthread_mutex_lock(&present_priv->mutex_xcb_wait); pthread_mutex_unlock(&present_priv->mutex_xcb_wait); /* the problem here is that we don't have access to the event the other thread got. * It is either presented event, idle event or notify event. */ while (present_priv->pixmap_present_pending >= 2) PRESENTwait_events(present_priv, FALSE); PRESENTflush_events(present_priv, TRUE); /* Remaining events to come can be a pair of present/idle, * or an idle, or nothing. To be sure we are after all pixmaps * have been presented, add an event to the queue that can only * be after the present event, then if we receive an event more, * we are sure all pixmaps were presented */ present_priv->notify_with_serial_pending = TRUE; xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 1, present_priv->last_target + 5, 0, 0); xcb_flush(present_priv->xcb_connection); while (present_priv->notify_with_serial_pending) PRESENTwait_events(present_priv, FALSE); /* Now we are sure we are not expecting any new event */ } else { while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */ PRESENTwait_events(present_priv, FALSE); PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */ /* Since idle events are send with the complete events when it is not flips, * we are not expecting any new event here */ } current = present_priv->first_present_priv; while (current) { if (!current->released) { if (!current->last_present_was_flip && !present_priv->xcb_wait) { ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n"); } else { /* Present the same pixmap with a non-valid part to force the copy mode and the releases */ xcb_xfixes_region_t valid, update; xcb_rectangle_t rect_update; rect_update.x = 0; rect_update.y = 0; rect_update.width = 8; rect_update.height = 1; valid = xcb_generate_id(present_priv->xcb_connection); update = xcb_generate_id(present_priv->xcb_connection); xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update); xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update); /* here we know the pixmap has been presented. Thus if it is on screen, * the following request can only make it released by the server if it is not */ xcb_present_pixmap(present_priv->xcb_connection, present_priv->window, current->pixmap, 0, valid, update, 0, 0, None, None, None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL); xcb_flush(present_priv->xcb_connection); PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */ PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */ } } current = current->next; } /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet), * and we don't expect any new Present event to come from Xserver */ }
BOOL PRESENTPixmap(Display *dpy, XID window, PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters, const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion) { PRESENTpriv *present_priv = present_pixmap_priv->present_priv; #ifdef D3DADAPTER9_DRI2 struct DRI2priv *dri2_priv = present_pixmap_priv->dri2_info.dri2_priv; EGLenum current_api = 0; #endif xcb_void_cookie_t cookie; xcb_generic_error_t *error; int64_t target_msc, presentationInterval; xcb_xfixes_region_t valid, update; int16_t x_off, y_off; uint32_t options = XCB_PRESENT_OPTION_NONE; pthread_mutex_lock(&present_priv->mutex_present); if (window != present_priv->window) PRESENTPrivChangeWindow(present_priv, window); if (!window) { ERR("ERROR: Try to Present a pixmap on a NULL window\n"); pthread_mutex_unlock(&present_priv->mutex_present); return FALSE; } PRESENTflush_events(present_priv, FALSE); if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) { ERR("FATAL ERROR: Trying to Present a pixmap not released\n"); pthread_mutex_unlock(&present_priv->mutex_present); return FALSE; } #ifdef D3DADAPTER9_DRI2 if (present_pixmap_priv->dri2_info.is_dri2) { current_api = eglQueryAPI(); eglBindAPI(EGL_OPENGL_API); if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) { glBindFramebuffer(GL_READ_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_read); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_write); glBlitFramebuffer(0, 0, present_pixmap_priv->width, present_pixmap_priv->height, 0, 0, present_pixmap_priv->width, present_pixmap_priv->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glFlush(); /* Perhaps useless */ } else { ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError()); } eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglBindAPI(current_api); } #endif target_msc = present_priv->last_msc; switch(pPresentationParameters->PresentationInterval) { case D3DPRESENT_INTERVAL_DEFAULT: case D3DPRESENT_INTERVAL_ONE: presentationInterval = 1; break; case D3DPRESENT_INTERVAL_TWO: presentationInterval = 2; break; case D3DPRESENT_INTERVAL_THREE: presentationInterval = 3; break; case D3DPRESENT_INTERVAL_FOUR: presentationInterval = 4; break; case D3DPRESENT_INTERVAL_IMMEDIATE: default: presentationInterval = 0; options |= XCB_PRESENT_OPTION_ASYNC; break; } target_msc += presentationInterval * (present_priv->pixmap_present_pending + 1); /* Note: PRESENT defines some way to do partial copy: * presentproto: * 'x-off' and 'y-off' define the location in the window where * the 0,0 location of the pixmap will be presented. valid-area * and update-area are relative to the pixmap. */ if (!pSourceRect && !pDestRect && !pDirtyRegion) { valid = 0; update = 0; x_off = 0; y_off = 0; } else { xcb_rectangle_t rect_update; xcb_rectangle_t *rect_updates; int i; rect_update.x = 0; rect_update.y = 0; rect_update.width = present_pixmap_priv->width; rect_update.height = present_pixmap_priv->height; x_off = 0; y_off = 0; if (pSourceRect) { x_off = -pSourceRect->left; y_off = -pSourceRect->top; rect_update.x = pSourceRect->left; rect_update.y = pSourceRect->top; rect_update.width = pSourceRect->right - pSourceRect->left; rect_update.height = pSourceRect->bottom - pSourceRect->top; } if (pDestRect) { x_off += pDestRect->left; y_off += pDestRect->top; rect_update.width = pDestRect->right - pDestRect->left; rect_update.height = pDestRect->bottom - pDestRect->top; /* Note: the size of pDestRect and pSourceRect are supposed to be the same size * because the driver would have done things to assure that. */ } valid = xcb_generate_id(present_priv->xcb_connection_bis); update = xcb_generate_id(present_priv->xcb_connection_bis); xcb_xfixes_create_region(present_priv->xcb_connection_bis, valid, 1, &rect_update); if (pDirtyRegion && pDirtyRegion->rdh.nCount) { rect_updates = (void *) calloc(pDirtyRegion->rdh.nCount, sizeof(xcb_rectangle_t)); for (i = 0; i < pDirtyRegion->rdh.nCount; i++) { RECT rc; memcpy(&rc, pDirtyRegion->Buffer + i * sizeof(RECT), sizeof(RECT)); rect_update.x = rc.left; rect_update.y = rc.top; rect_update.width = rc.right - rc.left; rect_update.height = rc.bottom - rc.top; memcpy(rect_updates + i * sizeof(xcb_rectangle_t), &rect_update, sizeof(xcb_rectangle_t)); } xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, pDirtyRegion->rdh.nCount, rect_updates); free(rect_updates); } else xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, 1, &rect_update); } if (pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY) options |= XCB_PRESENT_OPTION_COPY; cookie = xcb_present_pixmap_checked(present_priv->xcb_connection_bis, window, present_pixmap_priv->pixmap, present_pixmap_priv->serial, valid, update, x_off, y_off, None, None, None, options, target_msc, 0, 0, 0, NULL); error = xcb_request_check(present_priv->xcb_connection_bis, cookie); /* performs a flush */ if (update) xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, update); if (valid) xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, valid); if (error) { xcb_get_geometry_cookie_t cookie_geom; xcb_get_geometry_reply_t *reply; cookie_geom = xcb_get_geometry(present_priv->xcb_connection_bis, window); reply = xcb_get_geometry_reply(present_priv->xcb_connection_bis, cookie_geom, NULL); ERR("Error using PRESENT. Here some debug info\n"); if (!reply) { ERR("Error querying window info. Perhaps it doesn't exist anymore\n"); pthread_mutex_unlock(&present_priv->mutex_present); return FALSE; } ERR("Pixmap: width=%d, height=%d, depth=%d\n", present_pixmap_priv->width, present_pixmap_priv->height, present_pixmap_priv->depth); ERR("Window: width=%d, height=%d, depth=%d, x=%d, y=%d\n", (int) reply->width, (int) reply->height, (int) reply->depth, (int) reply->x, (int) reply->y); ERR("Present parameter: PresentationInterval=%d, BackBufferCount=%d, Pending presentations=%d\n", pPresentationParameters->PresentationInterval, pPresentationParameters->BackBufferCount, present_priv->pixmap_present_pending ); if (present_pixmap_priv->depth != reply->depth) ERR("Depths are different. PRESENT needs the pixmap and the window have same depth\n"); free(reply); pthread_mutex_unlock(&present_priv->mutex_present); return FALSE; } present_priv->last_target = target_msc; present_priv->pixmap_present_pending++; present_pixmap_priv->present_complete_pending = TRUE; present_pixmap_priv->released = FALSE; pthread_mutex_unlock(&present_priv->mutex_present); return TRUE; }
Compositor::Compositor() : connection_(QX11Info::connection()), root_(QX11Info::appRootWindow()), damageExt_(xcb_get_extension_data(connection_, &xcb_damage_id)), initFinished_(false) { qRegisterMetaType<ClientWindow *>(); Q_ASSERT(QCoreApplication::instance()); QCoreApplication::instance()->installNativeEventFilter(this); auto ewmhCookie = xcb_ewmh_init_atoms(connection_, &ewmh_); if (!xcb_ewmh_init_atoms_replies(&ewmh_, ewmhCookie, Q_NULLPTR)) { qFatal("Cannot init EWMH"); } auto wmCmCookie = xcb_ewmh_get_wm_cm_owner_unchecked(&ewmh_, QX11Info::appScreen()); xcb_window_t wmCmOwnerWin = XCB_NONE; if (!xcb_ewmh_get_wm_cm_owner_reply(&ewmh_, wmCmCookie, &wmCmOwnerWin, Q_NULLPTR)) { qFatal("Cannot check _NET_WM_CM_Sn"); } if (wmCmOwnerWin) { qFatal("Another compositing manager is already running"); } auto attributesCookie = xcb_get_window_attributes_unchecked(connection_, root_); auto damageQueryVersionCookie = xcb_damage_query_version_unchecked(connection_, 1, 1); auto overlayWindowCookie = xcb_composite_get_overlay_window_unchecked(connection_, root_); auto attributes = xcbReply(xcb_get_window_attributes_reply(connection_, attributesCookie, Q_NULLPTR)); if (!attributes) { qFatal("Cannot get root window attributes"); } auto newEventMask = attributes->your_event_mask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; xcb_change_window_attributes(connection_, root_, XCB_CW_EVENT_MASK, &newEventMask); auto treeCookie = xcb_query_tree_unchecked(connection_, root_); auto rootGeometryCookie = xcb_get_geometry_unchecked(connection_, root_); auto damageVersion = xcbReply(xcb_damage_query_version_reply(connection_, damageQueryVersionCookie, Q_NULLPTR)); if (!damageVersion) { qFatal("Cannot query version of Damage extension"); } auto overlayWindow = xcbReply(xcb_composite_get_overlay_window_reply(connection_, overlayWindowCookie, Q_NULLPTR)); if (!overlayWindow) { qFatal("Cannot get overlay window"); } overlayWindow_.reset(QWindow::fromWinId(overlayWindow->overlay_win)); auto region = xcb_generate_id(connection_); xcb_xfixes_create_region(connection_, region, 0, Q_NULLPTR); xcb_xfixes_set_window_shape_region(connection_, overlayWindow->overlay_win, XCB_SHAPE_SK_INPUT, 0, 0, region); xcb_xfixes_destroy_region(connection_, region); xcb_composite_redirect_subwindows(connection_, root_, XCB_COMPOSITE_REDIRECT_MANUAL); auto rootGeometry = xcbReply(xcb_get_geometry_reply(connection_, rootGeometryCookie, Q_NULLPTR)); if (!rootGeometry) { qFatal("Cannot query root window geometry"); } rootGeometry_ = QRect(rootGeometry->x, rootGeometry->y, rootGeometry->width, rootGeometry->height); auto tree = xcbReply(xcb_query_tree_reply(connection_, treeCookie, Q_NULLPTR)); if (!tree) { qFatal("Cannot query window tree"); } auto children = xcb_query_tree_children(tree.get()); for (int i = 0; i < xcb_query_tree_children_length(tree.get()); i++) { addChildWindow(children[i]); } updateActiveWindow(); initFinished_ = true; }