From ea57fd8fc9e55e0240f04e061121b6ec72ae369b Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 28 Jan 2008 18:30:23 +0100 Subject: [PATCH] add support for smart windows placement in floating layout --- awesome-message.c | 3 ++- client.c | 43 +++++++++++++++++++++++++++++++ common/draw.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++- common/draw.h | 41 +++++++++++++++++++++++++----- mouse.c | 2 +- screen.c | 5 ++-- statusbar.c | 2 +- widgets/taglist.c | 3 ++- 8 files changed, 150 insertions(+), 14 deletions(-) diff --git a/awesome-message.c b/awesome-message.c index 05458cea2..800cedd5c 100644 --- a/awesome-message.c +++ b/awesome-message.c @@ -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))) diff --git a/client.c b/client.c index de2024fca..bb2fd59bb 100644 --- a/client.c +++ b/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 */ diff --git a/common/draw.c b/common/draw.c index 319f35185..753015ff9 100644 --- a/common/draw.c +++ b/common/draw.c @@ -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 diff --git a/common/draw.h b/common/draw.h index 6556453b6..50857d215 100644 --- a/common/draw.h +++ b/common/draw.h @@ -26,6 +26,9 @@ #include #include +#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 diff --git a/mouse.c b/mouse.c index dd0f1042c..9706cec53 100644 --- a/mouse.c +++ b/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 */ diff --git a/screen.c b/screen.c index 7a89cd1a6..ad22c69b4 100644 --- a/screen.c +++ b/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; } diff --git a/statusbar.c b/statusbar.c index 8802453a5..efb0dd2d2 100644 --- a/statusbar.c +++ b/statusbar.c @@ -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 */ diff --git a/widgets/taglist.c b/widgets/taglist.c index 617d169f0..8cdf42b08 100644 --- a/widgets/taglist.c +++ b/widgets/taglist.c @@ -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;