Exemplo n.º 1
0
Arquivo: main.c Projeto: stfnm/i3
/*
 * Creates the config file and tells i3 to reload.
 *
 */
static void finish() {
    printf("creating \"%s\"...\n", config_path);

    if (!(dpy = XOpenDisplay(NULL)))
        errx(1, "Could not connect to X11");

    FILE *kc_config = fopen(SYSCONFDIR "/i3/config.keycodes", "r");
    if (kc_config == NULL)
        err(1, "Could not open input file \"%s\"", SYSCONFDIR "/i3/config.keycodes");

    FILE *ks_config = fopen(config_path, "w");
    if (ks_config == NULL)
        err(1, "Could not open output config file \"%s\"", config_path);
    free(config_path);

    char *line = NULL;
    size_t len = 0;
#ifndef USE_FGETLN
    ssize_t read;
#endif
    bool head_of_file = true;

    /* write a header about auto-generation to the output file */
    fputs("# This file has been auto-generated by i3-config-wizard(1).\n", ks_config);
    fputs("# It will not be overwritten, so edit it as you like.\n", ks_config);
    fputs("#\n", ks_config);
    fputs("# Should you change your keyboard layout somewhen, delete\n", ks_config);
    fputs("# this file and re-run i3-config-wizard(1).\n", ks_config);
    fputs("#\n", ks_config);

#ifdef USE_FGETLN
    char *buf = NULL;
    while ((buf = fgetln(kc_config, &len)) != NULL) {
        /* fgetln does not return null-terminated strings */
        FREE(line);
        sasprintf(&line, "%.*s", len, buf);
#else
    size_t linecap = 0;
    while ((read = getline(&line, &linecap, kc_config)) != -1) {
        len = strlen(line);
#endif
        /* skip the warning block at the beginning of the input file */
        if (head_of_file &&
            strncmp("# WARNING", line, strlen("# WARNING")) == 0)
            continue;

        head_of_file = false;

        /* Skip leading whitespace */
        char *walk = line;
        while (isspace(*walk) && walk < (line + len)) {
            /* Pre-output the skipped whitespaces to keep proper indentation */
            fputc(*walk, ks_config);
            walk++;
        }

        /* Set the modifier the user chose */
        if (strncmp(walk, "set $mod ", strlen("set $mod ")) == 0) {
            if (modifier == MOD_Mod1)
                fputs("set $mod Mod1\n", ks_config);
            else fputs("set $mod Mod4\n", ks_config);
            continue;
        }

        /* Check for 'bindcode'. If it’s not a bindcode line, we
         * just copy it to the output file */
        if (strncmp(walk, "bindcode", strlen("bindcode")) != 0) {
            fputs(walk, ks_config);
            continue;
        }
        char *result = rewrite_binding(walk);
        fputs(result, ks_config);
        free(result);
    }

    /* sync to do our best in order to have the file really stored on disk */
    fflush(ks_config);
    fsync(fileno(ks_config));

#ifndef USE_FGETLN
    free(line);
#endif

    fclose(kc_config);
    fclose(ks_config);

    /* tell i3 to reload the config file */
    int sockfd = ipc_connect(socket_path);
    ipc_send_message(sockfd, strlen("reload"), 0, (uint8_t*)"reload");
    close(sockfd);

    exit(0);
}

int main(int argc, char *argv[]) {
    config_path = resolve_tilde("~/.i3/config");
    socket_path = getenv("I3SOCK");
    char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1";
    char *patternbold = "-misc-fixed-bold-r-normal--13-120-75-75-C-70-iso10646-1";
    int o, option_index = 0;

    static struct option long_options[] = {
        {"socket", required_argument, 0, 's'},
        {"version", no_argument, 0, 'v'},
        {"limit", required_argument, 0, 'l'},
        {"prompt", required_argument, 0, 'P'},
        {"prefix", required_argument, 0, 'p'},
        {"font", required_argument, 0, 'f'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
    };

    char *options_string = "s:vh";

    while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
        switch (o) {
            case 's':
                FREE(socket_path);
                socket_path = strdup(optarg);
                break;
            case 'v':
                printf("i3-config-wizard " I3_VERSION "\n");
                return 0;
            case 'h':
                printf("i3-config-wizard " I3_VERSION "\n");
                printf("i3-config-wizard [-s <socket>] [-v]\n");
                return 0;
        }
    }

    /* Check if the destination config file does not exist but the path is
     * writable. If not, exit now, this program is not useful in that case. */
    struct stat stbuf;
    if (stat(config_path, &stbuf) == 0) {
        printf("The config file \"%s\" already exists. Exiting.\n", config_path);
        return 0;
    }

    /* Create ~/.i3 if it does not yet exist */
    char *config_dir = resolve_tilde("~/.i3");
    if (stat(config_dir, &stbuf) != 0)
        if (mkdir(config_dir, 0755) == -1)
            err(1, "mkdir(%s) failed", config_dir);
    free(config_dir);

    int fd;
    if ((fd = open(config_path, O_CREAT | O_RDWR, 0644)) == -1) {
        printf("Cannot open file \"%s\" for writing: %s. Exiting.\n", config_path, strerror(errno));
        return 0;
    }
    close(fd);
    unlink(config_path);

    if (socket_path == NULL)
        socket_path = root_atom_contents("I3_SOCKET_PATH");

    if (socket_path == NULL)
        socket_path = "/tmp/i3-ipc.sock";

    int screens;
    if ((conn = xcb_connect(NULL, &screens)) == NULL ||
        xcb_connection_has_error(conn))
        errx(1, "Cannot open display\n");

    xcb_get_modifier_mapping_cookie_t modmap_cookie;
    modmap_cookie = xcb_get_modifier_mapping(conn);
    symbols = xcb_key_symbols_alloc(conn);

    /* Place requests for the atoms we need as soon as possible */
    #define xmacro(atom) \
        xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
    #include "atoms.xmacro"
    #undef xmacro

    root_screen = xcb_aux_get_screen(conn, screens);
    root = root_screen->root;

    if (!(modmap_reply = xcb_get_modifier_mapping_reply(conn, modmap_cookie, NULL)))
        errx(EXIT_FAILURE, "Could not get modifier mapping\n");

    xcb_numlock_mask = get_mod_mask_for(XCB_NUM_LOCK, symbols, modmap_reply);

    font = load_font(pattern, true);
    bold_font = load_font(patternbold, true);

    /* Open an input window */
    win = xcb_generate_id(conn);
    xcb_create_window(
        conn,
        XCB_COPY_FROM_PARENT,
        win, /* the window id */
        root, /* parent == root */
        490, 297, 300, 205, /* dimensions */
        0, /* X11 border = 0, we draw our own */
        XCB_WINDOW_CLASS_INPUT_OUTPUT,
        XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
        XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
        (uint32_t[]){
            0, /* back pixel: black */
            XCB_EVENT_MASK_EXPOSURE |
            XCB_EVENT_MASK_BUTTON_PRESS
        });

    /* Map the window (make it visible) */
    xcb_map_window(conn, win);

    /* Setup NetWM atoms */
    #define xmacro(name) \
        do { \
            xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
            if (!reply) \
                errx(EXIT_FAILURE, "Could not get atom " # name "\n"); \
            \
            A_ ## name = reply->atom; \
            free(reply); \
        } while (0);
    #include "atoms.xmacro"
    #undef xmacro

    /* Set dock mode */
    xcb_change_property(conn,
        XCB_PROP_MODE_REPLACE,
        win,
        A__NET_WM_WINDOW_TYPE,
        A_ATOM,
        32,
        1,
        (unsigned char*) &A__NET_WM_WINDOW_TYPE_DIALOG);

    /* Set window title */
    xcb_change_property(conn,
        XCB_PROP_MODE_REPLACE,
        win,
        A__NET_WM_NAME,
        A_UTF8_STRING,
        8,
        strlen("i3: first configuration"),
        "i3: first configuration");

    /* Create pixmap */
    pixmap = xcb_generate_id(conn);
    pixmap_gc = xcb_generate_id(conn);
    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, 500);
    xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);

    /* Grab the keyboard to get all input */
    xcb_flush(conn);

    /* Try (repeatedly, if necessary) to grab the keyboard. We might not
     * get the keyboard at the first attempt because of the keybinding
     * still being active when started via a wm’s keybinding. */
    xcb_grab_keyboard_cookie_t cookie;
    xcb_grab_keyboard_reply_t *reply = NULL;

    int count = 0;
    while ((reply == NULL || reply->status != XCB_GRAB_STATUS_SUCCESS) && (count++ < 500)) {
        cookie = xcb_grab_keyboard(conn, false, win, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
        reply = xcb_grab_keyboard_reply(conn, cookie, NULL);
        usleep(1000);
    }

    if (reply->status != XCB_GRAB_STATUS_SUCCESS) {
        fprintf(stderr, "Could not grab keyboard, status = %d\n", reply->status);
        exit(-1);
    }

    xcb_flush(conn);

    xcb_generic_event_t *event;
    while ((event = xcb_wait_for_event(conn)) != NULL) {
        if (event->response_type == 0) {
            fprintf(stderr, "X11 Error received! sequence %x\n", event->sequence);
            continue;
        }

        /* Strip off the highest bit (set if the event is generated) */
        int type = (event->response_type & 0x7F);

        switch (type) {
            case XCB_KEY_PRESS:
                handle_key_press(NULL, conn, (xcb_key_press_event_t*)event);
                break;

            /* TODO: handle mappingnotify */

            case XCB_BUTTON_PRESS:
                handle_button_press((xcb_button_press_event_t*)event);
                break;

            case XCB_EXPOSE:
                handle_expose();
                break;
        }

        free(event);
    }

    return 0;
}
Exemplo n.º 2
0
/*
 * Flush before blocking (and waiting for new events)
 *
 */
static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
    xcb_flush(conn);
}
Exemplo n.º 3
0
/** Changes the EWMH state of the window */
static void set_wm_state (vout_window_t *wnd, bool on, xcb_atom_t state)
{
    vout_window_sys_t *sys = wnd->sys;
    /* From EWMH "_WM_STATE" */
    xcb_client_message_event_t ev = {
         .response_type = XCB_CLIENT_MESSAGE,
         .format = 32,
         .window = wnd->handle.xid,
         .type = sys->wm_state,
    };

    ev.data.data32[0] = on ? NET_WM_STATE_ADD : NET_WM_STATE_REMOVE;
    ev.data.data32[1] = state;
    ev.data.data32[2] = 0;
    ev.data.data32[3] = 1;

    /* From ICCCM "Changing Window State" */
    xcb_send_event (sys->conn, 0, sys->root,
                    XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
                    XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
                    (const char *)&ev);
}


