add support for smart windows placement in floating layout

This commit is contained in:
Julien Danjou 2008-01-28 18:30:23 +01:00
parent e233c2bfab
commit ea57fd8fc9
8 changed files with 150 additions and 14 deletions

View File

@ -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)))

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;