Support for RandR
This should allow lemonbar to dynamically detect and handle RandR changes. When ever a RandR ouput change notification is received we fetch all the randr monitors and resize the bars to fit them. Creating new ones where they are missing.
This commit is contained in:
parent
3020df1923
commit
0d6f35383b
185
lemonbar.c
185
lemonbar.c
|
@ -85,6 +85,7 @@ static xcb_screen_t *scr;
|
|||
static xcb_gcontext_t gc[GC_MAX];
|
||||
static xcb_visualid_t visual;
|
||||
static xcb_colormap_t colormap;
|
||||
static const xcb_query_extension_reply_t *randr;
|
||||
static monitor_t *monhead, *montail;
|
||||
static font_t *font_list[MAX_FONT_COUNT];
|
||||
static int font_count = 0;
|
||||
|
@ -92,6 +93,7 @@ static int font_index = -1;
|
|||
static uint32_t attrs = 0;
|
||||
static bool dock = false;
|
||||
static bool topbar = true;
|
||||
static char *wm_name;
|
||||
static int bw = -1, bh = -1, bx = 0, by = 0;
|
||||
static int bu = 1; // Underline height
|
||||
static rgba_t fgc, bgc, ugc;
|
||||
|
@ -731,7 +733,7 @@ set_ewmh_atoms (void)
|
|||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_DESKTOP], XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){ -1 } );
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_STRUT_PARTIAL], XCB_ATOM_CARDINAL, 32, 12, strut);
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_STRUT], XCB_ATOM_CARDINAL, 32, 4, strut);
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 3, "bar");
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 3, wm_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -801,23 +803,8 @@ rect_sort_cb (const void *p1, const void *p2)
|
|||
}
|
||||
|
||||
void
|
||||
monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
||||
bar_calculate_size (int width, int height)
|
||||
{
|
||||
int i;
|
||||
int width = 0, height = 0;
|
||||
int left = bx;
|
||||
|
||||
// Sort before use
|
||||
qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int h = rects[i].y + rects[i].height;
|
||||
// Accumulated width of all monitors
|
||||
width += rects[i].width;
|
||||
// Get height of screen from y_offset + height of lowest monitor
|
||||
if (h >= height)
|
||||
height = h;
|
||||
}
|
||||
|
||||
if (bw < 0)
|
||||
bw = width - bx;
|
||||
|
@ -831,6 +818,35 @@ monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
|||
fprintf(stderr, "The geometry specified doesn't fit the screen!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
calculate_screen_size(xcb_rectangle_t *rects, const int num, int* width, int* height)
|
||||
{
|
||||
int i;
|
||||
// Sort before use
|
||||
qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int h = rects[i].y + rects[i].height;
|
||||
// Accumulated width of all monitors
|
||||
*width += rects[i].width;
|
||||
// Get height of screen from y_offset + height of lowest monitor
|
||||
if (h >= *height)
|
||||
*height = h;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
||||
{
|
||||
int i;
|
||||
int width = 0, height = 0;
|
||||
int left = bx;
|
||||
|
||||
calculate_screen_size(rects, num, &width, &height);
|
||||
|
||||
bar_calculate_size(width, height);
|
||||
|
||||
// Left is a positive number or zero therefore monitors with zero width are excluded
|
||||
width = bw;
|
||||
|
@ -863,6 +879,77 @@ monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
monitor_update_chain (xcb_rectangle_t *rects, const int num)
|
||||
{
|
||||
int i;
|
||||
int width = 0, height = 0;
|
||||
int left = bx;
|
||||
|
||||
calculate_screen_size(rects, num, &width, &height);
|
||||
|
||||
bar_calculate_size(width, height);
|
||||
|
||||
// Left is a positive number or zero therefore monitors with zero width are excluded
|
||||
width = bw;
|
||||
monitor_t *this = monhead;
|
||||
for (i = 0; i < num; i++) {
|
||||
if (rects[i].y + rects[i].height < by)
|
||||
continue;
|
||||
if (rects[i].width > left) {
|
||||
if (this == NULL) {
|
||||
this = monitor_new(
|
||||
rects[i].x + left,
|
||||
rects[i].y,
|
||||
min(width, rects[i].width - left),
|
||||
rects[i].height);
|
||||
|
||||
if (!this)
|
||||
break;
|
||||
|
||||
monitor_add(this);
|
||||
} else {
|
||||
this->x = rects[i].x + left;
|
||||
this->y = (topbar ? by : height - bh - by) + rects[i].y;
|
||||
this->width = min(width, rects[i].width - left);
|
||||
|
||||
xcb_configure_window(c, this->window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, (const uint32_t []){ this->x, this->y, this->width, bh });
|
||||
|
||||
xcb_free_pixmap(c, this->pixmap);
|
||||
this->pixmap = xcb_generate_id(c);
|
||||
int depth = (visual == scr->root_visual) ? XCB_COPY_FROM_PARENT : 32;
|
||||
xcb_create_pixmap(c, depth, this->pixmap, this->window, this->width, bh);
|
||||
|
||||
}
|
||||
this = this->next;
|
||||
|
||||
width -= rects[i].width - left;
|
||||
|
||||
// No need to check for other monitors
|
||||
if (width <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
left -= rects[i].width;
|
||||
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
}
|
||||
|
||||
//Do we have too many monitors (Some were disconnected)
|
||||
if(this) {
|
||||
montail = this->prev;
|
||||
this->prev->next = NULL;
|
||||
while(this) {
|
||||
monitor_t *next = this->next;
|
||||
xcb_destroy_window(c, this->window);
|
||||
xcb_free_pixmap(c, this->window);
|
||||
free(this);
|
||||
this = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
get_randr_monitors (void)
|
||||
{
|
||||
|
@ -954,7 +1041,10 @@ get_randr_monitors (void)
|
|||
if (rects[i].width != 0)
|
||||
r[j++] = rects[i];
|
||||
|
||||
monitor_create_chain(r, valid);
|
||||
if (!monhead)
|
||||
monitor_create_chain(r, valid);
|
||||
else
|
||||
monitor_update_chain(r, valid);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1076,10 +1166,26 @@ xconn (void)
|
|||
|
||||
colormap = xcb_generate_id(c);
|
||||
xcb_create_colormap(c, XCB_COLORMAP_ALLOC_NONE, colormap, scr->root, visual);
|
||||
|
||||
randr = xcb_get_extension_data(c, &xcb_randr_id);
|
||||
xcb_randr_select_input(c, scr->root, XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE);
|
||||
}
|
||||
|
||||
void
|
||||
init (char *wm_name)
|
||||
map_monitors (void)
|
||||
{
|
||||
for (monitor_t *mon = monhead; mon; mon = mon->next) {
|
||||
fill_rect(mon->pixmap, gc[GC_CLEAR], 0, 0, mon->width, bh);
|
||||
xcb_map_window(c, mon->window);
|
||||
|
||||
// Make sure that the window really gets in the place it's supposed to be
|
||||
// Some WM such as Openbox need this
|
||||
xcb_configure_window(c, mon->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, (const uint32_t []){ mon->x, mon->y });
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init (void)
|
||||
{
|
||||
// Try to load a default font
|
||||
if (!font_count)
|
||||
|
@ -1159,19 +1265,7 @@ init (char *wm_name)
|
|||
gc[GC_ATTR] = xcb_generate_id(c);
|
||||
xcb_create_gc(c, gc[GC_ATTR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ ugc.v });
|
||||
|
||||
// Make the bar visible and clear the pixmap
|
||||
for (monitor_t *mon = monhead; mon; mon = mon->next) {
|
||||
fill_rect(mon->pixmap, gc[GC_CLEAR], 0, 0, mon->width, bh);
|
||||
xcb_map_window(c, mon->window);
|
||||
|
||||
// Make sure that the window really gets in the place it's supposed to be
|
||||
// Some WM such as Openbox need this
|
||||
xcb_configure_window(c, mon->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, (const uint32_t []){ mon->x, mon->y });
|
||||
|
||||
// Set the WM_NAME atom to the user specified value
|
||||
if (wm_name)
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, monhead->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8 ,strlen(wm_name), wm_name);
|
||||
}
|
||||
map_monitors();
|
||||
|
||||
xcb_flush(c);
|
||||
}
|
||||
|
@ -1228,7 +1322,6 @@ main (int argc, char **argv)
|
|||
bool permanent = false;
|
||||
int geom_v[4] = { -1, -1, 0, 0 };
|
||||
int ch, areas;
|
||||
char *wm_name;
|
||||
|
||||
// Install the parachute!
|
||||
atexit(cleanup);
|
||||
|
@ -1242,7 +1335,7 @@ main (int argc, char **argv)
|
|||
|
||||
// A safe default
|
||||
areas = 10;
|
||||
wm_name = NULL;
|
||||
wm_name = "bar";
|
||||
|
||||
// Connect to the Xserver and initialize scr
|
||||
xconn();
|
||||
|
@ -1300,7 +1393,7 @@ main (int argc, char **argv)
|
|||
by = geom_v[3];
|
||||
|
||||
// Do the heavy lifting
|
||||
init(wm_name);
|
||||
init();
|
||||
// Get the fd to Xserver
|
||||
pollin[1].fd = xcb_get_file_descriptor(c);
|
||||
|
||||
|
@ -1327,7 +1420,8 @@ main (int argc, char **argv)
|
|||
while ((ev = xcb_poll_for_event(c))) {
|
||||
expose_ev = (xcb_expose_event_t *)ev;
|
||||
|
||||
switch (ev->response_type & 0x7F) {
|
||||
uint8_t type = ev->response_type & 0x7F;
|
||||
switch (type) {
|
||||
case XCB_EXPOSE:
|
||||
if (expose_ev->count == 0)
|
||||
redraw = true;
|
||||
|
@ -1343,6 +1437,25 @@ main (int argc, char **argv)
|
|||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(type == randr->first_event + XCB_RANDR_NOTIFY) {
|
||||
xcb_randr_notify_event_t *event = (void *)ev;
|
||||
switch(event->subCode) {
|
||||
case XCB_RANDR_NOTIFY_OUTPUT_CHANGE:
|
||||
bw = geom_v[0];
|
||||
bh = geom_v[1];
|
||||
bx = geom_v[2];
|
||||
by = geom_v[3];
|
||||
get_randr_monitors();
|
||||
set_ewmh_atoms();
|
||||
map_monitors();
|
||||
parse(input);
|
||||
redraw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(ev);
|
||||
|
|
Loading…
Reference in New Issue
Block a user