static int Control (vout_window_t *wnd, int cmd, va_list ap)
{
    vout_window_sys_t *p_sys = wnd->sys;
    xcb_connection_t *conn = p_sys->conn;

    switch (cmd)
    {
        case VOUT_WINDOW_SET_SIZE:
        {
            if (p_sys->embedded)
                return VLC_EGENERIC;

            unsigned width = va_arg (ap, unsigned);
            unsigned height = va_arg (ap, unsigned);
            const uint32_t values[] = { width, height, };

            xcb_configure_window (conn, wnd->handle.xid,
                                  XCB_CONFIG_WINDOW_WIDTH |
                                  XCB_CONFIG_WINDOW_HEIGHT, values);
            break;
        }

        case VOUT_WINDOW_SET_STATE:
        {
            unsigned state = va_arg (ap, unsigned);
            bool above = (state & VOUT_WINDOW_STATE_ABOVE) != 0;
            bool below = (state & VOUT_WINDOW_STATE_BELOW) != 0;

            set_wm_state (wnd, above, p_sys->wm_state_above);
            set_wm_state (wnd, below, p_sys->wm_state_below);
            break;
        }

        case VOUT_WINDOW_SET_FULLSCREEN:
        {
            bool fs = va_arg (ap, int);
            if (!fs && var_GetBool (wnd, "video-wallpaper"))
                return VLC_EGENERIC;
            set_wm_state (wnd, fs, p_sys->wm_state_fullscreen);
            break;
        }

        default:
            msg_Err (wnd, "request %d not implemented", cmd);
            return VLC_EGENERIC;
    }
    xcb_flush (p_sys->conn);
    return VLC_SUCCESS;
}
Exemplo n.º 4
0
void draw_gc(xcb_window_t win)
{
	xcb_rectangle_t      r = { 0, 0,  0,0 };
	xcb_connection_t    *c = G.conn;
	xcb_get_geometry_reply_t *geo;

	geo = xcb_get_geometry_reply(c, 
			xcb_get_geometry(c, win), NULL);

	if(0)printf("get (%hdx%hd)@(%dx%d)\n",  
			geo->x, geo->y, geo->width, geo->height);

	xcb_get_image_cookie_t cookie;
	xcb_get_image_reply_t *reply;
	xcb_generic_error_t *error;
	xcb_void_cookie_t ck;

	if(geo!=NULL){
		r.width = geo->width ;
		r.height=geo->height;
		r.x=0;
		r.y=0;
		//printf("window depth=%d\n", geo->depth);
		if(geo->depth == 24 |  geo->depth == 32)
			psize = r.width * r.height * 4; //correct
		else if(geo->depth==16)
			psize = r.width * r.height * 2; //correct
		else
			printf(" *** unsupported window depth\n");
	}else
		psize = r.width * r.height * 4; //correct
	free(geo);

	static cairo_surface_t *cmask;
	if( pbuf == NULL){
		//			psize = geo->width *geo->height*4; //for test
		pbuf = malloc(psize);
		printf("malloc pbuf=0x%x size=%d\n",pbuf, psize);
		memset(pbuf, 0x18, psize);

		cmask = cairo_image_surface_create_for_data ((unsigned char *) pbuf,
				CAIRO_FORMAT_ARGB32, 
				geo->width, geo->height, geo->width*4);
		//	12, 4, 48);
		if(cmask == NULL){
			perror("cairo surface create"); exit(1);
		}

	}
	if(0)printf("width (%dx%d=%d\n",  geo->width, geo->height,  geo->width *geo->height*4);
	draw_cairo(cmask);

	//draw image with xcb_put_image
	// creat gc and draw to parent window
	xcb_gcontext_t       g;
	g = xcb_generate_id(c);
	xcb_create_gc(c, g, win, 0,NULL);

	ck = xcb_put_image_checked(c, XCB_IMAGE_FORMAT_Z_PIXMAP,
			win, g,
			r.width, r.height, r.x,r.y,
			0, G.s->root_depth,
			psize, pbuf);
	xcb_flush(c);

}
Exemplo n.º 5
0
int vkDisplay::create_window(const unsigned int width, const unsigned int height)
{
#if defined(PLATFORM_LINUX)

    uint32_t value_mask, value_list[32];
    m_XcbWindow = xcb_generate_id(m_pXcbConnection);

    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    value_list[0] = m_pXcbScreen->black_pixel;
    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
                    XCB_EVENT_MASK_EXPOSURE;

    xcb_create_window(m_pXcbConnection,
            XCB_COPY_FROM_PARENT,
            m_XcbWindow, m_pXcbScreen->root,
            0, 0, width, height, 0,
            XCB_WINDOW_CLASS_INPUT_OUTPUT,
            m_pXcbScreen->root_visual,
            value_mask, value_list);

    xcb_map_window(m_pXcbConnection, m_XcbWindow);
    xcb_flush(m_pXcbConnection);
    // TODO : Not sure of best place to put this, but I have all the info I need here so just setting it all here for now
    //m_XcbPlatformHandle.connection = m_pXcbConnection;
    //m_XcbPlatformHandle.root = m_pXcbScreen->root;
    m_surface.base.platform = VK_ICD_WSI_PLATFORM_XCB;
    m_surface.connection = m_pXcbConnection;
    m_surface.window = m_XcbWindow;
    return 0;
#elif defined(WIN32)
    // Register Window class
    WNDCLASSEX wcex = {};
	m_connection = GetModuleHandle(0);
    wcex.cbSize = sizeof( WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WindowProcVk;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = m_connection;
    wcex.hIcon = LoadIcon(wcex.hInstance, MAKEINTRESOURCE( IDI_ICON));
    wcex.hCursor = LoadCursor( NULL, IDC_ARROW);
    wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = APP_NAME;
    wcex.hIconSm = LoadIcon( wcex.hInstance, MAKEINTRESOURCE( IDI_ICON));
    if( !RegisterClassEx( &wcex))
    {
        vktrace_LogError("Failed to register windows class");
        return -1;
    }

    // create the window
    m_windowHandle = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, 0, 0,
                          width, height, NULL, NULL, wcex.hInstance, NULL);

    if (m_windowHandle)
    {
        ShowWindow( m_windowHandle, SW_SHOWDEFAULT);
        m_windowWidth = width;
        m_windowHeight = height;
    } else {
        vktrace_LogError("Failed to create window");
        return -1;
    }
    // TODO : Not sure of best place to put this, but I have all the info I need here so just setting it all here for now
    m_surface.base.platform = VK_ICD_WSI_PLATFORM_WIN32;
    m_surface.hinstance = wcex.hInstance;
    m_surface.hwnd = m_windowHandle;
    return 0;
#endif
}
Exemplo n.º 6
0
/*
 * 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;
}
Exemplo n.º 7
0
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);
}
Exemplo n.º 8
0
Arquivo: x11.c Projeto: Annovae/vlc
static int Control (vout_display_t *vd, int query, va_list ap)
{
    vout_display_sys_t *sys = vd->sys;

    switch (query)
    {
    case VOUT_DISPLAY_CHANGE_FULLSCREEN:
    {
        const vout_display_cfg_t *c = va_arg (ap, const vout_display_cfg_t *);
        return vout_window_SetFullScreen (sys->embed, c->is_fullscreen);
    }

    case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
    {
        const vout_display_cfg_t *p_cfg =
            (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *);
        const bool is_forced = (bool)va_arg (ap, int);

        if (is_forced)
        {   /* Changing the dimensions of the parent window takes place
             * asynchronously (in the X server). Also it might fail or result
             * in different dimensions than requested. Request the size change
             * and return a failure since the size is not (yet) changed.
             * If the change eventually succeeds, HandleParentStructure()
             * will trigger a non-forced display size change later. */
            vout_window_SetSize (sys->embed, p_cfg->display.width,
                                 p_cfg->display.height);
            return VLC_EGENERIC;
        }

        vout_display_place_t place;
        vout_display_PlacePicture (&place, &vd->source, p_cfg, false);

        if (place.width  != vd->fmt.i_visible_width ||
            place.height != vd->fmt.i_visible_height)
        {
            vout_display_SendEventPicturesInvalid (vd);
            return VLC_SUCCESS;
        }

        /* Move the picture within the window */
        const uint32_t values[] = { place.x, place.y };
        xcb_configure_window (sys->conn, sys->window,
                              XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
                              values);
        return VLC_SUCCESS;
    }
    case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
    {
        unsigned state = va_arg (ap, unsigned);
        return vout_window_SetState (sys->embed, state);
    }

    case VOUT_DISPLAY_CHANGE_ZOOM:
    case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
    case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
    case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
        /* I am not sure it is always necessary, but it is way simpler ... */
        vout_display_SendEventPicturesInvalid (vd);
        return VLC_SUCCESS;

    case VOUT_DISPLAY_RESET_PICTURES:
    {
        ResetPictures (vd);

        vout_display_place_t place;
        vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);

        vd->fmt.i_width  = vd->source.i_width  * place.width  / vd->source.i_visible_width;
        vd->fmt.i_height = vd->source.i_height * place.height / vd->source.i_visible_height;

        vd->fmt.i_visible_width  = place.width;
        vd->fmt.i_visible_height = place.height;
        vd->fmt.i_x_offset = vd->source.i_x_offset * place.width  / vd->source.i_visible_width;
        vd->fmt.i_y_offset = vd->source.i_y_offset * place.height / vd->source.i_visible_height;
        return VLC_SUCCESS;
    }

    /* Hide the mouse. It will be send when
     * vout_display_t::info.b_hide_mouse is false */
    case VOUT_DISPLAY_HIDE_MOUSE:
        xcb_change_window_attributes (sys->conn, sys->embed->handle.xid,
                                  XCB_CW_CURSOR, &(uint32_t){ sys->cursor });
        xcb_flush (sys->conn);
        return VLC_SUCCESS;

    default:
        msg_Err (vd, "Unknown request in XCB vout display");
        return VLC_EGENERIC;
    }
}
Exemplo n.º 9
0
/* @brief Processes an entered key by:
 * 
 * 1) Adding the key to the query buffer (backspace will remove a character).
 * 2) Drawing the updated query to the screen if necessary.
 * 3) Writing the updated query to the child process if necessary.
 * 
 * @param query_buffer The string of the current query (what is typed).
 * @param query_index A reference to the current length of the query.
 * @param query_cursor_index A reference to the current index of the cursor
          in the query.
 * @param key The key enetered.
 * @param connection A connection to the Xorg server.
 * @param cairo_context A cairo context for drawing to the screen.
 * @param cairo_surface A cairo surface for drawing to the screen.
 * @param to_write A descriptor to write to the child process.
 * @return 0 on success and 1 on failure.
 */
static inline int32_t process_key_stroke(char *query_buffer, uint32_t *query_index, uint32_t *query_cursor_index, xcb_keysym_t key, xcb_connection_t *connection, cairo_t *cairo_context, cairo_surface_t *cairo_surface, FILE *to_write) {
  pthread_mutex_lock(&global.result_mutex);

  /* Check when we should update. */
  int32_t redraw = 0;
  int32_t resend = 0;

  debug("key: %u\n", key);

  switch (key) {
    case 65293: /* Enter. */
      if (global.results && global.result_highlight < global.result_count && global.result_highlight >= 0) {
        printf("%s", global.results[global.result_highlight].action);
        goto cleanup;
      }
      break;
    case 65361: /* Left. */
      if (*query_cursor_index > 0) {
        (*query_cursor_index)--;
        redraw = 1;
      }
      break;
    case 65363: /* Right. */
      if (*query_cursor_index < *query_index) {
        (*query_cursor_index)++;
        redraw = 1;
      }
      break;
    case 65362: /* Up. */
      if (global.result_highlight > 0) {
        global.result_highlight--;
        draw_response_text(connection, 0, cairo_context, cairo_surface, global.results, global.result_count);
      }
      break;
    case 65364: /* Down. */
      if (global.result_count && global.result_highlight < global.result_count - 1) {
        global.result_highlight++;
        draw_response_text(connection, 0, cairo_context, cairo_surface, global.results, global.result_count);
      }
      break;
    case 65289: /* Tab. */
      if (global.result_count && global.result_highlight < global.result_count - 1) {
        global.result_highlight++;
        draw_response_text(connection, 0, cairo_context, cairo_surface, global.results, global.result_count);
      } else if(global.result_count && global.result_highlight == global.result_count - 1) {
        global.result_highlight = 0;
        draw_response_text(connection, 0, cairo_context, cairo_surface, global.results, global.result_count);
      }
      break;
    case 65056: /* Shift Tab */
      if (global.result_count && global.result_highlight > 0) {
        global.result_highlight--;
        draw_response_text(connection, 0, cairo_context, cairo_surface, global.results, global.result_count);
      } else if(global.result_count && global.result_highlight == 0) {
        global.result_highlight = global.result_count - 1;
        draw_response_text(connection, 0, cairo_context, cairo_surface, global.results, global.result_count);
      }
      break;
    case 65307: /* Escape. */
      goto cleanup;
    case 65288: /* Backspace. */
      if (*query_index > 0 && *query_cursor_index > 0) {
        memmove(&query_buffer[(*query_cursor_index) - 1], &query_buffer[*query_cursor_index], *query_index - *query_cursor_index + 1);
        (*query_cursor_index)--;
        (*query_index)--;
        query_buffer[(*query_index)] = 0;
        redraw = 1;
        resend = 1;
      } else if (*query_index == 0 && settings.backspace_exit) { /* Backspace with nothing? */
        goto cleanup;
      }
      break;
    default:
      if (isprint((char)key) && *query_index < MAX_QUERY) {
        memmove(&query_buffer[(*query_cursor_index) + 1], &query_buffer[*query_cursor_index], *query_index - *query_cursor_index + 1);
        query_buffer[(*query_cursor_index)++] = key;
        (*query_index)++;
        redraw = 1;
        resend = 1;
      }
      break;
  }

  if (redraw) {
    draw_query_text(cairo_context, cairo_surface, query_buffer, *query_cursor_index);
    xcb_flush(connection);
  }

  if (resend) {
    if (write_to_remote(to_write, "%s\n", query_buffer)) {
      fprintf(stderr, "Failed to write.\n");
    }
  }

  pthread_mutex_unlock(&global.result_mutex);
  return 1;

cleanup:
  pthread_mutex_unlock(&global.result_mutex);
  return 0;
}
Exemplo n.º 10
0
/** 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, screen_nbr, opt, colors_nbr;
    xcolor_init_request_t colors_reqs[2];
    ssize_t cmdlen = 1;
    xdgHandle xdg;
    xcb_generic_event_t *event;
    static struct option long_options[] =
    {
        { "help",    0, NULL, 'h' },
        { "version", 0, NULL, 'v' },
        { "config",  1, NULL, 'c' },
        { "check",   0, NULL, 'k' },
        { 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;

    globalconf.argv = p_new(char, cmdlen);
    a_strcpy(globalconf.argv, cmdlen, argv[0]);

    for(i = 1; i < argc; i++)
    {
        a_strcat(globalconf.argv, cmdlen, " ");
        a_strcat(globalconf.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:",
                             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;
        }

    globalconf.loop = ev_default_loop(0);
    ev_timer_init(&globalconf.timer, &luaA_on_timer, 0., 0.);

    /* 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);

    /* XLib sucks */
    XkbIgnoreExtension(True);

    /* X stuff */
    globalconf.display = XOpenDisplay(NULL);
    if (globalconf.display == NULL)
        fatal("cannot open display");

    globalconf.default_screen = XDefaultScreen(globalconf.display);

    globalconf.connection = XGetXCBConnection(globalconf.display);

    /* Double checking then everything is OK. */
    if(xcb_connection_has_error(globalconf.connection))
        fatal("cannot open display");

    /* 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_shape_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);
    }

    for(screen_nbr = 0;
        screen_nbr < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
        screen_nbr++)
    {
        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,
                                     xutil_screen_get(globalconf.connection, screen_nbr)->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();

    /* init default font and colors */
    colors_reqs[0] = xcolor_init_unchecked(&globalconf.colors.fg,
                                           "black", sizeof("black") - 1);

    colors_reqs[1] = xcolor_init_unchecked(&globalconf.colors.bg,
                                           "white", sizeof("white") - 1);

    globalconf.font = draw_font_new("sans 8");

    for(colors_nbr = 0; colors_nbr < 2; colors_nbr++)
        xcolor_init_reply(colors_reqs[colors_nbr]);

    xutil_lock_mask_get(globalconf.connection, xmapping_cookie,
                        globalconf.keysyms, &globalconf.numlockmask,
                        &globalconf.shiftlockmask, &globalconf.capslockmask,
                        &globalconf.modeswitchmask);

    /* Get the window tree associated to this screen */
    const int screen_max = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
    xcb_query_tree_cookie_t tree_c[screen_max];

    /* do this only for real screen */
    for(screen_nbr = 0; screen_nbr < screen_max; screen_nbr++)
    {
        /* select for events */
        const uint32_t change_win_vals[] =
        {
            XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY
                | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW
                | XCB_EVENT_MASK_STRUCTURE_NOTIFY
                | XCB_EVENT_MASK_PROPERTY_CHANGE
                | XCB_EVENT_MASK_BUTTON_PRESS
                | XCB_EVENT_MASK_BUTTON_RELEASE
                | XCB_EVENT_MASK_FOCUS_CHANGE
        };

        tree_c[screen_nbr] = xcb_query_tree_unchecked(globalconf.connection,
                                                      xutil_screen_get(globalconf.connection, screen_nbr)->root);

        xcb_change_window_attributes(globalconf.connection,
                                     xutil_screen_get(globalconf.connection, screen_nbr)->root,
                                     XCB_CW_EVENT_MASK,
                                     change_win_vals);
        ewmh_init(screen_nbr);
        systray_init(screen_nbr);
    }

    /* init spawn (sn) */
    spawn_init();

    /* 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");

    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;
}
Exemplo n.º 11
0
Arquivo: x11.c Projeto: Annovae/vlc
/**
 * Return a direct buffer
 */
