Beispiel #1
0
    std::vector<std::shared_ptr<monitor_t>> get_list(xcb_connection_t *connection, xcb_window_t root)
    {
      std::vector<std::shared_ptr<monitor_t>> monitors;

      xcb_randr_get_screen_resources_reply_t *sres =
        xcb_randr_get_screen_resources_reply(connection,
          xcb_randr_get_screen_resources(connection, root), nullptr);

      if (sres == nullptr)
        return monitors;

      int len = xcb_randr_get_screen_resources_outputs_length(sres);
      xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs(sres);

      for (int i = 0; i < len; i++) {
        xcb_randr_get_output_info_cookie_t cookie =
          xcb_randr_get_output_info(connection, outputs[i], XCB_CURRENT_TIME);
        xcb_randr_get_output_info_reply_t *info =
          xcb_randr_get_output_info_reply(connection, cookie, nullptr);
        xcb_randr_get_output_info(connection, outputs[i], XCB_CURRENT_TIME);

        if (info == nullptr)
          continue;

        if (info->crtc == XCB_NONE) {
          free(info);
          continue;
        }

        xcb_randr_get_crtc_info_reply_t *cir =
          xcb_randr_get_crtc_info_reply(connection,
            xcb_randr_get_crtc_info(connection, info->crtc, XCB_CURRENT_TIME), nullptr);

        if (cir == nullptr) {
          free(info);
          continue;
        }

        char *monitor_name = (char *) xcb_randr_get_output_info_name(info);
        monitors.emplace_back(make_object(monitor_name, info->name_len, i,
            {cir->x, cir->y, cir->width, cir->height}));

        free(cir);
      }

      std::sort(monitors.begin(), monitors.end(), [](std::shared_ptr<monitor_t> m1, std::shared_ptr<monitor_t> m2) -> bool
      {
        if (m1->bounds.x < m2->bounds.x || m1->bounds.y + m1->bounds.height <= m2->bounds.y)
          return 1;
        if (m1->bounds.x > m2->bounds.x || m1->bounds.y + m1->bounds.height > m2->bounds.y)
          return -1;
        return 0;
      });

      return monitors;
    }
Beispiel #2
0
xcb_randr_get_output_info_reply_t *
get_output_info(xcb_connection_t * conn, xcb_randr_output_t output)
{
	xcb_randr_get_output_info_cookie_t oic;

	oic = xcb_randr_get_output_info(conn, output, 0);
	xcb_randr_get_output_info_reply_t *output_info_reply;

	output_info_reply = xcb_randr_get_output_info_reply(conn, oic, NULL);
	if (!output_info_reply)
		errx(1, "Could not get output info.");

	return output_info_reply;
}
Beispiel #3
0
/*
 * Initialize RandR and obtain current monitors
 */
