add support for smart windows placement in floating layout
This commit is contained in:
parent
e233c2bfab
commit
ea57fd8fc9
|
@ -47,7 +47,8 @@ main(int argc, char **argv)
|
|||
const char *fg_color = "#000000";
|
||||
const char *bg_color = "#ffffff";
|
||||
int opt;
|
||||
Area geometry = { 0, 0, 200, 50 }, icon_geometry = { -1, -1, -1, -1 };
|
||||
Area geometry = { 0, 0, 200, 50, NULL },
|
||||
icon_geometry = { -1, -1, -1, -1, NULL };
|
||||
XftFont *font = NULL;
|
||||
|
||||
if(!(disp = XOpenDisplay(NULL)))
|
||||
|
|
43
client.c
43
client.c
|
@ -212,6 +212,47 @@ client_focus(Client *c, int screen, Bool from_mouse)
|
|||
globalconf.drop_events |= EnterWindowMask;
|
||||
}
|
||||
|
||||
/** Compute smart coordinates for a client window
|
||||
* \param geometry current/requested client geometry
|
||||
* \param screen screen used
|
||||
* \return new geometry
|
||||
*/
|
||||
static Area
|
||||
client_get_smart_geometry(Area geometry, int screen)
|
||||
{
|
||||
Client *c;
|
||||
Area newgeometry = { 0, 0, 0, 0, NULL };
|
||||
Area *screen_geometry, *arealist = NULL, *r;
|
||||
|
||||
screen_geometry = p_new(Area, 1);
|
||||
|
||||
*screen_geometry = get_screen_area(screen,
|
||||
globalconf.screens[screen].statusbar,
|
||||
&globalconf.screens[screen].padding);
|
||||
|
||||
area_list_push(&arealist, screen_geometry);
|
||||
|
||||
for(c = globalconf.clients; c; c = c->next)
|
||||
if(client_isvisible(c, screen))
|
||||
area_list_remove(&arealist, &c->f_geometry);
|
||||
|
||||
newgeometry.x = geometry.x;
|
||||
newgeometry.y = geometry.y;
|
||||
|
||||
for(r = arealist; r; r = r->next)
|
||||
if(r->width >= geometry.width && r->height >= geometry.height
|
||||
&& r->width * r->height > newgeometry.width * newgeometry.height)
|
||||
newgeometry = *r;
|
||||
|
||||
area_list_wipe(&arealist);
|
||||
|
||||
/* restore height and width */
|
||||
newgeometry.width = geometry.width;
|
||||
newgeometry.height = geometry.height;
|
||||
|
||||
return newgeometry;
|
||||
}
|
||||
|
||||
/** Manage a new client
|
||||
* \param w The window
|
||||
* \param wa Window attributes
|
||||
|
@ -307,6 +348,8 @@ client_manage(Window w, XWindowAttributes *wa, int screen)
|
|||
client_setfloating(c, rettrans || c->isfixed);
|
||||
}
|
||||
|
||||
c->f_geometry = client_get_smart_geometry(c->f_geometry, c->screen);
|
||||
|
||||
XSelectInput(globalconf.display, w, StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
|
||||
|
||||
/* handle xshape */
|
||||
|
|
|
@ -321,7 +321,7 @@ draw_image(DrawCtx *ctx, int x, int y, int wanted_h, const char *filename)
|
|||
Area
|
||||
draw_get_image_size(const char *filename)
|
||||
{
|
||||
Area size = { -1, -1, -1, -1 };
|
||||
Area size = { -1, -1, -1, -1, NULL };
|
||||
cairo_surface_t *surface;
|
||||
cairo_status_t cairo_st;
|
||||
|
||||
|
@ -428,4 +428,67 @@ draw_color_new(Display *disp, int phys_screen, const char *colstr)
|
|||
return screenColor;
|
||||
}
|
||||
|
||||
/** Remove a area from a list of them,
|
||||
* spliting the space between several area that
|
||||
* can overlaps
|
||||
* \param head list head
|
||||
* \param elem area to remove
|
||||
*/
|
||||
void
|
||||
area_list_remove(Area **head, Area *elem)
|
||||
{
|
||||
Area *r, inter, *extra;
|
||||
|
||||
area_list_detach(head, elem);
|
||||
|
||||
for(r = *head; r; r = r->next)
|
||||
if(area_intersect_area(*r, *elem))
|
||||
{
|
||||
/* remove it from the list */
|
||||
area_list_detach(head, r);
|
||||
|
||||
inter = area_get_intersect_area(*r, *elem);
|
||||
|
||||
if(AREA_LEFT(inter) > AREA_LEFT(*r))
|
||||
{
|
||||
extra = p_new(Area, 1);
|
||||
extra->x = r->x;
|
||||
extra->y = r->y;
|
||||
extra->width = AREA_LEFT(inter) - r->x;
|
||||
extra->height = r->height;
|
||||
area_list_push(head, extra);
|
||||
}
|
||||
|
||||
if(AREA_TOP(inter) > AREA_TOP(*r))
|
||||
{
|
||||
extra = p_new(Area, 1);
|
||||
extra->x = r->x;
|
||||
extra->y = r->y;
|
||||
extra->width = r->width;
|
||||
extra->height = AREA_TOP(inter) - r->y;
|
||||
area_list_push(head, extra);
|
||||
}
|
||||
|
||||
if(AREA_RIGHT(inter) < AREA_RIGHT(*r))
|
||||
{
|
||||
extra = p_new(Area, 1);
|
||||
extra->x = AREA_RIGHT(inter);
|
||||
extra->y = r->y;
|
||||
extra->width = AREA_RIGHT(*r) - AREA_RIGHT(inter);
|
||||
extra->height = r->height;
|
||||
area_list_push(head, extra);
|
||||
}
|
||||
|
||||
if(AREA_BOTTOM(inter) < AREA_BOTTOM(*r))
|
||||
{
|
||||
extra = p_new(Area, 1);
|
||||
extra->x = r->x;
|
||||
extra->y = AREA_BOTTOM(inter);
|
||||
extra->width = r->width;
|
||||
extra->height = AREA_BOTTOM(*r) - AREA_BOTTOM(inter);
|
||||
area_list_push(head, extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/list.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AlignLeft,
|
||||
|
@ -34,14 +37,23 @@ typedef enum
|
|||
AlignCenter
|
||||
} Alignment;
|
||||
|
||||
typedef struct
|
||||
typedef struct Area Area;
|
||||
struct Area
|
||||
{
|
||||
/* Co-ords of upper left corner */
|
||||
/** Co-ords of upper left corner */
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
} Area;
|
||||
Area *next;
|
||||
};
|
||||
|
||||
DO_SLIST(Area, area, p_delete);
|
||||
|
||||
#define AREA_LEFT(a) ((a).x)
|
||||
#define AREA_TOP(a) ((a).y)
|
||||
#define AREA_RIGHT(a) ((a).x + (a).width)
|
||||
#define AREA_BOTTOM(a) ((a).y + (a).height)
|
||||
|
||||
/** Check if coordinates matches given area */
|
||||
static inline Bool
|
||||
|
@ -54,10 +66,25 @@ area_match_coords(Area geometry, int x, int y)
|
|||
}
|
||||
|
||||
static inline Bool
|
||||
area_match_area(Area a, Area b)
|
||||
area_intersect_area(Area a, Area b)
|
||||
{
|
||||
return (area_match_coords(a, b.x, b.y)
|
||||
&& area_match_coords(a, b.x + b.width, b.y + b.height));
|
||||
return (b.x < a.x + a.width
|
||||
&& b.x + b.width > a.x
|
||||
&& b.y < a.y + a.height
|
||||
&& b.y + b.height > a.y);
|
||||
}
|
||||
|
||||
static inline Area
|
||||
area_get_intersect_area(Area a, Area b)
|
||||
{
|
||||
Area g;
|
||||
|
||||
g.x = MAX(a.x, b.x);
|
||||
g.y = MAX(a.y, b.y);
|
||||
g.width = MIN(a.x + a.width, b.x + b.width) - g.x;
|
||||
g.height = MIN(a.y + a.height, b.y + b.height) - g.y;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
@ -89,5 +116,7 @@ unsigned short draw_textwidth(Display *, XftFont *, char *);
|
|||
Alignment draw_get_align(const char *);
|
||||
XColor draw_color_new(Display *, int, const char *);
|
||||
|
||||
void area_list_remove(Area **, Area *);
|
||||
|
||||
#endif
|
||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
||||
|
|
2
mouse.c
2
mouse.c
|
@ -151,7 +151,7 @@ uicb_client_resizemouse(int screen, char *arg __attribute__ ((unused)))
|
|||
Client *c = globalconf.focus->client;
|
||||
Tag **curtags = get_current_tags(screen);
|
||||
Layout *layout = curtags[0]->layout;
|
||||
Area area = { 0, 0, 0, 0 }, geometry;
|
||||
Area area = { 0, 0, 0, 0 , NULL}, geometry;
|
||||
double mwfact;
|
||||
|
||||
/* only handle floating and tiled layouts */
|
||||
|
|
5
screen.c
5
screen.c
|
@ -82,11 +82,9 @@ get_screen_area(int screen, Statusbar *statusbar, Padding *padding)
|
|||
Area
|
||||
get_display_area(int screen, Statusbar *statusbar, Padding *padding)
|
||||
{
|
||||
Area area;
|
||||
Area area = { 0, 0, 0, 0, NULL };
|
||||
Statusbar *sb;
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = DisplayWidth(globalconf.display, screen);
|
||||
area.height = DisplayHeight(globalconf.display, screen);
|
||||
|
||||
|
@ -142,6 +140,7 @@ screen_xsi_to_area(XineramaScreenInfo si)
|
|||
a.y = si.y_org;
|
||||
a.width = si.width;
|
||||
a.height = si.height;
|
||||
a.next = NULL;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ statusbar_draw(Statusbar *statusbar)
|
|||
int phys_screen = get_phys_screen(statusbar->screen);
|
||||
Widget *widget, *last_drawn = NULL;
|
||||
int left = 0, right = 0;
|
||||
Area rectangle = { 0, 0, 0, 0 };
|
||||
Area rectangle = { 0, 0, 0, 0, NULL };
|
||||
Drawable d;
|
||||
|
||||
/* don't waste our time */
|
||||
|
|
|
@ -113,7 +113,8 @@ taglist_draw(Widget *widget,
|
|||
Area rectangle = { widget->area.x + widget->area.width,
|
||||
widget->area.y,
|
||||
flagsize,
|
||||
flagsize };
|
||||
flagsize,
|
||||
NULL };
|
||||
draw_rectangle(ctx, rectangle, sel && is_client_tagged(sel, tag), colors[ColFG]);
|
||||
}
|
||||
widget->area.width += w;
|
||||
|
|
Loading…
Reference in New Issue