add initial randr support and adjust xinerama support

This commit is contained in:
John Vogel 2013-12-14 23:57:09 -05:00
parent 7b76711980
commit e7df9b0b91
2 changed files with 197 additions and 74 deletions

View File

@ -1,12 +1,7 @@
CC ?= gcc
STRIP ?= strip
CFLAGS = -std=c99 -fshort-wchar -Os
LDFLAGS = -lxcb
XINERAMA ?= 0
ifneq "$(XINERAMA)" "0"
LDFLAGS += -lxcb-xinerama
CFLAGS += -DXINERAMA=${XINERAMA}
endif
LDFLAGS = -lxcb -lxcb-xinerama -lxcb-randr
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long\
-Wsign-conversion -Wconversion -Wimplicit-function-declaration

264
bar.c
View File

@ -8,9 +8,8 @@
#include <getopt.h>
#include <unistd.h>
#include <xcb/xcb.h>
#if XINERAMA
#include <xcb/xinerama.h>
#endif
#include <xcb/randr.h>
#include "config.h"
@ -58,13 +57,10 @@ static fontset_item_t *sel_font = NULL;
static screen_t *screens;
static int num_screens;
static int randr_event = -1;
static const unsigned palette[] = {COLOR0,COLOR1,COLOR2,COLOR3,COLOR4,COLOR5,COLOR6,COLOR7,COLOR8,COLOR9,BACKGROUND,FOREGROUND};
#if XINERAMA
static const char *control_characters = "fbulcsr";
#else
static const char *control_characters = "fbulcr";
#endif
static inline void
xcb_set_bg (int i)
@ -137,8 +133,9 @@ draw_char (screen_t *screen, int x, int align, wchar_t ch)
(xcb_char2b_t *)&ch);
/* Draw the underline */
if (BAR_UNDERLINE_HEIGHT)
if (BAR_UNDERLINE_HEIGHT) {
xcb_fill_rect (underl_gc, x + screen->x, BAR_UNDERLINE*(BAR_HEIGHT-BAR_UNDERLINE_HEIGHT), ch_width, BAR_UNDERLINE_HEIGHT);
}
return ch_width;
}
@ -153,7 +150,6 @@ parse (char *text)
screen_t *screen = &screens[0];
xcb_fill_rect (clear_gc, 0, 0, bar_width, BAR_HEIGHT);
for (;;) {
if (*p == '\0')
return;
@ -162,7 +158,7 @@ parse (char *text)
if (*p == '\\' && p++ && *p != '\\' && strchr (control_characters, *p)) {
switch (*p++) {
case 'f':
case 'f':
xcb_set_fg (isdigit(*p) ? (*p)-'0' : 11);
p++;
break;
@ -174,8 +170,9 @@ parse (char *text)
xcb_set_ud (isdigit(*p) ? (*p)-'0' : 10);
p++;
break;
#if XINERAMA
case 's':
if (num_screens == 1)
break;
if ((*p) == 'r') {
screen = &screens[num_screens - 1];
} else if ((*p) == 'l') {
@ -202,7 +199,6 @@ parse (char *text)
pos_x = 0;
p++;
break;
#endif
case 'l':
align = ALIGN_L;
pos_x = 0;
@ -215,6 +211,8 @@ parse (char *text)
align = ALIGN_R;
pos_x = 0;
break;
default:
break;
}
} else { /* utf-8 -> ucs-2 */
wchar_t t;
@ -349,21 +347,152 @@ set_ewmh_atoms ()
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atom_list[NET_WM_STRUT], XCB_ATOM_CARDINAL, 32, 4, strut);
}
int
get_xinerama_outputs(xcb_window_t w, screen_t **spp)
{
int i, num = 0;
screen_t *ret;
xcb_generic_error_t *err;
xcb_xinerama_query_screens_cookie_t xinerama_query;
xcb_xinerama_query_screens_reply_t *xinerama_reply;
xcb_xinerama_screen_info_t *xinerama_info;
xcb_xinerama_is_active_cookie_t xia_query;
xcb_xinerama_is_active_reply_t *xia_reply;
xia_query = xcb_xinerama_is_active(c);
xia_reply = xcb_xinerama_is_active_reply(c, xia_query, &err);
if (xia_reply && xia_reply->state) {
free(xia_reply);
xinerama_query = xcb_xinerama_query_screens(c);
xinerama_reply = xcb_xinerama_query_screens_reply(c, xinerama_query, &err);
if (err != NULL || xinerama_reply == NULL) {
fprintf(stderr, "xinerama_query_screens failed\n");
return 0;
}
num = xcb_xinerama_query_screens_screen_info_length(xinerama_reply);
xinerama_info = xcb_xinerama_query_screens_screen_info(xinerama_reply);
ret = calloc (num_screens, sizeof(screen_t));
if (ret == NULL)
exit (1);
for (int i = num_screens-1; i >= 0; i--) {
ret[i].x = xinerama_info[i].x_org;
ret[i].width = xinerama_info[i].width;
}
free(xinerama_reply);
*spp = ret;
}
return num;
}
struct rect {
uint32_t x;
uint32_t y;
uint32_t width;
uint32_t height;
};
int
get_randr_outputs(xcb_window_t w, screen_t **spp)
{
int i, j, num, cnt = 0;
screen_t *s;
xcb_generic_error_t *err;
xcb_randr_get_screen_resources_current_cookie_t rres_query;
xcb_randr_get_screen_resources_current_reply_t *rres_reply;
xcb_randr_output_t *outputs;
rres_query = xcb_randr_get_screen_resources_current(c, w);
rres_reply = xcb_randr_get_screen_resources_current_reply(c, rres_query, &err);
if (rres_reply == NULL || err != NULL) {
fprintf(stderr, "Failed to get current randr screen resources\n");
return 0;
}
num = xcb_randr_get_screen_resources_current_outputs_length(rres_reply);
outputs = xcb_randr_get_screen_resources_current_outputs(rres_reply);
struct rect temp[num];
/* use all outputs connected to a crtc */
for (i = 0; i < num; i++) {
xcb_randr_get_output_info_cookie_t output_cookie;
xcb_randr_get_output_info_reply_t *output_reply;
xcb_randr_get_crtc_info_cookie_t crtc_cookie;
xcb_randr_get_crtc_info_reply_t *crtc_reply;
output_cookie = xcb_randr_get_output_info(c, outputs[i],
rres_reply->config_timestamp);
output_reply = xcb_randr_get_output_info_reply(c, output_cookie, &err);
if (err != NULL || output_reply == NULL || output_reply->crtc == XCB_NONE) {
temp[i].width = 0;
continue;
}
crtc_cookie = xcb_randr_get_crtc_info(c, output_reply->crtc,
rres_reply->config_timestamp);
crtc_reply = xcb_randr_get_crtc_info_reply(c, crtc_cookie, &err);
if (err != NULL || crtc_reply == NULL) {
fprintf(stderr, "Failed to get randr crtc info\n");
temp[i].width = 0;
free(output_reply);
continue;
}
temp[i].x = crtc_reply->x;
temp[i].y = crtc_reply->y;
temp[i].width = crtc_reply->width;
temp[i].height = crtc_reply->height;
free(crtc_reply);
free(output_reply);
cnt++;
}
/* check for clones */
for (i = 0; i < num; i++) {
if (temp[i].width == 0)
continue;
for (j = 0; j < num; j++) {
if (i == j || temp[j].width == 0 || temp[i].x != temp[j].x || temp[i].y != temp[j].y)
continue;
temp[i].width = (temp[i].width < temp[j].width) ? temp[i].width : temp[j].width;
temp[i].height = (temp[i].height < temp[j].height) ? temp[i].height : temp[j].height;
temp[j].width = 0;
cnt--;
}
}
if (cnt < 1) {
fprintf(stderr, "No usable randr outputs\n");
return 0;
}
s = calloc(cnt, sizeof(screen_t));
if (s == NULL)
exit(1);
for (i = j = 0; i < num && j < cnt; i++)
if (temp[i].width) {
s[j].x = temp[i].x;
s[j++].width = temp[i].width;
}
*spp = s;
return cnt;
}
void
init (void)
{
xcb_screen_t *scr;
xcb_window_t root;
screen_t *temp;
int y;
int right_bar_offset;
#if XINERAMA
xcb_generic_error_t* err = NULL;
xcb_xinerama_query_screens_reply_t *xinerama_reply;
xcb_xinerama_query_screens_cookie_t xinerama_query;
xcb_xinerama_screen_info_iterator_t xinerama_iter;
screen_t *cur_screen;
#endif
xcb_generic_error_t *err;
const xcb_query_extension_reply_t *ext_reply;
/* Connect to X */
c = xcb_connect (NULL, NULL);
@ -385,62 +514,61 @@ init (void)
exit (1);
/* Generate a list of screens */
#if XINERAMA
xinerama_query = xcb_xinerama_query_screens_unchecked (c);
xinerama_reply = xcb_xinerama_query_screens_reply (c, xinerama_query, &err);
if (err != NULL || xinerama_reply == NULL)
exit (1);
num_screens = 0;
if ((ext_reply = xcb_get_extension_data(c, &xcb_randr_id)) && ext_reply->present) {
num_screens = get_randr_outputs(root, &screens);
randr_event = ext_reply->first_event;
}
else if ((ext_reply = xcb_get_extension_data(c, &xcb_xinerama_id)) && ext_reply->present)
num_screens = get_xinerama_outputs(root, &screens);
xinerama_iter = xcb_xinerama_query_screens_screen_info_iterator (xinerama_reply);
#if 0
if (num_screens) {
/* Add BAR_OFFSET to the last screen */
right_bar_offset = scr->width_in_pixels - bar_width - BAR_OFFSET;
for (cur_screen = &screens[num_screens-1]; cur_screen >= screens; xcb_xinerama_screen_info_next (&xinerama_iter), cur_screen--) {
cur_screen->width = xinerama_iter.data->width;
if (right_bar_offset > 0) {
if (right_bar_offset >= cur_screen->width) {
/* Remove the screen */
num_screens--;
right_bar_offset -= cur_screen->width;
} else {
cur_screen->width -= right_bar_offset;
right_bar_offset = 0;
}
}
num_screens = xinerama_iter.rem;
screens = calloc (num_screens, sizeof(screen_t));
if (screens == NULL)
exit (1);
/* Add BAR_OFFSET to the last screen */
right_bar_offset = scr->width_in_pixels - bar_width - BAR_OFFSET;
for (cur_screen = &screens[num_screens-1]; cur_screen >= screens; xcb_xinerama_screen_info_next (&xinerama_iter), cur_screen--) {
cur_screen->width = xinerama_iter.data->width;
if (right_bar_offset > 0) {
if (right_bar_offset >= cur_screen->width) {
/* Remove the screen */
num_screens--;
right_bar_offset -= cur_screen->width;
} else {
cur_screen->width -= right_bar_offset;
right_bar_offset = 0;
cur_screen->x = xinerama_iter.data->x_org - BAR_OFFSET;
if (cur_screen->x < 0) {
/* First screen */
cur_screen->x = 0;
break;
}
}
cur_screen->x = xinerama_iter.data->x_org - BAR_OFFSET;
if (cur_screen->x < 0) {
/* First screen */
cur_screen->x = 0;
break;
/* Remove BAR_OFFSET from the first screen */
cur_screen->width -= BAR_OFFSET;
/* Shift */
if (cur_screen > screens) {
memmove (screens, cur_screen, sizeof(screen_t) * num_screens);
}
/* Reallocate */
screens = realloc (screens, num_screens);
if (screens == NULL)
exit (1);
}
free(xinerama_reply);
/* Remove BAR_OFFSET from the first screen */
cur_screen->width -= BAR_OFFSET;
/* Shift */
if (cur_screen > screens) {
memmove (screens, cur_screen, sizeof(screen_t) * num_screens);
}
/* Reallocate */
screens = realloc (screens, num_screens);
if (screens == NULL)
exit (1);
#else
num_screens = 1;
screens = calloc(1, sizeof(screen_t));
screens[0].x = 0;
screens[0].width = bar_width;
else
#endif
if (num_screens == 0)
{
num_screens = 1;
screens = calloc(1, sizeof(screen_t));
if (screens == NULL)
exit(1);
screens[0].x = 0;
screens[0].width = bar_width;
}
/* Create the main window */
win = xcb_generate_id (c);