/* * 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, wm_user_time_cookie, wm_desktop_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)); wm_user_time_cookie = GET_PROPERTY(A__NET_WM_USER_TIME, UINT32_MAX); wm_desktop_cookie = GET_PROPERTY(A__NET_WM_DESKTOP, UINT32_MAX); DLOG("Managing window 0x%08x\n", window); i3Window *cwindow = scalloc(1, sizeof(i3Window)); cwindow->id = window; cwindow->depth = get_visual_depth(attr->visual); int *buttons = bindings_get_buttons_to_grab(); xcb_grab_buttons(conn, window, buttons); FREE(buttons); /* 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); /* Get _NET_WM_DESKTOP if it was set. */ xcb_get_property_reply_t *wm_desktop_reply; wm_desktop_reply = xcb_get_property_reply(conn, wm_desktop_cookie, NULL); cwindow->wm_desktop = NET_WM_DESKTOP_NONE; if (wm_desktop_reply != NULL && xcb_get_property_value_length(wm_desktop_reply) != 0) { uint32_t *wm_desktops = xcb_get_property_value(wm_desktop_reply); cwindow->wm_desktop = (int32_t)wm_desktops[0]; } FREE(wm_desktop_reply); /* 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_primary_name(output)); 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); /* See if any container swallows this new window */ Match *match = NULL; Con *nc = con_for_window(search_at, cwindow, &match); const bool match_from_restart_mode = (match && match->restart_mode); if (nc == NULL) { Con *wm_desktop_ws = NULL; Assignment *assignment; /* If not, check if it is assigned to a specific workspace */ if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE)) || (assignment = assignment_for(cwindow, A_TO_WORKSPACE_NUMBER))) { DLOG("Assignment matches (%p)\n", match); Con *assigned_ws = NULL; if (assignment->type == A_TO_WORKSPACE_NUMBER) { long parsed_num = ws_name_to_number(assignment->dest.workspace); assigned_ws = get_existing_workspace_by_num(parsed_num); } /* A_TO_WORKSPACE type assignment or fallback from A_TO_WORKSPACE_NUMBER * when the target workspace number does not exist yet. */ if (!assigned_ws) { 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 (cwindow->wm_desktop != NET_WM_DESKTOP_NONE && cwindow->wm_desktop != NET_WM_DESKTOP_ALL && (wm_desktop_ws = ewmh_get_workspace_by_index(cwindow->wm_desktop)) != NULL) { /* If _NET_WM_DESKTOP is set to a specific desktop, we open it * there. Note that we ignore the special value 0xFFFFFFFF here * since such a window will be made sticky anyway. */ DLOG("Using workspace %p / %s because _NET_WM_DESKTOP = %d.\n", wm_desktop_ws, wm_desktop_ws->name, cwindow->wm_desktop); nc = con_descend_tiling_focused(wm_desktop_ws); if (nc->type == CT_WORKSPACE) nc = tree_open_con(nc, cwindow); else nc = tree_open_con(nc->parent, cwindow); } else if (startup_ws) { /* If it 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); } if ((assignment = assignment_for(cwindow, A_TO_OUTPUT))) { con_move_to_output_name(nc, assignment->dest.output, true); } } 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); 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); free(first); } } } xcb_window_t old_frame = XCB_NONE; if (nc->window != cwindow && nc->window != NULL) { window_free(nc->window); /* Match frame and window depth. This is needed because X will refuse to reparent a * window whose background is ParentRelative under a window with a different depth. */ if (nc->depth != cwindow->depth) { old_frame = nc->frame.id; nc->depth = cwindow->depth; x_con_reframe(nc); } } 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 = con_get_fullscreen_covering_ws(ws); 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) { Output *output = get_output_with_dimensions((Rect){geom->x, geom->y, geom->width, geom->height}); /* If the requested window geometry spans the whole area * of an output, move the window to that output. This is * needed e.g. for LibreOffice Impress multi-monitor * presentations to work out of the box. */ if (output != NULL) con_move_to_output(nc, output, false); 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_from_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; /* We ignore the hint for an internal workspace because windows in the * scratchpad also have this value, but upon restarting i3 we don't want * them to become sticky windows. */ if (cwindow->wm_desktop == NET_WM_DESKTOP_ALL && (ws == NULL || !con_is_internal(ws))) { DLOG("This window has _NET_WM_DESKTOP = 0xFFFFFFFF. Will float it and make it sticky.\n"); nc->sticky = true; want_floating = 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; } if (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { DLOG("Window specifies minimum size %d x %d\n", wm_size_hints.min_width, wm_size_hints.min_height); nc->window->min_width = wm_size_hints.min_width; nc->window->min_height = wm_size_hints.min_height; } if (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { DLOG("Window specifies maximum size %d x %d\n", wm_size_hints.max_width, wm_size_hints.max_height); nc->window->max_width = wm_size_hints.max_width; nc->window->max_height = wm_size_hints.max_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.id, 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_windows(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; } } if (set_focus) { DLOG("Checking con = %p for _NET_WM_USER_TIME.\n", nc); uint32_t *wm_user_time; xcb_get_property_reply_t *wm_user_time_reply = xcb_get_property_reply(conn, wm_user_time_cookie, NULL); if (wm_user_time_reply != NULL && xcb_get_property_value_length(wm_user_time_reply) != 0 && (wm_user_time = xcb_get_property_value(wm_user_time_reply)) && wm_user_time[0] == 0) { DLOG("_NET_WM_USER_TIME set to 0, not focusing con = %p.\n", nc); set_focus = false; } FREE(wm_user_time_reply); } else { xcb_discard_reply(conn, wm_user_time_cookie.sequence); } if (set_focus) { /* Even if the client doesn't want focus, we still need to focus the * container to not break focus workflows. Our handling towards X will * take care of not setting the input focus. However, one exception to * this are clients using the globally active input model which we * don't want to focus at all. */ if (nc->window->doesnt_accept_focus && !nc->window->needs_take_focus) { set_focus = false; } } /* Defer setting focus after the 'new' event has been sent to ensure the * proper window event sequence. */ if (set_focus && nc->mapped) { DLOG("Now setting focus.\n"); con_activate(nc); } tree_render(); /* Destroy the old frame if we had to reframe the container. This needs to be done * after rendering in order to prevent the background from flickering in its place. */ if (old_frame != XCB_NONE) { xcb_destroy_window(conn, old_frame); } /* 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); /* Update _NET_WM_DESKTOP. We invalidate the cached value first to force an update. */ cwindow->wm_desktop = NET_WM_DESKTOP_NONE; ewmh_update_wm_desktop(); /* If a sticky window was mapped onto another workspace, make sure to pop it to the front. */ output_push_sticky_windows(focused); geom_out: free(geom); out: free(attr); }
static void weston_dnd_stop(struct weston_wm *wm) { xcb_destroy_window(wm->conn, wm->dnd_window); wm->dnd_window = XCB_WINDOW_NONE; }
/// Destructor ~scr_window() { // clean up xcb_unmap_window(con, win); xcb_destroy_window(con, win); }
Window::~Window() { xcb_destroy_window( Parameters.Connection, Parameters.Handle ); xcb_disconnect( Parameters.Connection ); }
int setup_and_run(Display *display, xcb_connection_t *connection, int default_screen, xcb_screen_t *screen) { int visualID = 0; /*Query framebuffer configurations */ GLXFBConfig *fb_configs = 0; int num_fb_configs = 0; fb_configs = glXGetFBConfigs(display, default_screen, &num_fb_configs); if (!fb_configs || num_fb_configs == 0) { fprintf(stderr, "glXGetFBConfigs failed\n"); return -1; } /* Select first framebuffer config and query visualID */ GLXFBConfig fb_config = fb_configs[0]; glXGetFBConfigAttrib(display, fb_config, GLX_VISUAL_ID, &visualID); GLXContext context; /* Create OpenGL context */ context = glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True); if (!context) { fprintf(stderr, "glXCreateNewContext failed\n"); return -1; } /* Create XID's for colormap and window */ xcb_colormap_t colormap = xcb_generate_id(connection); xcb_window_t window = xcb_generate_id(connection); /* Create colormap */ xcb_create_colormap( connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visualID); /* Create window */ uint32_t eventmask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS; uint32_t valuelist[] = {eventmask, colormap, 0}; uint32_t valuemask = XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; xcb_create_window( connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, window_width, window_height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visualID, valuemask, valuelist); /* NOTE: window must be mapped before glXMakeContextCurrent */ xcb_map_window(connection, window); /* Create GLX window */ GLXDrawable drawable = 0; GLXWindow glxwindow = glXCreateWindow(display, fb_config, window, 0); if (!glxwindow) { xcb_destroy_window(connection, window); glXDestroyContext(display, context); fprintf(stderr, "glXCreateWindow failed\n"); return -1; } drawable = glxwindow; /* make OpenGL context current */ #if 1 if (!glXMakeContextCurrent(display, drawable, drawable, context)) { xcb_destroy_window(connection, window); glXDestroyContext(display, context); fprintf(stderr, "glXMakeContextCurrent failed\n"); return -1; } #else if (!glXMakeCurrent(display, drawable, context)) { xcb_destroy_window(connection, window); glXDestroyContext(display, context); fprintf(stderr, "glXMakeContextCurrent failed\n"); return -1; } #endif /* run main loop */ int retval = main_loop (display, connection, screen, window, drawable); /* Cleanup */ glXDestroyWindow(display, glxwindow); xcb_destroy_window(connection, window); glXDestroyContext(display, context); return retval; }
X11Output::~X11Output() { if(eglSurface_)backend().eglContext()->destroySurface(eglSurface_); xcb_destroy_window(backend().xConnection(), xWindow_); }
int main(int argc, char *argv[]) { struct spwd *sp = getspnam(getenv("USER")); if (!sp) { fprintf(stderr, "Get password failed\n"); return EXIT_FAILURE; } char *password = sp->sp_pwdp; // Parse command line parameters. struct arguments arguments = { .radius = 16, .iterations = 2, }; argp_parse(&argp, argc, argv, 0, NULL, &arguments); // Connect to X11. xcb_connection_t *conn = xcb_connect(NULL, NULL); const xcb_setup_t *setup = xcb_get_setup(conn); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); xcb_screen_t *screen = iter.data; // Initialize keyboard stuff. Keyboard keyboard = { .conn = conn, }; init_keyboard(&keyboard); // Take a screenshot and blur it. xcb_image_t *screenshot = take_screenshot(conn, screen); blur_image(screenshot, arguments.radius, arguments.iterations); // Create window. xcb_window_t window = create_window(conn, screen, screenshot); if (!grab_inputs(conn, screen)) { fprintf(stderr, "Failed to grab keyboard and pointer.\n"); exit(EXIT_FAILURE); } xcb_map_window(conn, window); // Original screenshot image is not needed anymore because it's copied to the X server as pixmap. xcb_image_destroy(screenshot); xcb_flush(conn); // XXX: Max password length? char input[256] = { '\0' }; char *cursor = &input[0]; running = true; xcb_generic_event_t *event; while (running && (event = xcb_wait_for_event(conn))) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: break; case XCB_KEY_PRESS: if (handle_key_press(&keyboard, ((xcb_key_press_event_t *)event)->detail, input, &cursor)) { if (strcmp(crypt(input, password), password) == 0) { running = false; } else { input[0] = '\0'; cursor = &input[0]; } } break; default: if (event->response_type == keyboard.first_xkb_event) { process_keyboard_event(&keyboard, event); } break; } free(event); } free_keyboard(&keyboard); xcb_unmap_window(conn, window); xcb_destroy_window(conn, window); xcb_disconnect(conn); return EXIT_SUCCESS; }
void xcbosd_drawable_changed(xcbosd *osd, xcb_window_t window) { xcb_get_geometry_cookie_t get_geometry_cookie; xcb_get_geometry_reply_t *get_geometry_reply; assert (osd); lprintf("drawable changed\n"); /* Do I need to recreate the GC's?? XFreeGC (osd->display, osd->gc); XFreeGC (osd->display, osd->mask_gc); XFreeGC (osd->display, osd->mask_gc_back); */ xcb_free_pixmap(osd->connection, osd->bitmap); xcb_free_colormap(osd->connection, osd->cmap); /* we need to call XSync(), because otherwise, calling XDestroyWindow() on the parent window could destroy our OSD window twice !! */ /* XSync (osd->display, False); FIXME don't think that we need that --pfister */ osd->window = window; get_geometry_cookie = xcb_get_geometry(osd->connection, osd->window); get_geometry_reply = xcb_get_geometry_reply(osd->connection, get_geometry_cookie, NULL); osd->depth = get_geometry_reply->depth; osd->width = get_geometry_reply->width; osd->height = get_geometry_reply->height; free(get_geometry_reply); assert(osd->width); assert(osd->height); switch(osd->mode) { case XCBOSD_SHAPED: { xcb_free_pixmap(osd->connection, osd->u.shaped.mask_bitmap); xcb_destroy_window(osd->connection, osd->u.shaped.window); unsigned int window_params[] = { osd->screen->black_pixel, 1, XCB_EVENT_MASK_EXPOSURE }; osd->u.shaped.window = xcb_generate_id(osd->connection); xcb_create_window(osd->connection, XCB_COPY_FROM_PARENT, osd->u.shaped.window, osd->window, 0, 0, osd->width, osd->height, 0, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, window_params); osd->u.shaped.mapped = 0; osd->u.shaped.mask_bitmap = xcb_generate_id(osd->connection); xcb_create_pixmap(osd->connection, 1, osd->u.shaped.mask_bitmap, osd->u.shaped.window, osd->width, osd->height); osd->bitmap = xcb_generate_id(osd->connection); xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->u.shaped.window, osd->width, osd->height); osd->cmap = xcb_generate_id(osd->connection); xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->u.shaped.window, osd->visual); break; } case XCBOSD_COLORKEY: osd->bitmap = xcb_generate_id(osd->connection); xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->window, osd->width, osd->height); osd->cmap = xcb_generate_id(osd->connection); xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->window, osd->visual); break; } osd->clean = UNDEFINED; /* do not xcbosd_clear() here: osd->u.colorkey.sc has not being updated yet */ }
xcbosd *xcbosd_create(xine_t *xine, xcb_connection_t *connection, xcb_screen_t *screen, xcb_window_t window, enum xcbosd_mode mode) { xcbosd *osd; xcb_get_geometry_cookie_t get_geometry_cookie; xcb_get_geometry_reply_t *get_geometry_reply; xcb_void_cookie_t generic_cookie; xcb_generic_error_t *generic_error; osd = calloc(1, sizeof(xcbosd)); if (!osd) return NULL; osd->mode = mode; osd->xine = xine; osd->connection = connection; osd->screen = screen; osd->window = window; osd->visual = osd->screen->root_visual; get_geometry_cookie = xcb_get_geometry(osd->connection, osd->window); get_geometry_reply = xcb_get_geometry_reply(osd->connection, get_geometry_cookie, NULL); osd->depth = get_geometry_reply->depth; osd->width = get_geometry_reply->width; osd->height = get_geometry_reply->height; free(get_geometry_reply); assert(osd->width); assert(osd->height); switch (mode) { case XCBOSD_SHAPED: { const xcb_query_extension_reply_t *query_extension_reply = xcb_get_extension_data(osd->connection, &xcb_shape_id); if (!query_extension_reply || !query_extension_reply->present) { xprintf(osd->xine, XINE_VERBOSITY_LOG, _("x11osd: XShape extension not available. unscaled overlay disabled.\n")); goto error2; } unsigned int window_params[] = { osd->screen->black_pixel, 1, XCB_EVENT_MASK_EXPOSURE }; osd->u.shaped.window = xcb_generate_id(osd->connection); generic_cookie = xcb_create_window_checked(osd->connection, XCB_COPY_FROM_PARENT, osd->u.shaped.window, osd->window, 0, 0, osd->width, osd->height, 0, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, window_params); generic_error = xcb_request_check(osd->connection, generic_cookie); if (generic_error != NULL) { xprintf(osd->xine, XINE_VERBOSITY_LOG, _("x11osd: error creating window. unscaled overlay disabled.\n")); free(generic_error); goto error_window; } osd->u.shaped.mask_bitmap = xcb_generate_id(osd->connection); generic_cookie = xcb_create_pixmap_checked(osd->connection, 1, osd->u.shaped.mask_bitmap, osd->u.shaped.window, osd->width, osd->height); generic_error = xcb_request_check(osd->connection, generic_cookie); if (generic_error != NULL) { xprintf(osd->xine, XINE_VERBOSITY_LOG, _("x11osd: error creating pixmap. unscaled overlay disabled.\n")); free(generic_error); goto error_aftermaskbitmap; } osd->bitmap = xcb_generate_id(osd->connection); xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->u.shaped.window, osd->width, osd->height); osd->gc = xcb_generate_id(osd->connection); xcb_create_gc(osd->connection, osd->gc, osd->u.shaped.window, 0, NULL); osd->u.shaped.mask_gc = xcb_generate_id(osd->connection); xcb_create_gc(osd->connection, osd->u.shaped.mask_gc, osd->u.shaped.mask_bitmap, XCB_GC_FOREGROUND, &osd->screen->white_pixel); osd->u.shaped.mask_gc_back = xcb_generate_id(osd->connection); xcb_create_gc(osd->connection, osd->u.shaped.mask_gc_back, osd->u.shaped.mask_bitmap, XCB_GC_FOREGROUND, &osd->screen->black_pixel); osd->u.shaped.mapped = 0; osd->cmap = xcb_generate_id(osd->connection); xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->u.shaped.window, osd->visual); break; } case XCBOSD_COLORKEY: osd->bitmap = xcb_generate_id(osd->connection); xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->window, osd->width, osd->height); osd->gc = xcb_generate_id(osd->connection); xcb_create_gc(osd->connection, osd->gc, osd->window, 0, NULL); osd->cmap = xcb_generate_id(osd->connection); xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->window, osd->visual); /* FIXME: the expose event doesn't seem to happen? */ /*XSelectInput (osd->display, osd->window, ExposureMask);*/ break; default: goto error2; } osd->clean = UNDEFINED; xcbosd_expose(osd); xprintf(osd->xine, XINE_VERBOSITY_DEBUG, _("x11osd: unscaled overlay created (%s mode).\n"), (mode==XCBOSD_SHAPED) ? "XShape" : "Colorkey" ); return osd; /* XFreeGC (osd->display, osd->gc); XFreeGC (osd->display, osd->mask_gc); XFreeGC (osd->display, osd->mask_gc_back); */ error_aftermaskbitmap: if(mode==XCBOSD_SHAPED) xcb_free_pixmap(osd->connection, osd->u.shaped.mask_bitmap); error_window: if(mode==XCBOSD_SHAPED) xcb_destroy_window(osd->connection, osd->u.shaped.window); error2: free (osd); return NULL; }
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) { DLOG("resize handler\n"); /* TODO: previously, we were getting a rect containing all screens. why? */ Con *output = con_get_output(first); DLOG("x = %d, width = %d\n", output->rect.x, output->rect.width); x_mask_event_mask(~XCB_EVENT_MASK_ENTER_WINDOW); xcb_flush(conn); uint32_t mask = 0; uint32_t values[2]; mask = XCB_CW_OVERRIDE_REDIRECT; values[0] = 1; /* Open a new window, the resizebar. Grab the pointer and move the window around as the user moves the pointer. */ xcb_window_t grabwin = create_window(conn, output->rect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_WINDOW_CLASS_INPUT_ONLY, XCURSOR_CURSOR_POINTER, true, mask, values); /* Keep track of the coordinate orthogonal to motion so we can determine * the length of the resize afterward. */ uint32_t initial_position, new_position; /* Configure the resizebar and snap the pointer. The resizebar runs along * the rect of the second con and follows the motion of the pointer. */ Rect helprect; if (orientation == HORIZ) { helprect.x = second->rect.x; helprect.y = second->rect.y; helprect.width = logical_px(2); helprect.height = second->rect.height; initial_position = second->rect.x; xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, second->rect.x, event->root_y); } else { helprect.x = second->rect.x; helprect.y = second->rect.y; helprect.width = second->rect.width; helprect.height = logical_px(2); initial_position = second->rect.y; xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, event->root_x, second->rect.y); } mask = XCB_CW_BACK_PIXEL; values[0] = config.client.focused.border; mask |= XCB_CW_OVERRIDE_REDIRECT; values[1] = 1; xcb_window_t helpwin = create_window(conn, helprect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_WINDOW_CLASS_INPUT_OUTPUT, (orientation == HORIZ ? XCURSOR_CURSOR_RESIZE_HORIZONTAL : XCURSOR_CURSOR_RESIZE_VERTICAL), true, mask, values); xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin); xcb_flush(conn); /* `new_position' will be updated by the `resize_callback'. */ new_position = initial_position; const struct callback_params params = {orientation, output, helpwin, &new_position}; /* `drag_pointer' blocks until the drag is completed. */ drag_result_t drag_result = drag_pointer(NULL, event, grabwin, BORDER_TOP, 0, resize_callback, ¶ms); xcb_destroy_window(conn, helpwin); xcb_destroy_window(conn, grabwin); xcb_flush(conn); /* User cancelled the drag so no action should be taken. */ if (drag_result == DRAG_REVERT) return 0; int pixels = (new_position - initial_position); DLOG("Done, pixels = %d\n", pixels); // if we got thus far, the containers must have // percentages associated with them assert(first->percent > 0.0); assert(second->percent > 0.0); // calculate the new percentage for the first container double new_percent, difference; double percent = first->percent; DLOG("percent = %f\n", percent); int original = (orientation == HORIZ ? first->rect.width : first->rect.height); DLOG("original = %d\n", original); new_percent = (original + pixels) * (percent / original); difference = percent - new_percent; DLOG("difference = %f\n", difference); DLOG("new percent = %f\n", new_percent); first->percent = new_percent; // calculate the new percentage for the second container double s_percent = second->percent; second->percent = s_percent + difference; DLOG("second->percent = %f\n", second->percent); // now we must make sure that the sum of the percentages remain 1.0 con_fix_percent(first->parent); return 0; }
void createWindowXcb(int argc, char **argv) { // XCB connection int scr; xcb_connection_t* connection = xcb_connect(NULL, &scr); if (connection == NULL) { printf("Cannot open a XCB connection.\nExiting...\n"); exit(1); } const xcb_setup_t *setup = xcb_get_setup(connection); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); while (scr-- > 0) { xcb_screen_next(&iter); } xcb_screen_t* screen = iter.data; // XCB window properties const char* title = "Nucleus"; unsigned int width = 960; unsigned int height = 544; uint32_t value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; uint32_t value_list[32]; value_list[0] = screen->black_pixel; value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; xcb_window_t window = xcb_generate_id(connection); xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list); xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(title), title); // Notification when window is destroyed xcb_intern_atom_cookie_t cookie1 = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS"); xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(connection, cookie1, 0); xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW"); xcb_intern_atom_reply_t* atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0); xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, (*reply).atom, 4, 32, 1, &(*atom_wm_delete_window).atom); free(reply); const uint32_t coords[] = {100, 100}; xcb_map_window(connection, window); xcb_configure_window(connection, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); xcb_flush(connection); // Events bool quit = false; while (!quit) { xcb_generic_event_t* event; event = xcb_poll_for_event(connection); if (!event) { continue; } uint8_t code = event->response_type & 0x7f; switch (code) { case XCB_EXPOSE: // TODO: Resize window break; case XCB_CLIENT_MESSAGE: { const auto& msg = *(const xcb_client_message_event_t*)event; if (msg.data.data32[0] == atom_wm_delete_window->atom) { quit = true; } break; } case XCB_KEY_RELEASE: { const auto& key = *(const xcb_key_release_event_t*)event; // TODO: Handle event break; } case XCB_CONFIGURE_NOTIFY: { const auto& cfg = *(const xcb_configure_notify_event_t*)event; // TODO: Handle event break; } default: break; } free(event); } xcb_destroy_window(connection, window); xcb_disconnect(connection); }
static int CreateWindowAndContext( Display* display, xcb_connection_t* connection, int default_screen, xcb_screen_t* screen, int width, int height, ae3d::WindowCreateFlags flags ) { GLXFBConfig* fb_configs = nullptr; int num_fb_configs = 0; fb_configs = glXGetFBConfigs( display, default_screen, &num_fb_configs ); if (!fb_configs || num_fb_configs == 0) { std::cerr << "glXGetFBConfigs failed." << std::endl; return -1; } /* Select first framebuffer config and query visualID */ int visualID = 0; GLXFBConfig fb_config = fb_configs[ 0 ]; glXGetFBConfigAttrib( display, fb_config, GLX_VISUAL_ID, &visualID ); GLXContext context = glXCreateNewContext( display, fb_config, GLX_RGBA_TYPE, nullptr, True ); if (!context) { std::cerr << "glXCreateNewContext failed." << std::endl; return -1; } /* Create XID's for colormap and window */ xcb_colormap_t colormap = xcb_generate_id( connection ); WindowGlobal::window = xcb_generate_id( connection ); WindowGlobal::windowWidth = width == 0 ? screen->width_in_pixels : width; WindowGlobal::windowHeight = height == 0 ? screen->height_in_pixels : height; xcb_create_colormap( connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visualID ); const uint32_t eventmask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION; const uint32_t valuelist[] = { eventmask, colormap, 0 }; const uint32_t valuemask = XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; xcb_create_window( connection, XCB_COPY_FROM_PARENT, WindowGlobal::window, screen->root, 0, 0, WindowGlobal::windowWidth, WindowGlobal::windowHeight, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visualID, valuemask, valuelist ); xcb_map_window( connection, WindowGlobal::window ); if ((flags & ae3d::WindowCreateFlags::Fullscreen) != 0) { WindowGlobal::EWMHCookie = xcb_ewmh_init_atoms( WindowGlobal::connection, &WindowGlobal::EWMH ); if (!xcb_ewmh_init_atoms_replies( &WindowGlobal::EWMH, WindowGlobal::EWMHCookie, nullptr )) { std::cout << "Fullscreen not supported." << std::endl; } xcb_ewmh_request_change_wm_state( &WindowGlobal::EWMH, XDefaultScreen( display ), WindowGlobal::window, XCB_EWMH_WM_STATE_ADD, WindowGlobal::EWMH._NET_WM_STATE_FULLSCREEN, 0, XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL ); xcb_ewmh_request_change_active_window( &WindowGlobal::EWMH, XDefaultScreen( display ), WindowGlobal::window, XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL, XCB_CURRENT_TIME, XCB_WINDOW_NONE ); xcb_generic_error_t* error; xcb_get_window_attributes_reply_t* reply = xcb_get_window_attributes_reply( WindowGlobal::connection, xcb_get_window_attributes( WindowGlobal::connection, WindowGlobal::window ), &error ); if (!reply) { std::cerr << "Full screen reply failed" << std::endl; } } //xcb_change_property( WindowGlobal::connection, XCB_PROP_MODE_REPLACE, WindowGlobal::window, WindowGlobal::EWMH._NET_WM_STATE, XCB_ATOM, 32, 1, &(WindowGlobal::EWMH._NET_WM_STATE_FULLSCREEN)); // End test GLXWindow glxwindow = glXCreateWindow( display, fb_config, WindowGlobal::window, nullptr ); if (!glxwindow) { xcb_destroy_window( connection, WindowGlobal::window ); glXDestroyContext( display, context ); std::cerr << "glXDestroyContext failed" << std::endl; return -1; } WindowGlobal::drawable = glxwindow; if (!glXMakeContextCurrent( display, WindowGlobal::drawable, WindowGlobal::drawable, context )) { xcb_destroy_window( connection, WindowGlobal::window ); glXDestroyContext( display, context ); std::cerr << "glXMakeContextCurrent failed" << std::endl; return -1; } return 0; }
XCBWindow::~XCBWindow() { xcb_destroy_window(m_connection, m_handle); xcb_disconnect(m_connection); }
/** Hello, this is main. * \param argc Who knows. * \param argv Who knows. * \return EXIT_SUCCESS I hope. */ int main(int argc, char **argv) { char *confpath = NULL; int xfd, i, opt; ssize_t cmdlen = 1; xdgHandle xdg; bool no_argb = false; xcb_generic_event_t *event; xcb_query_tree_cookie_t tree_c; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, { "check", 0, NULL, 'k' }, { "no-argb", 0, NULL, 'a' }, { NULL, 0, NULL, 0 } }; /* event loop watchers */ ev_io xio = { .fd = -1 }; ev_check xcheck; ev_prepare a_refresh; ev_signal sigint; ev_signal sigterm; ev_signal sighup; /* clear the globalconf structure */ p_clear(&globalconf, 1); globalconf.keygrabber = LUA_REFNIL; globalconf.mousegrabber = LUA_REFNIL; buffer_init(&globalconf.startup_errors); /* save argv */ for(i = 0; i < argc; i++) cmdlen += a_strlen(argv[i]) + 1; awesome_argv = p_new(char, cmdlen); a_strcpy(awesome_argv, cmdlen, argv[0]); for(i = 1; i < argc; i++) { a_strcat(awesome_argv, cmdlen, " "); a_strcat(awesome_argv, cmdlen, argv[i]); } /* Text won't be printed correctly otherwise */ setlocale(LC_CTYPE, ""); /* Get XDG basedir data */ xdgInitHandle(&xdg); /* init lua */ luaA_init(&xdg); /* check args */ while((opt = getopt_long(argc, argv, "vhkc:a", long_options, NULL)) != -1) switch(opt) { case 'v': eprint_version(); break; case 'h': exit_help(EXIT_SUCCESS); break; case 'k': if(!luaA_parserc(&xdg, confpath, false)) { fprintf(stderr, "✘ Configuration file syntax error.\n"); return EXIT_FAILURE; } else { fprintf(stderr, "✔ Configuration file syntax OK.\n"); return EXIT_SUCCESS; } case 'c': if(a_strlen(optarg)) confpath = a_strdup(optarg); else fatal("-c option requires a file name"); break; case 'a': no_argb = true; break; } globalconf.loop = ev_default_loop(EVFLAG_NOSIGFD); /* register function for signals */ ev_signal_init(&sigint, exit_on_signal, SIGINT); ev_signal_init(&sigterm, exit_on_signal, SIGTERM); ev_signal_init(&sighup, restart_on_signal, SIGHUP); ev_signal_start(globalconf.loop, &sigint); ev_signal_start(globalconf.loop, &sigterm); ev_signal_start(globalconf.loop, &sighup); ev_unref(globalconf.loop); ev_unref(globalconf.loop); ev_unref(globalconf.loop); struct sigaction sa = { .sa_handler = signal_fatal, .sa_flags = 0 }; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, 0); /* X stuff */ globalconf.connection = xcb_connect(NULL, &globalconf.default_screen); if(xcb_connection_has_error(globalconf.connection)) fatal("cannot open display"); globalconf.screen = xcb_aux_get_screen(globalconf.connection, globalconf.default_screen); /* FIXME The following two assignments were swapped on purpose */ if(!no_argb) globalconf.visual = a_default_visual(globalconf.screen); if(!globalconf.visual) globalconf.visual = a_argb_visual(globalconf.screen); globalconf.default_depth = a_visual_depth(globalconf.screen, globalconf.visual->visual_id); globalconf.default_cmap = globalconf.screen->default_colormap; if(globalconf.default_depth != globalconf.screen->root_depth) { // We need our own color map if we aren't using the default depth globalconf.default_cmap = xcb_generate_id(globalconf.connection); xcb_create_colormap(globalconf.connection, XCB_COLORMAP_ALLOC_NONE, globalconf.default_cmap, globalconf.screen->root, globalconf.visual->visual_id); } /* Prefetch all the extensions we might need */ xcb_prefetch_extension_data(globalconf.connection, &xcb_big_requests_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_test_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_randr_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_xinerama_id); /* initialize dbus */ a_dbus_init(); /* Get the file descriptor corresponding to the X connection */ xfd = xcb_get_file_descriptor(globalconf.connection); ev_io_init(&xio, &a_xcb_io_cb, xfd, EV_READ); ev_io_start(globalconf.loop, &xio); ev_check_init(&xcheck, &a_xcb_check_cb); ev_check_start(globalconf.loop, &xcheck); ev_unref(globalconf.loop); ev_prepare_init(&a_refresh, &a_refresh_cb); ev_prepare_start(globalconf.loop, &a_refresh); ev_unref(globalconf.loop); /* Grab server */ xcb_grab_server(globalconf.connection); /* Make sure there are no pending events. Since we didn't really do anything * at all yet, we will just discard all events which we received so far. * The above GrabServer should make sure no new events are generated. */ xcb_aux_sync(globalconf.connection); while ((event = xcb_poll_for_event(globalconf.connection)) != NULL) { /* Make sure errors are printed */ uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(event); if(response_type == 0) event_handle(event); p_delete(&event); } { const uint32_t select_input_val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; /* This causes an error if some other window manager is running */ xcb_change_window_attributes(globalconf.connection, globalconf.screen->root, XCB_CW_EVENT_MASK, &select_input_val); } /* Need to xcb_flush to validate error handler */ xcb_aux_sync(globalconf.connection); /* Process all errors in the queue if any. There can be no events yet, so if * this function returns something, it must be an error. */ if (xcb_poll_for_event(globalconf.connection) != NULL) fatal("another window manager is already running"); /* Prefetch the maximum request length */ xcb_prefetch_maximum_request_length(globalconf.connection); /* check for xtest extension */ const xcb_query_extension_reply_t *xtest_query; xtest_query = xcb_get_extension_data(globalconf.connection, &xcb_test_id); globalconf.have_xtest = xtest_query->present; /* Allocate the key symbols */ globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection); xcb_get_modifier_mapping_cookie_t xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection); /* init atom cache */ atoms_init(globalconf.connection); /* init screens information */ screen_scan(); xutil_lock_mask_get(globalconf.connection, xmapping_cookie, globalconf.keysyms, &globalconf.numlockmask, &globalconf.shiftlockmask, &globalconf.capslockmask, &globalconf.modeswitchmask); /* do this only for real screen */ ewmh_init(); systray_init(); /* init spawn (sn) */ spawn_init(); /* The default GC is just a newly created associated with a window with * depth globalconf.default_depth */ xcb_window_t tmp_win = xcb_generate_id(globalconf.connection); globalconf.gc = xcb_generate_id(globalconf.connection); xcb_create_window(globalconf.connection, globalconf.default_depth, tmp_win, globalconf.screen->root, -1, -1, 1, 1, 0, XCB_COPY_FROM_PARENT, globalconf.visual->visual_id, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, (const uint32_t []) { globalconf.screen->black_pixel, globalconf.screen->black_pixel, globalconf.default_cmap }); xcb_create_gc(globalconf.connection, globalconf.gc, tmp_win, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, (const uint32_t[]) { globalconf.screen->black_pixel, globalconf.screen->white_pixel }); xcb_destroy_window(globalconf.connection, tmp_win); /* Get the window tree associated to this screen */ tree_c = xcb_query_tree_unchecked(globalconf.connection, globalconf.screen->root); xcb_change_window_attributes(globalconf.connection, globalconf.screen->root, XCB_CW_EVENT_MASK, ROOT_WINDOW_EVENT_MASK); /* we will receive events, stop grabbing server */ xcb_ungrab_server(globalconf.connection); /* Parse and run configuration file */ if (!luaA_parserc(&xdg, confpath, true)) fatal("couldn't find any rc file"); p_delete(&confpath); xdgWipeHandle(&xdg); /* scan existing windows */ scan(tree_c); xcb_flush(globalconf.connection); /* main event loop */ ev_loop(globalconf.loop, 0); /* cleanup event loop */ ev_ref(globalconf.loop); ev_check_stop(globalconf.loop, &xcheck); ev_ref(globalconf.loop); ev_prepare_stop(globalconf.loop, &a_refresh); ev_ref(globalconf.loop); ev_io_stop(globalconf.loop, &xio); awesome_atexit(false); return EXIT_SUCCESS; }