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 *fg_color = "#000000";
|
||||||
const char *bg_color = "#ffffff";
|
const char *bg_color = "#ffffff";
|
||||||
int opt;
|
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;
|
XftFont *font = NULL;
|
||||||
|
|
||||||
if(!(disp = XOpenDisplay(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;
|
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
|
/** Manage a new client
|
||||||
* \param w The window
|
* \param w The window
|
||||||
* \param wa Window attributes
|
* \param wa Window attributes
|
||||||
|
@ -307,6 +348,8 @@ client_manage(Window w, XWindowAttributes *wa, int screen)
|
||||||
client_setfloating(c, rettrans || c->isfixed);
|
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);
|
XSelectInput(globalconf.display, w, StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
|
||||||
|
|
||||||
/* handle xshape */
|
/* handle xshape */
|
||||||
|
|
|
@ -321,7 +321,7 @@ draw_image(DrawCtx *ctx, int x, int y, int wanted_h, const char *filename)
|
||||||
Area
|
Area
|
||||||
draw_get_image_size(const char *filename)
|
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_surface_t *surface;
|
||||||
cairo_status_t cairo_st;
|
cairo_status_t cairo_st;
|
||||||
|
|
||||||
|
@ -428,4 +428,67 @@ draw_color_new(Display *disp, int phys_screen, const char *colstr)
|
||||||
return screenColor;
|
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
|
// 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/Xlib.h>
|
||||||
#include <X11/Xft/Xft.h>
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "common/list.h"
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
AlignLeft,
|
AlignLeft,
|
||||||
|
@ -34,14 +37,23 @@ typedef enum
|
||||||
AlignCenter
|
AlignCenter
|
||||||
} Alignment;
|
} Alignment;
|
||||||
|
|
||||||
typedef struct
|
typedef struct Area Area;
|
||||||
|
struct Area
|
||||||
{
|
{
|
||||||
/* Co-ords of upper left corner */
|
/** Co-ords of upper left corner */
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
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 */
|
/** Check if coordinates matches given area */
|
||||||
static inline Bool
|
static inline Bool
|
||||||
|
@ -54,10 +66,25 @@ area_match_coords(Area geometry, int x, int y)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Bool
|
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)
|
return (b.x < a.x + a.width
|
||||||
&& area_match_coords(a, b.x + b.width, b.y + b.height));
|
&& 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
|
typedef struct
|
||||||
|
@ -89,5 +116,7 @@ unsigned short draw_textwidth(Display *, XftFont *, char *);
|
||||||
Alignment draw_get_align(const char *);
|
Alignment draw_get_align(const char *);
|
||||||
XColor draw_color_new(Display *, int, const char *);
|
XColor draw_color_new(Display *, int, const char *);
|
||||||
|
|
||||||
|
void area_list_remove(Area **, Area *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
// 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;
|
Client *c = globalconf.focus->client;
|
||||||
Tag **curtags = get_current_tags(screen);
|
Tag **curtags = get_current_tags(screen);
|
||||||
Layout *layout = curtags[0]->layout;
|
Layout *layout = curtags[0]->layout;
|
||||||
Area area = { 0, 0, 0, 0 }, geometry;
|
Area area = { 0, 0, 0, 0 , NULL}, geometry;
|
||||||
double mwfact;
|
double mwfact;
|
||||||
|
|
||||||
/* only handle floating and tiled layouts */
|
/* 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
|
Area
|
||||||
get_display_area(int screen, Statusbar *statusbar, Padding *padding)
|
get_display_area(int screen, Statusbar *statusbar, Padding *padding)
|
||||||
{
|
{
|
||||||
Area area;
|
Area area = { 0, 0, 0, 0, NULL };
|
||||||
Statusbar *sb;
|
Statusbar *sb;
|
||||||
|
|
||||||
area.x = 0;
|
|
||||||
area.y = 0;
|
|
||||||
area.width = DisplayWidth(globalconf.display, screen);
|
area.width = DisplayWidth(globalconf.display, screen);
|
||||||
area.height = DisplayHeight(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.y = si.y_org;
|
||||||
a.width = si.width;
|
a.width = si.width;
|
||||||
a.height = si.height;
|
a.height = si.height;
|
||||||
|
a.next = NULL;
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ statusbar_draw(Statusbar *statusbar)
|
||||||
int phys_screen = get_phys_screen(statusbar->screen);
|
int phys_screen = get_phys_screen(statusbar->screen);
|
||||||
Widget *widget, *last_drawn = NULL;
|
Widget *widget, *last_drawn = NULL;
|
||||||
int left = 0, right = 0;
|
int left = 0, right = 0;
|
||||||
Area rectangle = { 0, 0, 0, 0 };
|
Area rectangle = { 0, 0, 0, 0, NULL };
|
||||||
Drawable d;
|
Drawable d;
|
||||||
|
|
||||||
/* don't waste our time */
|
/* don't waste our time */
|
||||||
|
|
|
@ -113,7 +113,8 @@ taglist_draw(Widget *widget,
|
||||||
Area rectangle = { widget->area.x + widget->area.width,
|
Area rectangle = { widget->area.x + widget->area.width,
|
||||||
widget->area.y,
|
widget->area.y,
|
||||||
flagsize,
|
flagsize,
|
||||||
flagsize };
|
flagsize,
|
||||||
|
NULL };
|
||||||
draw_rectangle(ctx, rectangle, sel && is_client_tagged(sel, tag), colors[ColFG]);
|
draw_rectangle(ctx, rectangle, sel && is_client_tagged(sel, tag), colors[ColFG]);
|
||||||
}
|
}
|
||||||
widget->area.width += w;
|
widget->area.width += w;
|
||||||
|
|
Loading…
Reference in New Issue