static int ya_init_randr() {
	xcb_randr_get_screen_resources_current_reply_t *res_reply;
	res_reply = xcb_randr_get_screen_resources_current_reply(ya.c,
			xcb_randr_get_screen_resources_current(ya.c, ya.scr->root), NULL);
	if (!res_reply) {
		return -1; //just report error
	}
	int mon_num = xcb_randr_get_screen_resources_current_outputs_length(res_reply);
	xcb_randr_output_t *ops = xcb_randr_get_screen_resources_current_outputs(res_reply);

	xcb_randr_get_output_info_reply_t *op_reply;
	xcb_randr_get_crtc_info_reply_t *crtc_reply;

	ya_monitor_t *tmpmon;
	char *tname;
	int tname_len;

	for (int i=0; i < mon_num; i++) {
		op_reply = xcb_randr_get_output_info_reply(ya.c,
				xcb_randr_get_output_info(ya.c, ops[i], XCB_CURRENT_TIME), NULL);
		if (op_reply->crtc == XCB_NONE)
			continue;
		crtc_reply = xcb_randr_get_crtc_info_reply(ya.c,
				xcb_randr_get_crtc_info(ya.c, op_reply->crtc, XCB_CURRENT_TIME), NULL);
		if(!crtc_reply)
			continue;
		tmpmon = calloc(1, sizeof(ya_monitor_t));
		tmpmon->pos = (xcb_rectangle_t){crtc_reply->x,
			crtc_reply->y, crtc_reply->width, crtc_reply->height};
		tname = (char *)xcb_randr_get_output_info_name(op_reply);
		tname_len = xcb_randr_get_output_info_name_length(op_reply);
		strncpy(tmpmon->name, tname, tname_len);
		tmpmon->name[CMONLEN-1] = '\0';
		if (ya.curmon) {
			ya.curmon->next_mon = tmpmon;
			tmpmon->prev_mon = ya.curmon;
		}
		ya.curmon = tmpmon;
		//printf("%s %d %d %d %d %d\n", tmpmon->name, tname_len, tmpmon->pos.x,
		//		tmpmon->pos.y, tmpmon->pos.width, tmpmon->pos.height);
	}
	return 0;
}
Beispiel #4
0
static gboolean
_eventd_nd_xcb_randr_check_primary(EventdNdBackendContext *self)
{
    xcb_randr_get_output_primary_cookie_t pcookie;
    xcb_randr_get_output_primary_reply_t *primary;

    pcookie = xcb_randr_get_output_primary(self->xcb_connection, self->screen->root);
    if ( ( primary = xcb_randr_get_output_primary_reply(self->xcb_connection, pcookie, NULL) ) == NULL )
        return FALSE;

    gboolean found = FALSE;

    xcb_randr_get_output_info_cookie_t ocookie;
    xcb_randr_get_output_info_reply_t *output;

    ocookie = xcb_randr_get_output_info(self->xcb_connection, primary->output, 0);
    if ( ( output = xcb_randr_get_output_info_reply(self->xcb_connection, ocookie, NULL) ) != NULL )
    {

        xcb_randr_get_crtc_info_cookie_t ccookie;
        xcb_randr_get_crtc_info_reply_t *crtc;

        ccookie = xcb_randr_get_crtc_info(self->xcb_connection, output->crtc, output->timestamp);
        if ( ( crtc = xcb_randr_get_crtc_info_reply(self->xcb_connection, ccookie, NULL) ) != NULL )
        {
            found = TRUE;

            self->geometry.x = crtc->x;
            self->geometry.y = crtc->y;
            self->geometry.w = crtc->width;
            self->geometry.h = crtc->height;

            free(crtc);
        }
        free(output);
    }
    free(primary);

    return found;
}
Beispiel #5
0
/*
 * Get RANDR resources and figure out how many outputs there are.
 */ 