static picture_pool_t *Pool (vout_display_t *vd, unsigned requested_count)
{
    vout_display_sys_t *sys = vd->sys;
    (void)requested_count;

    if (sys->pool)
        return sys->pool;

    vout_display_place_t place;

    vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);

    /* */
    const uint32_t values[] = { place.x, place.y, place.width, place.height };
    xcb_configure_window (sys->conn, sys->window,
                          XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
                          XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
                          values);

    picture_t *pic = picture_NewFromFormat (&vd->fmt);
    if (!pic)
        return NULL;

    assert (pic->i_planes == 1);

    picture_resource_t res = {
       .p = {
           [0] = {
               .i_lines = pic->p->i_lines,
               .i_pitch = pic->p->i_pitch,
           },
       },
    };
    picture_Release (pic);

    unsigned count;
    picture_t *pic_array[MAX_PICTURES];
    const size_t size = res.p->i_pitch * res.p->i_lines;
    for (count = 0; count < MAX_PICTURES; count++)
    {
        xcb_shm_seg_t seg = (sys->seg_base != 0) ? (sys->seg_base + count) : 0;

        if (XCB_picture_Alloc (vd, &res, size, sys->conn, seg))
            break;
        pic_array[count] = XCB_picture_NewFromResource (&vd->fmt, &res);
        if (unlikely(pic_array[count] == NULL))
        {
            if (seg != 0)
                xcb_shm_detach (sys->conn, seg);
            break;
        }
    }
    xcb_flush (sys->conn);

    if (count == 0)
        return NULL;

    sys->pool = picture_pool_New (count, pic_array);
    if (unlikely(sys->pool == NULL))
        while (count > 0)
            picture_Release(pic_array[--count]);
    return sys->pool;
}
Exemplo n.º 12
0
int main(int argc, char *argv[])
{

	int screenNumber;
	xcb_connection_t *connection = xcb_connect (NULL, &screenNumber); // DISPLAY=NULL -> uses environment DISPLAY
	const xcb_setup_t *setup = xcb_get_setup(connection);
	xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
	for (int i = 0; i < screenNumber; i++)	xcb_screen_next(&iter);
	xcb_screen_t *screen = iter.data;
	xcb_window_t root = screen->root;

	xcb_drawable_t window;
	uint32_t mask;
	uint32_t value[2];

	xcb_generic_error_t *error;
	xcb_generic_event_t *event;


	// color maps
	// use existing screen's color map
	xcb_colormap_t currentColorMap = screen->default_colormap;
	uint16_t colorRed = 255;
	// uint16_t colorRed = 65535;
	uint16_t colorGreen = 0;
	uint16_t colorBlue = 0;
	xcb_alloc_color_cookie_t allocColorCookie = xcb_alloc_color(
													connection,
													currentColorMap,
													colorRed,
													colorGreen,
													colorBlue
	);
	xcb_alloc_color_reply_t *allocColorReply = xcb_alloc_color_reply(
													connection,
													allocColorCookie,
													&error
	);

	uint32_t pixel = allocColorReply->pixel;

	delete allocColorReply;

	// create a window
	window = xcb_generate_id(connection);	// ask for an ID like in OpenGL
	std::string windowTitle = "My first window";
	std::string windowTitleIconified = "My first window (iconified)";
	mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	value[0] = pixel;
	// value[0] = screen->white_pixel;
	value[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_KEY_RELEASE;
	xcb_create_window(connection,
					XCB_COPY_FROM_PARENT,				// depth same as parent window
					window,								// create a window using this ID
					screen->root,						// setting root as parent window
					100, 100,							// (x,y) offset from top left corner
					600, 600,							// window's width and height
					10,									// window's border
					XCB_WINDOW_CLASS_INPUT_OUTPUT,		// (uint16t) "_class" (TODO: check this out)
					screen->root_visual,				// (xcb_visualid_t) "visual" (TODO: check this out)
					mask,									// (uint32t) "value_mask" (TODO: check this out)
					value								// (const uint32_t) "*value_list" (TODO: check this out)
	);
	xcb_void_cookie_t changePropertyCookie = xcb_change_property_checked(
												connection,
												XCB_PROP_MODE_REPLACE,
												window,
												XCB_ATOM_WM_NAME,
												XCB_ATOM_STRING,
												8,
												windowTitle.size(),
												windowTitle.c_str()
	);
	if ((error = xcb_request_check(connection, changePropertyCookie))) {
		std::cerr << "ERROR: trying to change window's property" << std::endl;
		delete error;
	} else {
		std::cout << "changing window's property ....SUCCESS" << std::endl;
	}

	xcb_window_t window2 = xcb_generate_id(connection);	// ask for an ID like in OpenGL
	mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	value[0] = screen->white_pixel;
	value[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_KEY_RELEASE;
	xcb_create_window(connection,
					XCB_COPY_FROM_PARENT,				// depth same as parent window
					window2,								// create a window using this ID
					window,						// setting root as parent window
					10, 10,							// (x,y) offset from top left corner
					400, 400,							// window's width and height
					10,									// window's border
					XCB_WINDOW_CLASS_INPUT_OUTPUT,		// (uint16t) "_class" (TODO: check this out)
					screen->root_visual,				// (xcb_visualid_t) "visual" (TODO: check this out)
					mask,									// (uint32t) "value_mask" (TODO: check this out)
					value								// (const uint32_t) "*value_list" (TODO: check this out)
	);

	xcb_map_window(connection, window);
	xcb_map_window(connection, window2);
	xcb_flush(connection);

	bool escPressed = false;
	bool windowIsMapped = true;

	while (!escPressed) {
		if ( (event = xcb_poll_for_event(connection)) ) {
			// event is NULL if there is no event. if error occurs, erros will have an error status
			// std::cout << "before switch..." << std::endl;
			switch(event->response_type & ~0x80) {
				case XCB_EXPOSE:
					{
					xcb_expose_event_t *ev = (xcb_expose_event_t *) event;
					break;
					}
				case XCB_BUTTON_PRESS:
					{
					xcb_button_press_event_t *ev = (xcb_button_press_event_t *) event;
					break;
					}
				case XCB_KEY_RELEASE:
					{
					xcb_key_release_event_t *ev = (xcb_key_release_event_t *) event;
					break;
					}
				default:
					std::cout << "unknown event" <<std::endl;
					break;
			}
			delete event;
		}

		// std::cout << "after processing events..." << std::endl;
	}
	// std::cout << "after while true..." << std::endl;

	// pause();

	// shut down connection
	xcb_disconnect(connection);
	return 0;
}
Exemplo n.º 13
0
int main() {
	xcb_connection_t 	* conn;
	xcb_screen_t 		* scrn;
	xcb_drawable_t 		win;
	xcb_gcontext_t 		foreground;
	xcb_generic_event_t	* e;
	uint32_t			mask = 0;
	uint32_t			values[2];
	
	xcb_point_t points[] = { { 10, 10 },
							 { 10, 20 },
							 { 20, 10 },
							 { 20, 20 } };
	xcb_point_t polyline[] = { { 50, 10 },
							   {  5, 20 },
							   { 25,-20 },
							   { 10, 10 } };
	xcb_segment_t segments[] = { { 100, 10, 140, 30 },
								 { 110, 25, 130, 60 } };
	xcb_rectangle_t rectangles[] = { { 10, 50, 40, 30 },
								     { 80, 50, 10, 40 } };
	xcb_arc_t arcs[] = { { 10, 100, 60, 40, 0,  90 << 6 },
						 { 90, 100, 55, 40, 0, 270 << 6 } };
	
	//initialize the connection to X
	conn = xcb_connect(NULL, &scrnNum);
	
	//get the first screen data
	scrn = get_setup_roots_iterator(xcb_get_setup(conn)).data;
	
	foreground = xcb_generate_id(conn);
	mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
	values[0] = scrn->black_pixel;
	values[1] = 0;
	xcb_create_gc(conn, foreground, win, mask, values);
	
	//ask for the window's id
	win = xcb_generate_id(conn);
	
	//create the window
	mask = XCB_CW_BLACK_PIXEL | XCB_GC_GRAPHICS_EXPOSURES
	values[0] = scrn->white_pixel;
	values[1] = XCB_EVENT_MASK_EXPOSURE;
	xcb_create_window(conn,
					  XCB_COPY_FROM_PARENT,
					  win,
					  scrn->root,
					  0, 0,
					  150, 150,
					  10,
					  XCB_WINDOW_CLASS_INPUT_OUTPUT,
					  scrn->root_visual,
					  mask, values);
	
	//map the window
	xcb_map_window(conn, win);
	xcb_flush(conn);
	
	while (( e = xcb_wait_for_event(conn)) {
		switch (e->response_type & ~0x80) {
		case XCB_EXPOSE: {
			//draw things
			xcb_poly_point(conn, XCB_COORD_MODE_ORIGIN, win, foreground, 4, points);
			
			xcb_poly_line(conn, XCB_COORD_MODE_PREVIOUS, win, foreground, 4, polyline);
			
			xcb_poly_segment(conn, win, foreground, 2, segments);
			
			xcb_poly_rectangle(conn, win, foreground, 2 , rectangles);
			
			xcb_poly_arc(conn, win, foreground, 2, arcs);
			
			xcb_flush(conn);
			
			break;
		}
		default: {
			break;
		}
		}
		free(e);
	}
	return 0;
}
Exemplo n.º 14
0
int main(int argc, char *argv[])
{
	char opt;
	char *fifo_path = NULL;
	char *socket_path = NULL;
	status_fifo = NULL;
	config_path = NULL;
	mapping_count = 0;
	timeout = TIMEOUT;
	grabbed = false;
	sock_address.sun_family = AF_UNIX;
	sock_address.sun_path[0] = 0;
	snprintf(motion_msg_tpl, sizeof(motion_msg_tpl), "%s", MOTION_MSG_TPL);
	unsigned int max_freq = 0;
	motion_interval = 0;
	last_motion_time = 0;
	redir_fd = -1;

	while ((opt = getopt(argc, argv, "vhm:t:c:r:s:f:o:g:")) != (char)-1) {
		switch (opt) {
			case 'v':
				printf("%s\n", VERSION);
				exit(EXIT_SUCCESS);
				break;
			case 'h':
				printf("sxhkd [-h|-v|-m COUNT|-t TIMEOUT|-c CONFIG_FILE|-r REDIR_FILE|-s STATUS_FIFO|-o MOTION_SOCKET|-g MOTION_MSG_TPL] [EXTRA_CONFIG ...]\n");
				exit(EXIT_SUCCESS);
				break;
			case 'm':
				if (sscanf(optarg, "%i", &mapping_count) != 1)
					warn("Can't parse mapping count.\n");
				break;
			case 't':
				timeout = atoi(optarg);
				break;
			case 'c':
				config_path = optarg;
				break;
			case 'r':
				redir_fd = open(optarg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
				if (redir_fd == -1)
					warn("Failed to open the command redirection file.\n");
				break;
			case 's':
				fifo_path = optarg;
				break;
			case 'o':
				socket_path = optarg;
				break;
			case 'g':
				snprintf(motion_msg_tpl, sizeof(motion_msg_tpl), "%s", optarg);
				break;
			case 'f':
				if (sscanf(optarg, "%u", &max_freq) != 1)
					warn("Can't parse maximum pointer frequency.\n");
				break;
		}
	}

	num_extra_confs = argc - optind;
	extra_confs = argv + optind;

	if (config_path == NULL) {
		char *config_home = getenv(CONFIG_HOME_ENV);
		if (config_home != NULL)
			snprintf(config_file, sizeof(config_file), "%s/%s", config_home, CONFIG_PATH);
		else
			snprintf(config_file, sizeof(config_file), "%s/%s/%s", getenv("HOME"), ".config", CONFIG_PATH);
	} else {
		snprintf(config_file, sizeof(config_file), "%s", config_path);
	}

	if (socket_path == NULL) {
		socket_path = getenv(SOCKET_ENV);
	}

	if (socket_path == NULL) {
		char *host = NULL;
		int dn = 0, sn = 0;
		if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
			snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), SOCKET_PATH_TPL, host, dn, sn);
		} else {
			warn("Failed to set motion socket address.");
		}
		free(host);
	} else {
		snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", socket_path);
	}

	if (fifo_path != NULL) {
		int fifo_fd = open(fifo_path, O_RDWR | O_NONBLOCK);
		if (fifo_fd != -1)
			status_fifo = fdopen(fifo_fd, "w");
		else
			warn("Couldn't open status fifo.\n");
	}

	if (max_freq != 0)
		motion_interval = 1000.0 / max_freq;

	signal(SIGINT, hold);
	signal(SIGHUP, hold);
	signal(SIGTERM, hold);
	signal(SIGUSR1, hold);
	signal(SIGUSR2, hold);
	signal(SIGALRM, hold);

	setup();
	get_standard_keysyms();
	get_lock_fields();
	escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false);
	load_config(config_file);
	for (int i = 0; i < num_extra_confs; i++)
		load_config(extra_confs[i]);
	grab();

	xcb_generic_event_t *evt;
	int fd = xcb_get_file_descriptor(dpy);

	fd_set descriptors;

	reload = toggle_grab = bell = chained = locked = false;
	running = true;

	xcb_flush(dpy);

	while (running) {
		FD_ZERO(&descriptors);
		FD_SET(fd, &descriptors);

		if (select(fd + 1, &descriptors, NULL, NULL, NULL) > 0) {
			while ((evt = xcb_poll_for_event(dpy)) != NULL) {
				uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(evt);
				switch (event_type) {
					case XCB_KEY_PRESS:
					case XCB_KEY_RELEASE:
					case XCB_BUTTON_PRESS:
					case XCB_BUTTON_RELEASE:
						key_button_event(evt, event_type);
						break;
					case XCB_MOTION_NOTIFY:
						motion_notify(evt);
						break;
					case XCB_MAPPING_NOTIFY:
						mapping_notify(evt);
						break;
					default:
						PRINTF("received event %u\n", event_type);
						break;
				}
				free(evt);
			}
		}

		if (reload) {
			signal(SIGUSR1, hold);
			reload_cmd();
			reload = false;
		}

		if (toggle_grab) {
			signal(SIGUSR2, hold);
			toggle_grab_cmd();
			toggle_grab = false;
		}

		if (bell) {
			signal(SIGALRM, hold);
			abort_chain();
			if (status_fifo != NULL)
				put_status(TIMEOUT_PREFIX, "Timeout reached");
			bell = false;
		}

		if (xcb_connection_has_error(dpy)) {
			warn("The server closed the connection.\n");
			running = false;
		}
	}

	if (redir_fd != -1)
		close(redir_fd);
	if (status_fifo != NULL)
		fclose(status_fifo);
	ungrab();
	cleanup();
	destroy_chord(escape_chord);
	xcb_key_symbols_free(symbols);
	xcb_disconnect(dpy);
	return EXIT_SUCCESS;
}
Exemplo n.º 15
0
void
xpost_view_main_loop(const Xpost_View_Window *win)
{
    xcb_intern_atom_cookie_t cookie1;
    xcb_intern_atom_cookie_t cookie2;
    xcb_intern_atom_reply_t* reply1;
    xcb_intern_atom_reply_t* reply2;
    int finished;

    /*
     * Listen to X client messages in order to be able to pickup
     * the "delete window" message that is generated for example
     * when someone clicks the top-right X button within the window
     * manager decoration (or when user hits ALT-F4).
     */
    cookie1 = xcb_intern_atom(win->c, 1,
                              sizeof("WM_DELETE_WINDOW") - 1, "WM_DELETE_WINDOW");
    cookie2 = xcb_intern_atom(win->c, 1,
                              sizeof("WM_PROTOCOLS") - 1, "WM_PROTOCOLS");
    reply1 = xcb_intern_atom_reply(win->c, cookie1, 0);
    reply2 = xcb_intern_atom_reply(win->c, cookie2, 0);
    xcb_change_property(win->c, XCB_PROP_MODE_REPLACE, win->window, reply2->atom, 4, 32, 1,
                        &reply1->atom);

    finished = 0;
    while (!finished)
    {
        xcb_generic_event_t *e;

        if ((e = xcb_poll_for_event(win->c)))
        {
            switch (XCB_EVENT_RESPONSE_TYPE(e))
            {
                case XCB_EXPOSE:
                    xcb_image_put(win->c, win->window, win->gc, win->image, 0, 0, 0);
                    xcb_flush(win->c);
                    break;
                case XCB_CLIENT_MESSAGE:
                {
                    xcb_client_message_event_t *event;

                    printf("client message\n");
                    event = (xcb_client_message_event_t *)e;
                    if (event->data.data32[0] == reply1->atom)
                        finished = 1;
                    break;
                }
                case XCB_BUTTON_PRESS:
                    printf("button pressed\n");
                    finished = 1;
                    break;
                case XCB_KEY_RELEASE:
                {
                    xcb_key_release_event_t *event;

                    event = (xcb_key_release_event_t *)e;
                    if (event->detail == 113)
                        xpost_view_page_change(-1);
                    if (event->detail == 114)
                        xpost_view_page_change(1);
                    break;
                }
            }
            free (e);
        }

        xcb_flush (win->c);
    }

    free(reply2);
    free(reply1);
}
Exemplo n.º 16
0
void *
run_event_loop(void *thread_arg_struct)
{
    _connection_data *conn_data;
    xcwm_context_t *context;
    xcb_connection_t *event_conn;
    xcb_generic_event_t *evt;
    xcwm_event_t return_evt;
    xcwm_event_cb_t callback_ptr;

    conn_data = thread_arg_struct;
    context = conn_data->context;
    event_conn = context->conn;
    callback_ptr = conn_data->callback;

    free(thread_arg_struct);

    _xcwm_windows_adopt(context, callback_ptr);

    /* Start the event loop, and flush if first */
    xcb_flush(event_conn);

    while ((evt = xcb_wait_for_event(event_conn))) {
        uint8_t response_type = evt->response_type  & ~0x80;
        if (response_type == context->damage_event_mask) {
            xcb_damage_notify_event_t *dmgevnt =
                (xcb_damage_notify_event_t *)evt;

            /* printf("damage %d,%d @ %d,%d reported against window 0x%08x\n", */
            /*        dmgevnt->area.width, dmgevnt->area.height, dmgevnt->area.x, dmgevnt->area.y, */
            /*        dmgevnt->drawable); */

            xcwm_window_t *window = _xcwm_get_window_node_by_window_id(dmgevnt->drawable);

            return_evt.event_type = XCWM_EVENT_WINDOW_DAMAGE;
            return_evt.window = window;

            if (!window) {
                printf("damage reported against unknown window 0x%08x\n", dmgevnt->drawable);
                continue;
            }

            /* Increase the damaged area of window if new damage is
             * larger than current. */
            xcwm_event_get_thread_lock();

            /* Initial damage events for override-redirect windows are
             * reported relative to the root window, subsequent events
             * are relative to the window itself. We also catch cases
             * where the damage area is larger than the bounds of the
             * window. */
            if (window->initial_damage == 1
                || (dmgevnt->area.width > window->bounds.width)
                || (dmgevnt->area.height > window->bounds.height) ) {
                xcb_xfixes_region_t region =
                    xcb_generate_id(window->context->conn);
                xcb_rectangle_t rect;

                /* printf("initial damage on window 0x%08x\n", dmgevnt->drawable); */

                /* Remove the damage */
                xcb_xfixes_create_region(window->context->conn,
                                         region,
                                         1,
                                         &dmgevnt->area);
                xcb_damage_subtract(window->context->conn,
                                    window->damage,
                                    region,
                                    XCB_NONE);

                /* Add new damage area for entire window */
                rect.x = 0;
                rect.y = 0;
                rect.width = window->bounds.width;
                rect.height = window->bounds.height;
                xcb_xfixes_set_region(window->context->conn,
                                      region,
                                      1,
                                      &rect);
                xcb_damage_add(window->context->conn,
                               window->window_id,
                               region);

                window->initial_damage = 0;
                xcb_xfixes_destroy_region(window->context->conn,
                                          region);
                xcwm_event_release_thread_lock();
                continue;
            }

            window->dmg_bounds.x = dmgevnt->area.x;
            window->dmg_bounds.y = dmgevnt->area.y;
            window->dmg_bounds.width = dmgevnt->area.width;
            window->dmg_bounds.height = dmgevnt->area.height;

            xcwm_event_release_thread_lock();

            callback_ptr(&return_evt);

        }
        else if (response_type == context->shape_event) {
            xcb_shape_notify_event_t *shapeevnt =
                (xcb_shape_notify_event_t *)evt;

            if (shapeevnt->shape_kind == XCB_SHAPE_SK_BOUNDING) {
                xcwm_window_t *window = _xcwm_get_window_node_by_window_id(shapeevnt->affected_window);
                _xcwm_window_set_shape(window, shapeevnt->shaped);

                return_evt.event_type = XCWM_EVENT_WINDOW_SHAPE;
                return_evt.window = window;
                callback_ptr(&return_evt);
            }
        }
        else if (response_type == context->fixes_event_base + XCB_XFIXES_CURSOR_NOTIFY) {
            /* xcb_xfixes_cursor_notify_event_t *cursorevnt = */
            /*     (xcb_xfixes_cursor_notify_event_t *)evt; */

            return_evt.event_type = XCWM_EVENT_CURSOR;
            return_evt.window = NULL;
            callback_ptr(&return_evt);
        }
        else {
            switch (response_type) {
            case 0:
            {
                /* Error case. Something very bad has happened. Spit
                 * out some hopefully useful information and then
                 * die.
                 * FIXME: Decide under what circumstances we should
                 * acutally kill the application. */
                xcb_generic_error_t *err = (xcb_generic_error_t *)evt;
                fprintf(stderr, "Error received in event loop.\n"
                        "Error code: %i\n",
                        err->error_code);
                if ((err->error_code >= XCB_VALUE)
                    && (err->error_code <= XCB_FONT)) {
                    xcb_value_error_t *val_err = (xcb_value_error_t *)evt;
                    fprintf(stderr, "Bad value: %i\n"
                            "Major opcode: %i\n"
                            "Minor opcode: %i\n",
                            val_err->bad_value,
                            val_err->major_opcode,
                            val_err->minor_opcode);
                }
                break;
            }

            case XCB_EXPOSE:
            {
                xcb_expose_event_t *exevnt = (xcb_expose_event_t *)evt;

                printf(
                    "Window %u exposed. Region to be redrawn at location (%d, %d), ",
                    exevnt->window, exevnt->x, exevnt->y);
                printf("with dimensions (%d, %d).\n", exevnt->width,
                       exevnt->height);

                return_evt.event_type = XCWM_EVENT_WINDOW_EXPOSE;
                callback_ptr(&return_evt);
                break;
            }

            case XCB_CREATE_NOTIFY:
            {
                /* We don't actually allow our client to create its
                 * window here, wait until the XCB_MAP_REQUEST */
                break;
            }

            case XCB_DESTROY_NOTIFY:
            {
                // Window destroyed in root window
                xcb_destroy_notify_event_t *notify =
                    (xcb_destroy_notify_event_t *)evt;
                xcwm_window_t *window =
                    _xcwm_window_remove(event_conn, notify->window);

                if (!window) {
                    /* Not a window in the list, don't try and destroy */
                    break;
                }

                return_evt.event_type = XCWM_EVENT_WINDOW_DESTROY;
                return_evt.window = window;

                callback_ptr(&return_evt);

                // Release memory for the window
                _xcwm_window_release(window);
                break;
            }

            case XCB_MAP_NOTIFY:
            {
                xcb_map_notify_event_t *notify =
                    (xcb_map_notify_event_t *)evt;

                /* notify->event holds parent of the window */

                xcwm_window_t *window =
                    _xcwm_get_window_node_by_window_id(notify->window);
                if (!window)
                {
                    /*
                      No MAP_REQUEST for override-redirect windows, so
                      need to create the xcwm_window_t for it now
                    */
                    /* printf("MAP_NOTIFY without MAP_REQUEST\n"); */
                    window =
                        _xcwm_window_create(context, notify->window,
                                            notify->event);

                    if (window)
                    {
                        _xcwm_window_composite_pixmap_update(window);

                        return_evt.window = window;
                        return_evt.event_type = XCWM_EVENT_WINDOW_CREATE;
                        callback_ptr(&return_evt);
                    }
                }
                else
                {
                    _xcwm_window_composite_pixmap_update(window);
                }

                break;
            }

            case XCB_MAP_REQUEST:
            {
                xcb_map_request_event_t *request =
                    (xcb_map_request_event_t *)evt;

                /* Map the window */
                xcb_map_window(context->conn, request->window);
                xcb_flush(context->conn);

                return_evt.window =
                    _xcwm_window_create(context, request->window,
                                        request->parent);
                if (!return_evt.window) {
                    break;
                }

                return_evt.event_type = XCWM_EVENT_WINDOW_CREATE;
                callback_ptr(&return_evt);
                break;
            }

            case XCB_UNMAP_NOTIFY:
            {
                xcb_unmap_notify_event_t *notify =
                    (xcb_unmap_notify_event_t *)evt;

                xcwm_window_t *window =
                    _xcwm_window_remove(event_conn, notify->window);

                if (!window) {
                    /* Not a window in the list, don't try and destroy */
                    break;
                }

                return_evt.event_type = XCWM_EVENT_WINDOW_DESTROY;
                return_evt.window = window;

                callback_ptr(&return_evt);

                _xcwm_window_composite_pixmap_release(window);

                // Release memory for the window
                _xcwm_window_release(window);
                break;
            }

            case XCB_CONFIGURE_NOTIFY:
            {
                xcb_configure_notify_event_t *request =
                    (xcb_configure_notify_event_t *)evt;

                printf("CONFIGURE_NOTIFY: XID 0x%08x %dx%d @ %d,%d\n",
                       request->window, request->width, request->height,
                       request->x, request->y);

                xcwm_window_t *window =
                    _xcwm_get_window_node_by_window_id(request->window);
                if (window)
                    _xcwm_window_composite_pixmap_update(window);
                break;
            }

            case XCB_CONFIGURE_REQUEST:
            {
                xcb_configure_request_event_t *request =
                    (xcb_configure_request_event_t *)evt;

                printf("CONFIGURE_REQUEST: XID 0x%08x %dx%d @ %d,%d mask 0x%04x\n",
                       request->window, request->width, request->height,
                       request->x, request->y, request->value_mask);

                /*
                   relying on the server's idea of the current values of values not
                   in value_mask is a bad idea, we might have a configure request of
                   our own on this window in flight
                */
                if (request->value_mask &
                    (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT))
                    _xcwm_resize_window(event_conn, request->window,
                                        request->x, request->y,
                                        request->width, request->height);

                /* Ignore requests to change stacking ? */

                break;
            }

            case XCB_PROPERTY_NOTIFY:
            {
                xcb_property_notify_event_t *notify =
                    (xcb_property_notify_event_t *)evt;
                xcwm_window_t *window =
                    _xcwm_get_window_node_by_window_id(notify->window);
                if (!window) {
                    break;
                }

                /* If this is WM_PROTOCOLS, do not send event, just
                 * handle internally */
                if (notify->atom == window->context->atoms.ewmh_conn.WM_PROTOCOLS) {
                    _xcwm_atoms_set_wm_delete(window);
                    break;
                }

                xcwm_event_type_t event;
                if (_xcwm_atom_change_to_event(notify->atom, window, &event))
                {
                    /* Send the appropriate event */
                    return_evt.event_type = event;
                    return_evt.window = window;
                    callback_ptr(&return_evt);
                }
                else {
                    printf("PROPERTY_NOTIFY for ignored property atom %d\n", notify->atom);
                    /*
                      We need a mechanism to forward properties we don't know about to WM,
                      otherwise everything needs to be in libXcwm ...?
                    */
                }

                break;
            }

            case XCB_MAPPING_NOTIFY:
                break;

            default:
            {
                printf("UNKNOWN EVENT: %i\n", (evt->response_type & ~0x80));
                break;
            }
            }
        }
        /* Free the event */
        free(evt);
    }
    return NULL;
}
Exemplo n.º 17
0
Xpost_View_Window *
xpost_view_win_new(int xorig, int yorig, int width, int height)
{
    xcb_screen_iterator_t iter;
    xcb_rectangle_t rect;
    xcb_get_geometry_reply_t *geom;
    Xpost_View_Window *win;
    int scrno;
    unsigned int values[3];
    unsigned int mask;

    win = (Xpost_View_Window *)calloc(1, sizeof(Xpost_View_Window));
    if (!win)
        return NULL;

    win->width = width;
    win->height = height;

    /* open a connection */
    win->c = xcb_connect(NULL, &scrno);
    if (xcb_connection_has_error(win->c))
    {
        fprintf(stderr, "Fail to connect to the X server\n");
        goto free_win;
    }

    /* get the screen */
    iter = xcb_setup_roots_iterator(xcb_get_setup(win->c));
    for (; iter.rem; --scrno, xcb_screen_next(&iter))
    {
        if (scrno == 0)
        {
            win->scr = iter.data;
            break;
        }
    }

    /* get the depth of the screen */
    geom = xcb_get_geometry_reply(win->c,
                                  xcb_get_geometry(win->c, win->scr->root), 0);
    if (!geom)
    {
        fprintf(stderr, "Fail to the geometry of the root window\n");
        goto disconnect_c;
    }

    win->depth = geom->depth;
    free(geom);

    /* create the window */
    win->window = xcb_generate_id(win->c);
    mask = XCB_CW_BACK_PIXMAP | XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    values[0] = XCB_NONE;
    values[1] = win->scr->white_pixel;
    values[2] = XCB_EVENT_MASK_EXPOSURE |
                XCB_EVENT_MASK_BUTTON_PRESS |
                XCB_EVENT_MASK_KEY_RELEASE;
    xcb_create_window(win->c, XCB_COPY_FROM_PARENT,
                      win->window, win->scr->root,
                      xorig, yorig,
                      width, height,
                      5,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                      win->scr->root_visual,
                      mask,
                      values);

    /* set title of the window */
    xcb_change_property(win->c,
                        XCB_PROP_MODE_REPLACE,
                        win->window,
                        XCB_ATOM_WM_NAME,
                        XCB_ATOM_STRING,
                        8,
                        sizeof("Xpost viewer") - 1,
                        "Xpost viewer");

    /* set background context */
    win->gc = xcb_generate_id(win->c);
    values[0] = win->scr->white_pixel;
    values[1] = 0;
    xcb_create_gc(win->c, win->gc, win->window,
                  XCB_GC_BACKGROUND | XCB_GC_GRAPHICS_EXPOSURES,
                  values);

    /* set background pixmap */
    rect.x = 0;
    rect.y = 0;
    rect.width = width;
    rect.height = height;
    win->pixmap = xcb_generate_id(win->c);
    xcb_create_pixmap(win->c,
                      win->depth, win->pixmap,
                      win->window, width, height);
    xcb_poly_fill_rectangle(win->c, win->pixmap, win->gc, 1, &rect);

    xcb_map_window(win->c, win->window);
    xcb_flush(win->c);

    return win;

  disconnect_c:
    xcb_disconnect(win->c);
  free_win:
    free(win);

    return NULL;
}
Exemplo n.º 18
0
static int
weston_wm_read_data_source(int fd, uint32_t mask, void *data)
{
	struct weston_wm *wm = data;
	int len, current, available;
	void *p;

	current = wm->source_data.size;
	if (wm->source_data.size < incr_chunk_size)
		p = wl_array_add(&wm->source_data, incr_chunk_size);
	else
		p = (char *) wm->source_data.data + wm->source_data.size;
	available = wm->source_data.alloc - current;

	len = read(fd, p, available);
	if (len == -1) {
		weston_log("read error from data source: %m\n");
		weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
		wl_event_source_remove(wm->property_source);
		close(fd);
		wl_array_release(&wm->source_data);
	}

	weston_log("read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
		len, available, mask, len, (char *) p);

	wm->source_data.size = current + len;
	if (wm->source_data.size >= incr_chunk_size) {
		if (!wm->incr) {
			weston_log("got %zu bytes, starting incr\n",
				wm->source_data.size);
			wm->incr = 1;
			xcb_change_property(wm->conn,
					    XCB_PROP_MODE_REPLACE,
					    wm->selection_request.requestor,
					    wm->selection_request.property,
					    wm->atom.incr,
					    32, /* format */
					    1, &incr_chunk_size);
			wm->selection_property_set = 1;
			wm->flush_property_on_delete = 1;
			wl_event_source_remove(wm->property_source);
			weston_wm_send_selection_notify(wm, wm->selection_request.property);
		} else if (wm->selection_property_set) {
			weston_log("got %zu bytes, waiting for "
				"property delete\n", wm->source_data.size);

			wm->flush_property_on_delete = 1;
			wl_event_source_remove(wm->property_source);
		} else {
			weston_log("got %zu bytes, "
				"property deleted, seting new property\n",
				wm->source_data.size);
			weston_wm_flush_source_data(wm);
		}
	} else if (len == 0 && !wm->incr) {
		weston_log("non-incr transfer complete\n");
		/* Non-incr transfer all done. */
		weston_wm_flush_source_data(wm);
		weston_wm_send_selection_notify(wm, wm->selection_request.property);
		xcb_flush(wm->conn);
		wl_event_source_remove(wm->property_source);
		close(fd);
		wl_array_release(&wm->source_data);
		wm->selection_request.requestor = XCB_NONE;
	} else if (len == 0 && wm->incr) {
		weston_log("incr transfer complete\n");

		wm->flush_property_on_delete = 1;
		if (wm->selection_property_set) {
			weston_log("got %zu bytes, waiting for "
				"property delete\n", wm->source_data.size);
		} else {
			weston_log("got %zu bytes, "
				"property deleted, seting new property\n",
				wm->source_data.size);
			weston_wm_flush_source_data(wm);
		}
		xcb_flush(wm->conn);
		wl_event_source_remove(wm->property_source);
		close(wm->data_source_fd);
		wm->data_source_fd = -1;
		close(fd);
	} else {
		weston_log("nothing happened, buffered the bytes\n");
	}

	return 1;
}
Exemplo n.º 19
0
xcb_window_t Select_Window(xcb_connection_t *dpy,
			   const xcb_screen_t *screen,
			   int descend)
{
    xcb_cursor_t cursor;
    xcb_generic_event_t *event;
    xcb_window_t target_win = XCB_WINDOW_NONE;
    xcb_window_t root = screen->root;
    int buttons = 0;
    xcb_generic_error_t *err;
    xcb_grab_pointer_cookie_t grab_cookie;
    xcb_grab_pointer_reply_t *grab_reply;

    /* Make the target cursor */
    cursor = Create_Font_Cursor (dpy, XC_crosshair);

    /* Grab the pointer using target cursor, letting it room all over */
    grab_cookie = xcb_grab_pointer
	(dpy, False, root,
	 XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
	 XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
	 root, cursor, XCB_TIME_CURRENT_TIME);
    grab_reply = xcb_grab_pointer_reply (dpy, grab_cookie, &err);
    if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS)
	Fatal_Error ("Can't grab the mouse.");

    /* Let the user select a window... */
    while ((target_win == XCB_WINDOW_NONE) || (buttons != 0)) {
	/* allow one more event */
	xcb_allow_events (dpy, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME);
	xcb_flush (dpy);
	event = xcb_wait_for_event (dpy);
	switch (event->response_type & 0x7f) {
	case XCB_BUTTON_PRESS:
	{
	    xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event;

	    if (target_win == XCB_WINDOW_NONE) {
		target_win = bp->child; /* window selected */
		if (target_win == XCB_WINDOW_NONE)
		    target_win = root;
	    }
	    buttons++;
	    break;
	}
	case XCB_BUTTON_RELEASE:
	    if (buttons > 0) /* there may have been some down before we started */
		buttons--;
	    break;
	default:
	    /* just discard all other events */
	    break;
	}
	free (event);
    }

    xcb_ungrab_pointer (dpy, XCB_TIME_CURRENT_TIME); /* Done with pointer */

    if (!descend || (target_win == root))
	return (target_win);

    target_win = Find_Client (dpy, root, target_win);

    return (target_win);
}
Exemplo n.º 20
0
void init_tabletwm() {

	memset(&key_win, 0, sizeof(key_win));
	memset(&shutdown_win, 0, sizeof(shutdown_win));
	xcb_void_cookie_t void_cookie;
	xcb_intern_atom_cookie_t atom_cookie[TWM_ATOM_LAST_VALUE];
	uint32_t v[] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_PROPERTY_CHANGE};
	int i;

	char *a_atoms[TWM_ATOM_LAST_VALUE] = {
		"WM_SIZE_HINTS",
		"WM_NORMAL_HINTS",
		"WM_PROTOCOLS",
		"WM_DELETE_WINDOW",
		"WM_TRANSIENT_FOR",
		"_NET_SUPPORTING_WM_CHECK",
		"_NET_WM_NAME",
		"_NET_SUPPORTED",

		"_NET_WM_WINDOW_TYPE",
		"_NET_WM_WINDOW_TYPE_DESKTOP",
		"_NET_WM_WINDOW_TYPE_DOCK",
		"_NET_WM_WINDOW_TYPE_TOOLBAR",
		"_NET_WM_WINDOW_TYPE_MENU",
		"_NET_WM_WINDOW_TYPE_UTILITY",
		"_NET_WM_WINDOW_TYPE_SPLASH",
		"_NET_WM_WINDOW_TYPE_DIALOG",
		"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
		"_NET_WM_WINDOW_TYPE_POPUP_MENU",
		"_NET_WM_WINDOW_TYPE_TOOLTIP",
		"_NET_WM_WINDOW_TYPE_NOTIFICATION",
		"_NET_WM_WINDOW_TYPE_COMBO",
		"_NET_WM_WINDOW_TYPE_DND",
		"_NET_WM_WINDOW_TYPE_NORMAL",

		"_NET_WM_ALLOWED_ACTIONS",
		"_NET_WM_ACTION_MOVE",
		"_NET_WM_ACTION_RESIZE",
		"_NET_WM_ACTION_MINIMIZE",
		"_NET_WM_ACTION_SHADE",
		"_NET_WM_ACTION_STICK",
		"_NET_WM_ACTION_MAXIMIZE_HORZ",
		"_NET_WM_ACTION_MAXIMIZE_VERT",
		"_NET_WM_ACTION_FULLSCREEN",
		"_NET_WM_ACTION_CHANGE_DESKTOP",
		"_NET_WM_ACTION_CLOSE",
		"_NET_WM_ACTION_ABOVE",
		"_NET_WM_ACTION_BELOW",

		"WM_CLASS",
		"WM_STATE",
		"_NET_ACTIVE_WINDOW",
		"WM_HINTS",
		"_XKB_RULES_NAMES",
	};

	init_load_config();

	wincache_init();

	conn = xcb_connect(0, 0);
	assert(conn);

	scr = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
	width = scr->width_in_pixels;
	height = scr->height_in_pixels; // reserve the bottom part for the 1pixel-height, collapsed menu bar

	xcb_change_window_attributes(conn, scr->root, XCB_CW_EVENT_MASK, v);

	xcb_depth_iterator_t depth_iter;
	xcb_visualid_t root_visual = { 0 };
	visual_type = NULL;

	for (depth_iter = xcb_screen_allowed_depths_iterator (scr); depth_iter.rem; xcb_depth_next (&depth_iter)) {
		xcb_visualtype_iterator_t visual_iter;

		visual_iter = xcb_depth_visuals_iterator (depth_iter.data);
		for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
			if (scr->root_visual == visual_iter.data->visual_id) {
				visual_type = visual_iter.data;
				break;
			}
		}
	}

	/* get atoms */
	for(i=0; i < TWM_ATOM_LAST_VALUE; i++) {
		atom_cookie[i] = xcb_intern_atom_unchecked(conn, 0, strlen(a_atoms[i]), a_atoms[i]);
	};

	xcb_flush(conn);

	xcb_intern_atom_reply_t *atom_reply;
	for(i=0; i < TWM_ATOM_LAST_VALUE; i++) {
		atom_reply = xcb_intern_atom_reply(conn, atom_cookie[i], 0),
		atoms[i] = atom_reply->atom;
		free(atom_reply);
	};

	xcb_change_property(conn, XCB_PROP_MODE_REPLACE, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM_WM_DELETE_WINDOW]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DESKTOP]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DOCK]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_TOOLBAR]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_MENU]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED] , XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_UTILITY]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_SPLASH]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DIALOG]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DROPDOWN_MENU]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_POPUP_MENU]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_TOOLTIP]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_NOTIFICATION]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_COMBO]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DND]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_NORMAL]);

	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ALLOWED_ACTIONS]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_MOVE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_RESIZE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_MINIMIZE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_SHADE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_STICK]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_MAXIMIZE_HORZ]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_MAXIMIZE_VERT]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_FULLSCREEN]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_CHANGE_DESKTOP]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_CLOSE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_ABOVE]);
	xcb_change_property(conn, XCB_PROP_MODE_APPEND, scr->root, atoms[TWM_ATOM__NET_SUPPORTED], XCB_ATOM_ATOM, 32, 1, &atoms[TWM_ATOM__NET_WM_ACTION_BELOW]);

	// This window contains the menu and the virtual keyboard (when showed)
	// It is also used to ensure that the window manager is recognized as an Extended Window Manager Hints WM
	// By default it occupies one pixel at the bottom of the screen, to allow to detect when the mouse is moved to the bottom

	xcb_get_property_cookie_t kbd_info_cookie;
	xcb_get_property_reply_t *kbd_info;
	kbd_info_cookie = xcb_get_property(conn, 0, scr->root, atoms[TWM__XKB_RULES_NAMES], XCB_ATOM_STRING, 0, 1024);

	key_win.window = xcb_generate_id(conn);
	uint32_t values[1] = {XCB_EVENT_MASK_EXPOSURE|XCB_EVENT_MASK_BUTTON_RELEASE|XCB_EVENT_MASK_BUTTON_PRESS|XCB_EVENT_MASK_ENTER_WINDOW|XCB_EVENT_MASK_LEAVE_WINDOW};
	void_cookie=xcb_create_window_checked (conn, XCB_COPY_FROM_PARENT, key_win.window, scr->root, 0, height-1, width, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, scr->root_visual, XCB_CW_EVENT_MASK, values);

	xcb_flush(conn);

	kbd_info = xcb_get_property_reply(conn, kbd_info_cookie, 0);
	if (kbd_info!=NULL) {
		if (kbd_info->length>0) {
			char *p=((char *)(xcb_get_property_value(kbd_info)));
			int counter=0;
			int len, max;
			max=xcb_get_property_value_length(kbd_info);
			char *end=p+max;
			do {
				len = strnlen(p, max);
				if (*p!=0) {
					xkb_names[counter++] = strdup(p);
				}
				p+=len+1;
				max-=len+1;
			} while ((p < end) && (counter < 5));
		}
		free(kbd_info);
	}

	if (xcb_request_check(conn, void_cookie)) {
		printf("Can't create the fake window\n");
	} else {
		menuwin_init();
	}
	shutdown_init();
}
Exemplo n.º 21
0
void track_pointer(coordinates_t loc, pointer_action_t pac, xcb_point_t pos)
{
	node_t *n = loc.node;
	resize_handle_t rh = get_handle(loc.node, pos, pac);

	uint16_t last_motion_x = pos.x, last_motion_y = pos.y;
	xcb_timestamp_t last_motion_time = 0;

	xcb_generic_event_t *evt = NULL;

	grabbing = true;
	grabbed_node = n;

	do {
		free(evt);
		while ((evt = xcb_wait_for_event(dpy)) == NULL) {
			xcb_flush(dpy);
		}
		uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
		if (resp_type == XCB_MOTION_NOTIFY) {
			xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t*) evt;
			uint32_t dtime = e->time - last_motion_time;
			if (dtime < pointer_motion_interval) {
				continue;
			}
			last_motion_time = e->time;
			int16_t dx = e->root_x - last_motion_x;
			int16_t dy = e->root_y - last_motion_y;
			if (pac == ACTION_MOVE) {
				move_client(&loc, dx, dy);
			} else {
				resize_client(&loc, rh, e->root_x, e->root_y, false);
			}
			last_motion_x = e->root_x;
			last_motion_y = e->root_y;
			xcb_flush(dpy);
		} else if (resp_type == XCB_BUTTON_RELEASE) {
			grabbing = false;
		} else {
			handle_event(evt);
		}
	} while (grabbing && grabbed_node != NULL);
	free(evt);

	xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME);

	if (grabbed_node == NULL) {
		grabbing = false;
		return;
	}

	if (pac == ACTION_MOVE) {
		put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X move end\n", loc.monitor->id, loc.desktop->id, n->id);
	} else if (pac == ACTION_RESIZE_CORNER) {
		put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X resize_corner end\n", loc.monitor->id, loc.desktop->id, n->id);
	} else if (pac == ACTION_RESIZE_SIDE) {
		put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X resize_side end\n", loc.monitor->id, loc.desktop->id, n->id);
	}

	xcb_rectangle_t r = get_rectangle(NULL, NULL, n);

	put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, loc.node->id, r.width, r.height, r.x, r.y);

	if ((pac == ACTION_MOVE && IS_TILED(n->client)) ||
	    ((pac == ACTION_RESIZE_CORNER || pac == ACTION_RESIZE_SIDE) &&
	     n->client->state == STATE_TILED)) {
		for (node_t *f = first_extrema(loc.desktop->root); f != NULL; f = next_leaf(f, loc.desktop->root)) {
			if (f == n || f->client == NULL || !IS_TILED(f->client)) {
				continue;
			}
			xcb_rectangle_t r = f->client->tiled_rectangle;
			put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, f->id, r.width, r.height, r.x, r.y);
		}
	}
}
Exemplo n.º 22
0
void map_client(client_t *client)
{
    xcb_map_window(wm_conf.connection, client->window);
    /* the map won't happen immediately unless we flush the connection */
    xcb_flush(wm_conf.connection);
}
Exemplo n.º 23
0
int main(void)
{
	xcb_connection_t    *c;
	xcb_screen_t        *s;
	xcb_window_t         w;
	xcb_gcontext_t       g;
	xcb_generic_event_t *e;
	uint32_t             mask;
	uint32_t             values[4];
  int done =0 ;

	signal(SIGSEGV, handler);
	/* open connection with the server */
	c = xcb_connect(NULL,NULL);
	if (xcb_connection_has_error(c)) {
		printf("Cannot open display\n");
		exit(1);
	}

	/* get the first screen */
	s = xcb_setup_roots_iterator( xcb_get_setup(c) ).data;

  xcb_get_geometry_reply_t *geo;

  
  /* create sub window */
  w= xcb_generate_id(c);
	mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	values[0] = s->black_pixel;
	values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
  xcb_void_cookie_t cookie;

  int width =640;
  int height =480;
	mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	values[0] = s->white_pixel;
	values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS
    | XCB_EVENT_MASK_VISIBILITY_CHANGE    
    ;
	values[1] = 0xffff;
	xcb_create_window(c, s->root_depth, w, s->root,
      10, 10, width, height,
      1,
			XCB_WINDOW_CLASS_INPUT_OUTPUT, s->root_visual,
			mask, values);

  xcb_map_window(c, w); xcb_flush(c);

//  xcb_reparent_window(c, child,  G.s->root,100,100);

  values[1] |= XCB_EVENT_MASK_POINTER_MOTION |
     XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE;
  xcb_change_window_attributes_checked(c, w, mask, values); xcb_flush(c);

	G.conn = c;
	G.s = s;
  create_dri_drawable();

  printf("wait event\n");
  while (!done ) {
		//printf("\re=>(x%x)", e->response_type); fflush(stdout);
    e = xcb_wait_for_event(c);
    if(!e) { printf("wait event error\n");
    	break;}
    else{
      switch (e->response_type & ~0x80) {
        case XCB_EXPOSE:    /* draw or redraw the window */
          printf("XCB_EXPOSE\n");
   //     draw_gc(w);
          break;
        case XCB_KEY_PRESS:  /* exit on key press */
          printf("KEY\n");
        	struct xcb_key_press_event_t  *ep = e;
        	printf("key=%d\n", (char)ep->detail);
        	if(ep->detail == 9)
        		exit(1);
					draw_gc(w);
          //gwj done = 1;
          break;
			case XCB_MOTION_NOTIFY:
				{
          printf("XCB_MOTION\n");
					}
          break;
			default:
          printf("default e=%d\n",e->response_type);
					break;
      }
      free(e);
    }
  }
  xcb_unmap_window(c, w);
  xcb_destroy_window(c, w);
  return 0;
}
Exemplo n.º 24
0
int main(int argc, char **argv)
{
    xcb_connection_t *connection = xcb_connect(NULL, &wm_conf.default_screen_num);
    if (xcb_connection_has_error(connection)) {
        fprintf(stderr, "failed to open display\n");
        exit(1);
    }

    init_wm_conf();
    init_conf_dir();
    wm_conf.connection = connection;

    const xcb_setup_t *setup = xcb_get_setup(connection);
    int num_screens = xcb_setup_roots_length(setup);
    fprintf(stderr, "init: num_screens = %d\n", num_screens);
    fprintf(stderr, "init: default_screen_num = %d\n", wm_conf.default_screen_num);

    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
    wm_conf.screen = screen;
    xcb_window_t root_window = screen->root;

    xcb_grab_server(connection);
    xcb_flush(connection);

    xcb_event_handlers_t *event_handlers = &wm_conf.event_handlers;
    xcb_event_handlers_init(connection, event_handlers);
    set_exclusive_error_handler(event_handlers, handle_startup_error);
    /* Try to get substructure redirect events from root window.
     * This will cause an error if a window manager is already running.
     */
    const uint32_t sub_redirect = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
    xcb_change_window_attributes(connection,
                                 root_window,
                                 XCB_CW_EVENT_MASK,
                                 &sub_redirect);

    /* Need to xcb_flush to validate error handler */
    xcb_aux_sync(connection);

    /* Process all errors in the queue if any */
    xcb_event_poll_for_event_loop(event_handlers);

    scan_windows();

    xinerama_test();

    set_exclusive_error_handler(event_handlers, handle_error);
    set_event_handlers(event_handlers);

    /* Allocate the key symbols */
    wm_conf.key_syms = xcb_key_symbols_alloc(connection);

    fprintf(stderr, "selecting events from root window\n");
    const uint32_t root_win_event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
        XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
        XCB_EVENT_MASK_ENTER_WINDOW |
        XCB_EVENT_MASK_LEAVE_WINDOW |
        XCB_EVENT_MASK_STRUCTURE_NOTIFY |
        XCB_EVENT_MASK_PROPERTY_CHANGE |
        XCB_EVENT_MASK_BUTTON_PRESS |
        XCB_EVENT_MASK_BUTTON_RELEASE |
        XCB_EVENT_MASK_FOCUS_CHANGE;
    xcb_change_window_attributes(connection, root_window, XCB_CW_EVENT_MASK, &root_win_event_mask);

    xcb_ungrab_server(connection);
    xcb_flush(connection);

    wm_conf.repl_server = repl_server_init();
    load_init_scheme();

    fprintf(stderr, "entering event loop\n");
    event_loop();

    xcb_disconnect(connection);

    return 0;
}
Exemplo n.º 25
0
static void input_done(void) {
    STOP_TIMER(clear_pam_wrong_timeout);
    pam_state = STATE_PAM_VERIFY;
    redraw_screen();

    if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
        DEBUG("successfully authenticated\n");
        clear_password_memory();

        /* PAM credentials should be refreshed, this will for example update any kerberos tickets.
         * Related to credentials pam_end() needs to be called to cleanup any temporary
         * credentials like kerberos /tmp/krb5cc_pam_* files which may of been left behind if the
         * refresh of the credentials failed. */
        pam_setcred(pam_handle, PAM_REFRESH_CRED);
        pam_end(pam_handle, PAM_SUCCESS);

        exit(0);
    }

    if (debug_mode)
        fprintf(stderr, "Authentication failure\n");

    /* Get state of Caps and Num lock modifiers, to be displayed in
     * STATE_PAM_WRONG state */
    xkb_mod_index_t idx, num_mods;
    const char *mod_name;

    num_mods = xkb_keymap_num_mods(xkb_keymap);

    for (idx = 0; idx < num_mods; idx++) {
        if (!xkb_state_mod_index_is_active(xkb_state, idx, XKB_STATE_MODS_EFFECTIVE))
            continue;

        mod_name = xkb_keymap_mod_get_name(xkb_keymap, idx);
        if (mod_name == NULL)
            continue;

        /* Replace certain xkb names with nicer, human-readable ones. */
        if (strcmp(mod_name, XKB_MOD_NAME_CAPS) == 0)
            mod_name = "Caps Lock";
        else if (strcmp(mod_name, XKB_MOD_NAME_ALT) == 0)
            mod_name = "Alt";
        else if (strcmp(mod_name, XKB_MOD_NAME_NUM) == 0)
            mod_name = "Num Lock";
        else if (strcmp(mod_name, XKB_MOD_NAME_LOGO) == 0)
            mod_name = "Win";

        char *tmp;
        if (modifier_string == NULL) {
            if (asprintf(&tmp, "%s", mod_name) != -1)
                modifier_string = tmp;
        } else if (asprintf(&tmp, "%s, %s", modifier_string, mod_name) != -1) {
            free(modifier_string);
            modifier_string = tmp;
        }
    }

    pam_state = STATE_PAM_WRONG;
    failed_attempts += 1;
    clear_input();
    if (unlock_indicator)
        redraw_screen();

    /* Skip all the events during the pam verification to avoid bad people
     * spamming keys and locking pam in an endless validation loop */
    xcb_generic_event_t *ev = xcb_poll_for_event(conn);
    free(ev);
    while (ev != NULL)
    {
        ev = xcb_poll_for_queued_event(conn);
        free(ev);
    }

    /* Clear this state after 2 seconds (unless the user enters another
     * password during that time). */
    ev_now_update(main_loop);
    START_TIMER(clear_pam_wrong_timeout, TSTAMP_N_SECS(2), clear_pam_wrong);

    /* Cancel the clear_indicator_timeout, it would hide the unlock indicator
     * too early. */
    STOP_TIMER(clear_indicator_timeout);

    /* beep on authentication failure, if enabled */
    if (beep) {
        xcb_bell(conn, 100);
        xcb_flush(conn);
    }
}
Exemplo n.º 26
0
static void
_e_alert_display(void)
{
   xcb_char2b_t *str = NULL;
   xcb_query_text_extents_cookie_t cookie;
   xcb_query_text_extents_reply_t *reply;
   int x = 0, w = 0;

   tainted = _e_alert_root_tainted_get();

   str = _e_alert_build_string(title);

   cookie =
     xcb_query_text_extents_unchecked(conn, font, strlen(title), str);
   reply = xcb_query_text_extents_reply(conn, cookie, NULL);
   if (reply)
     {
        fa = reply->font_ascent;
        fh = (fa + reply->font_descent);
        fw = reply->overall_width;
        free(reply);
     }
   free(str);

   /* move buttons */
   x = 20;
   w = (WINDOW_WIDTH / 2) - 40;
   _e_alert_button_move_resize(btn1, x, WINDOW_HEIGHT - 20 - (fh + 20),
                               w, (fh + 20));

   x = ((WINDOW_WIDTH / 2) + 20);
   _e_alert_button_move_resize(btn2, x, WINDOW_HEIGHT - 20 - (fh + 20),
                               w, (fh + 20));

   comp_win = _e_alert_comp_win_get();
   if (comp_win)
     {
        xcb_rectangle_t rect;
        int wx = 0, wy = 0;

        wx = ((sw - WINDOW_WIDTH) / 2);
        wy = ((sh - WINDOW_HEIGHT) / 2);

        rect.x = wx;
        rect.y = wy;
        rect.width = WINDOW_WIDTH;
        rect.height = WINDOW_HEIGHT;

        xcb_shape_rectangles(conn, XCB_SHAPE_SO_SET,
                             XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
                             comp_win, 0, 0, 1, &rect);

        xcb_reparent_window(conn, win, comp_win, wx, wy);
     }

   /* map and raise main window */
   xcb_map_window(conn, win);
   _e_alert_window_raise(win);

   /* grab pointer & keyboard */
   xcb_grab_pointer_unchecked(conn, 0, win,
                              (XCB_EVENT_MASK_BUTTON_PRESS |
                               XCB_EVENT_MASK_BUTTON_RELEASE),
                              XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
                              XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
   xcb_grab_keyboard_unchecked(conn, 0, win, XCB_CURRENT_TIME,
                               XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
   xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
                       win, XCB_CURRENT_TIME);

   /* flush screen */
   xcb_flush(conn);

   /* sync */
   _e_alert_sync();
}
Exemplo n.º 27
0
/**
 * Create an X11 window.
 */
static int Open (vout_window_t *wnd, const vout_window_cfg_t *cfg)
{
    xcb_generic_error_t *err;
    xcb_void_cookie_t ck;

    vout_window_sys_t *p_sys = malloc (sizeof (*p_sys));
    if (p_sys == NULL)
        return VLC_ENOMEM;
    p_sys->embedded = false;

    /* Connect to X */
    char *display = var_InheritString (wnd, "x11-display");
    int snum;

    xcb_connection_t *conn = xcb_connect (display, &snum);
    if (xcb_connection_has_error (conn) /*== NULL*/)
        goto error;

    /* Find configured screen */
    const xcb_setup_t *setup = xcb_get_setup (conn);
    const xcb_screen_t *scr = NULL;
    for (xcb_screen_iterator_t i = xcb_setup_roots_iterator (setup);
         i.rem > 0; xcb_screen_next (&i))
    {
        if (snum == 0)
        {
            scr = i.data;
            break;
        }
        snum--;
    }
    if (scr == NULL)
    {
        msg_Err (wnd, "bad X11 screen number");
        goto error;
    }

    /* Create window */
    const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    uint32_t values[2] = {
        /* XCB_CW_BACK_PIXEL */
        scr->black_pixel,
        /* XCB_CW_EVENT_MASK */
        XCB_EVENT_MASK_KEY_PRESS,
    };

    xcb_window_t window = xcb_generate_id (conn);
    ck = xcb_create_window_checked (conn, scr->root_depth, window, scr->root,
                                    cfg->x, cfg->y, cfg->width, cfg->height, 0,
                                    XCB_WINDOW_CLASS_INPUT_OUTPUT,
                                    scr->root_visual, mask, values);
    err = xcb_request_check (conn, ck);
    if (err)
    {
        msg_Err (wnd, "creating window: X11 error %d", err->error_code);
        free (err);
        goto error;
    }

    wnd->handle.xid = window;
    wnd->display.x11 = display;
    wnd->control = Control;
    wnd->sys = p_sys;

    p_sys->conn = conn;
    if (var_InheritBool (wnd, "keyboard-events"))
        p_sys->keys = CreateKeyHandler (VLC_OBJECT(wnd), conn);
    else
        p_sys->keys = NULL;
    p_sys->root = scr->root;

    /* ICCCM
     * No cut&paste nor drag&drop, only Window Manager communication. */
    set_ascii_prop (conn, window, XA_WM_NAME,
    /* xgettext: This is a plain ASCII spelling of "VLC media player"
       for the ICCCM window name. This must be pure ASCII.
       The limitation is partially with ICCCM and partially with VLC.
       For Latin script languages, you may need to strip accents.
       For other scripts, you will need to transliterate into Latin. */
                    vlc_pgettext ("ASCII", "VLC media player"));

    set_ascii_prop (conn, window, XA_WM_ICON_NAME,
    /* xgettext: This is a plain ASCII spelling of "VLC"
       for the ICCCM window name. This must be pure ASCII. */
                    vlc_pgettext ("ASCII", "VLC"));
    set_wm_hints (conn, window);
    xcb_change_property (conn, XCB_PROP_MODE_REPLACE, window, XA_WM_CLASS,
                         XA_STRING, 8, 8, "vlc\0Vlc");
    set_hostname_prop (conn, window);

    /* EWMH */
    xcb_intern_atom_cookie_t utf8_string_ck
        = intern_string (conn, "UTF8_STRING");;
    xcb_intern_atom_cookie_t net_wm_name_ck
        = intern_string (conn, "_NET_WM_NAME");
    xcb_intern_atom_cookie_t net_wm_icon_name_ck
        = intern_string (conn, "_NET_WM_ICON_NAME");
    xcb_intern_atom_cookie_t wm_window_role_ck
        = intern_string (conn, "WM_WINDOW_ROLE");

    xcb_atom_t utf8 = get_atom (conn, utf8_string_ck);

    xcb_atom_t net_wm_name = get_atom (conn, net_wm_name_ck);
    char *title = var_InheritString (wnd, "video-title");
    if (title)
    {
        set_string (conn, window, utf8, net_wm_name, title);
        free (title);
    }
    else
        set_string (conn, window, utf8, net_wm_name, _("VLC media player"));

    xcb_atom_t net_wm_icon_name = get_atom (conn, net_wm_icon_name_ck);
    set_string (conn, window, utf8, net_wm_icon_name, _("VLC"));

    xcb_atom_t wm_window_role = get_atom (conn, wm_window_role_ck);
    set_ascii_prop (conn, window, wm_window_role, "vlc-video");

    /* Cache any EWMH atom we may need later */
    CacheAtoms (p_sys);

    /* Make the window visible */
    xcb_map_window (conn, window);

    if (var_InheritBool (wnd, "video-wallpaper"))
    {
        vout_window_SetState (wnd, VOUT_WINDOW_STATE_BELOW);
        vout_window_SetFullScreen (wnd, true);
    }

    /* Create the event thread. It will dequeue all events, so any checked
     * request from this thread must be completed at this point. */
    if ((p_sys->keys != NULL)
     && vlc_clone (&p_sys->thread, Thread, wnd, VLC_THREAD_PRIORITY_LOW))
        DestroyKeyHandler (p_sys->keys);

    xcb_flush (conn); /* Make sure map_window is sent (should be useless) */
    return VLC_SUCCESS;

error:
    xcb_disconnect (conn);
    free (display);
    free (p_sys);
    return VLC_EGENERIC;
}
Exemplo n.º 28
0
ZLEwlViewWidget::ZLEwlViewWidget(ZLApplication *application, ZLView::Angle initialAngle) : ZLViewWidget(initialAngle) {
	myApplication = application;
	w = 600;
	h = 800;

	xcb_screen_iterator_t screen_iter;
	const xcb_setup_t    *setup;
	xcb_generic_event_t  *e;
	xcb_generic_error_t  *error;
	xcb_void_cookie_t     cookie_window;
	xcb_void_cookie_t     cookie_map;
	uint32_t              mask;
	uint32_t              values[2];
	int                   screen_number;
	uint8_t               is_hand = 0;
	xcb_rectangle_t     rect_coord = { 0, 0, 600, 800};

	/* getting the connection */
	connection = xcb_connect (NULL, &screen_number);
	if (xcb_connection_has_error(connection)) {
		fprintf (stderr, "ERROR: can't connect to an X server\n");
		exit(-1);
	}

	screen = xcb_aux_get_screen (connection, screen_number);

	gc = xcb_generate_id (connection);
	mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
	values[0] = screen->black_pixel;
	values[1] = 0; /* no graphics exposures */
	xcb_create_gc (connection, gc, screen->root, mask, values);

	bgcolor = xcb_generate_id (connection);
	mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
	values[0] = screen->white_pixel;
	values[1] = 0; /* no graphics exposures */
	xcb_create_gc (connection, bgcolor, screen->root, mask, values);

	/* creating the window */
	window = xcb_generate_id(connection);
	mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	values[0] = screen->white_pixel;
	values[1] =
		XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
		XCB_EVENT_MASK_BUTTON_PRESS |
		XCB_EVENT_MASK_EXPOSURE |
		XCB_EVENT_MASK_POINTER_MOTION |
		XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
		XCB_EVENT_MASK_FOCUS_CHANGE      | XCB_EVENT_MASK_PROPERTY_CHANGE;

	uint8_t depth = xcb_aux_get_depth (connection, screen);
	xcb_create_window(connection,
			depth,
			window, screen->root,
			0, 0, 600, 800,
			0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
			screen->root_visual,
			mask, values);

	rect = xcb_generate_id (connection);
	xcb_create_pixmap (connection, depth,
			rect, window,
			600, 800);

	xcb_map_window(connection, window);

	xcb_colormap_t    colormap;
	colormap = screen->default_colormap;

	xcb_alloc_color_reply_t *rep;
	rep = xcb_alloc_color_reply (connection, xcb_alloc_color (connection, colormap, 0, 0, 0), NULL);
	pal_[0] = rep->pixel;
	free(rep);
	rep = xcb_alloc_color_reply (connection, xcb_alloc_color (connection, colormap, 0x55<<8, 0x55<<8, 0x55<<8), NULL);
	pal_[1] = rep->pixel;
	free(rep);
	rep = xcb_alloc_color_reply (connection, xcb_alloc_color (connection, colormap, 0xaa<<8, 0xaa<<8, 0xaa<<8), NULL);
	pal_[2] = rep->pixel;
	free(rep);
	rep = xcb_alloc_color_reply (connection, xcb_alloc_color (connection, colormap, 0xff<<8, 0xff<<8, 0xff<<8), NULL);
	pal_[3] = rep->pixel;
	free(rep);

	pal = pal_;

	xcb_shm_query_version_reply_t *rep_shm;

	rep_shm = xcb_shm_query_version_reply (connection,
			xcb_shm_query_version (connection),
			NULL);
	if(rep_shm) {
		xcb_image_format_t format;
		int shmctl_status;

		if (rep_shm->shared_pixmaps &&
				(rep_shm->major_version > 1 || rep_shm->minor_version > 0))
			format = (xcb_image_format_t)rep_shm->pixmap_format;
		else
			format = (xcb_image_format_t)0;

		im = xcb_image_create_native (connection, 600, 800,
				format, depth, NULL, ~0, NULL);
		assert(im);

		shminfo.shmid = shmget (IPC_PRIVATE,
				im->stride*im->height,
				IPC_CREAT | 0777);
		assert(shminfo.shmid != -1);
		shminfo.shmaddr = (uint8_t*)shmat (shminfo.shmid, 0, 0);
		assert(shminfo.shmaddr);
		im->data = shminfo.shmaddr;

		shminfo.shmseg = xcb_generate_id (connection);
		xcb_shm_attach (connection, shminfo.shmseg,
				shminfo.shmid, 0);
		shmctl_status = shmctl(shminfo.shmid, IPC_RMID, 0);
		assert(shmctl_status != -1);
		free (rep_shm);
	}

	xcb_flush(connection);
}
Exemplo n.º 29
0
void VulkanExampleBase::renderLoop()
{
	destWidth = width;
	destHeight = height;
#if defined(_WIN32)
	MSG msg;
	while (TRUE)
	{
		auto tStart = std::chrono::high_resolution_clock::now();
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				break;
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		render();
		frameCounter++;
		auto tEnd = std::chrono::high_resolution_clock::now();
		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
		frameTimer = (float)tDiff / 1000.0f;
		// Convert to clamped timer value
		if (!paused)
		{
			timer += timerSpeed * frameTimer;
			if (timer > 1.0)
			{
				timer -= 1.0f;
			}
		}
		fpsTimer += (float)tDiff;
		if (fpsTimer > 1000.0f)
		{
			std::string windowTitle = getWindowTitle();
			SetWindowText(window, windowTitle.c_str());
			lastFPS = frameCounter;
			fpsTimer = 0.0f;
			frameCounter = 0.0f;
		}
	}
#elif defined(__ANDROID__)
	while (1)
	{
		int ident;
		int events;
		struct android_poll_source* source;
		bool destroy = false;

		focused = true;

		while ((ident = ALooper_pollAll(focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
		{
			if (source != NULL)
			{
				source->process(androidApp, source);
			}
			if (androidApp->destroyRequested != 0)
			{
				LOGD("Android app destroy requested");
				destroy = true;
				break;
			}
		}

		// App destruction requested
		// Exit loop, example will be destroyed in application main
		if (destroy)
		{
			break;
		}

		// Render frame
		if (prepared)
		{
			auto tStart = std::chrono::high_resolution_clock::now();
			render();
			frameCounter++;
			auto tEnd = std::chrono::high_resolution_clock::now();
			auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
			frameTimer = tDiff / 1000.0f;
			// Convert to clamped timer value
			if (!paused)
			{
				timer += timerSpeed * frameTimer;
				if (timer > 1.0)
				{
					timer -= 1.0f;
				}
			}
			fpsTimer += (float)tDiff;
			if (fpsTimer > 1000.0f)
			{
				LOGD("%d fps", frameCounter);
				lastFPS = frameCounter;
				fpsTimer = 0.0f;
				frameCounter = 0.0f;
			}
			// Check gamepad state
			const float deadZone = 0.0015f;
			// todo : check if gamepad is present
			// todo : time based and relative axis positions
			bool updateView = false;
			// Rotate
			if (std::abs(gamePadState.axes.x - deadZone) > 0.0f)
			{
				rotation.y += gamePadState.axes.x * 0.5f * rotationSpeed;
				updateView = true;
			}
			if (std::abs(gamePadState.axes.y - deadZone) > 0.0f)
			{
				rotation.x -= gamePadState.axes.y * 0.5f * rotationSpeed;
				updateView = true;
			}
			// Zoom
			if (std::abs(gamePadState.axes.rz - deadZone) > 0.0f)
			{
				zoom -= gamePadState.axes.rz * 0.01f * zoomSpeed;
				updateView = true;
			}
			if (updateView)
			{
				viewChanged();
			}


		}
	}
#elif defined(__linux__)
	xcb_flush(connection);
	while (!quit)
	{
		auto tStart = std::chrono::high_resolution_clock::now();
		xcb_generic_event_t *event;
		event = xcb_poll_for_event(connection);
		if (event)
		{
			handleEvent(event);
			free(event);
		}
		render();
		frameCounter++;
		auto tEnd = std::chrono::high_resolution_clock::now();
		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
		frameTimer = tDiff / 1000.0f;
		// Convert to clamped timer value
		if (!paused)
		{
			timer += timerSpeed * frameTimer;
			if (timer > 1.0)
			{
				timer -= 1.0f;
			}
		}
		fpsTimer += (float)tDiff;
		if (fpsTimer > 1000.0f)
		{
			std::string windowTitle = getWindowTitle();
			xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
				window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
				windowTitle.size(), windowTitle.c_str());
			lastFPS = frameCounter;
			fpsTimer = 0.0f;
			frameCounter = 0.0f;
		}
	}
#endif
}
Exemplo n.º 30
0
Arquivo: main.c Projeto: stfnm/i3
static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
    printf("Keypress %d, state raw = %d\n", event->detail, event->state);

    /* Remove the numlock bit, all other bits are modifiers we can bind to */
    uint16_t state_filtered = event->state & ~(xcb_numlock_mask | XCB_MOD_MASK_LOCK);
    /* Only use the lower 8 bits of the state (modifier masks) so that mouse
     * button masks are filtered out */
    state_filtered &= 0xFF;

    xcb_keysym_t sym = xcb_key_press_lookup_keysym(symbols, event, state_filtered);

    printf("sym = %c (%d)\n", sym, sym);

    if (sym == XK_Return || sym == XK_KP_Enter) {
        if (current_step == STEP_WELCOME) {
            current_step = STEP_GENERATE;
            /* Set window title */
            xcb_change_property(conn,
                XCB_PROP_MODE_REPLACE,
                win,
                A__NET_WM_NAME,
                A_UTF8_STRING,
                8,
                strlen("i3: generate config"),
                "i3: generate config");
            xcb_flush(conn);
        }
        else finish();
    }

    /* cancel any time */
    if (sym == XK_Escape)
        exit(0);

    /* Check if this is Mod1 or Mod4. The modmap contains Shift, Lock, Control,
     * Mod1, Mod2, Mod3, Mod4, Mod5 (in that order) */
    xcb_keycode_t *modmap = xcb_get_modifier_mapping_keycodes(modmap_reply);
    /* Mod1? */
    int mask = 3;
    for (int i = 0; i < modmap_reply->keycodes_per_modifier; i++) {
        xcb_keycode_t code = modmap[(mask * modmap_reply->keycodes_per_modifier) + i];
        if (code == XCB_NONE)
            continue;
        printf("Modifier keycode for Mod1: 0x%02x\n", code);
        if (code == event->detail) {
            modifier = MOD_Mod1;
            printf("This is Mod1!\n");
        }
    }

    /* Mod4? */
    mask = 6;
    for (int i = 0; i < modmap_reply->keycodes_per_modifier; i++) {
        xcb_keycode_t code = modmap[(mask * modmap_reply->keycodes_per_modifier) + i];
        if (code == XCB_NONE)
            continue;
        printf("Modifier keycode for Mod4: 0x%02x\n", code);
        if (code == event->detail) {
            modifier = MOD_Mod4;
            printf("This is Mod4!\n");
        }
    }

    handle_expose();
    return 1;
}