/** * Probes and initializes. */ static int Open (vlc_object_t *obj) { services_discovery_t *sd = (services_discovery_t *)obj; services_discovery_sys_t *p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) return VLC_ENOMEM; sd->p_sys = p_sys; sd->description = _("Screen capture"); /* Connect to X server */ char *display = var_InheritString (obj, "x11-display"); int snum; xcb_connection_t *conn = xcb_connect (display, &snum); free (display); if (xcb_connection_has_error (conn)) { free (p_sys); return VLC_EGENERIC; } p_sys->conn = conn; /* 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 (obj, "bad X11 screen number"); goto error; } /* Add a permanent item for the entire desktop */ AddDesktop (sd); p_sys->root_window = scr->root; xcb_change_window_attributes (conn, scr->root, XCB_CW_EVENT_MASK, &(uint32_t) { XCB_EVENT_MASK_PROPERTY_CHANGE }); /* TODO: check that _NET_CLIENT_LIST is in _NET_SUPPORTED * (and _NET_SUPPORTING_WM_CHECK) */ xcb_intern_atom_reply_t *r; xcb_intern_atom_cookie_t ncl, nwn; ncl = xcb_intern_atom (conn, 1, strlen ("_NET_CLIENT_LIST"), "_NET_CLIENT_LIST"); nwn = xcb_intern_atom (conn, 0, strlen ("_NET_WM_NAME"), "_NET_WM_NAME"); r = xcb_intern_atom_reply (conn, ncl, NULL); if (r == NULL || r->atom == 0) { vlc_dialog_display_error (sd, _("Screen capture"), _("Your window manager does not provide a list of applications.")); msg_Err (sd, "client list not supported (_NET_CLIENT_LIST absent)"); } p_sys->net_client_list = r ? r->atom : 0; free (r); r = xcb_intern_atom_reply (conn, nwn, NULL); if (r != NULL) { p_sys->net_wm_name = r->atom; free (r); } p_sys->apps = NULL; p_sys->apps_root = input_item_NewExt("vlc://nop", _("Applications"), -1, ITEM_TYPE_NODE, ITEM_LOCAL); if (likely(p_sys->apps_root != NULL)) services_discovery_AddItem(sd, p_sys->apps_root); UpdateApps (sd); if (vlc_clone (&p_sys->thread, Run, sd, VLC_THREAD_PRIORITY_LOW)) goto error; return VLC_SUCCESS; error: xcb_disconnect (p_sys->conn); tdestroy (p_sys->apps, DelApp); if (p_sys->apps_root != NULL) input_item_Release(p_sys->apps_root); free (p_sys); return VLC_EGENERIC; }
int randr_start(randr_state_t *state) { xcb_generic_error_t *error; int screen_num = state->screen_num; if (screen_num < 0) screen_num = state->preferred_screen; /* Get screen */ const xcb_setup_t *setup = xcb_get_setup(state->conn); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); state->screen = NULL; for (int i = 0; iter.rem > 0; i++) { if (i == screen_num) { state->screen = iter.data; break; } xcb_screen_next(&iter); } if (state->screen == NULL) { fprintf(stderr, _("Screen %i could not be found.\n"), screen_num); return -1; } /* Get list of CRTCs for the screen */ xcb_randr_get_screen_resources_current_cookie_t res_cookie = xcb_randr_get_screen_resources_current(state->conn, state->screen->root); xcb_randr_get_screen_resources_current_reply_t *res_reply = xcb_randr_get_screen_resources_current_reply(state->conn, res_cookie, &error); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get Screen Resources Current", error->error_code); return -1; } state->crtc_count = res_reply->num_crtcs; state->crtcs = calloc(state->crtc_count, sizeof(randr_crtc_state_t)); if (state->crtcs == NULL) { perror("malloc"); state->crtc_count = 0; return -1; } xcb_randr_crtc_t *crtcs = xcb_randr_get_screen_resources_current_crtcs(res_reply); /* Save CRTC identifier in state */ for (int i = 0; i < state->crtc_count; i++) { state->crtcs[i].crtc = crtcs[i]; } free(res_reply); /* Save size and gamma ramps of all CRTCs. Current gamma ramps are saved so we can restore them at program exit. */ for (int i = 0; i < state->crtc_count; i++) { xcb_randr_crtc_t crtc = state->crtcs[i].crtc; /* Request size of gamma ramps */ xcb_randr_get_crtc_gamma_size_cookie_t gamma_size_cookie = xcb_randr_get_crtc_gamma_size(state->conn, crtc); xcb_randr_get_crtc_gamma_size_reply_t *gamma_size_reply = xcb_randr_get_crtc_gamma_size_reply(state->conn, gamma_size_cookie, &error); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get CRTC Gamma Size", error->error_code); return -1; } unsigned int ramp_size = gamma_size_reply->size; state->crtcs[i].ramp_size = ramp_size; free(gamma_size_reply); if (ramp_size == 0) { fprintf(stderr, _("Gamma ramp size too small: %i\n"), ramp_size); return -1; } /* Request current gamma ramps */ xcb_randr_get_crtc_gamma_cookie_t gamma_get_cookie = xcb_randr_get_crtc_gamma(state->conn, crtc); xcb_randr_get_crtc_gamma_reply_t *gamma_get_reply = xcb_randr_get_crtc_gamma_reply(state->conn, gamma_get_cookie, &error); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get CRTC Gamma", error->error_code); return -1; } uint16_t *gamma_r = xcb_randr_get_crtc_gamma_red(gamma_get_reply); uint16_t *gamma_g = xcb_randr_get_crtc_gamma_green(gamma_get_reply); uint16_t *gamma_b = xcb_randr_get_crtc_gamma_blue(gamma_get_reply); /* Allocate space for saved gamma ramps */ state->crtcs[i].saved_ramps = malloc(3*ramp_size*sizeof(uint16_t)); if (state->crtcs[i].saved_ramps == NULL) { perror("malloc"); free(gamma_get_reply); return -1; } /* Copy gamma ramps into CRTC state */ memcpy(&state->crtcs[i].saved_ramps[0*ramp_size], gamma_r, ramp_size*sizeof(uint16_t)); memcpy(&state->crtcs[i].saved_ramps[1*ramp_size], gamma_g, ramp_size*sizeof(uint16_t)); memcpy(&state->crtcs[i].saved_ramps[2*ramp_size], gamma_b, ramp_size*sizeof(uint16_t)); free(gamma_get_reply); } return 0; }
static void init_xcb() { const xcb_query_extension_reply_t *qer; const xcb_setup_t *setup; xcb_screen_t *screen; xcb_screen_iterator_t screen_iter; xcb_drawable_t win; guint num_screens; guint i; xcb_generic_error_t *err = NULL; /* Open xcb connection */ conn = xcb_connect(gdk_get_display_arg_name(), NULL); if (xcb_connection_has_error(conn)) { g_error("Failed to connect to display\n"); exit(EXIT_FAILURE); } /* query the version to prevent error 16 when setting config */ xcb_randr_query_version_unchecked(conn, 1, 5); qer = xcb_get_extension_data(conn, &xcb_randr_id); if (!qer || !qer->present) { g_error("RandR extension missing\n"); exit(EXIT_FAILURE); } randr_base = qer->first_event; xcb_source = g_xcb_source_new_for_connection(NULL, conn); g_xcb_source_set_event_callback(xcb_source, on_xcb_event, NULL); /* get the screens */ setup = xcb_get_setup(conn); screen_iter = xcb_setup_roots_iterator(setup); num_screens = setup->roots_len; /* Set up space for cookies */ xcb_randr_get_screen_info_cookie_t get_screen_info_cookies[num_screens]; for (i = 0; i < num_screens; i++) { /* Get root window */ screen = screen_iter.data; win = screen->root; /* Register for screen change events */ xcb_randr_select_input(conn, win, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); /* Get screen info */ get_screen_info_cookies[i] = xcb_randr_get_screen_info_unchecked(conn, win); xcb_screen_next(&screen_iter); } /* TODO: detect adding and removal of screens */ xcb_flush(conn); /* Get screen info replies */ for (i = 0; i < num_screens; i++) { xcb_randr_get_screen_info_reply_t *reply = xcb_randr_get_screen_info_reply(conn, get_screen_info_cookies[i], &err); if (err) { g_warning("Error getting info for screen %u\n", i); err = NULL; continue; } add_screen(reply); free(reply); } xcb_flush(conn); }
/* Get the number of outputs */ static unsigned CountMonitors( vlc_object_t *obj ) { char *psz_display = var_InheritString( obj, "x11-display" ); int snum; xcb_connection_t *conn = xcb_connect( psz_display, &snum ); free( psz_display ); if( xcb_connection_has_error( conn ) ) return 0; const xcb_setup_t *setup = xcb_get_setup( conn ); 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--; } unsigned n = 0; if( scr == NULL ) goto error; xcb_randr_query_version_reply_t *v = xcb_randr_query_version_reply( conn, xcb_randr_query_version( conn, 1, 2 ), NULL ); if( v == NULL ) goto error; msg_Dbg( obj, "using X RandR extension v%"PRIu32".%"PRIu32, v->major_version, v->minor_version ); free( v ); xcb_randr_get_screen_resources_reply_t *r = xcb_randr_get_screen_resources_reply( conn, xcb_randr_get_screen_resources( conn, scr->root ), NULL ); if( r == NULL ) goto error; const xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs( r ); for( unsigned i = 0; i < r->num_outputs; i++ ) { xcb_randr_get_output_info_reply_t *output = xcb_randr_get_output_info_reply( conn, xcb_randr_get_output_info( conn, outputs[i], 0 ), NULL ); if( output == NULL ) continue; /* FIXME: do not count cloned outputs multiple times */ /* XXX: what to do with UNKNOWN state connections? */ n += output->connection == XCB_RANDR_CONNECTION_CONNECTED; free( output ); } free( r ); msg_Dbg( obj, "X randr has %u outputs", n ); error: xcb_disconnect( conn ); return n; }
int main(int argc, char *argv[]) { int i; char *displayname = NULL; Bool all_screens = False; Bool verbose = False; xcb_connection_t *dpy; const xcb_setup_t *setup; int screen_number = 0; int maxcmdlen = 10000; ProgramName = argv[0]; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (arg[0] == '-') { char *cp; switch (arg[1]) { case 'd': /* -display dpyname */ if (++i >= argc) usage (); displayname = argv[i]; continue; case 'm': /* -max maxcmdlen */ if (++i >= argc) usage (); maxcmdlen = atoi (argv[i]); continue; case 'v': /* -version */ printf("%s\n", PACKAGE_STRING); exit(0); } for (cp = &arg[1]; *cp; cp++) { switch (*cp) { case 'a': /* -all */ all_screens = True; continue; case 'l': /* -long */ verbose = True; continue; default: usage (); } } } else { usage (); } } dpy = xcb_connect(displayname, &screen_number); if (xcb_connection_has_error(dpy)) { const char *name = displayname; if (!name) name = getenv("DISPLAY"); if (!name) name = ""; fprintf (stderr, "%s: unable to open display \"%s\"\r\n", ProgramName, name); exit (1); } init_atoms(dpy); setup = xcb_get_setup(dpy); if (all_screens) { xcb_screen_iterator_t screen; screen = xcb_setup_roots_iterator(setup); do { lookat(dpy, screen.data->root, verbose, maxcmdlen); xcb_screen_next(&screen); } while (screen.rem); } else { xcb_screen_iterator_t screen; screen = xcb_setup_roots_iterator(setup); for (i = 0; i < screen_number; i++) xcb_screen_next(&screen); lookat (dpy, screen.data->root, verbose, maxcmdlen); } run_queue(); xcb_disconnect(dpy); exit (0); }