void randr_get(xcb_connection_t * conn,xcb_screen_t * screen)
{
    xcb_randr_get_screen_resources_current_cookie_t rcookie;
    xcb_randr_get_screen_resources_current_reply_t *res;
    xcb_randr_output_t *outputs;
    int len;    
    xcb_timestamp_t timestamp;
    
    rcookie = xcb_randr_get_screen_resources_current(conn, screen->root);
    res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL);
    if (NULL == res)
    {
        printf("No RANDR extension available.\n");
        return;
    }
    timestamp = res->config_timestamp;

    len = xcb_randr_get_screen_resources_current_outputs_length(res);
    outputs = xcb_randr_get_screen_resources_current_outputs(res);
    free(res);
    PDEBUG("Found %d outputs.\n", len);
    
    /* Request information for all outputs. */

    char *name;
    xcb_randr_get_crtc_info_cookie_t icookie;
    xcb_randr_get_crtc_info_reply_t *crtc = NULL;
    xcb_randr_get_output_info_reply_t *output;
    struct monitor *mon;
    struct monitor *clonemon;
    xcb_randr_get_output_info_cookie_t ocookie[len];
    int i;
    
    for (i = 0; i < len; i++)
    {
        ocookie[i] = xcb_randr_get_output_info(conn, outputs[i], timestamp);
    }

    /* Loop through all outputs. */
    for (i = 0; i < len; i ++)
    {
        output = xcb_randr_get_output_info_reply(conn, ocookie[i], NULL);
        
        if (output == NULL)
        {
            continue;
        }

        asprintf(&name, "%.*s",
                 xcb_randr_get_output_info_name_length(output),
                 xcb_randr_get_output_info_name(output));

        PDEBUG("Name: %s\n", name);
        PDEBUG("id: %d\n" , outputs[i]);
        PDEBUG("Size: %d x %d mm.\n", output->mm_width, output->mm_height);

        if (XCB_NONE != output->crtc)
        {
            icookie = xcb_randr_get_crtc_info(conn, output->crtc, timestamp);
            crtc = xcb_randr_get_crtc_info_reply(conn, icookie, NULL);
            if (NULL == crtc)
            {
                return;
            }
            
            PDEBUG("CRTC: at %d, %d, size: %d x %d.\n", crtc->x, crtc->y,
                   crtc->width, crtc->height);

            /* Check if it's a clone. */
            clonemon = findclones(outputs[i], crtc->x, crtc->y);
            if (NULL != clonemon)
            {
                PDEBUG("Monitor %s, id %d is a clone of %s, id %d. Skipping.\n",
                       name, outputs[i],
                       clonemon->name, clonemon->id);
                continue;
            }

            /* Do we know this monitor already? */
            if (NULL == (mon = findmonitor(outputs[i])))
            {
                PDEBUG("Monitor not known, adding to list.\n");
                addmonitor(outputs[i], name, crtc->x, crtc->y, crtc->width,
                           crtc->height);
            }
            else
            {
                bool changed = false;
                
                /*
                 * We know this monitor. Update information. If it's
                 * smaller than before, rearrange windows.
                 */
                PDEBUG("Known monitor. Updating info.\n");

                if (crtc->x != mon->x)
                {
                    mon->x = crtc->x;
                    changed = true;
                }
                if (crtc->y != mon->y)
                {
                    mon->y = crtc->y;
                    changed = true;
                }

                if (crtc->width != mon->width)
                {
                    mon->width = crtc->width;                    
                    changed = true;
                }
                if (crtc->height != mon->height)
                {
                    mon->height = crtc->height;                    
                    changed = true;
                }
                
                if (changed)
                {
                    arrbymon(mon);
                }
            }

            free(crtc);
        }
        else
        {
            PDEBUG("Monitor not used at the moment.\n");
            /*
             * Check if it was used before. If it was, do something.
             */
            if ((mon = findmonitor(outputs[i])))
            {
                struct item *item;
                struct client *client;

                /* Check all windows on this monitor and move them to
                 * the next or to the first monitor if there is no
                 * next.
                 *
                 * FIXME: Use per monitor workspace list instead of
                 * global window list.
                 */
                for (item = winlist; item != NULL; item = item->next)
                {
                    client = item->data;
                    if (client->monitor == mon)
                    {
                        if (NULL == client->monitor->item->next)
                        {
                            if (NULL == monlist)
                            {
                                client->monitor = NULL;
                            }
                            else
                            {
                                client->monitor = monlist->data;
                            }
                        }
                        else
                        {
                            client->monitor =
                                client->monitor->item->next->data;
                        }

                        fitonscreen(client);
                    }
                } /* for */
                
                /* It's not active anymore. Forget about it. */
                delmonitor(mon);
            }
        }

        free(output);
    } /* for */
}
int x11_find_all_outputs(char*** out_outputs, size_t* out_outputs_count)
{
  xcb_generic_error_t* error = NULL;
  xcb_randr_query_version_cookie_t version_cookie;
  xcb_randr_query_version_reply_t* version_reply = NULL;
  const xcb_setup_t* setup;
  xcb_screen_iterator_t iter;
  xcb_screen_t* screen;
  xcb_randr_get_screen_resources_current_cookie_t screen_cookie;
  xcb_randr_get_output_info_cookie_t output_cookie;
  xcb_randr_output_t* outputs = NULL;
  
  *out_outputs_count = 0;
  *out_outputs = NULL;
  
  connection = xcb_connect(NULL, NULL);
  if (connection == NULL)
    goto pfail;
  
  version_cookie = xcb_randr_query_version(connection, RANDR_VERSION_MAJOR, RANDR_VERSION_MINOR);
  version_reply = xcb_randr_query_version_reply(connection, version_cookie, &error);
  
  if ((error != NULL) || (version_reply == NULL))
    {
      if ((error == NULL) && (version_reply == NULL))
	connection = NULL;
      goto pfail;
    }
  
  if ((version_reply->major_version != RANDR_VERSION_MAJOR) ||
      (version_reply->minor_version < RANDR_VERSION_MINOR))
    {
      fprintf(stderr, "%s: wrong RandR version\n", argv0);
      goto fail;
    }
  
  free(version_reply), version_reply = NULL;
  
  setup = xcb_get_setup(connection);
  if (setup == NULL)
    goto pfail;
  
  iter = xcb_setup_roots_iterator(setup);
  
  for (; iter.rem > 0; xcb_screen_next(&iter))
    {
      size_t i, n;
      
      screen = iter.data;
      if (screen == NULL)
	abort();
      
      screen_cookie = xcb_randr_get_screen_resources_current(connection, screen->root);
      screen_reply = xcb_randr_get_screen_resources_current_reply(connection, screen_cookie, &error);
      if (error != NULL)
	goto pfail;
      
      outputs = xcb_randr_get_screen_resources_current_outputs(screen_reply);
      if (outputs == NULL)
	goto pfail;
      
      for (i = 0, n = (size_t)(screen_reply->num_outputs); i < n; i++)
	{
	  uint8_t* name;
	  uint16_t length;
	  char* namez;
	  char** old;
	  
	  output_cookie = xcb_randr_get_output_info(connection, outputs[i], screen_reply->config_timestamp);
	  output_reply = xcb_randr_get_output_info_reply(connection, output_cookie, &error);
	  if (error != NULL)
	    goto pfail;
	  
	  if (output_reply->connection != XCB_RANDR_CONNECTION_CONNECTED)
	    goto next_output;
	  
	  name = xcb_randr_get_output_info_name(output_reply);
	  length = output_reply->name_len;
	  if (name == NULL)
	    goto pfail;
	  
	  *out_outputs = realloc(old = *out_outputs, (*out_outputs_count + 1) * sizeof(char*));
	  if (*out_outputs == NULL)
	    {
	      *out_outputs = old;
	      goto pfail;
	    }
	  
	  namez = malloc(((size_t)length + 1) * sizeof(char));
	  if (namez == NULL)
	    goto pfail;
	  namez[length] = '\0';
	  while (length--)
	    namez[length] = (char)(name[length]);
	  
	  (*out_outputs)[(*out_outputs_count)++] = namez;
	  
	next_output:
	  free(output_reply), output_reply = NULL;
	}
      
      free(screen_reply), screen_reply = NULL;
    }
  
  xcb_disconnect(connection);
  return 0;
  
 pfail:
  perror(argv0);
 fail:
  free(version_reply);
  free(screen_reply);
  free(output_reply);
  if (connection != NULL)
    xcb_disconnect(connection);
  return -1;
}
int x11_initialise_animation(int coarse_fine, double duration, double degrees, const char* output)
{
  xcb_generic_error_t* error = NULL;
  xcb_randr_query_version_cookie_t version_cookie;
  xcb_randr_query_version_reply_t* version_reply = NULL;
  const xcb_setup_t* setup;
  xcb_screen_iterator_t iter;
  xcb_screen_t* screen;
  xcb_randr_get_screen_resources_current_cookie_t screen_cookie;
  xcb_randr_get_output_info_cookie_t output_cookie;
  xcb_randr_crtc_t* crtcs = NULL;
  xcb_randr_output_t* outputs = NULL;
  int found_output = 0;
  size_t i, n;
  xcb_randr_get_crtc_transform_cookie_t transform_cookie;
  xcb_randr_get_crtc_transform_reply_t* transform_reply = NULL;
  
  fine = coarse_fine ? (coarse_fine == 1) : 1;
  
  connection = NULL;
  screen_reply = NULL;
  output_reply = NULL;
  
  connection = xcb_connect(NULL, NULL);
  if (connection == NULL)
    goto pfail;
  
  version_cookie = xcb_randr_query_version(connection, RANDR_VERSION_MAJOR, RANDR_VERSION_MINOR);
  version_reply = xcb_randr_query_version_reply(connection, version_cookie, &error);
  
  if ((error != NULL) || (version_reply == NULL))
    {
      if ((error == NULL) && (version_reply == NULL))
	connection = NULL;
      goto pfail;
    }
  
  if ((version_reply->major_version != RANDR_VERSION_MAJOR) ||
      (version_reply->minor_version < RANDR_VERSION_MINOR))
    {
      fprintf(stderr, "%s: wrong RandR version\n", argv0);
      goto fail;
    }
  
  free(version_reply), version_reply = NULL;
  
  setup = xcb_get_setup(connection);
  if (setup == NULL)
    goto pfail;
  
  iter = xcb_setup_roots_iterator(setup);
  
  for (; (iter.rem > 0) && !found_output; xcb_screen_next(&iter))
    {
      screen = iter.data;
      if (screen == NULL)
	abort();
      
      screen_cookie = xcb_randr_get_screen_resources_current(connection, screen->root);
      screen_reply = xcb_randr_get_screen_resources_current_reply(connection, screen_cookie, &error);
      if (error != NULL)
	goto pfail;
      
      crtcs = xcb_randr_get_screen_resources_current_crtcs(screen_reply);
      outputs = xcb_randr_get_screen_resources_current_outputs(screen_reply);
      if (outputs == NULL)
	goto pfail;
      
      for (i = 0, n = (size_t)(screen_reply->num_outputs); (i < n) && !found_output; i++)
	{
	  uint8_t* name;
	  uint16_t length;
	  char* namez = NULL;
	  uint16_t j;
	  
	  output_cookie = xcb_randr_get_output_info(connection, outputs[i], screen_reply->config_timestamp);
	  output_reply = xcb_randr_get_output_info_reply(connection, output_cookie, &error);
	  if (error != NULL)
	    goto pfail;
	  
	  if (output_reply->connection != XCB_RANDR_CONNECTION_CONNECTED)
	    goto next_output;
	  
	  name = xcb_randr_get_output_info_name(output_reply);
	  length = output_reply->name_len;
	  if (name == NULL)
	    goto pfail;
	  
	  namez = malloc(((size_t)length + 1) * sizeof(char));
	  if (namez == NULL)
	    goto pfail;
	  namez[length] = '\0';
	  while (length--)
	    namez[length] = (char)(name[length]);
	  
	  if (strcmp(namez, output))
	      goto next_output;
	  found_output = 1;
	  free(namez), namez = NULL;
	  
	  for (j = 0; j < screen_reply->num_crtcs; j++)
	    if (crtcs[j] == output_reply->crtc)
	      break;
	  if (j == screen_reply->num_crtcs)
	    {
	      fprintf(stderr, "%s: could not find CRTC associated with output: %s\n", argv0, output);
	      goto fail;
	    }
	  crtc = crtcs[j];
	  
	  goto exit_search_loop;
	  
	next_output:
	  free(namez);
	  free(output_reply), output_reply = NULL;
	}
      
      free(screen_reply), screen_reply = NULL;
    }
 exit_search_loop:
  
  if (!found_output)
    {
      fprintf(stderr, "%s: could not find output: %s\n", argv0, output);
      goto fail;
    }
  
  transform_cookie = xcb_randr_get_crtc_transform(connection, crtc);
  transform_reply = xcb_randr_get_crtc_transform_reply(connection, transform_cookie, &error);
  if (error != NULL)
    goto pfail;
  
  original_transform = transform_reply->pending_transform;
  free(transform_reply);
  
  return 0;
  
 pfail:
  perror(argv0);
 fail:
  free(version_reply);
  free(screen_reply);
  free(output_reply);
  free(transform_reply);
  if (connection != NULL)
    xcb_disconnect(connection);
  return -1;
  
  return (void)duration, (void)degrees, -1; /* TODO */
}
Beispiel #8
0
bool import_monitors(void)
{
    PUTS("import monitors");
    xcb_randr_get_screen_resources_current_reply_t *sres = xcb_randr_get_screen_resources_current_reply(dpy, xcb_randr_get_screen_resources_current(dpy, root), NULL);
    if (sres == NULL)
        return false;

    monitor_t *m, *mm = NULL;

    int len = xcb_randr_get_screen_resources_current_outputs_length(sres);
    xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres);

    xcb_randr_get_output_info_cookie_t cookies[len];
    for (int i = 0; i < len; i++)
        cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);

    for (m = mon_head; m != NULL; m = m->next)
        m->wired = false;

    for (int i = 0; i < len; i++) {
        xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL);
        if (info != NULL) {
            if (info->crtc != XCB_NONE) {
                xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL);
                if (cir != NULL) {
                    xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height};
                    mm = get_monitor_by_id(outputs[i]);
                    if (mm != NULL) {
                        mm->rectangle = rect;
                        update_root(mm);
                        for (desktop_t *d = mm->desk_head; d != NULL; d = d->next)
                            for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
                                translate_client(mm, mm, n->client);
                        arrange(mm, mm->desk);
                        mm->wired = true;
                        PRINTF("update monitor %s (0x%X)\n", mm->name, mm->id);
                    } else {
                        mm = add_monitor(rect);
                        char *name = (char *)xcb_randr_get_output_info_name(info);
                        size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info) + 1);
                        snprintf(mm->name, name_len, "%s", name);
                        mm->id = outputs[i];
                        PRINTF("add monitor %s (0x%X)\n", mm->name, mm->id);
                    }
                }
                free(cir);
            } else if (!remove_disabled_monitor && info->connection != XCB_RANDR_CONNECTION_DISCONNECTED) {
                m = get_monitor_by_id(outputs[i]);
                if (m != NULL)
                    m->wired = true;
            }
        }
        free(info);
    }

    /* initially focus the primary monitor and add the first desktop to it */
    xcb_randr_get_output_primary_reply_t *gpo = xcb_randr_get_output_primary_reply(dpy, xcb_randr_get_output_primary(dpy, root), NULL);
    if (gpo != NULL) {
        pri_mon = get_monitor_by_id(gpo->output);
        if (!running && pri_mon != NULL) {
            if (mon != pri_mon)
                mon = pri_mon;
            add_desktop(pri_mon, make_desktop(NULL));
            ewmh_update_current_desktop();
        }
    }
    free(gpo);

    /* handle overlapping monitors */
    m = mon_head;
    while (m != NULL) {
        monitor_t *next = m->next;
        if (m->wired) {
            for (monitor_t *mb = mon_head; mb != NULL; mb = mb->next)
                if (mb != m && mb->wired && (m->desk == NULL || mb->desk == NULL)
                        && contains(mb->rectangle, m->rectangle)) {
                    if (mm == m)
                        mm = mb;
                    merge_monitors(m, mb);
                    remove_monitor(m);
                    break;
                }
        }
        m = next;
    }

    /* merge and remove disconnected monitors */
    m = mon_head;
    while (m != NULL) {
        monitor_t *next = m->next;
        if (!m->wired) {
            merge_monitors(m, mm);
            remove_monitor(m);
        }
        m = next;
    }

    /* add one desktop to each new monitor */
    for (m = mon_head; m != NULL; m = m->next)
        if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon))
            add_desktop(m, make_desktop(NULL));

    free(sres);
    update_motion_recorder();
    return (num_monitors > 0);
}
Beispiel #9
0
/* 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;
}
Beispiel #10
0
/* @brief Attempts to find secondary displays and updates settings.screen_* data
 *        with the dimensions of the found screens.
 *
 * Note: failure is somewhat expected and is handled by simply using the default
 *       xcb screen's dimension parameters.
 *
 * @param connection A connection to the Xorg server.
 * @param screen A screen created by xcb's xcb_setup_roots function.
 * @return 0 on success and 1 on failure.
 */
