static VkResult x11_image_init(VkDevice device_h, struct x11_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator, struct x11_image *image) { xcb_void_cookie_t cookie; VkResult result; uint32_t row_pitch; uint32_t offset; uint32_t bpp = 32; int fd; uint32_t size; result = chain->base.image_fns->create_wsi_image(device_h, pCreateInfo, pAllocator, &image->image, &image->memory, &size, &offset, &row_pitch, &fd); if (result != VK_SUCCESS) return result; image->pixmap = xcb_generate_id(chain->conn); cookie = xcb_dri3_pixmap_from_buffer_checked(chain->conn, image->pixmap, chain->window, size, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height, row_pitch, chain->depth, bpp, fd); xcb_discard_reply(chain->conn, cookie.sequence); int fence_fd = xshmfence_alloc_shm(); if (fence_fd < 0) goto fail_pixmap; image->shm_fence = xshmfence_map_shm(fence_fd); if (image->shm_fence == NULL) goto fail_shmfence_alloc; image->sync_fence = xcb_generate_id(chain->conn); xcb_dri3_fence_from_fd(chain->conn, image->pixmap, image->sync_fence, false, fence_fd); image->busy = false; xshmfence_trigger(image->shm_fence); return VK_SUCCESS; fail_shmfence_alloc: close(fence_fd); fail_pixmap: cookie = xcb_free_pixmap(chain->conn, image->pixmap); xcb_discard_reply(chain->conn, cookie.sequence); chain->base.image_fns->free_wsi_image(device_h, pAllocator, image->image, image->memory); return result; }
static void dri3_copy_area(xcb_connection_t *c, xcb_drawable_t src_drawable, xcb_drawable_t dst_drawable, xcb_gcontext_t gc, int16_t src_x, int16_t src_y, int16_t dst_x, int16_t dst_y, uint16_t width, uint16_t height) { xcb_void_cookie_t cookie; cookie = xcb_copy_area_checked(c, src_drawable, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height); xcb_discard_reply(c, cookie.sequence); }
static VkResult x11_swapchain_destroy(struct wsi_swapchain *anv_chain, const VkAllocationCallbacks *pAllocator) { struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain; xcb_void_cookie_t cookie; for (uint32_t i = 0; i < chain->image_count; i++) x11_image_finish(chain, pAllocator, &chain->images[i]); if (chain->threaded) { chain->status = VK_ERROR_OUT_OF_DATE_KHR; /* Push a UINT32_MAX to wake up the manager */ wsi_queue_push(&chain->present_queue, UINT32_MAX); pthread_join(chain->queue_manager, NULL); wsi_queue_destroy(&chain->acquire_queue); wsi_queue_destroy(&chain->present_queue); } xcb_unregister_for_special_event(chain->conn, chain->special_event); cookie = xcb_present_select_input_checked(chain->conn, chain->event_id, chain->window, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(chain->conn, cookie.sequence); vk_free(pAllocator, chain); return VK_SUCCESS; }
static void x11_image_finish(struct x11_swapchain *chain, const VkAllocationCallbacks* pAllocator, struct x11_image *image) { xcb_void_cookie_t cookie; cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence); xcb_discard_reply(chain->conn, cookie.sequence); xshmfence_unmap_shm(image->shm_fence); cookie = xcb_free_pixmap(chain->conn, image->pixmap); xcb_discard_reply(chain->conn, cookie.sequence); chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator, image->image, image->memory); }
static void xpybCookie_dealloc(xpybCookie *self) { if (self->conn->conn) xcb_discard_reply(self->conn->conn, self->cookie.sequence); Py_CLEAR(self->reply_type); Py_CLEAR(self->request); Py_CLEAR(self->conn); self->ob_type->tp_free((PyObject *)self); }
bool Shadow::init(const QVector< uint32_t > &data) { QVector<Xcb::WindowGeometry> pixmapGeometries(ShadowElementsCount); QVector<xcb_get_image_cookie_t> getImageCookies(ShadowElementsCount); auto *c = connection(); for (int i = 0; i < ShadowElementsCount; ++i) { pixmapGeometries[i] = Xcb::WindowGeometry(data[i]); } auto discardReplies = [&getImageCookies](int start) { for (int i = start; i < getImageCookies.size(); ++i) { xcb_discard_reply(connection(), getImageCookies.at(i).sequence); } }; for (int i = 0; i < ShadowElementsCount; ++i) { auto &geo = pixmapGeometries[i]; if (geo.isNull()) { discardReplies(0); return false; } getImageCookies[i] = xcb_get_image_unchecked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, data[i], 0, 0, geo->width, geo->height, ~0); } for (int i = 0; i < ShadowElementsCount; ++i) { auto *reply = xcb_get_image_reply(c, getImageCookies.at(i), nullptr); if (!reply) { discardReplies(i+1); return false; } auto &geo = pixmapGeometries[i]; QImage image(xcb_get_image_data(reply), geo->width, geo->height, QImage::Format_ARGB32); m_shadowElements[i] = QPixmap::fromImage(image); free(reply); } m_topOffset = data[ShadowElementsCount]; m_rightOffset = data[ShadowElementsCount+1]; m_bottomOffset = data[ShadowElementsCount+2]; m_leftOffset = data[ShadowElementsCount+3]; updateShadowRegion(); if (!prepareBackend()) { return false; } buildQuads(); return true; }
static VkResult x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index, uint32_t target_msc) { struct x11_image *image = &chain->images[image_index]; assert(image_index < chain->image_count); uint32_t options = XCB_PRESENT_OPTION_NONE; int64_t divisor = 0; int64_t remainder = 0; if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) options |= XCB_PRESENT_OPTION_ASYNC; xshmfence_reset(image->shm_fence); ++chain->send_sbc; xcb_void_cookie_t cookie = xcb_present_pixmap(chain->conn, chain->window, image->pixmap, (uint32_t) chain->send_sbc, 0, /* valid */ 0, /* update */ 0, /* x_off */ 0, /* y_off */ XCB_NONE, /* target_crtc */ XCB_NONE, image->sync_fence, options, target_msc, divisor, remainder, 0, NULL); xcb_discard_reply(chain->conn, cookie.sequence); image->busy = true; xcb_flush(chain->conn); return VK_SUCCESS; }
void loader_dri3_drawable_fini(struct loader_dri3_drawable *draw) { int i; (draw->ext->core->destroyDrawable)(draw->dri_drawable); for (i = 0; i < LOADER_DRI3_NUM_BUFFERS; i++) { if (draw->buffers[i]) dri3_free_render_buffer(draw, draw->buffers[i]); } if (draw->special_event) { xcb_void_cookie_t cookie = xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(draw->conn, cookie.sequence); xcb_unregister_for_special_event(draw->conn, draw->special_event); } }
static void vl_dri3_screen_destroy(struct vl_screen *vscreen) { struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen; int i; assert(vscreen); dri3_flush_present_events(scrn); if (scrn->front_buffer) { dri3_free_front_buffer(scrn, scrn->front_buffer); scrn->front_buffer = NULL; } for (i = 0; i < BACK_BUFFER_NUM; ++i) { if (scrn->back_buffers[i]) { dri3_free_back_buffer(scrn, scrn->back_buffers[i]); scrn->back_buffers[i] = NULL; } } if (scrn->special_event) { xcb_void_cookie_t cookie = xcb_present_select_input_checked(scrn->conn, scrn->eid, scrn->drawable, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(scrn->conn, cookie.sequence); xcb_unregister_for_special_event(scrn->conn, scrn->special_event); } scrn->pipe->destroy(scrn->pipe); scrn->base.pscreen->destroy(scrn->base.pscreen); pipe_loader_release(&scrn->base.dev, 1); FREE(scrn); return; }
/** * Processing callback */ static void Demux (void *data) { demux_t *demux = data; demux_sys_t *sys = demux->p_sys; xcb_connection_t *conn = sys->conn; /* Determine capture region */ xcb_get_geometry_cookie_t gc; xcb_query_pointer_cookie_t qc; gc = xcb_get_geometry (conn, sys->window); if (sys->follow_mouse) qc = xcb_query_pointer (conn, sys->window); xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); if (geo == NULL) { msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, sys->window); discard: if (sys->follow_mouse) xcb_discard_reply (conn, gc.sequence); return; } int w = sys->w; int h = sys->h; int x, y; if (sys->follow_mouse) { xcb_query_pointer_reply_t *ptr = xcb_query_pointer_reply (conn, qc, NULL); if (ptr == NULL) { free (geo); return; } if (w == 0 || w > geo->width) w = geo->width; x = ptr->win_x; if (x < w / 2) x = 0; else if (x >= (int)geo->width - (w / 2)) x = geo->width - w; else x -= w / 2; if (h == 0 || h > geo->height) h = geo->height; y = ptr->win_y; if (y < h / 2) y = 0; else if (y >= (int)geo->height - (h / 2)) y = geo->height - h; else y -= h / 2; } else { int max; x = sys->x; max = (int)geo->width - x; if (max <= 0) goto discard; if (w == 0 || w > max) w = max; y = sys->y; max = (int)geo->height - y; if (max <= 0) goto discard; if (h == 0 || h > max) h = max; } /* Update elementary stream format (if needed) */ if (w != sys->cur_w || h != sys->cur_h) { if (sys->es != NULL) es_out_Del (demux->out, sys->es); /* Update composite pixmap */ if (sys->window != geo->root) { xcb_free_pixmap (conn, sys->pixmap); /* no-op first time */ xcb_composite_name_window_pixmap (conn, sys->window, sys->pixmap); xcb_create_pixmap (conn, geo->depth, sys->pixmap, geo->root, geo->width, geo->height); } sys->es = InitES (demux, w, h, geo->depth); if (sys->es != NULL) { sys->cur_w = w; sys->cur_h = h; } } /* Capture screen */ xcb_drawable_t drawable = (sys->window != geo->root) ? sys->pixmap : sys->window; free (geo); xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable, x, y, w, h, ~0), NULL); if (img == NULL) return; block_t *block = block_heap_Alloc (img, xcb_get_image_data (img), xcb_get_image_data_length (img)); if (block == NULL) return; /* Send block - zero copy */ if (sys->es != NULL) { if (sys->pts == VLC_TS_INVALID) sys->pts = mdate (); block->i_pts = block->i_dts = sys->pts; es_out_Control (demux->out, ES_OUT_SET_PCR, sys->pts); es_out_Send (demux->out, sys->es, block); sys->pts += sys->interval; } }
virtual void discard_reply(unsigned int sequence) const { xcb_discard_reply(m_c.get(), sequence); }
XInputDevice::~XInputDevice() { Q_FOREACH (auto cookie, cookies_) { xcb_discard_reply(connection(), cookie.sequence); }
/** * Processing callback */ static void Demux (void *opaque) { demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; xcb_connection_t *conn = sys->conn; /* Determine capture region */ xcb_get_geometry_cookie_t gc; xcb_query_pointer_cookie_t qc; gc = xcb_get_geometry (conn, sys->window); if (sys->follow_mouse) qc = xcb_query_pointer (conn, sys->window); xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); if (geo == NULL) { msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, sys->window); discard: if (sys->follow_mouse) xcb_discard_reply (conn, gc.sequence); return; } int w = sys->w; int h = sys->h; int x, y; if (sys->follow_mouse) { xcb_query_pointer_reply_t *ptr = xcb_query_pointer_reply (conn, qc, NULL); if (ptr == NULL) { free (geo); return; } if (w == 0 || w > geo->width) w = geo->width; x = ptr->win_x; if (x < w / 2) x = 0; else if (x >= (int)geo->width - (w / 2)) x = geo->width - w; else x -= w / 2; if (h == 0 || h > geo->height) h = geo->height; y = ptr->win_y; if (y < h / 2) y = 0; else if (y >= (int)geo->height - (h / 2)) y = geo->height - h; else y -= h / 2; } else { int max; x = sys->x; max = (int)geo->width - x; if (max <= 0) goto discard; if (w == 0 || w > max) w = max; y = sys->y; max = (int)geo->height - y; if (max <= 0) goto discard; if (h == 0 || h > max) h = max; } /* Update elementary stream format (if needed) */ if (w != sys->cur_w || h != sys->cur_h) { if (sys->es != NULL) es_out_Del (demux->out, sys->es); /* Update composite pixmap */ if (sys->window != geo->root) { xcb_free_pixmap (conn, sys->pixmap); /* no-op first time */ xcb_composite_name_window_pixmap (conn, sys->window, sys->pixmap); xcb_create_pixmap (conn, geo->depth, sys->pixmap, geo->root, geo->width, geo->height); } sys->es = InitES (demux, w, h, geo->depth, &sys->bpp); if (sys->es != NULL) { sys->cur_w = w; sys->cur_h = h; sys->bpp /= 8; /* bits -> bytes */ } } /* Capture screen */ xcb_drawable_t drawable = (sys->window != geo->root) ? sys->pixmap : sys->window; free (geo); block_t *block = NULL; #if HAVE_SYS_SHM_H if (sys->shm) { /* Capture screen through shared memory */ size_t size = w * h * sys->bpp; int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); if (id == -1) /* XXX: fallback */ { msg_Err (demux, "shared memory allocation error: %m"); goto noshm; } /* Attach the segment to X and capture */ xcb_shm_get_image_reply_t *img; xcb_shm_get_image_cookie_t ck; xcb_shm_attach (conn, sys->segment, id, 0 /* read/write */); ck = xcb_shm_get_image (conn, drawable, x, y, w, h, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, sys->segment, 0); xcb_shm_detach (conn, sys->segment); img = xcb_shm_get_image_reply (conn, ck, NULL); xcb_flush (conn); /* ensure eventual detach */ if (img == NULL) { shmctl (id, IPC_RMID, 0); goto noshm; } free (img); /* Attach the segment to VLC */ void *shm = shmat (id, NULL, 0 /* read/write */); shmctl (id, IPC_RMID, 0); if (-1 == (intptr_t)shm) { msg_Err (demux, "shared memory attachment error: %m"); return; } block = block_shm_Alloc (shm, size); if (unlikely(block == NULL)) shmdt (shm); } noshm: #endif if (block == NULL) { /* Capture screen through socket (fallback) */ xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable, x, y, w, h, ~0), NULL); if (img == NULL) return; uint8_t *data = xcb_get_image_data (img); size_t datalen = xcb_get_image_data_length (img); block = block_heap_Alloc (img, data + datalen - (uint8_t *)img); if (block == NULL) return; block->p_buffer = data; block->i_buffer = datalen; } /* Send block - zero copy */ if (sys->es != NULL) { block->i_pts = block->i_dts = mdate (); es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts); es_out_Send (demux->out, sys->es, block); } }
static void ephyrProcessKeyRelease(xcb_generic_event_t *xev) { xcb_connection_t *conn = hostx_get_xcbconn(); xcb_key_release_event_t *key = (xcb_key_release_event_t *)xev; static xcb_key_symbols_t *keysyms; static int grabbed_screen = -1; int mod1_down = ephyrUpdateGrabModifierState(key->state); if (!keysyms) keysyms = xcb_key_symbols_alloc(conn); if (!EphyrWantNoHostGrab && (((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_L || xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_R) && (key->state & XCB_MOD_MASK_CONTROL)) || ((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_L || xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_R) && (key->state & XCB_MOD_MASK_SHIFT)))) { KdScreenInfo *screen = screen_from_window(key->event); EphyrScrPriv *scrpriv = screen->driver; if (grabbed_screen != -1) { xcb_ungrab_keyboard(conn, XCB_TIME_CURRENT_TIME); xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME); grabbed_screen = -1; hostx_set_win_title(screen, "(ctrl+shift grabs mouse and keyboard)"); } else if (!mod1_down) { /* Attempt grab */ xcb_grab_keyboard_cookie_t kbgrabc = xcb_grab_keyboard(conn, TRUE, scrpriv->win, XCB_TIME_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); xcb_grab_keyboard_reply_t *kbgrabr; xcb_grab_pointer_cookie_t pgrabc = xcb_grab_pointer(conn, TRUE, scrpriv->win, 0, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scrpriv->win, XCB_NONE, XCB_TIME_CURRENT_TIME); xcb_grab_pointer_reply_t *pgrabr; kbgrabr = xcb_grab_keyboard_reply(conn, kbgrabc, NULL); if (!kbgrabr || kbgrabr->status != XCB_GRAB_STATUS_SUCCESS) { xcb_discard_reply(conn, pgrabc.sequence); xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME); } else { pgrabr = xcb_grab_pointer_reply(conn, pgrabc, NULL); if (!pgrabr || pgrabr->status != XCB_GRAB_STATUS_SUCCESS) { xcb_ungrab_keyboard(conn, XCB_TIME_CURRENT_TIME); } else { grabbed_screen = scrpriv->mynum; hostx_set_win_title (screen, "(ctrl+shift releases mouse and keyboard)"); } } } } if (!ephyrKbd || !((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) { return; } /* Still send the release event even if above has happened server * will get confused with just an up event. Maybe it would be * better to just block shift+ctrls getting to kdrive all * together. */ ephyrUpdateModifierState(key->state); KdEnqueueKeyboardEvent(ephyrKbd, key->detail, TRUE); }
/* * Do some sanity checks and then reparent the window. * */ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cookie, bool needs_to_be_mapped) { xcb_drawable_t d = {window}; xcb_get_geometry_cookie_t geomc; xcb_get_geometry_reply_t *geom; xcb_get_window_attributes_reply_t *attr = NULL; xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie, utf8_title_cookie, title_cookie, class_cookie, leader_cookie, transient_cookie, role_cookie, startup_id_cookie, wm_hints_cookie, wm_normal_hints_cookie, motif_wm_hints_cookie; geomc = xcb_get_geometry(conn, d); /* Check if the window is mapped (it could be not mapped when intializing and calling manage_window() for every window) */ if ((attr = xcb_get_window_attributes_reply(conn, cookie, 0)) == NULL) { DLOG("Could not get attributes\n"); xcb_discard_reply(conn, geomc.sequence); return; } if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) { xcb_discard_reply(conn, geomc.sequence); goto out; } /* Don’t manage clients with the override_redirect flag */ if (attr->override_redirect) { xcb_discard_reply(conn, geomc.sequence); goto out; } /* Check if the window is already managed */ if (con_by_window_id(window) != NULL) { DLOG("already managed (by con %p)\n", con_by_window_id(window)); xcb_discard_reply(conn, geomc.sequence); goto out; } /* Get the initial geometry (position, size, …) */ if ((geom = xcb_get_geometry_reply(conn, geomc, 0)) == NULL) { DLOG("could not get geometry\n"); goto out; } uint32_t values[1]; /* Set a temporary event mask for the new window, consisting only of * PropertyChange and StructureNotify. We need to be notified of * PropertyChanges because the client can change its properties *after* we * requested them but *before* we actually reparented it and have set our * final event mask. * We need StructureNotify because the client may unmap the window before * we get to re-parent it. * If this request fails, we assume the client has already unmapped the * window between the MapRequest and our event mask change. */ values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; xcb_void_cookie_t event_mask_cookie = xcb_change_window_attributes_checked(conn, window, XCB_CW_EVENT_MASK, values); if (xcb_request_check(conn, event_mask_cookie) != NULL) { LOG("Could not change event mask, the window probably already disappeared.\n"); goto out; } #define GET_PROPERTY(atom, len) xcb_get_property(conn, false, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, len) wm_type_cookie = GET_PROPERTY(A__NET_WM_WINDOW_TYPE, UINT32_MAX); strut_cookie = GET_PROPERTY(A__NET_WM_STRUT_PARTIAL, UINT32_MAX); state_cookie = GET_PROPERTY(A__NET_WM_STATE, UINT32_MAX); utf8_title_cookie = GET_PROPERTY(A__NET_WM_NAME, 128); leader_cookie = GET_PROPERTY(A_WM_CLIENT_LEADER, UINT32_MAX); transient_cookie = GET_PROPERTY(XCB_ATOM_WM_TRANSIENT_FOR, UINT32_MAX); title_cookie = GET_PROPERTY(XCB_ATOM_WM_NAME, 128); class_cookie = GET_PROPERTY(XCB_ATOM_WM_CLASS, 128); role_cookie = GET_PROPERTY(A_WM_WINDOW_ROLE, 128); startup_id_cookie = GET_PROPERTY(A__NET_STARTUP_ID, 512); wm_hints_cookie = xcb_icccm_get_wm_hints(conn, window); wm_normal_hints_cookie = xcb_icccm_get_wm_normal_hints(conn, window); motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t)); DLOG("Managing window 0x%08x\n", window); i3Window *cwindow = scalloc(1, sizeof(i3Window)); cwindow->id = window; cwindow->depth = get_visual_depth(attr->visual); /* We need to grab buttons 1-3 for click-to-focus and buttons 1-5 * to allow for mouse bindings using --whole-window to work correctly. */ xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, XCB_BUTTON_INDEX_ANY, XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */); /* update as much information as possible so far (some replies may be NULL) */ window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL), true); window_update_name_legacy(cwindow, xcb_get_property_reply(conn, title_cookie, NULL), true); window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL), true); window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL)); window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL)); window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL)); window_update_role(cwindow, xcb_get_property_reply(conn, role_cookie, NULL), true); bool urgency_hint; window_update_hints(cwindow, xcb_get_property_reply(conn, wm_hints_cookie, NULL), &urgency_hint); border_style_t motif_border_style = BS_NORMAL; window_update_motif_hints(cwindow, xcb_get_property_reply(conn, motif_wm_hints_cookie, NULL), &motif_border_style); xcb_size_hints_t wm_size_hints; if (!xcb_icccm_get_wm_size_hints_reply(conn, wm_normal_hints_cookie, &wm_size_hints, NULL)) memset(&wm_size_hints, '\0', sizeof(xcb_size_hints_t)); xcb_get_property_reply_t *type_reply = xcb_get_property_reply(conn, wm_type_cookie, NULL); xcb_get_property_reply_t *state_reply = xcb_get_property_reply(conn, state_cookie, NULL); xcb_get_property_reply_t *startup_id_reply; startup_id_reply = xcb_get_property_reply(conn, startup_id_cookie, NULL); char *startup_ws = startup_workspace_for_window(cwindow, startup_id_reply); DLOG("startup workspace = %s\n", startup_ws); /* check if the window needs WM_TAKE_FOCUS */ cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS); /* read the preferred _NET_WM_WINDOW_TYPE atom */ cwindow->window_type = xcb_get_preferred_window_type(type_reply); /* Where to start searching for a container that swallows the new one? */ Con *search_at = croot; if (xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DOCK)) { LOG("This window is of type dock\n"); Output *output = get_output_containing(geom->x, geom->y); if (output != NULL) { DLOG("Starting search at output %s\n", output->name); search_at = output->con; } /* find out the desired position of this dock window */ if (cwindow->reserved.top > 0 && cwindow->reserved.bottom == 0) { DLOG("Top dock client\n"); cwindow->dock = W_DOCK_TOP; } else if (cwindow->reserved.top == 0 && cwindow->reserved.bottom > 0) { DLOG("Bottom dock client\n"); cwindow->dock = W_DOCK_BOTTOM; } else { DLOG("Ignoring invalid reserved edges (_NET_WM_STRUT_PARTIAL), using position as fallback:\n"); if (geom->y < (int16_t)(search_at->rect.height / 2)) { DLOG("geom->y = %d < rect.height / 2 = %d, it is a top dock client\n", geom->y, (search_at->rect.height / 2)); cwindow->dock = W_DOCK_TOP; } else { DLOG("geom->y = %d >= rect.height / 2 = %d, it is a bottom dock client\n", geom->y, (search_at->rect.height / 2)); cwindow->dock = W_DOCK_BOTTOM; } } } DLOG("Initial geometry: (%d, %d, %d, %d)\n", geom->x, geom->y, geom->width, geom->height); Con *nc = NULL; Match *match = NULL; Assignment *assignment; /* TODO: two matches for one container */ /* See if any container swallows this new window */ nc = con_for_window(search_at, cwindow, &match); if (nc == NULL) { /* If not, check if it is assigned to a specific workspace */ if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE))) { DLOG("Assignment matches (%p)\n", match); Con *assigned_ws = workspace_get(assignment->dest.workspace, NULL); nc = con_descend_tiling_focused(assigned_ws); DLOG("focused on ws %s: %p / %s\n", assigned_ws->name, nc, nc->name); if (nc->type == CT_WORKSPACE) nc = tree_open_con(nc, cwindow); else nc = tree_open_con(nc->parent, cwindow); /* set the urgency hint on the window if the workspace is not visible */ if (!workspace_is_visible(assigned_ws)) urgency_hint = true; } else if (startup_ws) { /* If it’s not assigned, but was started on a specific workspace, * we want to open it there */ DLOG("Using workspace on which this application was started (%s)\n", startup_ws); nc = con_descend_tiling_focused(workspace_get(startup_ws, NULL)); DLOG("focused on ws %s: %p / %s\n", startup_ws, nc, nc->name); if (nc->type == CT_WORKSPACE) nc = tree_open_con(nc, cwindow); else nc = tree_open_con(nc->parent, cwindow); } else { /* If not, insert it at the currently focused position */ if (focused->type == CT_CON && con_accepts_window(focused)) { LOG("using current container, focused = %p, focused->name = %s\n", focused, focused->name); nc = focused; } else nc = tree_open_con(NULL, cwindow); } } else { /* M_BELOW inserts the new window as a child of the one which was * matched (e.g. dock areas) */ if (match != NULL && match->insert_where == M_BELOW) { nc = tree_open_con(nc, cwindow); } /* If M_BELOW is not used, the container is replaced. This happens with * "swallows" criteria that are used for stored layouts, in which case * we need to remove that criterion, because they should only be valid * once. */ if (match != NULL && match->insert_where != M_BELOW) { DLOG("Removing match %p from container %p\n", match, nc); TAILQ_REMOVE(&(nc->swallow_head), match, matches); match_free(match); } } DLOG("new container = %p\n", nc); if (nc->window != NULL && nc->window != cwindow) { if (!restore_kill_placeholder(nc->window->id)) { DLOG("Uh?! Container without a placeholder, but with a window, has swallowed this to-be-managed window?!\n"); } else { /* Remove remaining criteria, the first swallowed window wins. */ while (!TAILQ_EMPTY(&(nc->swallow_head))) { Match *first = TAILQ_FIRST(&(nc->swallow_head)); TAILQ_REMOVE(&(nc->swallow_head), first, matches); match_free(first); } } } nc->window = cwindow; x_reinit(nc); nc->border_width = geom->border_width; char *name; sasprintf(&name, "[i3 con] container around %p", cwindow); x_set_name(nc, name); free(name); /* handle fullscreen containers */ Con *ws = con_get_workspace(nc); Con *fs = (ws ? con_get_fullscreen_con(ws, CF_OUTPUT) : NULL); if (fs == NULL) fs = con_get_fullscreen_con(croot, CF_GLOBAL); if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_FULLSCREEN)) { /* If this window is already fullscreen (after restarting!), skip * toggling fullscreen, that would drop it out of fullscreen mode. */ if (fs != nc) con_toggle_fullscreen(nc, CF_OUTPUT); fs = NULL; } bool set_focus = false; if (fs == NULL) { DLOG("Not in fullscreen mode, focusing\n"); if (!cwindow->dock) { /* Check that the workspace is visible and on the same output as * the current focused container. If the window was assigned to an * invisible workspace, we should not steal focus. */ Con *current_output = con_get_output(focused); Con *target_output = con_get_output(ws); if (workspace_is_visible(ws) && current_output == target_output) { if (!match || !match->restart_mode) { set_focus = true; } else DLOG("not focusing, matched with restart_mode == true\n"); } else DLOG("workspace not visible, not focusing\n"); } else DLOG("dock, not focusing\n"); } else { DLOG("fs = %p, ws = %p, not focusing\n", fs, ws); /* Insert the new container in focus stack *after* the currently * focused (fullscreen) con. This way, the new container will be * focused after we return from fullscreen mode */ Con *first = TAILQ_FIRST(&(nc->parent->focus_head)); if (first != nc) { /* We only modify the focus stack if the container is not already * the first one. This can happen when existing containers swallow * new windows, for example when restarting. */ TAILQ_REMOVE(&(nc->parent->focus_head), nc, focused); TAILQ_INSERT_AFTER(&(nc->parent->focus_head), first, nc, focused); } } /* set floating if necessary */ bool want_floating = false; if (xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DIALOG) || xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_UTILITY) || xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_TOOLBAR) || xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_SPLASH) || xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_MODAL) || (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE && wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE && wm_size_hints.min_height == wm_size_hints.max_height && wm_size_hints.min_width == wm_size_hints.max_width)) { LOG("This window is a dialog window, setting floating\n"); want_floating = true; } if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_STICKY)) nc->sticky = true; FREE(state_reply); FREE(type_reply); if (cwindow->transient_for != XCB_NONE || (cwindow->leader != XCB_NONE && cwindow->leader != cwindow->id && con_by_window_id(cwindow->leader) != NULL)) { LOG("This window is transient for another window, setting floating\n"); want_floating = true; if (config.popup_during_fullscreen == PDF_LEAVE_FULLSCREEN && fs != NULL) { LOG("There is a fullscreen window, leaving fullscreen mode\n"); con_toggle_fullscreen(fs, CF_OUTPUT); } else if (config.popup_during_fullscreen == PDF_SMART && fs != NULL && fs->window != NULL) { i3Window *transient_win = cwindow; while (transient_win != NULL && transient_win->transient_for != XCB_NONE) { if (transient_win->transient_for == fs->window->id) { LOG("This floating window belongs to the fullscreen window (popup_during_fullscreen == smart)\n"); set_focus = true; break; } Con *next_transient = con_by_window_id(transient_win->transient_for); if (next_transient == NULL) break; /* Some clients (e.g. x11-ssh-askpass) actually set * WM_TRANSIENT_FOR to their own window id, so break instead of * looping endlessly. */ if (transient_win == next_transient->window) break; transient_win = next_transient->window; } } } /* dock clients cannot be floating, that makes no sense */ if (cwindow->dock) want_floating = false; /* Plasma windows set their geometry in WM_SIZE_HINTS. */ if ((wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION || wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION) && (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_US_SIZE || wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_SIZE)) { DLOG("We are setting geometry according to wm_size_hints x=%d y=%d w=%d h=%d\n", wm_size_hints.x, wm_size_hints.y, wm_size_hints.width, wm_size_hints.height); geom->x = wm_size_hints.x; geom->y = wm_size_hints.y; geom->width = wm_size_hints.width; geom->height = wm_size_hints.height; } /* Store the requested geometry. The width/height gets raised to at least * 75x50 when entering floating mode, which is the minimum size for a * window to be useful (smaller windows are usually overlays/toolbars/… * which are not managed by the wm anyways). We store the original geometry * here because it’s used for dock clients. */ if (nc->geometry.width == 0) nc->geometry = (Rect){geom->x, geom->y, geom->width, geom->height}; if (motif_border_style != BS_NORMAL) { DLOG("MOTIF_WM_HINTS specifies decorations (border_style = %d)\n", motif_border_style); if (want_floating) { con_set_border_style(nc, motif_border_style, config.default_floating_border_width); } else { con_set_border_style(nc, motif_border_style, config.default_border_width); } } if (want_floating) { DLOG("geometry = %d x %d\n", nc->geometry.width, nc->geometry.height); /* automatically set the border to the default value if a motif border * was not specified */ bool automatic_border = (motif_border_style == BS_NORMAL); floating_enable(nc, automatic_border); } /* explicitly set the border width to the default */ if (nc->current_border_width == -1) { nc->current_border_width = (want_floating ? config.default_floating_border_width : config.default_border_width); } /* to avoid getting an UnmapNotify event due to reparenting, we temporarily * declare no interest in any state change event of this window */ values[0] = XCB_NONE; xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values); xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame, 0, 0); if (xcb_request_check(conn, rcookie) != NULL) { LOG("Could not reparent the window, aborting\n"); goto geom_out; } values[0] = CHILD_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW; xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values); xcb_flush(conn); /* Put the client inside the save set. Upon termination (whether killed or * normal exit does not matter) of the window manager, these clients will * be correctly reparented to their most closest living ancestor (= * cleanup) */ xcb_change_save_set(conn, XCB_SET_MODE_INSERT, window); /* Check if any assignments match */ run_assignments(cwindow); /* 'ws' may be invalid because of the assignments, e.g. when the user uses * "move window to workspace 1", but had it assigned to workspace 2. */ ws = con_get_workspace(nc); /* If this window was put onto an invisible workspace (via assignments), we * render this workspace. It wouldn’t be rendered in our normal code path * because only the visible workspaces get rendered. * * By rendering the workspace, we assign proper coordinates (read: not * width=0, height=0) to the window, which is important for windows who * actually use them to position their GUI elements, e.g. rhythmbox. */ if (ws && !workspace_is_visible(ws)) { /* This is a bit hackish: we need to copy the content container’s rect * to the workspace, because calling render_con() on the content * container would also take the shortcut and not render the invisible * workspace at all. However, just calling render_con() on the * workspace isn’t enough either — it needs the rect. */ ws->rect = ws->parent->rect; render_con(ws, true); /* Disable setting focus, otherwise we’d move focus to an invisible * workspace, which we generally prevent (e.g. in * con_move_to_workspace). */ set_focus = false; } render_con(croot, false); /* Send an event about window creation */ ipc_send_window_event("new", nc); if (set_focus && assignment_for(cwindow, A_NO_FOCUS) != NULL) { /* The first window on a workspace should always be focused. We have to * compare with == 1 because the container has already been inserted at * this point. */ if (con_num_children(ws) == 1) { DLOG("This is the first window on this workspace, ignoring no_focus.\n"); } else { DLOG("no_focus was set for con = %p, not setting focus.\n", nc); set_focus = false; } } /* Defer setting focus after the 'new' event has been sent to ensure the * proper window event sequence. */ if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) { DLOG("Now setting focus.\n"); con_focus(nc); } tree_render(); /* Windows might get managed with the urgency hint already set (Pidgin is * known to do that), so check for that and handle the hint accordingly. * This code needs to be in this part of manage_window() because the window * needs to be on the final workspace first. */ con_set_urgency(nc, urgency_hint); geom_out: free(geom); out: free(attr); return; }
static VkResult x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, VkDevice device, struct wsi_device *wsi_device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator, const struct wsi_image_fns *image_fns, struct wsi_swapchain **swapchain_out) { struct x11_swapchain *chain; xcb_void_cookie_t cookie; VkResult result; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); const unsigned num_images = pCreateInfo->minImageCount; size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); chain = vk_alloc(pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (chain == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; xcb_connection_t *conn = x11_surface_get_connection(icd_surface); xcb_window_t window = x11_surface_get_window(icd_surface); xcb_get_geometry_reply_t *geometry = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL); if (geometry == NULL) return VK_ERROR_SURFACE_LOST_KHR; chain->base.device = device; chain->base.destroy = x11_swapchain_destroy; chain->base.get_images = x11_get_images; chain->base.acquire_next_image = x11_acquire_next_image; chain->base.queue_present = x11_queue_present; chain->base.image_fns = image_fns; chain->base.present_mode = pCreateInfo->presentMode; chain->conn = conn; chain->window = window; chain->depth = geometry->depth; chain->extent = pCreateInfo->imageExtent; chain->image_count = num_images; chain->send_sbc = 0; chain->last_present_msc = 0; chain->threaded = false; chain->status = VK_SUCCESS; free(geometry); chain->event_id = xcb_generate_id(chain->conn); xcb_present_select_input(chain->conn, chain->event_id, chain->window, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); /* Create an XCB event queue to hold present events outside of the usual * application event queue */ chain->special_event = xcb_register_for_special_xge(chain->conn, &xcb_present_id, chain->event_id, NULL); chain->gc = xcb_generate_id(chain->conn); if (!chain->gc) { /* FINISHME: Choose a better error. */ result = VK_ERROR_OUT_OF_HOST_MEMORY; goto fail_register; } cookie = xcb_create_gc(chain->conn, chain->gc, chain->window, XCB_GC_GRAPHICS_EXPOSURES, (uint32_t []) { 0 }); xcb_discard_reply(chain->conn, cookie.sequence); uint32_t image = 0; for (; image < chain->image_count; image++) { result = x11_image_init(device, chain, pCreateInfo, pAllocator, &chain->images[image]); if (result != VK_SUCCESS) goto fail_init_images; } if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { chain->threaded = true; /* Initialize our queues. We make them image_count + 1 because we will * occasionally use UINT32_MAX to signal the other thread that an error * has occurred and we don't want an overflow. */ int ret; ret = wsi_queue_init(&chain->acquire_queue, chain->image_count + 1); if (ret) { goto fail_init_images; } ret = wsi_queue_init(&chain->present_queue, chain->image_count + 1); if (ret) { wsi_queue_destroy(&chain->acquire_queue); goto fail_init_images; } for (unsigned i = 0; i < chain->image_count; i++) wsi_queue_push(&chain->acquire_queue, i); ret = pthread_create(&chain->queue_manager, NULL, x11_manage_fifo_queues, chain); if (ret) { wsi_queue_destroy(&chain->present_queue); wsi_queue_destroy(&chain->acquire_queue); goto fail_init_images; } } *swapchain_out = &chain->base; return VK_SUCCESS; fail_init_images: for (uint32_t j = 0; j < image; j++) x11_image_finish(chain, pAllocator, &chain->images[j]); fail_register: xcb_unregister_for_special_event(chain->conn, chain->special_event); vk_free(pAllocator, chain); return result; }
static xcb_window_t recursive_Window_With_Name ( xcb_connection_t *dpy, xcb_window_t window, struct wininfo_cookies *cookies, const char *name) { xcb_window_t *children; unsigned int nchildren; int i; xcb_window_t w = 0; xcb_generic_error_t *err; xcb_query_tree_reply_t *tree; struct wininfo_cookies *child_cookies; xcb_get_property_reply_t *prop; if (cookies->get_net_wm_name.sequence) { prop = xcb_get_property_reply (dpy, cookies->get_net_wm_name, &err); if (prop) { if (prop->type == atom_utf8_string) { const char *prop_name = xcb_get_property_value (prop); int prop_name_len = xcb_get_property_value_length (prop); /* can't use strcmp, since prop.name is not null terminated */ if (strncmp (prop_name, name, prop_name_len) == 0) { w = window; } } free (prop); } else if (err) { if (err->response_type == 0) Print_X_Error (dpy, err); return 0; } } if (w) { xcb_discard_reply (dpy, cookies->get_wm_name.sequence); } else { #ifdef USE_XCB_ICCCM xcb_get_text_property_reply_t nameprop; if (xcb_get_wm_name_reply (dpy, cookies->get_wm_name, &nameprop, &err)) { /* can't use strcmp, since nameprop.name is not null terminated */ if (strncmp (nameprop.name, name, nameprop.name_len) == 0) { w = window; } xcb_get_text_property_reply_wipe (&nameprop); } #else prop = xcb_get_property_reply (dpy, cookies->get_wm_name, &err); if (prop) { if (prop->type == XCB_ATOM_STRING) { const char *prop_name = xcb_get_property_value (prop); int prop_name_len = xcb_get_property_value_length (prop); /* can't use strcmp, since prop.name is not null terminated */ if (strncmp (prop_name, name, prop_name_len) == 0) { w = window; } } free (prop); } #endif else if (err) { if (err->response_type == 0) Print_X_Error (dpy, err); return 0; } } if (w) { xcb_discard_reply (dpy, cookies->query_tree.sequence); return w; } tree = xcb_query_tree_reply (dpy, cookies->query_tree, &err); if (!tree) { if (err->response_type == 0) Print_X_Error (dpy, err); return 0; } nchildren = xcb_query_tree_children_length (tree); children = xcb_query_tree_children (tree); child_cookies = calloc(nchildren, sizeof(struct wininfo_cookies)); if (child_cookies == NULL) Fatal_Error("Failed to allocate memory in recursive_Window_With_Name"); for (i = 0; i < nchildren; i++) { if (atom_net_wm_name && atom_utf8_string) child_cookies[i].get_net_wm_name = xcb_get_net_wm_name (dpy, children[i]); child_cookies[i].get_wm_name = xcb_get_wm_name (dpy, children[i]); child_cookies[i].query_tree = xcb_query_tree (dpy, children[i]); } xcb_flush (dpy); for (i = 0; i < nchildren; i++) { w = recursive_Window_With_Name (dpy, children[i], &child_cookies[i], name); if (w) break; } if (w) { /* clean up remaining replies */ for (/* keep previous i */; i < nchildren; i++) { if (child_cookies[i].get_net_wm_name.sequence) xcb_discard_reply (dpy, child_cookies[i].get_net_wm_name.sequence); xcb_discard_reply (dpy, child_cookies[i].get_wm_name.sequence); xcb_discard_reply (dpy, child_cookies[i].query_tree.sequence); } } free (child_cookies); free (tree); /* includes storage for children[] */ return (w); }
static bool dri3_set_drawable(struct vl_dri3_screen *scrn, Drawable drawable) { xcb_get_geometry_cookie_t geom_cookie; xcb_get_geometry_reply_t *geom_reply; xcb_void_cookie_t cookie; xcb_generic_error_t *error; bool ret = true; assert(drawable); if (scrn->drawable == drawable) return true; scrn->drawable = drawable; geom_cookie = xcb_get_geometry(scrn->conn, scrn->drawable); geom_reply = xcb_get_geometry_reply(scrn->conn, geom_cookie, NULL); if (!geom_reply) return false; scrn->width = geom_reply->width; scrn->height = geom_reply->height; scrn->depth = geom_reply->depth; free(geom_reply); if (scrn->special_event) { xcb_unregister_for_special_event(scrn->conn, scrn->special_event); scrn->special_event = NULL; cookie = xcb_present_select_input_checked(scrn->conn, scrn->eid, scrn->drawable, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(scrn->conn, cookie.sequence); } scrn->is_pixmap = false; scrn->eid = xcb_generate_id(scrn->conn); cookie = xcb_present_select_input_checked(scrn->conn, scrn->eid, scrn->drawable, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); error = xcb_request_check(scrn->conn, cookie); if (error) { if (error->error_code != BadWindow) ret = false; else { scrn->is_pixmap = true; if (scrn->front_buffer) { dri3_free_front_buffer(scrn, scrn->front_buffer); scrn->front_buffer = NULL; } } free(error); } else scrn->special_event = xcb_register_for_special_xge(scrn->conn, &xcb_present_id, scrn->eid, 0); dri3_flush_present_events(scrn); return ret; }