diff --git a/src/clientwin.c b/src/clientwin.c index 82a6920..fceb2aa 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -31,7 +31,7 @@ clientwin_cmp_func(dlist *l, void *data) { return ((ClientWin*)l->data)->client.window == (Window)data; } - +//int g_all_desktops=1; int clientwin_validate_func(dlist *l, void *data) { ClientWin *cw = (ClientWin *)l->data; @@ -40,10 +40,11 @@ clientwin_validate_func(dlist *l, void *data) { CARD32 desktop = (*(CARD32*)data), w_desktop = wm_get_window_desktop(mw->ps->dpy, cw->client.window); + // Todo: resolve how multi-desktops vs multi-monitor works. #ifdef CFG_XINERAMA - if(mw->xin_active && ! INTERSECTS(cw->client.x, cw->client.y, cw->client.width, cw->client.height, + if(!(mw->ps->o.xinerama_showAll) && mw->xin_active && (!INTERSECTS(cw->client.x, cw->client.y, cw->client.width, cw->client.height, mw->xin_active->x_org, mw->xin_active->y_org, - mw->xin_active->width, mw->xin_active->height)) + mw->xin_active->width, mw->xin_active->height))) return 0; #endif @@ -200,11 +201,12 @@ static void clientwin_repaint(ClientWin *cw, XRectangle *rect) { XRenderColor *tint = cw->focused ? &cw->mainwin->highlightTint : &cw->mainwin->normalTint; - int s_x = (double)rect->x * cw->factor, +/* int s_x = (double)rect->x * cw->factor, s_y = (double)rect->y * cw->factor, s_w = (double)rect->width * cw->factor, s_h = (double)rect->height * cw->factor; - +*/ + int s_x=0,s_y=0, s_w=cw->mini.width, s_h=cw->mini.height; if(cw->mainwin->ps->o.lazyTrans) { XRenderComposite(cw->mainwin->ps->dpy, PictOpSrc, cw->origin, @@ -214,6 +216,7 @@ clientwin_repaint(ClientWin *cw, XRectangle *rect) else { XRenderComposite(cw->mainwin->ps->dpy, PictOpSrc, cw->mainwin->background, None, cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, s_x, s_y, s_w, s_h); + XRenderComposite(cw->mainwin->ps->dpy, PictOpOver, cw->origin, cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture, cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); @@ -230,8 +233,8 @@ clientwin_render(ClientWin *cw) { XRectangle rect; rect.x = rect.y = 0; - rect.width = cw->client.width; - rect.height = cw->client.height; + rect.width = cw->mini.width; + rect.height = cw->mini.height; clientwin_repaint(cw, &rect); } @@ -262,16 +265,12 @@ clientwin_schedule_repair(ClientWin *cw, XRectangle *area) cw->damaged = true; } -void -clientwin_move(ClientWin *cw, float f, int x, int y) -{ - /* int border = MAX(1, (double)DISTANCE(cw->mainwin) * f * 0.25); */ - int border = 0; - XSetWindowBorderWidth(cw->mainwin->ps->dpy, cw->mini.window, border); - - cw->factor = f; - cw->mini.x = x + (int)cw->x * f; - cw->mini.y = y + (int)cw->y * f; +// This functionality moved into layout -"layout_run_scale_all". +void clientwin_move_sub(ClientWin* cw, int dx,int dy,float f) { + printf("OBSELETE\n"); +// cw->factor = f; + cw->mini.x = dx + (int)cw->x * f; + cw->mini.y = dy + (int)cw->y * f; if(cw->mainwin->ps->o.lazyTrans) { cw->mini.x += cw->mainwin->x; @@ -279,6 +278,22 @@ clientwin_move(ClientWin *cw, float f, int x, int y) } cw->mini.width = MAX(1, (int)cw->client.width * f); cw->mini.height = MAX(1, (int)cw->client.height * f); + +} + + +void +clientwin_move_and_create_scaled_image(ClientWin *cw, float f, int dx, int dy) { + clientwin_move_sub(cw, dx,dy,f); + clientwin_create_scaled_image( cw); +} +void +clientwin_create_scaled_image(ClientWin *cw) +{ + /* int border = MAX(1, (double)DISTANCE(cw->mainwin) * f * 0.25); */ + int border = 0; + XSetWindowBorderWidth(cw->mainwin->ps->dpy, cw->mini.window, border); + XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); if(cw->pixmap) @@ -286,20 +301,49 @@ clientwin_move(ClientWin *cw, float f, int x, int y) if(cw->destination) XRenderFreePicture(cw->mainwin->ps->dpy, cw->destination); - + printf("create image %d %d %d %d\n",cw->mini.x,cw->mini.y, cw->mini.width,cw->mini.height); cw->pixmap = XCreatePixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.width, cw->mini.height, cw->mainwin->depth); XSetWindowBackgroundPixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->pixmap); cw->destination = XRenderCreatePicture(cw->mainwin->ps->dpy, cw->pixmap, cw->mini.format, 0, 0); } + +void +clientwin_lerp_client_to_mini(ClientWin* cw,float t){ + Rect2i dst_rc=sw_rect(&cw->mini); + Rect2i src_rc=sw_rect(&cw->client); + int denom=1<<12; + int ti=(int)(t*(float)denom); + Rect2i rc; + rc.min=v2i_lerp(src_rc.min,dst_rc.min, ti, denom); + rc.max=v2i_lerp(src_rc.max,dst_rc.max, ti, denom); + sw_set_rect(&cw->mini,&rc); +} + void clientwin_map(ClientWin *cw) { session_t *ps = cw->mainwin->ps; free_damage(ps, &cw->damage); cw->damage = XDamageCreate(ps->dpy, cw->client.window, XDamageReportDeltaRectangles); - XRenderSetPictureTransform(ps->dpy, cw->origin, &cw->mainwin->transform); + +// calculate transform for scaling.. + XTransform transform; + + transform.matrix[0][0] = XDoubleToFixed((float)cw->client.width/(float)cw->mini.width); + transform.matrix[0][1] = 0.0; + transform.matrix[0][2] = 0.0; + transform.matrix[1][0] = 0.0; + transform.matrix[1][1] = XDoubleToFixed((float)cw->client.height/(float)cw->mini.height); + transform.matrix[1][2] = 0.0; + transform.matrix[2][0] = 0.0; + transform.matrix[2][1] = 0.0; + transform.matrix[2][2] = XDoubleToFixed(1.0); + + XRenderSetPictureTransform(ps->dpy, cw->origin, &transform); + +// XRenderSetPictureTransform(ps->dpy, cw->origin, &cw->mainwin->transform); clientwin_render(cw); @@ -337,11 +381,13 @@ clientwin_unmap(ClientWin *cw) static void childwin_focus(ClientWin *cw) { - XWarpPointer(cw->mainwin->ps->dpy, None, cw->client.window, 0, 0, 0, 0, cw->client.width / 2, cw->client.height / 2); + // how to handle it offscreen? need to map to screen coords, if its outside, do this warp in screen space +// if (!cw->mainwin->ps->o.xinerama_showAll) + XWarpPointer(cw->mainwin->ps->dpy, None, cw->client.window, 0, 0, 0, 0, sw_width(&cw->client) / 2, sw_height(&cw->client) / 2); XRaiseWindow(cw->mainwin->ps->dpy, cw->client.window); XSetInputFocus(cw->mainwin->ps->dpy, cw->client.window, RevertToParent, CurrentTime); } - +extern int g_redo_layout; int clientwin_handle(ClientWin *cw, XEvent *ev) { session_t *ps = cw->mainwin->ps; @@ -378,6 +424,14 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { || ev->xkey.keycode == cw->mainwin->key_space) { childwin_focus(cw); return 1; + } else if (ev->xkey.keycode == cw->mainwin->key_page_up) { + ps->o.layout_grid^=true; + if (!(ps->o.layout_grid)) { ps->o.xinerama_showAll^=true;} + g_redo_layout=1; + } else if (ev->xkey.keycode == cw->mainwin->key_page_down) { + ps->o.layout_grid=true; + ps->o.xinerama_showAll=false; + g_redo_layout=1; } else report_key_unbinded(ev); diff --git a/src/clientwin.h b/src/clientwin.h index f8d87d6..beacc9a 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -20,10 +20,15 @@ #ifndef SKIPPY_CLIENT_H #define SKIPPY_CLIENT_H +//#define SW_POS_SIZE typedef struct { Window window; +#ifndef SW_POS_SIZE int x, y; unsigned int width, height; +#else + PosSize rect; +#endif XRenderPictFormat *format; } SkippyWindow; @@ -41,7 +46,6 @@ typedef struct { Pixmap pixmap; Picture origin, destination; Damage damage; - float factor; int focused; @@ -63,6 +67,9 @@ int clientwin_sort_func(dlist *, dlist *, void *); ClientWin *clientwin_create(struct _MainWin *, Window); void clientwin_destroy(ClientWin *, bool destroyed); void clientwin_move(ClientWin *, float, int, int); +void clientwin_create_scaled_image(ClientWin *cw); +void clientwin_move_and_create_scaled_image(ClientWin *cw, float f, int dx, int dy); + void clientwin_map(ClientWin *); void clientwin_unmap(ClientWin *); int clientwin_handle(ClientWin *, XEvent *); @@ -73,4 +80,60 @@ void clientwin_render(ClientWin *); void clientwin_schedule_repair(ClientWin *cw, XRectangle *area); void clientwin_repair(ClientWin *cw); +void +clientwin_lerp_client_to_mini(ClientWin* cw,float t); + +// accessors, less needed if code is refactored to use vec2i etc. +// bloats the headers whilst the change is in progress, can be search-replaced when done +// +// abreviations: +// +// sw_ SkippyWindow +// +// cw_ ClientWindow +// mw_ MainWindow + +#ifdef SW_POS_SIZE +inline Vec2i sw_pos(const SkippyWindow* w) { return w->rect.pos; } +inline Vec2i sw_size(const SkippyWindow* w) { return w->rect.size; } +inline void sw_set_pos(SkippyWindow* sw, const Vec2i p) { sw->rect.pos=p; } +inline void sw_set_size(SkippyWindow* sw, const Vec2i sz) { sw->rect.size=sz; } +inline void sw_set_rect(SkippyWindow* sw, const Rect2i* r) { sw_set_pos(sw,r->min); sw_set_size(sw, rect2i_size(r));} +inline int sw_width(const SkippyWindow* w) { return w->rect.size.x;} // => w->rect.size.x +inline int sw_height(const SkippyWindow* w) { return w->rect.size.y;} // => w->rect.size.y +inline int sw_x(const SkippyWindow* w) { return w->rect.pos.x;} // => w->rect.pos.x +inline int sw_y(const SkippyWindow* w) { return w->rect.pos.y;} // => w->rect.pos.y +#else +inline Vec2i sw_pos(const SkippyWindow* w) { return vec2i_mk(w->x,w->y); } +inline Vec2i sw_size(const SkippyWindow* w) { return vec2i_mk(w->width,w->height); } +inline void sw_set_pos(SkippyWindow* sw, const Vec2i p) { sw->x=p.x; sw->y=p.y; } +inline void sw_set_size(SkippyWindow* sw, const Vec2i sz) { sw->width=sz.x; sw->height=sz.y; } +inline void sw_set_rect(SkippyWindow* sw, const Rect2i* r) { sw_set_pos(sw,r->min); sw->width=r->max.x-r->min.x; sw->height=r->max.y-r->min.y;} +inline int sw_width(const SkippyWindow* w) { return w->width;} // => w->rect.size.x +inline int sw_height(const SkippyWindow* w) { return w->height;} // => w->rect.size.y +inline int sw_x(const SkippyWindow* w) { return w->x;} // => w->rect.pos.x +inline int sw_y(const SkippyWindow* w) { return w->y;} // => w->rect.pos.y +#endif +inline Vec2i sw_set_xy(SkippyWindow* sw,int x,int y) { sw_set_pos(sw,vec2i_mk(x,y)); } +inline Vec2i sw_set_width_height(SkippyWindow* sw,int w,int h) { sw_set_size(sw,vec2i_mk(w,h)); } +inline Rect2i sw_rect(const SkippyWindow* sw) { return rect2i_mk_at(sw_pos(sw),sw_size(sw));} +inline PosSize sw_pos_size(const SkippyWindow* sw) { return pos_size_mk(sw_pos(sw),sw_size(sw));} +inline void sw_set_pos_size(SkippyWindow* sw, const Vec2i p,const Vec2i sz) { sw_set_pos(sw,p); sw_set_size(sw,sz);} + + +inline Rect2i cw_client_rect(const ClientWin* w) { return rect2i_mk_at(sw_pos(&w->client),sw_size(&w->client));} +inline Rect2i cw_client_mini_rect(const ClientWin* w) { return rect2i_mk_at(sw_pos(&w->mini),sw_size(&w->mini));} +inline Vec2i cw_client_pos(const ClientWin* w) { return sw_pos(&w->client);} +inline Vec2i cw_client_size(const ClientWin* w) { return sw_size(&w->client);} +inline int cw_client_width(const ClientWin* w) { return sw_size(&w->client).x;} +inline int cw_client_height(const ClientWin* w) { return sw_size(&w->client).y;} +inline void cw_set_tmp_xy(ClientWin* w, int x, int y) { w->x = x; w->y=y;} +inline void cw_set_tmp_pos(ClientWin* w, Vec2i pos) { w->x = pos.x; w->y=pos.y;} +inline Vec2i cw_tmp_pos(ClientWin* w) { return vec2i_mk(w->x,w->y);} +inline float cw_client_aspect(const ClientWin* w) { Vec2i delta=sw_size(&w->client); return MAX(1,delta.x)/(float)MAX(1,delta.y);} +inline void cw_set_mini_size( ClientWin* w,Vec2i sz) { sw_set_size(&w->mini,sz);} +inline Vec2i cw_mini_centre(const ClientWin* cw) { return v2i_mad(sw_pos(&cw->mini), sw_size(&cw->mini), 1,2); } +inline Rect2i cw_mini_rect(const ClientWin* cw) { return sw_rect(&cw->mini); } +inline Vec2i cw_client_centre(const ClientWin* cw) { return v2i_mad(sw_pos(&cw->client), sw_size(&cw->client), 1,2); } +inline void cw_set_mini_rect(ClientWin* cw, const Rect2i* rc) { sw_set_rect(&cw->mini, rc);} #endif /* SKIPPY_CLIENT_H */ diff --git a/src/config.h b/src/config.h index 1663787..b720cda 100644 --- a/src/config.h +++ b/src/config.h @@ -131,5 +131,44 @@ config_get_double_wrap(dlist *config, const char *section, const char *key, *tgt = config_get_double(config, section, key, *tgt, min, max); } +/** + * @brief Get a float value from configuration. + */ +static inline float +config_get_float(dlist *config, const char *section, const char *key, + float def, float min, float max) { + const char *result = config_get(config, section, key, NULL); + if (!result) + return def; + char *endptr = NULL; + float fresult = strtof(result, &endptr); + if (!endptr || (*endptr && !isspace(*endptr))) { + printfef("(%s, %s, %f): Value \"%s\" is not a valid floating-point number.", + section, key, def, result); + return def; + } + if (fresult > max) { + printfef("(%s, %s, %f): Value \"%s\" larger than maximum value %f.", + section, key, def, result, max); + return max; + } + if (fresult < min) { + printfef("(%s, %s, %f): Value \"%s\" smaller than minimal value %f.", + section, key, def, result, min); + return min; + } + return fresult; +} + +/** + * @brief Wrapper of config_get_float(). + */ +static inline void +config_get_float_wrap(dlist *config, const char *section, const char *key, + float *tgt, float min, float max) { + *tgt = config_get_float(config, section, key, *tgt, min, max); +} + + #endif /* SKIPPY_CONFIG_H */ diff --git a/src/dlist.h b/src/dlist.h index 913375d..d146235 100644 --- a/src/dlist.h +++ b/src/dlist.h @@ -91,4 +91,9 @@ void dlist_swap(dlist *, dlist *); typedef int (*dlist_cmp_func)(dlist *, dlist *, void *); void dlist_sort(dlist *, dlist_cmp_func, void *); +/* Iteration helper macro */ +#define DLIST_FOREACH(TYPE,ITER_PTR,IN_LIST) for (dlist* iter=IN_LIST; iter;iter=iter->next){ TYPE* ITER_PTR=(TYPE*)(iter->data); +#define DLIST_NEXT } + + #endif /* SKIPPY_DLIST_H */ diff --git a/src/layout.c b/src/layout.c index 78fb3be..88a45b4 100644 --- a/src/layout.c +++ b/src/layout.c @@ -19,25 +19,102 @@ #include "skippy.h" +// TODO - layout which biases desktop sizes according to recent use. +// or grid mode including desktops placed as individual windows similar to gnomeshell +void layout_scale_all(const MainWin *mw, dlist *windows, Vec2i total_size); +void layout_original(int separation, dlist *windows, Vec2i* total_size); +void layout_desktop(MainWin *mw, dlist *windows, Vec2i* total_size); +void layout_grid(int separation, Vec2i size, dlist* windows); + +void +layout_run(MainWin *mw,LAYOUT_MODE mode, dlist *windows, Vec2i* total_size) +{ + Rect2i main_rect=rect2i_mk(vec2i_mk(0,0), mw_size(mw)); + if (mode==LAYOUT_DESKTOP){ + layout_desktop(mw,windows,total_size); + layout_scale_all(mw, windows, *total_size); + //fill_within_region(windows, &main_rect,false); + } else if (mode==LAYOUT_GRID) { + layout_grid(mw->distance, mw_size(mw),windows); + *total_size=mw_size(mw); + } else { + layout_original(mw->distance,windows,total_size); + layout_scale_all(mw, windows, *total_size); + } + +} + + + +void +layout_dump(const dlist* windows,Vec2i total_size) { + const dlist* iter; + for(iter = windows; iter; iter = iter->next){ + const ClientWin *cw = (const ClientWin*)iter->data; + printf("mini pos:%d,%d size= %d,%d/ %d %d\n",cw->x,cw->y,cw->mini.width,cw->mini.height, total_size.x, total_size.y); + } + +} + +void +windows_get_rect2i(Rect2i* ret,const dlist* windows) { + const dlist* iter; + *ret=rect2i_init(); + for (iter=windows; iter; iter=iter->next) { + const ClientWin* cw=(const ClientWin*) iter->data; + Rect2i cwr=cw_client_rect(cw); + rect2i_include_rect2i(ret, &cwr); + } +} + + + +void +layout_desktop(MainWin *mw, dlist *windows, Vec2i* total_size) +{ + // dumb grid layout; TODO: Find aspect ratios, use to calculate w/hoptimal + dlist* iter; + int num_win=dlist_len(windows); + + Rect2i rect_all; + windows_get_rect2i(&rect_all ,windows); + for (iter=windows; iter; iter=iter->next) { + ClientWin* cw=(ClientWin*) iter->data; + + Vec2i ofs_pos = v2i_sub(sw_pos(&cw->client), rect_all.min); + cw_set_tmp_pos(cw,ofs_pos); + } + Vec2i size_all=rect2i_size(&rect_all); + + *total_size=size_all; + //layout_dump(windows,total_width,total_height); + layout_scale_all(mw, windows, *total_size); + + +} + +// Skippy Original layout - Slot-together into rows adaptively +// void -layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) +layout_original(int separation, dlist *windows, Vec2i* total_size) { - int sum_w = 0, max_h = 0, max_w = 0, max_row_w = 0; +// mw->distance=8; + int sum_w = 0, max_row_w = 0; int row_y = 0, y = 0, x = 0, row_h = 0; + Vec2i max_win_size=vec2i_mk(0,0); dlist *iter, *slots = 0, *slot_iter, *rows; rows = dlist_add(0, 0); windows = dlist_first(windows); - *total_width = *total_height = 0; + *total_size=vec2i_mk(0,0); for(iter = windows; iter; iter = iter->next) { ClientWin *cw = (ClientWin *)iter->data; - sum_w += cw->client.width; - max_w = MAX(max_w, cw->client.width); - max_h = MAX(max_h, cw->client.height); + sum_w += cw_client_width(cw); + max_win_size = v2i_max(max_win_size, cw_client_size(cw)); } for(iter = windows; iter; iter = iter->next) @@ -47,9 +124,9 @@ layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int for(; slot_iter; slot_iter = slot_iter->next) { dlist *slot = (dlist *)slot_iter->data; - int slot_h = -mw->distance; - REDUCE(slot_h = slot_h + ((ClientWin*)iter->data)->client.height + mw->distance, slot); - if(slot_h + mw->distance + cw->client.height < max_h) + int slot_h = -separation; + REDUCE(slot_h = slot_h + ((ClientWin*)iter->data)->client.height + separation, slot); + if(slot_h + separation + cw->client.height < max_win_size.y) { slot_iter->data = dlist_add(slot, cw); break; @@ -59,7 +136,7 @@ layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int slots = dlist_add(slots, dlist_add(0, cw)); } - max_row_w = sqrt(sum_w * max_h); + max_row_w = sqrt(sum_w * max_win_size.y); for(slot_iter = dlist_first(slots); slot_iter; slot_iter = slot_iter->next) { dlist *slot = (dlist *)slot_iter->data; @@ -69,15 +146,14 @@ layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int for(iter = dlist_first(slot); iter; iter = iter->next) { ClientWin *cw = (ClientWin *)iter->data; - cw->x = x + (slot_w - cw->client.width) / 2; - cw->y = y; - y += cw->client.height + mw->distance; + cw_set_tmp_xy(cw,x + (slot_w - cw->client.width) / 2,y); + y += cw_client_height(cw) + separation; rows->data = dlist_add((dlist *)rows->data, cw); } row_h = MAX(row_h, y - row_y); - *total_height = MAX(*total_height, y); - x += slot_w + mw->distance; - *total_width = MAX(*total_width, x); + total_size->y = MAX(total_size->y, y); + x += slot_w + separation; + total_size->x = MAX(total_size->x, x); if(x > max_row_w) { x = 0; @@ -89,18 +165,263 @@ layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int } dlist_free(slots); - *total_width -= mw->distance; - *total_height -= mw->distance; + //*total_width -= mw->distance; + //*total_height -= mw->distance; + *total_size=v2i_sub(*total_size, vec2i_mk(separation,separation)); for(iter = dlist_first(rows); iter; iter = iter->next) { dlist *row = (dlist *)iter->data; int row_w = 0, xoff; REDUCE(row_w = MAX(row_w, ((ClientWin*)iter->data)->x + ((ClientWin*)iter->data)->client.width), row); - xoff = (*total_width - row_w) / 2; + xoff = (total_size->x - row_w) / 2; REDUCE(((ClientWin*)iter->data)->x += xoff, row); dlist_free(row); } + + //layout_dump(windows,total_width,total_height); + + //layout_run_scale_all(mw,windows,*total_size); dlist_free(rows); } + +// simple grid layout + +void sort_objects_by_fn(void** pp,int count, int(*f_sort_val)(void*)) { + // yikes, do we have ptr-to-member in C? would take templates to write safe/generic + int i,ii=count-1; + for (ii=count-1; ii>0;ii--) { + bool ok=true; + for (i=0; inum) continue; + printf("win(%d/%d)/(i,j=%d,%d)\tx=y=\t%d\t%d\n",ii,num,i,j, wins[ii]->client.x,wins[ii]->client.y); + } + } +} + + +void layout_grid(int separation, Vec2i size, dlist* windows) { + int num= dlist_len(windows); + if (!num) return; + int denom=1<<12; + // duplicate the pointer array-for sorting + // sort by x TODO - pick major sort axis based on outer aspect ratio + ClientWin** wins = (ClientWin*) malloc(sizeof(ClientWin)*num); + int i=0; + DLIST_FOREACH(ClientWin, cw,/*IN*/ windows ) + wins[i++]=cw; + DLIST_NEXT +// sort_objects_by_fn((void**)wins,num,cw_centre_x); + + // get min,max aspect ratios. if the windows are all landscape or portrait it changes numx/numy + float min_aspect=100000.0f,max_aspect=0.f; + float sum_aspect=0.f; + float total_area=0.f; + DLIST_FOREACH(ClientWin, cw,/*IN*/ windows ) + float aspect=cw_client_aspect(cw); + min_aspect=MIN(min_aspect,aspect); max_aspect=MAX(max_aspect,aspect); + Vec2i wsize=cw_client_size(cw); + float area=wsize.x*wsize.y; + total_area += area; + sum_aspect+=aspect;//*area; + DLIST_NEXT + float win_aspect=(float)size.x/(float)size.y; + float av_aspect = sum_aspect/(float)num;// total_area; + + printf("row0=%.3f row1=%.3f row2=%.3f avasp%.3f main_asp%.3f\n", + sqrt((num*win_aspect)/av_aspect), + sqrt((num*av_aspect)/win_aspect), + sqrt(num)*(av_aspect/win_aspect), + av_aspect, + win_aspect); +// int num_rows = MAX(1,sqrt((num/win_aspect)* av_aspect )); + //printf("aspect="); +// av_aspect=1.0f; + float d=sqrt(num*(av_aspect/win_aspect)) ; + int num_rows = MAX(1,d+0.5f); + int num_cols = (num+(num_rows-1))/num_rows;// todo: per row, for last one.. + + + printf("%.3f d=%.3f num=%d rows=%d cols=%d \n",av_aspect,d, num,num_rows,num_cols); + + + printf("row0=%.3f row1=%.3f row2=%.3f avasp%.3f main_asp%.3f\n", + sqrt((num*win_aspect)/av_aspect), + sqrt((num*av_aspect)/win_aspect), + sqrt(num)*(av_aspect/win_aspect), + av_aspect, + win_aspect); + + // TODO Sort horizontally. + // todo: pick major axis. widescreen monitor, its usually horiz, but we might be placing in subwindows. + + sort_objects_by_fn((void**)wins,num,cw_centre_x); + // within each column, sort by Y + int row=0,col=0; + Vec2i pos=vec2i_mk(0,0); + int j=0; + for (j=0; j1.0) { + mini_size.y*=(1.0/f); + } else { + mini_size.x*=f; + } + cw_set_mini_size(cw,mini_size); + + cw_set_tmp_pos(cw, v2i_sub(rect2i_centre(&cell),v2i_half(mini_size))); + cw->mini.x=cw->x; cw->mini.y=cw->y; + row++; + if (row>=num_rows) { + row=0; col++; + } + // todo: size per row. + } + + + //layout_dump(windows,size); + free(wins); +} + + +void fill_within_region(dlist* windows, const Rect2i* region,bool preserve_win_aspect) { + int denom=1<<12; + if (!rect2i_area(region,denom)) { + printf("divide by zero,can't do this"); + return; + } + // find all the windows in a region (eg desktop?), expand their mini's to fill it + // [.1] Find the extents of everything within this rect + rect2i_print(region); + Rect2i region_contents_rc=rect2i_init(); + DLIST_FOREACH(ClientWin, cw, windows) + if (!rect2i_contains(region, cw_mini_centre(cw))) + continue; + Rect2i mini_rect = cw_mini_rect(cw); + rect2i_include_rect2i(®ion_contents_rc, &mini_rect); + DLIST_NEXT + printf("region contents rect="); + rect2i_print(®ion_contents_rc); + // [.2] rescale those to fill the region, preserving individual aspect + // this will give a slight spread in whatever axis has the most unused space + // todo: calculate a transformation + printf("lerpi test %d %d %d \n", + lerpi(100, 200, 1024,denom), + invlerpi(100,200, 125,denom), + lerpi(100,200,invlerpi(100,200,125,denom),denom)); + + if (!rect2i_area(®ion_contents_rc,denom)) { + printf("divide by zero,can't do this"); + return; + } + + DLIST_FOREACH(ClientWin, cw, windows) + Rect2i mini_rect = cw_mini_rect(cw); + int aspect=rect2i_aspect(&mini_rect,denom); + //rect2i_print(&mini_rect); + Rect2i new_rect; + vec2i_print(rect2i_invlerp(®ion_contents_rc, mini_rect.min,denom)); + Rect2i rect_frac; + rect_frac.min=rect2i_invlerp(®ion_contents_rc, mini_rect.min,denom); + rect_frac.max=rect2i_invlerp(®ion_contents_rc, mini_rect.max,denom); + //printf("fractional subrect="); rect2i_print(&rect_frac); + new_rect.min = rect2i_lerp(region, rect_frac.min,denom); + new_rect.max = rect2i_lerp(region, rect_frac.max,denom); + //rect2i_print(&new_rect);printf("\n"); + + if (preserve_win_aspect){ + Vec2i new_centre=rect2i_centre(&new_rect); + Vec2i half_size=v2i_sub(new_rect.max,new_centre); + // correct the aspect ratio.. + if (aspect>denom) { + half_size.y=(half_size.x*denom)/aspect; + } else { + half_size.x=(half_size.y*aspect)/denom; + } + new_rect=rect2i_mk_at_centre(new_centre,half_size); + } + cw_set_mini_rect(cw, &new_rect); + DLIST_NEXT +} + +float layout_factor(const MainWin *mw,Vec2i size, unsigned int extra_border) { + + float factor = (float)(mw_width(mw) - extra_border) / size.x; + if(factor * size.y > mw_height(mw) - extra_border) + factor = (float)(mw_height(mw) - extra_border) / size.y; + return factor; +} +void layout_scale_all(const MainWin *mw, dlist *windows, Vec2i total_size) +{ + dlist* iter; + + float factor=layout_factor(mw,total_size, mw->distance); + int denom=1<<12; int ifactor=(int)(factor*(float)denom); + + + Vec2i delta= v2i_mul(v2i_mad(mw_size(mw), total_size, -ifactor,denom),1,2); + + for(iter = windows; iter; iter = iter->next) + { + ClientWin *cw = (ClientWin*)iter->data; + +// cw->factor=factor; + + sw_set_pos_size(&cw->mini, + v2i_mad(delta, cw_tmp_pos(cw), ifactor,denom), + v2i_max(vec2i_mk(1,1), v2i_mul(cw_client_size(cw),ifactor,denom))); + +// printf("%d %d %d %d\n",cw->mini.x,cw->mini.y, cw->mini.width,cw->mini.height); + } +} + + diff --git a/src/layout.h b/src/layout.h index 36469ea..162f106 100644 --- a/src/layout.h +++ b/src/layout.h @@ -20,6 +20,15 @@ #ifndef SKIPPY_LAYOUT_H #define SKIPPY_LAYOUT_H -void layout_run(MainWin *, dlist *, unsigned int *, unsigned int *); +typedef enum LAYOUT_MODE { + LAYOUT_ORIGINAL, + LAYOUT_DESKTOP, + LAYOUT_GRID +} +LAYOUT_MODE; + +void layout_run(MainWin *, LAYOUT_MODE m, dlist *, Vec2i* total_size); +float layout_factor(const MainWin*,Vec2i size, unsigned int extra_border); + #endif /* SKIPPY_LAYOUT_H */ diff --git a/src/mainwin.c b/src/mainwin.c index f637430..74be8be 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -96,6 +96,8 @@ mainwin_create(session_t *ps) { mw->key_l = XKeysymToKeycode(dpy, XK_l); mw->key_enter = XKeysymToKeycode(dpy, XK_Return); mw->key_space = XKeysymToKeycode(dpy, XK_space); + mw->key_page_up = XKeysymToKeycode(dpy, XK_Page_Up); + mw->key_page_down = XKeysymToKeycode(dpy, XK_Page_Down); mw->key_escape = XKeysymToKeycode(dpy, XK_Escape); mw->key_q = XKeysymToKeycode(dpy, XK_q); @@ -286,8 +288,7 @@ mainwin_map(MainWin *mw) { XRaiseWindow(ps->dpy, mw->window); // Might because of WM reparent, XSetInput() doesn't work here - XSetInputFocus(ps->dpy, mw->window, RevertToParent, CurrentTime); - XGrabKeyboard(ps->dpy, mw->window, True, GrabModeAsync, GrabModeAsync, + XSetInputFocus(ps->dpy, mw->window, RevertToParent, CurrentTime); XGrabKeyboard(ps->dpy, mw->window, True, GrabModeAsync, GrabModeAsync, CurrentTime); } diff --git a/src/mainwin.h b/src/mainwin.h index 0fe8c33..afbe6fa 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -39,7 +39,9 @@ struct _MainWin Picture background; Pixmap bg_pixmap; int x, y; - unsigned int width, height, distance; + unsigned int width, height; + //PosSize rect; + unsigned int distance; XRenderPictFormat *format; XTransform transform; @@ -53,13 +55,27 @@ struct _MainWin KeyCode key_act, key_up, key_down, key_left, key_right, key_h, key_j, key_k, key_l, - key_enter, key_space, key_q, key_escape; + key_enter, key_space, key_q, key_escape,key_page_up,key_page_down; #ifdef CFG_XINERAMA int xin_screens; XineramaScreenInfo *xin_info, *xin_active; #endif /* CFG_XINERAMA */ }; +#ifdef MW_POS_SIZE +#define mw_pos(mw) ((mw)->rect.pos) +#define mw_size(mw) ((mw)->rect.max) +#define mw_max(mw) (vec2i_add(mw_pos(mw),mw_size(mw))) +#else +#define mw_pos(mw) (vec2i_mk((mw)->x,(mw)->y)) +#define mw_size(mw) (vec2i_mk((mw)->width,(mw)->height)) +#endif +#define mw_min(mw) ((mw)->rect.pos) +#define mw_max(mw) (v2i_add((mw)->rect.pos,(mw)->rect.size)) +#define mw_rect(mw) (rect2i_mk_at(mw_pos(mw),mw_size(mw))) +#define mw_width(mw) (mw_size(mw).x) +#define mw_height(mw) (mw_size(mw).y) + typedef struct _MainWin MainWin; MainWin *mainwin_create(session_t *ps); @@ -70,5 +86,8 @@ int mainwin_handle(MainWin *, XEvent *); void mainwin_update_background(MainWin *mw); void mainwin_update(MainWin *mw); void mainwin_transform(MainWin *mw, float f); +inline Vec2i mainwin_pos(const MainWin* mw) { vec2i_mk( mw->x,mw->y);} +inline Vec2i mainwin_size(const MainWin* mw) { vec2i_mk( mw->width,mw->height);} +inline Rect2i mainwin_rect(const MainWin* mw) { rect2i_mk_at( mainwin_pos(mw), mainwin_size(mw) );} #endif /* SKIPPY_MAINWIN_H */ diff --git a/src/skippy.c b/src/skippy.c index c11c66f..49b6818 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -114,20 +114,35 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) *touched = True; } } + + logd("update clients: %d active\n ", dlist_len(clients)); dlist_free(stack); return clients; } +static LAYOUT_MODE +get_layout_mode(const session_t* ps) { + // TODO: some of these modes will be combined flags. + if (ps->o.layout_desktop) { + return LAYOUT_DESKTOP; + } + else if (ps->o.layout_grid) { + return LAYOUT_GRID; + + } else { + return LAYOUT_ORIGINAL; + } +} + static dlist * -do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) +do_layout(MainWin *mw, dlist *clients, Window focus, Window leader,float t) { session_t * const ps = mw->ps; CARD32 desktop = wm_get_current_desktop(ps->dpy); unsigned int width, height; - float factor; int xoff, yoff; dlist *iter, *tmp; @@ -138,29 +153,37 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) dlist_free(mw->cod); tmp = dlist_first(dlist_find_all(clients, (dlist_match_func)clientwin_validate_func, &desktop)); + logd("clients:%d,valid:%d\n",dlist_len(clients),dlist_len(tmp)); if(leader != None) { mw->cod = dlist_first(dlist_find_all(tmp, clientwin_check_group_leader_func, (void*)&leader)); dlist_free(tmp); } else mw->cod = tmp; - if(! mw->cod) return clients; dlist_sort(mw->cod, clientwin_sort_func, 0); /* Move the mini windows around */ - layout_run(mw, mw->cod, &width, &height); - factor = (float)(mw->width - 100) / width; - if(factor * height > mw->height - 100) - factor = (float)(mw->height - 100) / height; + LAYOUT_MODE mode=get_layout_mode(ps); + Vec2i total_size; + layout_run(mw, mode, mw->cod, &total_size); + int extra_border=mw->distance; +// float factor=layout_factor(mw,width,height,mw->distance); + for(iter = mw->cod; iter; iter = iter->next) + clientwin_lerp_client_to_mini((ClientWin*)iter->data,t); + + + float factor = (float)(mw->width - extra_border) / total_size.x; + if(factor * height > mw->height - extra_border) + factor = (float)(mw->height - extra_border) / total_size.y; - xoff = (mw->width - (float)width * factor) / 2; - yoff = (mw->height - (float)height * factor) / 2; + xoff = (mw->width - (float)total_size.x * factor) / 2; + yoff = (mw->height - (float)total_size.y * factor) / 2; mainwin_transform(mw, factor); for(iter = mw->cod; iter; iter = iter->next) - clientwin_move((ClientWin*)iter->data, factor, xoff, yoff); + clientwin_create_scaled_image((ClientWin*)iter->data /*, factor, xoff, yoff*/); /* Get the currently focused window and select which mini-window to focus */ iter = dlist_find(mw->cod, clientwin_cmp_func, (void *)focus); @@ -174,11 +197,18 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) clientwin_map((ClientWin*)iter->data); if (ps->o.movePointerOnStart) XWarpPointer(mw->ps->dpy, None, mw->focus->mini.window, 0, 0, 0, 0, - mw->focus->mini.width / 2, mw->focus->mini.height / 2); + sw_width(&mw->focus->mini) / 2, sw_height(&mw->focus->mini) / 2); return clients; } +void mw_animate(MainWin* mw) { + dlist* iter; + for (iter=mw->cod;iter;iter=iter->next){ + ClientWin* cw=(ClientWin*) iter->data; + } +} + static inline const char * ev_dumpstr_type(const XEvent *ev) { switch (ev->type) { @@ -278,6 +308,7 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { printfd("Event %-13.13s wid %#010lx %s", name, wid, wextra); } +int g_redo_layout=0; // todo, poast message back?! static dlist * skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xin) { @@ -301,7 +332,10 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi XFlush(ps->dpy); } - clients = do_layout(mw, clients, focus, leader); + float anim_time=ps->o.animTime; // slow for debug + float anim_t=(anim_time<=0.f)?anim_t=1.0:0.0f; + + clients = do_layout(mw, clients, focus, leader,anim_t); if (!mw->cod) { printfef("(): No client windows found."); return clients; @@ -314,6 +348,7 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi int last_rendered = time_in_millis(); while (!die) { + //printf("polling\n7"); int i, now, timeout; struct pollfd r_fd; @@ -330,11 +365,22 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi now = time_in_millis(); if(now >= last_rendered + mw->poll_time) { + REDUCE(if( ((ClientWin*)iter->data)->damaged ) clientwin_repair(iter->data), mw->cod); - last_rendered = now; + //last_rendered = now; } + if (g_redo_layout) { g_redo_layout=0; anim_t=0.f;} i = XPending(ps->dpy); + if (!i && ((anim_t<1.0f) || (last_rendereddpy, &ev); #ifdef DEBUG_EVENTS @@ -530,6 +576,8 @@ void show_help() "\t--activate-window-picker - tells the daemon to show the window picker.\n" "\t--help - show this message.\n" "\t-S - Synchronize X operation (debugging).\n" + "\t-a - show windows from all desktops.\n" + "\t-d - 'expo' style Desktop layout .\n" , stdout); } @@ -646,13 +694,17 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { OPT_DM_START, OPT_DM_STOP, }; - static const char * opts_short = "hS"; + static const char * opts_short = "hSagds"; static const struct option opts_long[] = { - { "help", no_argument, NULL, 'h' }, - { "config", required_argument, NULL, OPT_CONFIG }, - { "activate-window-picker", no_argument, NULL, OPT_ACTV_PICKER }, - { "start-daemon", no_argument, NULL, OPT_DM_START }, - { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, + { "help", no_argument, NULL, 'h'}, + { "config", required_argument, NULL, OPT_CONFIG}, + { "activate-window-picker", no_argument, NULL, OPT_ACTV_PICKER}, + { "start-daemon", no_argument, NULL, OPT_DM_START}, + { "stop-daemon", no_argument, NULL, OPT_DM_STOP}, + { "all desktops", no_argument, NULL, 'a'}, +// { "keep layout", no_argument, NULL, 'k' }, +// { "grid layout", no_argument, NULL, 'g' }, +// { "smart layout", no_argument, NULL, 's' }, { NULL, no_argument, NULL, 0 } }; @@ -683,6 +735,10 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG: break; #define T_CASEBOOL(idx, option) case idx: ps->o.option = true; break T_CASEBOOL('S', synchronize); + T_CASEBOOL('a', xinerama_showAll); + T_CASEBOOL('d', layout_desktop); + T_CASEBOOL('s', layout_smart); + T_CASEBOOL('g', layout_grid); case OPT_ACTV_PICKER: ps->o.mode = PROGMODE_ACTV_PICKER; break; @@ -771,6 +827,7 @@ int main(int argc, char *argv[]) { config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse); config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX); config_get_int_wrap(config, "tooltip", "offsetY", &ps->o.tooltip_offsetY, INT_MIN, INT_MAX); + config_get_float_wrap(config, "general", "animTime", &ps->o.animTime, 0.0f, 2.0f); if (!parse_align(ps, config_get(config, "tooltip", "align", "left"), &ps->o.tooltip_align)) return RET_BADARG; config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); diff --git a/src/skippy.h b/src/skippy.h index d3e3eaf..4525bcf 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -112,6 +112,9 @@ typedef struct { bool movePointerOnStart; bool xinerama_showAll; + bool layout_desktop; + bool layout_grid; + bool layout_smart; char *normal_tint; int normal_tintOpacity; @@ -133,6 +136,8 @@ typedef struct { char *tooltip_textShadow; char *tooltip_font; + float animTime; + enum cliop bindings_miwMouse[MAX_MOUSE_BUTTONS]; } options_t; @@ -142,7 +147,7 @@ typedef struct { .runAsDaemon = false, \ .synchronize = false, \ \ - .distance = 50, \ + .distance = 8, \ .useNetWMFullscreen = true, \ .ignoreSkipTaskbar = false, \ .updateFreq = 10.0, \ @@ -153,9 +158,9 @@ typedef struct { .xinerama_showAll = false, \ .normal_tint = NULL, \ .normal_tintOpacity = 0, \ - .normal_opacity = 200, \ + .normal_opacity = 248, \ .highlight_tint = NULL, \ - .highlight_tintOpacity = 64, \ + .highlight_tintOpacity = 32, \ .highlight_opacity = 255, \ .tooltip_show = true, \ .tooltip_followsMouse = true, \ @@ -168,6 +173,7 @@ typedef struct { .tooltip_text = NULL, \ .tooltip_textShadow = NULL, \ .tooltip_font = NULL, \ + .animTime = 0.f \ } /// @brief X information structure. @@ -253,6 +259,18 @@ allocchk_(void *ptr, const char *func_name) { statement; \ } +#ifndef TYPEOF +#ifdef __cplusplus + #define TYPEOF __decltype +#else + #define TYPEOF typeof +#endif +#endif +#define LET(varname,expr) typeof(expr) varname = expr; +#define MALLOCS(TYPE,COUNT) ((TYPE*)malloc(sizeof(TYPE)*COUNT)) +#define REALLOCS(ptr,COUNT) ((TYPEOF(ptr)realloc(ptr,sizeof(*ptr)*COUNT)) +#define FREE(PTR) {if (PTR) {free((void*)(PTR)); PTR=0;}} + /** * @brief Get current time, in milliseconds. */ @@ -435,6 +453,7 @@ ev_key_str(XKeyEvent *ev) { printfef("(): KeyRelease %u (%s) not binded to anything.", \ (ev)->xkey.keycode, ev_key_str(&(ev)->xkey)) +#include "vecmath2d.h" #include "wm.h" #include "clientwin.h" #include "mainwin.h" @@ -445,6 +464,8 @@ ev_key_str(XKeyEvent *ev) { extern session_t *ps_g; +#define logd // + #define ACTIVATE_WINDOW_PICKER 1 #define EXIT_RUNNING_DAEMON 2 diff --git a/src/vecmath2d.h b/src/vecmath2d.h new file mode 100644 index 0000000..0394a5f --- /dev/null +++ b/src/vecmath2d.h @@ -0,0 +1,189 @@ +#ifndef vecmath2d_h +#define vecmath2d_h + +// 2d int maths - types and inline helper functions/accessors +// +// type_op_(optional types, usually same as type if not mentioned) +// common type vec2i has abreviation v2i_ +// type_set -- setter +// type_noun/adj -- getter +// type_verb/question -- calculate something + +typedef int VScalar; // Scalar value used here. TODO: int? i32? i64? :) +typedef struct Vec2i { // todo: refactor to use this + VScalar x,y; +} Vec2i; + +// rectangular region, aka RECT, AABB, 'Extents' +typedef struct Rect2i { + Vec2i min,max; +} Rect2i; + +// alternative way of specifying rectanglular region +typedef struct PosSize { + Vec2i pos,size; +} PosSize; + +#ifndef CLAMP +#define CLAMP(V,LO,HI) (MIN(HI,(MAX(LO,V)))) +#endif + +inline VScalar invlerpi(VScalar lo,VScalar hi,VScalar v,int one) { + return ((v-lo)*one)/(hi-lo); +} +inline int lerpi(VScalar lo,VScalar hi,VScalar f,VScalar one) { + return lo+(((hi-lo)*f)/one); +} +inline void v2i_set(Vec2i* dst, VScalar x, VScalar y) { + dst->x=x;dst->y=y; +} +inline Vec2i vec2i_mk(VScalar x, VScalar y) { + Vec2i v; v.x=x; v.y=y; return v; +} +inline Vec2i vec2i_splat(VScalar v) { + return vec2i_mk(v,v); +} +inline Vec2i v2i_sub(Vec2i a,Vec2i b) { + Vec2i ret= {a.x-b.x,a.y-b.y};return ret; +} +inline Vec2i v2i_add(Vec2i a,Vec2i b) { + Vec2i ret= {a.x+b.x,a.y+b.y};return ret; +} +inline Vec2i v2i_mul(Vec2i a,VScalar f,VScalar prec) { + Vec2i ret= {(a.x*f)/prec,(a.y*f)/prec};return ret; +} +inline Vec2i v2i_half(Vec2i a) { + return vec2i_mk(a.x/2,a.y/2); +} +inline Vec2i v2i_avr(Vec2i a,Vec2i b) { + Vec2i ret=v2i_mul(v2i_add(a,b),1,2); return ret; +} +inline Vec2i v2i_mad(Vec2i a,Vec2i b,VScalar f,VScalar prec) { + return v2i_add(a, v2i_mul(b,f,prec)); +} +inline Vec2i v2i_lerp(Vec2i a,Vec2i b,VScalar f,VScalar prec) { + return v2i_add(a, v2i_mul(v2i_sub(b,a),f,prec)); +} +inline Vec2i v2i_invlerp(const Vec2i vmin,const Vec2i vmax, Vec2i v,VScalar precision ) { + Vec2i ret={invlerpi(vmin.x, vmax.x, v.x,precision), invlerpi(vmin.y, vmax.y, v.y,precision)}; return ret; +} +// turn a fractional position into a position within a rect +inline Vec2i rect2i_lerp(const Rect2i* r, Vec2i v, VScalar precision) { + Vec2i ret; ret.x=lerpi(r->min.x,r->max.x, v.x,precision); ret.y=lerpi(r->min.y,r->max.y, v.y,precision); return ret; +} +// get a vector which is the fractional position of a point in a rect +inline Vec2i rect2i_invlerp(const Rect2i* r, Vec2i v, VScalar precision) { + return v2i_invlerp(r->min,r->max, v, precision); +} +inline Vec2i v2i_min(Vec2i a,Vec2i b) { + Vec2i ret={MIN(a.x,b.x),MIN(a.y,b.y)}; return ret; +} +inline Vec2i v2i_max(Vec2i a,Vec2i b) { + Vec2i ret={MAX(a.x,b.x),MAX(a.y,b.y)}; return ret; +} +inline Rect2i rect2i_init(void){ + Rect2i ret={{INT_MAX,INT_MAX},{-INT_MAX,-INT_MAX}}; return ret; +} +inline Rect2i rect2i_mk_at(Vec2i pos, Vec2i size){ + Rect2i ret; ret.min=pos; ret.max=v2i_add(pos,size); return ret; +} +inline Rect2i rect2i_mk_at_centre(Vec2i centre, Vec2i half_size){ + Rect2i ret; ret.min=v2i_sub(centre,half_size); ret.max=v2i_add(centre,half_size); return ret; +} +inline Rect2i rect2i_mk(Vec2i a, Vec2i b){ + Rect2i ret; ret.min=a; ret.max=b; return ret; +} +inline void rect2i_set_init(Rect2i* ret){ + v2i_set(&ret->min,INT_MAX,INT_MAX);v2i_set(&ret->max,-INT_MAX,-INT_MAX); +} +// expand a rectangle to include a vector +inline void rect2i_include(Rect2i* r,Vec2i v){ + r->min=v2i_min(r->min,v); r->max=v2i_max(r->max,v); +} +// expand a rect to include a rect +inline void rect2i_include_rect2i(Rect2i* r,const Rect2i* src){ + r->min=v2i_min(r->min,src->min);r->max=v2i_max(r->max,src->max); +} +inline Vec2i rect2i_size(const Rect2i* r) { + return v2i_sub(r->max,r->min); +} +inline int rect2i_aspect(const Rect2i* r,VScalar precision) { + Vec2i sz=rect2i_size(r); return (sz.x*precision)/sz.y; +} +inline Rect2i rect2i_add(const Rect2i* a, Vec2i ofs) { + Rect2i ret={v2i_add(a->min,ofs),v2i_add(a->max,ofs)}; return ret; +} +inline int rect2i_area( const Rect2i* r,VScalar denom) { + Vec2i sz=rect2i_size(r); return (sz.x*sz.y/denom); +} +inline PosSize rect2i_pos_size(const Rect2i* r) { + PosSize psz; psz.pos=r->min; psz.size=v2i_sub(r->max,r->min); return psz; +} +inline void rect2i_set(Rect2i* rc, const Vec2i a, const Vec2i b) { rc->min=a; rc->max=b;} +inline void rect2i_set_pos_size(Rect2i* rc, const Vec2i pos, const Vec2i size) { rc->min=pos;rc->max=v2i_add(pos,size);} +inline VScalar rect2i_width(const Rect2i* r) { return rect2i_size(r).x;} +inline VScalar rect2i_height(const Rect2i* r) { return rect2i_size(r).y;} +inline Rect2i rect2i_intersect( const Rect2i* a,const Rect2i* b ) { + Rect2i r; r.min=v2i_max(a->min,b->min); r.max=v2i_min(a->max,b->max); return r; +} +inline VScalar rect2i_overlap_area( const Rect2i* a,const Rect2i* b) { + Rect2i ri=rect2i_intersect(a,b);Vec2i sz= rect2i_size(&ri);if (sz.x>0 && sz.y>0) return sz.x*sz.y; else return 0; +} +inline bool rect2i_contains( const Rect2i* rc, const Vec2i v){ + return v.x>=rc->min.x && v.xmax.x && v.y>=rc->min.y && v.ymax.y; +} +inline bool rect2i_overlap( const Rect2i* ra, const Rect2i* rb){ + //if boundaries touch, area of overlap is still zero + if (ra->max.x<=rb->min.x || ra->min.x>=rb->max.x) return false; + if (ra->max.y<=rb->min.y || ra->min.y>=rb->max.y) return false; + return true; +} +inline void rect2i_set_centre(Rect2i* rc, const Vec2i new_centre) { + Vec2i size=rect2i_size(rc); + rect2i_set_pos_size(rc, v2i_sub(new_centre, v2i_half(size)), size); +} +inline void rect2i_split_x(Rect2i* out0, Rect2i* out1,VScalar split, const Rect2i* rc ) { + out0->min=rc->min; + out0->max.x=split; + out0->max.y=rc->max.y; + + out1->min.x=split; + out1->min.y=rc->min.y; + out1->max=rc->max; +} +inline void rect2i_split_y(Rect2i* out0, Rect2i* out1,VScalar split, const Rect2i* rc ) { + out0->min=rc->min; + out0->max.y=split; + out0->max.x=rc->max.x; + + out1->min.y=split; + out1->min.x=rc->min.x; + out1->max=rc->max; +} +inline bool rect2i_valid(const Rect2i* a) { + return a->max.x>=a->min.x && a->max.y >= a->min.y; +} +inline void vec2i_print(const Vec2i v) { + printf("(%d %d)", v.x,v.y); +} +inline void rect2i_print(const Rect2i* a) { + printf("("); vec2i_print(a->min); printf(" "); vec2i_print(a->max); printf(")"); +} +inline Vec2i rect2i_centre(const Rect2i* r) { + return v2i_avr(r->min,r->max); +} +inline PosSize pos_size_mk(const Vec2i pos, const Vec2i size) { + PosSize psz;psz.pos=pos; psz.size=size; return psz; +} +inline void pos_size_set_rect(PosSize* psz, const Rect2i* r) { + psz->pos=r->min; + psz->size=rect2i_size(r); +} +inline PosSize pos_size_from_rect(const Rect2i* r) { + PosSize psz;pos_size_set_rect(&psz,r); return psz; +} +inline Rect2i rect2i_from_pos_size(const PosSize* psz) +{ rect2i_mk_at(psz->pos, psz->size); +} + +#endif diff --git a/src/wm.c b/src/wm.c index 04c80f4..407507b 100644 --- a/src/wm.c +++ b/src/wm.c @@ -498,15 +498,17 @@ wm_validate_window(Display *dpy, Window win) 0L, 8192L, False, XA_ATOM, &real_type, &real_format, &items_read, &items_left, &data); - if(status != Success) + if(status != Success) { return 0; + } atoms = (Atom *)data; for(i = 0; result && i < items_read; i++) { if(atoms[i] == _NET_WM_STATE_HIDDEN) result = 0; - else if(! IGNORE_SKIP_TASKBAR && atoms[i] == _NET_WM_STATE_SKIP_TASKBAR) + else + if(! IGNORE_SKIP_TASKBAR && atoms[i] == _NET_WM_STATE_SKIP_TASKBAR) result = 0; else if(atoms[i] == _NET_WM_STATE_SHADED) result = 0; @@ -515,8 +517,9 @@ wm_validate_window(Display *dpy, Window win) } XFree(data); - if(! result) + if(! result) { return 0; + } status = XGetWindowProperty(dpy, win, _NET_WM_WINDOW_TYPE, 0L, 1L, False, XA_ATOM, &real_type, &real_format, @@ -526,8 +529,9 @@ wm_validate_window(Display *dpy, Window win) atoms = (Atom *)data; - if(items_read && (atoms[0] == _NET_WM_WINDOW_TYPE_DESKTOP || atoms[0] == _NET_WM_WINDOW_TYPE_DOCK)) + if(items_read && (atoms[0] == _NET_WM_WINDOW_TYPE_DESKTOP || atoms[0] == _NET_WM_WINDOW_TYPE_DOCK)) { result = 0; + } XFree(data); @@ -542,16 +546,19 @@ wm_validate_window(Display *dpy, Window win) { if(status == Success) XFree(data); + printf("status\n"); return 0; } attr = (((CARD32*)data)[0]) & (WIN_STATE_MINIMIZED | WIN_STATE_SHADED | WIN_STATE_HIDDEN); - if(attr) + if(attr) { result = 0; + } XFree(data); - if(! result) + if(! result){ return 0; + } if(! IGNORE_SKIP_TASKBAR) { @@ -565,8 +572,9 @@ wm_validate_window(Display *dpy, Window win) return 1; /* If there's no _WIN_HINTS, assume it's 0, thus valid */ } attr = ((CARD32*)data)[0]; - if(attr & WIN_HINTS_SKIP_TASKBAR) + if(attr & WIN_HINTS_SKIP_TASKBAR) { result = 0; + } XFree(data); }