static int32_t get_multiscreen_settings(xcb_connection_t *connection, xcb_screen_t *screen) {
  /* First check randr. */
  const xcb_query_extension_reply_t *extension_reply = xcb_get_extension_data(connection, &xcb_randr_id);
  if (extension_reply && extension_reply->present) {
    debug("Found randr support, searching for displays.\n");
    /* Find x, y and width, height. */
    xcb_randr_get_screen_resources_current_reply_t *randr_reply = xcb_randr_get_screen_resources_current_reply(connection, xcb_randr_get_screen_resources_current(connection, screen->root), NULL);
    if (!randr_reply) {
      fprintf(stderr, "Failed to get randr set up.\n");
    } else {
      int32_t num_outputs = xcb_randr_get_screen_resources_current_outputs_length(randr_reply);
      if (num_outputs < settings.screen) {
        fprintf(stderr, "Screen selected not found.\n");
        /* Default back to the first screen. */
        settings.screen = 0;
      }
      xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(randr_reply);
      uint32_t output_index = settings.screen;
      xcb_randr_get_output_info_reply_t *randr_output = NULL;
      do {
        if (randr_output) { free(randr_output); }
        randr_output = xcb_randr_get_output_info_reply(connection, xcb_randr_get_output_info(connection, outputs[output_index], XCB_CURRENT_TIME), NULL);
        output_index++;
      } while ((randr_output->connection != XCB_RANDR_CONNECTION_CONNECTED) && (output_index < num_outputs));
      if (randr_output) {
        xcb_randr_get_crtc_info_reply_t *randr_crtc = xcb_randr_get_crtc_info_reply(connection, xcb_randr_get_crtc_info(connection, randr_output->crtc, XCB_CURRENT_TIME), NULL);
        if (!randr_crtc) {
          fprintf(stderr, "Unable to connect to randr crtc\n");
          free(randr_output);
          free(randr_reply);
          goto xinerama;
        }
        settings.screen_width = randr_crtc->width;
        settings.screen_height = randr_crtc->height;
        settings.screen_x = randr_crtc->x;
        settings.screen_y = randr_crtc->y;
        debug("randr screen initialization successful, x: %u y: %u w: %u h: %u.\n", settings.screen_x, settings.screen_y, settings.screen_width, settings.screen_height);

        free(randr_crtc);
        free(randr_output);
        free(randr_reply);
        return 0;
      }
      free(randr_output);
      free(randr_reply);
    }
  }
xinerama:
  debug("Did not find randr support, attempting xinerama\n");

  /* Still here? Let's try xinerama! */
  extension_reply = xcb_get_extension_data(connection, &xcb_xinerama_id);
  if (extension_reply && extension_reply->present) {
    debug("Found xinerama support, searching for displays.\n");
    xcb_xinerama_is_active_reply_t *xinerama_is_active_reply = xcb_xinerama_is_active_reply(connection, xcb_xinerama_is_active(connection), NULL);
    if (xinerama_is_active_reply && xinerama_is_active_reply->state) {
      free(xinerama_is_active_reply);
      /* Find x, y and width, height. */
      xcb_xinerama_query_screens_reply_t *screen_reply = xcb_xinerama_query_screens_reply(connection, xcb_xinerama_query_screens_unchecked(connection), NULL);
      xcb_xinerama_screen_info_iterator_t iter = xcb_xinerama_query_screens_screen_info_iterator(screen_reply);
      free(screen_reply);
      if (iter.rem < settings.screen) {
        fprintf(stderr, "Screen selected not found.\n");
        /* Default back to the first screen. */
        settings.screen = 0;
      }
      /* Jump to the appropriate screen. */
      int32_t i = 0;
      while (i < settings.screen) {
        xcb_xinerama_screen_info_next(&iter);
        i++;
      }
      settings.screen_width = iter.data->width;
      settings.screen_height = iter.data->height;
      settings.screen_x = iter.data->x_org;
      settings.screen_y = iter.data->y_org;
      debug("xinerama screen initialization successful, x: %u y: %u w: %u h: %u.\n", settings.screen_x, settings.screen_y, settings.screen_width, settings.screen_height);
      return 0;
    }
  }

  debug("Multiscreen search failed.\n");
  return 1;
}
Beispiel #11
0
bool update_monitors(void)
{
	xcb_randr_get_screen_resources_reply_t *sres = xcb_randr_get_screen_resources_reply(dpy, xcb_randr_get_screen_resources(dpy, root), NULL);
	if (sres == NULL) {
		return false;
	}

	monitor_t *m, *mm = NULL;

	int len = xcb_randr_get_screen_resources_outputs_length(sres);
	xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs(sres);

	xcb_randr_get_output_info_cookie_t cookies[len];
	for (int i = 0; i < len; i++) {
		cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
	}

	for (m = mon_head; m != NULL; m = m->next) {
		m->wired = false;
	}

	for (int i = 0; i < len; i++) {
		xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL);
		if (info != NULL) {
			if (info->crtc != XCB_NONE) {
				xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL);
				if (cir != NULL) {
					xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height};
					mm = get_monitor_by_randr_id(outputs[i]);
					if (mm != NULL) {
						update_root(mm, &rect);
						mm->wired = true;
					} else {
						mm = make_monitor(&rect, XCB_NONE);
						char *name = (char *)xcb_randr_get_output_info_name(info);
						int len = xcb_randr_get_output_info_name_length(info);
						size_t name_size = MIN(sizeof(mm->name), (size_t) len + 1);
						snprintf(mm->name, name_size, "%s", name);
						mm->randr_id = outputs[i];
						add_monitor(mm);
					}
				}
				free(cir);
			} else if (!remove_disabled_monitors && info->connection != XCB_RANDR_CONNECTION_DISCONNECTED) {
				m = get_monitor_by_randr_id(outputs[i]);
				if (m != NULL) {
					m->wired = true;
				}
			}
		}
		free(info);
	}

	xcb_randr_get_output_primary_reply_t *gpo = xcb_randr_get_output_primary_reply(dpy, xcb_randr_get_output_primary(dpy, root), NULL);
	if (gpo != NULL) {
		pri_mon = get_monitor_by_randr_id(gpo->output);
	}
	free(gpo);

	/* handle overlapping monitors */
	if (merge_overlapping_monitors) {
		m = mon_head;
		while (m != NULL) {
			monitor_t *next = m->next;
			if (m->wired) {
				monitor_t *mb = mon_head;
				while (mb != NULL) {
					monitor_t *mb_next = mb->next;
					if (m != mb && mb->wired && contains(m->rectangle, mb->rectangle)) {
						if (mm == mb) {
							mm = m;
						}
						if (next == mb) {
							next = mb_next;
						}
						merge_monitors(mb, m);
						remove_monitor(mb);
					}
					mb = mb_next;
				}
			}
			m = next;
		}
	}

	/* merge and remove disconnected monitors */
	if (remove_unplugged_monitors) {
		m = mon_head;
		while (m != NULL) {
			monitor_t *next = m->next;
			if (!m->wired) {
				merge_monitors(m, mm);
				remove_monitor(m);
			}
			m = next;
		}
	}

	/* add one desktop to each new monitor */
	for (m = mon_head; m != NULL; m = m->next) {
		if (m->desk == NULL) {
			add_desktop(m, make_desktop(NULL, XCB_NONE));
		}
	}

	if (!running && mon != NULL) {
		if (pri_mon != NULL) {
			mon = pri_mon;
		}
		center_pointer(mon->rectangle);
		ewmh_update_current_desktop();
	}

	free(sres);

	return (mon != NULL);
}
Beispiel #12
0
static gboolean
_eventd_nd_xcb_randr_check_outputs(EventdNdBackendContext *self)
{
    if ( ( self->follow_focus == EVENTD_ND_XCB_FOLLOW_FOCUS_NONE ) && ( self->outputs == NULL ) )
        return FALSE;

    xcb_randr_get_screen_resources_current_cookie_t rcookie;
    xcb_randr_get_screen_resources_current_reply_t *ressources;

    rcookie = xcb_randr_get_screen_resources_current(self->xcb_connection, self->screen->root);
    if ( ( ressources = xcb_randr_get_screen_resources_current_reply(self->xcb_connection, rcookie, NULL) ) == NULL )
    {
        g_warning("Couldn't get RandR screen ressources");
        return FALSE;
    }

    xcb_timestamp_t cts;
    xcb_randr_output_t *randr_outputs;
    gint i, length;

    cts = ressources->config_timestamp;

    length = xcb_randr_get_screen_resources_current_outputs_length(ressources);
    randr_outputs = xcb_randr_get_screen_resources_current_outputs(ressources);

    EventdNdXcbRandrOutput outputs[length + 1];
    EventdNdXcbRandrOutput *output;

    output = outputs;

    for ( i = 0 ; i < length ; ++i )
    {
        xcb_randr_get_output_info_cookie_t ocookie;

        ocookie = xcb_randr_get_output_info(self->xcb_connection, randr_outputs[i], cts);
        if ( ( output->output = xcb_randr_get_output_info_reply(self->xcb_connection, ocookie, NULL) ) == NULL )
            continue;

        xcb_randr_get_crtc_info_cookie_t ccookie;

        ccookie = xcb_randr_get_crtc_info(self->xcb_connection, output->output->crtc, cts);
        if ( ( output->crtc = xcb_randr_get_crtc_info_reply(self->xcb_connection, ccookie, NULL) ) == NULL )
            free(output->output);
        else
            ++output;
    }
    output->output = NULL;

    gboolean found;

    if ( self->follow_focus != EVENTD_ND_XCB_FOLLOW_FOCUS_NONE )
        found = _eventd_nd_xcb_randr_check_focused(self, outputs);
    else
        found = _eventd_nd_xcb_randr_check_config_outputs(self, outputs);

    for ( output = outputs ; output->output != NULL ; ++output )
    {
        free(output->crtc);
        free(output->output);
    }

    return found;
}
Beispiel #13
0
bool ScreenManager::scanRandR(xcb_connection_t *conn)
{
    if (!configureRandR(conn)) {
        LOG_ERROR("RandR extension not found.");
        return false;
    }

    xcb_randr_get_screen_resources_current_reply_t *res =
        xcb_randr_get_screen_resources_current_reply(conn,
            xcb_randr_get_screen_resources_current(conn, _rootWindow), NULL);
    if (!res) {
        LOG_ERROR("Failed to retrieve screen resources by RandR.");
        return false;
    }

    int length = xcb_randr_get_screen_resources_current_outputs_length(res);
    xcb_randr_output_t *outputs =
        xcb_randr_get_screen_resources_current_outputs(res);

    std::vector<xcb_randr_get_output_info_cookie_t> cookies;
    xcb_randr_get_output_info_reply_t *output_info;
    xcb_randr_get_crtc_info_reply_t *crtc;
    char *output_name;

    if (length == 0) {
        LOG_ERROR("No screen found using RandR.");
        return false;
    } else {
        LOG_INFO("Found %d screen(s).", length);
    }

    for (int i = 0; i < length; i++) {
        cookies.push_back(xcb_randr_get_output_info(conn, outputs[i],
            res->config_timestamp));
    }
    for (auto iter = cookies.begin(); iter != cookies.end(); ++iter) {
        output_info = xcb_randr_get_output_info_reply(conn, *iter, NULL);
        if (output_info == NULL) {
            continue;
        }
        asprintf(&output_name, "%.*s",
            xcb_randr_get_output_info_name_length(output_info),
            xcb_randr_get_output_info_name(output_info));

        Screen s;
        s.setName(output_name);
        free(output_name);

        if (output_info->crtc == XCB_NONE) {
            LOG_INFO("  Screen %s is disabled.", s.getName().c_str());
            continue;
        }
        crtc = xcb_randr_get_crtc_info_reply(conn,
            xcb_randr_get_crtc_info(
                conn, output_info->crtc, res->config_timestamp),
            NULL);
        if (!crtc) {
            LOG_ERROR("Failed to retrieve CRTC on screen %s.",
                s.getName().c_str());
            return 0;
        }
        s.setX(crtc->x);
        s.setY(crtc->y);
        s.setWidth(crtc->width);
        s.setHeight(crtc->height);
        updateScreen(s);
        free(crtc);
        free(output_info);
    }
    free(res);
    return true;
}