Add support for named rand outputs
This commit is contained in:
parent
89010c508d
commit
170a7261fa
|
@ -24,6 +24,10 @@ Display the help and exit.
|
|||
|
||||
Set the window geometry. If a parameter is omitted it's filled with the default value. If the I<y> parameter is specified along with the B<-b> switch then the position is relative to the bottom of the screen.
|
||||
|
||||
=item B<-o> I<name>
|
||||
|
||||
Set next output to I<name>. May be used multiple times; order is significant. If any B<-o> options are given, only B<-o> specified monitors will be used. Invalid output names are silently ignored. (only supported on randr configurations at this time)
|
||||
|
||||
=item B<-b>
|
||||
|
||||
Dock the bar at the bottom of the screen.
|
||||
|
@ -143,6 +147,11 @@ First/last monitor.
|
|||
|
||||
Nth monitor.
|
||||
|
||||
=item I<n>B<NAME>
|
||||
|
||||
Named monitor.
|
||||
Eg. I<%{SnHDMI-0} This text will show up on the HDMI-0 output>
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
|
173
lemonbar.c
173
lemonbar.c
|
@ -41,7 +41,8 @@ typedef struct font_t {
|
|||
} font_t;
|
||||
|
||||
typedef struct monitor_t {
|
||||
int x, y, width;
|
||||
char *name;
|
||||
int x, y, width, height;
|
||||
xcb_window_t window;
|
||||
xcb_pixmap_t pixmap;
|
||||
struct monitor_t *prev, *next;
|
||||
|
@ -127,6 +128,8 @@ static XftDraw *xft_draw;
|
|||
#define MAX_WIDTHS (1 << 16)
|
||||
static wchar_t xft_char[MAX_WIDTHS];
|
||||
static char xft_width[MAX_WIDTHS];
|
||||
static int num_outputs = 0;
|
||||
static char **output_names = NULL;
|
||||
|
||||
void
|
||||
update_gc (void)
|
||||
|
@ -652,6 +655,15 @@ parse (char *text)
|
|||
{ cur_mon = monhead; }
|
||||
else if (*p == 'l')
|
||||
{ cur_mon = montail ? montail : monhead; }
|
||||
else if (*p == 'n')
|
||||
{ cur_mon = monhead;
|
||||
while (cur_mon->next) {
|
||||
if (cur_mon->name && !strncmp(cur_mon->name, p+1, (block_end-p)-1)) {
|
||||
break;
|
||||
}
|
||||
cur_mon = cur_mon->next;
|
||||
}
|
||||
}
|
||||
else if (isdigit(*p))
|
||||
{ cur_mon = monhead;
|
||||
for (int i = 0; i != *p-'0' && cur_mon->next; i++)
|
||||
|
@ -900,7 +912,7 @@ set_ewmh_atoms (void)
|
|||
}
|
||||
|
||||
monitor_t *
|
||||
monitor_new (int x, int y, int width, int height)
|
||||
monitor_new (int x, int y, int width, int height, char *name)
|
||||
{
|
||||
monitor_t *ret;
|
||||
|
||||
|
@ -910,6 +922,7 @@ monitor_new (int x, int y, int width, int height)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret->name = name;
|
||||
ret->x = x;
|
||||
ret->y = (topbar ? by : height - bh - by) + y;
|
||||
ret->width = width;
|
||||
|
@ -947,17 +960,17 @@ monitor_add (monitor_t *mon)
|
|||
}
|
||||
|
||||
int
|
||||
rect_sort_cb (const void *p1, const void *p2)
|
||||
mon_sort_cb (const void *p1, const void *p2)
|
||||
{
|
||||
const xcb_rectangle_t *r1 = (xcb_rectangle_t *)p1;
|
||||
const xcb_rectangle_t *r2 = (xcb_rectangle_t *)p2;
|
||||
const monitor_t *m1 = (monitor_t *)p1;
|
||||
const monitor_t *m2 = (monitor_t *)p2;
|
||||
|
||||
if (r1->x < r2->x || r1->y + r1->height <= r2->y)
|
||||
if (m1->x < m2->x || m1->y + m1->height <= m2->y)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (r1->x > r2->x || r1->y + r1->height > r2->y)
|
||||
if (m1->x > m2->x || m1->y + m1->height > m2->y)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -966,19 +979,20 @@ rect_sort_cb (const void *p1, const void *p2)
|
|||
}
|
||||
|
||||
void
|
||||
monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
||||
monitor_create_chain (monitor_t *mons, const int num)
|
||||
{
|
||||
int i;
|
||||
int width = 0, height = 0;
|
||||
int left = bx;
|
||||
|
||||
// Sort before use
|
||||
qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb);
|
||||
if (!num_outputs)
|
||||
qsort(mons, num, sizeof(monitor_t), mon_sort_cb);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int h = rects[i].y + rects[i].height;
|
||||
int h = mons[i].y + mons[i].height;
|
||||
// Accumulated width of all monitors
|
||||
width += rects[i].width;
|
||||
width += mons[i].width;
|
||||
// Get height of screen from y_offset + height of lowest monitor
|
||||
if (h >= height)
|
||||
height = h;
|
||||
|
@ -1000,27 +1014,29 @@ monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
|||
// Left is a positive number or zero therefore monitors with zero width are excluded
|
||||
width = bw;
|
||||
for (i = 0; i < num; i++) {
|
||||
if (rects[i].y + rects[i].height < by)
|
||||
if (mons[i].y + mons[i].height < by)
|
||||
continue;
|
||||
if (rects[i].width > left) {
|
||||
if (mons[i].width > left) {
|
||||
monitor_t *mon = monitor_new(
|
||||
rects[i].x + left,
|
||||
rects[i].y,
|
||||
min(width, rects[i].width - left),
|
||||
rects[i].height);
|
||||
mons[i].x + left,
|
||||
mons[i].y,
|
||||
min(width, mons[i].width - left),
|
||||
mons[i].height,
|
||||
mons[i].name);
|
||||
|
||||
if (!mon)
|
||||
break;
|
||||
|
||||
monitor_add(mon);
|
||||
|
||||
width -= rects[i].width - left;
|
||||
width -= mons[i].width - left;
|
||||
|
||||
// No need to check for other monitors
|
||||
if (width <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
left -= rects[i].width;
|
||||
left -= mons[i].width;
|
||||
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
|
@ -1052,7 +1068,7 @@ get_randr_monitors (void)
|
|||
return;
|
||||
}
|
||||
|
||||
xcb_rectangle_t rects[num];
|
||||
monitor_t mons[num];
|
||||
|
||||
// Get all outputs
|
||||
for (i = 0; i < num; i++) {
|
||||
|
@ -1064,24 +1080,65 @@ get_randr_monitors (void)
|
|||
// Output disconnected or not attached to any CRTC ?
|
||||
if (!oi_reply || oi_reply->crtc == XCB_NONE || oi_reply->connection != XCB_RANDR_CONNECTION_CONNECTED) {
|
||||
free(oi_reply);
|
||||
rects[i].width = 0;
|
||||
mons[i].width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
ci_reply = xcb_randr_get_crtc_info_reply(c,
|
||||
xcb_randr_get_crtc_info(c, oi_reply->crtc, XCB_CURRENT_TIME), NULL);
|
||||
|
||||
free(oi_reply);
|
||||
|
||||
if (!ci_reply) {
|
||||
fprintf(stderr, "Failed to get RandR ctrc info\n");
|
||||
free(rres_reply);
|
||||
return;
|
||||
}
|
||||
|
||||
// There's no need to handle rotated screens here (see #69)
|
||||
rects[i] = (xcb_rectangle_t){ ci_reply->x, ci_reply->y, ci_reply->width, ci_reply->height };
|
||||
if (num_outputs) {
|
||||
for (j = 0; j < num_outputs; j++) {
|
||||
int namelen;
|
||||
uint8_t *str;
|
||||
char *name;
|
||||
|
||||
fprintf(stderr, "output_names: %s\n", output_names[j]);
|
||||
|
||||
// if this output name has been allocated, skip it
|
||||
if (!output_names[j])
|
||||
continue;
|
||||
|
||||
namelen = xcb_randr_get_output_info_name_length(oi_reply);
|
||||
name = malloc(namelen+1);
|
||||
|
||||
if (!name) {
|
||||
fprintf(stderr, "Failed to allocate randr output name\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
str = xcb_randr_get_output_info_name(oi_reply);
|
||||
memcpy(name, str, namelen);
|
||||
name[namelen] = '\0';
|
||||
|
||||
if (!memcmp(output_names[j], name, namelen)) {
|
||||
mons[j] = (monitor_t){ name, ci_reply->x, ci_reply->y, ci_reply->width, ci_reply->height, 0, 0, NULL, NULL };
|
||||
output_names[j] = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
free(name);
|
||||
}
|
||||
// if this output is not in the list, skip it
|
||||
if (j == num_outputs) {
|
||||
mons[i].width = 0;
|
||||
free(oi_reply);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There's no need to handle rotated screens here (see #69)
|
||||
mons[i] = (monitor_t){ NULL, ci_reply->x, ci_reply->y, ci_reply->width, ci_reply->height, 0, 0, NULL, NULL };
|
||||
}
|
||||
|
||||
|
||||
free(oi_reply);
|
||||
free(ci_reply);
|
||||
|
||||
valid++;
|
||||
|
@ -1089,18 +1146,21 @@ get_randr_monitors (void)
|
|||
|
||||
free(rres_reply);
|
||||
|
||||
if (num_outputs)
|
||||
free(output_names);
|
||||
|
||||
// Check for clones and inactive outputs
|
||||
for (i = 0; i < num; i++) {
|
||||
if (rects[i].width == 0)
|
||||
if (mons[i].width == 0)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < num; j++) {
|
||||
// Does I contain J ?
|
||||
|
||||
if (i != j && rects[j].width) {
|
||||
if (rects[j].x >= rects[i].x && rects[j].x + rects[j].width <= rects[i].x + rects[i].width &&
|
||||
rects[j].y >= rects[i].y && rects[j].y + rects[j].height <= rects[i].y + rects[i].height) {
|
||||
rects[j].width = 0;
|
||||
if (i != j && mons[j].width && !mons[j].name) {
|
||||
if (mons[j].x >= mons[i].x && mons[j].x + mons[j].width <= mons[i].x + mons[i].width &&
|
||||
mons[j].y >= mons[i].y && mons[j].y + mons[j].height <= mons[i].y + mons[i].height) {
|
||||
mons[j].width = 0;
|
||||
valid--;
|
||||
}
|
||||
}
|
||||
|
@ -1112,13 +1172,13 @@ get_randr_monitors (void)
|
|||
return;
|
||||
}
|
||||
|
||||
xcb_rectangle_t r[valid];
|
||||
monitor_t m[valid];
|
||||
|
||||
for (i = j = 0; i < num && j < valid; i++)
|
||||
if (rects[i].width != 0)
|
||||
r[j++] = rects[i];
|
||||
if (mons[i].width != 0)
|
||||
m[j++] = mons[i];
|
||||
|
||||
monitor_create_chain(r, valid);
|
||||
monitor_create_chain(m, valid);
|
||||
}
|
||||
|
||||
#ifdef WITH_XINERAMA
|
||||
|
@ -1129,26 +1189,32 @@ get_xinerama_monitors (void)
|
|||
xcb_xinerama_screen_info_iterator_t iter;
|
||||
int screens;
|
||||
|
||||
if (num_outputs) {
|
||||
fprintf(stderr, "Using output names with Xinerama is not yet supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
xqs_reply = xcb_xinerama_query_screens_reply(c,
|
||||
xcb_xinerama_query_screens_unchecked(c), NULL);
|
||||
|
||||
iter = xcb_xinerama_query_screens_screen_info_iterator(xqs_reply);
|
||||
screens = iter.rem;
|
||||
|
||||
xcb_rectangle_t rects[screens];
|
||||
monitor_t mons[screens];
|
||||
|
||||
// Fetch all the screens first
|
||||
for (int i = 0; iter.rem; i++) {
|
||||
rects[i].x = iter.data->x_org;
|
||||
rects[i].y = iter.data->y_org;
|
||||
rects[i].width = iter.data->width;
|
||||
rects[i].height = iter.data->height;
|
||||
mons[i].name = NULL;
|
||||
mons[i].x = iter.data->x_org;
|
||||
mons[i].y = iter.data->y_org;
|
||||
mons[i].width = iter.data->width;
|
||||
mons[i].height = iter.data->height;
|
||||
xcb_xinerama_screen_info_next(&iter);
|
||||
}
|
||||
|
||||
free(xqs_reply);
|
||||
|
||||
monitor_create_chain(rects, screens);
|
||||
monitor_create_chain(mons, screens);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1223,6 +1289,20 @@ parse_geometry_string (char *str, int *tmp)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parse_output_string(char *str)
|
||||
{
|
||||
if (!str || !*str)
|
||||
return;
|
||||
num_outputs++;
|
||||
output_names = realloc(output_names, num_outputs * sizeof(char *));
|
||||
if (!output_names) {
|
||||
fprintf(stderr, "failed to allocate output name\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
output_names[num_outputs-1] = str;
|
||||
}
|
||||
|
||||
void
|
||||
xconn (void)
|
||||
{
|
||||
|
@ -1301,6 +1381,10 @@ init (char *wm_name, char *wm_instance)
|
|||
#endif
|
||||
|
||||
if (!monhead) {
|
||||
if (num_outputs) {
|
||||
fprintf(stderr, "Failed to find any specified outputs\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// If I fits I sits
|
||||
if (bw < 0)
|
||||
bw = scr->width_in_pixels - bx;
|
||||
|
@ -1316,7 +1400,7 @@ init (char *wm_name, char *wm_instance)
|
|||
}
|
||||
|
||||
// If no RandR outputs or Xinerama screens, fall back to using whole screen
|
||||
monhead = monitor_new(0, 0, bw, scr->height_in_pixels);
|
||||
monhead = monitor_new(0, 0, bw, scr->height_in_pixels, NULL);
|
||||
}
|
||||
|
||||
if (!monhead)
|
||||
|
@ -1472,11 +1556,11 @@ main (int argc, char **argv)
|
|||
// Connect to the Xserver and initialize scr
|
||||
xconn();
|
||||
|
||||
while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:U:n:o:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "hg:o:bdf:a:pu:B:F:U:n:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
printf ("lemonbar version %s patched with XFT support\n", VERSION);
|
||||
printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -n | -u | -B | -F]\n"
|
||||
printf ("lemonbar version %s\n", VERSION);
|
||||
printf ("usage: %s [-h | -o | -g | -b | -d | -f | -a | -p | -n | -u | -B | -F]\n"
|
||||
"\t-h Show this help\n"
|
||||
"\t-g Set the bar geometry {width}x{height}+{xoffset}+{yoffset}\n"
|
||||
"\t-b Put the bar at the bottom of the screen\n"
|
||||
|
@ -1491,6 +1575,7 @@ main (int argc, char **argv)
|
|||
"\t-o Add a vertical offset to the text, it can be negative\n", argv[0]);
|
||||
exit (EXIT_SUCCESS);
|
||||
case 'g': (void)parse_geometry_string(optarg, geom_v); break;
|
||||
case 'o': (void)parse_output_string(optarg); break;
|
||||
case 'p': permanent = true; break;
|
||||
case 'n': wm_name = strdup(optarg); break;
|
||||
case 'b': topbar = false; break;
|
||||
|
|
Loading…
Reference in New Issue
Block a user