Prevent overflow while calculating frame size hints
[notion/jeffpc.git] / ioncore / resize.c
blobae45c5f45554502c46c59251357ada63f43c03fc
1 /*
2 * ion/ioncore/resize.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <stdio.h>
10 #include <limits.h>
12 #include <libtu/objp.h>
13 #include <libtu/minmax.h>
14 #include <libextl/extl.h>
15 #include <libmainloop/defer.h>
17 #include "common.h"
18 #include "global.h"
19 #include "resize.h"
20 #include "gr.h"
21 #include "sizehint.h"
22 #include "event.h"
23 #include "cursor.h"
24 #include "extlconv.h"
25 #include "grab.h"
26 #include "framep.h"
27 #include "infowin.h"
30 #define XOR_RESIZE (!ioncore_g.opaque_resize)
33 extern int ioncore_edge_resistance;
36 /*{{{ Size/position display and rubberband */
39 static void draw_rubberbox(WRootWin *rw, const WRectangle *rect)
41 XPoint fpts[5];
43 fpts[0].x=rect->x;
44 fpts[0].y=rect->y;
45 fpts[1].x=rect->x+rect->w;
46 fpts[1].y=rect->y;
47 fpts[2].x=rect->x+rect->w;
48 fpts[2].y=rect->y+rect->h;
49 fpts[3].x=rect->x;
50 fpts[3].y=rect->y+rect->h;
51 fpts[4].x=rect->x;
52 fpts[4].y=rect->y;
54 XDrawLines(ioncore_g.dpy, WROOTWIN_ROOT(rw), rw->xor_gc, fpts, 5,
55 CoordModeOrigin);
59 static int max_width(GrBrush *brush, const char *str)
61 int maxw=0, w;
63 while(str && *str!='\0'){
64 w=grbrush_get_text_width(brush, str, 1);
65 if(w>maxw)
66 maxw=w;
67 str++;
70 return maxw;
74 static int chars_for_num(int d)
76 int n=0;
78 do{
79 n++;
80 d/=10;
81 }while(d);
83 return n;
87 static WInfoWin *setup_moveres_display(WWindow *parent, int cx, int cy)
89 GrBorderWidths bdw;
90 GrFontExtents fnte;
91 WInfoWin *infowin;
92 WFitParams fp;
94 fp.mode=REGION_FIT_EXACT;
95 fp.g.x=0;
96 fp.g.y=0;
97 fp.g.w=1;
98 fp.g.h=1;
100 infowin=create_infowin(parent, &fp, "moveres_display");
102 if(infowin==NULL)
103 return NULL;
105 grbrush_get_border_widths(INFOWIN_BRUSH(infowin), &bdw);
106 grbrush_get_font_extents(INFOWIN_BRUSH(infowin), &fnte);
108 /* Create move/resize position/size display window */
109 fp.g.w=3;
110 fp.g.w+=chars_for_num(REGION_GEOM(parent).w);
111 fp.g.w+=chars_for_num(REGION_GEOM(parent).h);
112 fp.g.w*=max_width(INFOWIN_BRUSH(infowin), "0123456789x+");
113 fp.g.w+=bdw.left+bdw.right;
114 fp.g.h=fnte.max_height+bdw.top+bdw.bottom;;
116 fp.g.x=cx-fp.g.w/2;
117 fp.g.y=cy-fp.g.h/2;
119 region_fitrep((WRegion*)infowin, NULL, &fp);
120 region_map((WRegion*)infowin);
122 return infowin;
126 static void moveres_draw_infowin(WMoveresMode *mode)
128 WRectangle geom;
129 char *buf;
131 if(mode->infowin==NULL)
132 return;
134 buf=INFOWIN_BUFFER(mode->infowin);
136 if(buf==NULL)
137 return;
139 if(mode->mode==MOVERES_SIZE){
140 int w, h;
142 w=mode->geom.w;
143 h=mode->geom.h;
145 if(mode->hints.base_set){
146 w=maxof(0, w-mode->hints.base_width);
147 h=maxof(0, h-mode->hints.base_height);
150 if(mode->hints.inc_set){
151 w/=maxof(1, mode->hints.width_inc);
152 h/=maxof(1, mode->hints.height_inc);
155 snprintf(buf, INFOWIN_BUFFER_LEN, "%dx%d", w, h);
156 }else{
157 snprintf(buf, INFOWIN_BUFFER_LEN, "%+d %+d",
158 mode->geom.x, mode->geom.y);
161 window_draw((WWindow*)mode->infowin, TRUE);
165 static void moveres_draw_rubberband(WMoveresMode *mode)
167 WRectangle rgeom=mode->geom;
168 int rx, ry;
169 WRootWin *rootwin=(mode->reg==NULL
170 ? NULL
171 : region_rootwin_of(mode->reg));
173 if(rootwin==NULL)
174 return;
176 rgeom.x+=mode->parent_rx;
177 rgeom.y+=mode->parent_ry;
179 if(mode->rubfn==NULL)
180 draw_rubberbox(rootwin, &rgeom);
181 else
182 mode->rubfn(rootwin, &rgeom);
186 /*}}}*/
189 /*{{{ Move/resize mode */
192 WMoveresMode *tmpmode=NULL;
195 EXTL_EXPORT
196 IMPLCLASS(WMoveresMode, Obj, NULL, NULL);
199 WMoveresMode *moveres_mode(WRegion *reg)
201 if(tmpmode==NULL)
202 return NULL;
203 return ((reg==NULL || tmpmode->reg==reg) ? tmpmode : NULL);
207 WRegion *moveresmode_target(WMoveresMode *mode)
209 return mode->reg;
213 static bool moveresmode_init(WMoveresMode *mode, WRegion *reg,
214 WDrawRubberbandFn *rubfn, bool cumulative)
216 WWindow *parent;
217 WRegion *mgr;
219 if(tmpmode!=NULL)
220 return FALSE;
222 parent=REGION_PARENT(reg);
224 if(parent==NULL)
225 return FALSE;
227 tmpmode=mode;
229 mode->snap_enabled=FALSE;
230 region_size_hints(reg, &mode->hints);
232 region_rootpos((WRegion*)parent, &mode->parent_rx, &mode->parent_ry);
234 mode->geom=REGION_GEOM(reg);
235 mode->origgeom=REGION_GEOM(reg);
236 mode->dx1=0;
237 mode->dx2=0;
238 mode->dy1=0;
239 mode->dy2=0;
240 mode->rubfn=rubfn;
241 mode->resize_cumulative=cumulative;
242 mode->rqflags=(XOR_RESIZE ? REGION_RQGEOM_TRYONLY : 0);
243 mode->reg=reg;
244 mode->mode=MOVERES_SIZE;
246 /* Get snapping geometry */
247 mgr=REGION_MANAGER(reg);
249 if(mgr!=NULL){
250 mode->snapgeom=REGION_GEOM(mgr);
252 if(mgr==(WRegion*)parent){
253 mode->snapgeom.x=0;
254 mode->snapgeom.y=0;
255 /*mode->snap_enabled=FALSE;*/
257 mode->snap_enabled=TRUE;
260 if(!mode->hints.min_set || mode->hints.min_width<1)
261 mode->hints.min_width=1;
262 if(!mode->hints.min_set || mode->hints.min_height<1)
263 mode->hints.min_height=1;
265 /* Set up info window */
267 int x=mode->geom.x+mode->geom.w/2;
268 int y=mode->geom.y+mode->geom.h/2;
269 mode->infowin=setup_moveres_display(parent, x, y);
272 moveres_draw_infowin(mode);
274 if(XOR_RESIZE){
275 XGrabServer(ioncore_g.dpy);
276 moveres_draw_rubberband(mode);
279 return TRUE;
283 static WMoveresMode *create_moveresmode(WRegion *reg,
284 WDrawRubberbandFn *rubfn,
285 bool cumulative)
287 CREATEOBJ_IMPL(WMoveresMode, moveresmode, (p, reg, rubfn, cumulative));
291 WMoveresMode *region_begin_resize(WRegion *reg, WDrawRubberbandFn *rubfn,
292 bool cumulative)
294 WMoveresMode *mode=create_moveresmode(reg, rubfn, cumulative);
296 if(mode!=NULL){
297 mode->mode=MOVERES_SIZE;
298 ioncore_change_grab_cursor(IONCORE_CURSOR_RESIZE);
301 return mode;
305 WMoveresMode *region_begin_move(WRegion *reg, WDrawRubberbandFn *rubfn,
306 bool cumulative)
308 WMoveresMode *mode=create_moveresmode(reg, rubfn, cumulative);
310 if(mode!=NULL){
311 mode->mode=MOVERES_POS;
312 ioncore_change_grab_cursor(IONCORE_CURSOR_MOVE);
315 return mode;
319 static void moveresmode_setorig(WMoveresMode *mode)
321 mode->dx1=0;
322 mode->dx2=0;
323 mode->dy1=0;
324 mode->dy2=0;
325 mode->origgeom=mode->geom;
329 static void moveresmode_do_newgeom(WMoveresMode *mode, WRQGeomParams *rq)
331 if(XOR_RESIZE)
332 moveres_draw_rubberband(mode);
334 if(mode->reg!=NULL){
335 rq->flags|=mode->rqflags;
336 region_rqgeom(mode->reg, rq, &mode->geom);
339 moveres_draw_infowin(mode);
341 if(XOR_RESIZE)
342 moveres_draw_rubberband(mode);
346 static int clamp_up(int t, int low, int high)
348 return (t < high && t > low ? high : t);
352 static void moveresmode_delta(WMoveresMode *mode,
353 int dx1, int dx2, int dy1, int dy2,
354 WRectangle *rret)
356 int realdx1, realdx2, realdy1, realdy2;
357 WRQGeomParams rq=RQGEOMPARAMS_INIT;
358 int er=ioncore_edge_resistance;
359 int w=0, h=0;
361 realdx1=(mode->dx1+=dx1);
362 realdx2=(mode->dx2+=dx2);
363 realdy1=(mode->dy1+=dy1);
364 realdy2=(mode->dy2+=dy2);
365 rq.geom=mode->origgeom;
367 /* snap */
368 if(mode->snap_enabled){
369 WRectangle *sg=&mode->snapgeom;
371 if(mode->dx1!=0 && rq.geom.x+mode->dx1<sg->x && rq.geom.x+mode->dx1>sg->x-er)
372 realdx1=sg->x-rq.geom.x;
373 if(mode->dx2!=0 && rq.geom.x+rq.geom.w+mode->dx2>sg->x+sg->w && rq.geom.x+rq.geom.w+mode->dx2<sg->x+sg->w+er)
374 realdx2=sg->x+sg->w-rq.geom.x-rq.geom.w;
375 if(mode->dy1!=0 && rq.geom.y+mode->dy1<sg->y && rq.geom.y+mode->dy1>sg->y-er)
376 realdy1=sg->y-rq.geom.y;
377 if(mode->dy2!=0 && rq.geom.y+rq.geom.h+mode->dy2>sg->y+sg->h && rq.geom.y+rq.geom.h+mode->dy2<sg->y+sg->h+er)
378 realdy2=sg->y+sg->h-rq.geom.y-rq.geom.h;
381 w=maxof(1, mode->origgeom.w-realdx1+realdx2);
382 h=maxof(1, mode->origgeom.h-realdy1+realdy2);
384 if(mode->snap_enabled && mode->hints.base_set){
385 w=clamp_up(w, mode->hints.base_width-er, mode->hints.base_width);
386 h=clamp_up(h, mode->hints.base_height-er, mode->hints.base_height);
389 /* Correct size */
390 sizehints_correct(&mode->hints, &w, &h, TRUE, TRUE);
392 /* Do not modify coordinates and sizes that were not requested to be
393 * changed.
396 if(mode->dx1==mode->dx2){
397 if(mode->dx1==0 || realdx1!=mode->dx1)
398 rq.geom.x+=realdx1;
399 else
400 rq.geom.x+=realdx2;
401 }else{
402 rq.geom.w=w;
403 if(mode->dx1==0 || realdx1!=mode->dx1)
404 rq.geom.x+=realdx1;
405 else
406 rq.geom.x+=mode->origgeom.w-rq.geom.w;
410 if(mode->dy1==mode->dy2){
411 if(mode->dy1==0 || realdy1!=mode->dy1)
412 rq.geom.y+=realdy1;
413 else
414 rq.geom.y+=realdy2;
415 }else{
416 rq.geom.h=h;
417 if(mode->dy1==0 || realdy1!=mode->dy1)
418 rq.geom.y+=realdy1;
419 else
420 rq.geom.y+=mode->origgeom.h-rq.geom.h;
423 moveresmode_do_newgeom(mode, &rq);
425 if(!mode->resize_cumulative)
426 moveresmode_setorig(mode);
428 if(rret!=NULL)
429 *rret=mode->geom;
433 void moveresmode_delta_resize(WMoveresMode *mode,
434 int dx1, int dx2, int dy1, int dy2,
435 WRectangle *rret)
437 mode->mode=MOVERES_SIZE;
438 moveresmode_delta(mode, dx1, dx2, dy1, dy2, rret);
442 void moveresmode_delta_move(WMoveresMode *mode,
443 int dx, int dy, WRectangle *rret)
445 mode->mode=MOVERES_POS;
446 moveresmode_delta(mode, dx, dx, dy, dy, rret);
450 void moveresmode_rqgeom(WMoveresMode *mode, WRQGeomParams *rq,
451 WRectangle *rret)
453 mode->mode=MOVERES_SIZE;
454 moveresmode_do_newgeom(mode, rq);
455 moveresmode_setorig(mode);
459 /* It is ugly to do this here, but it will have to do for now... */
460 static void set_saved(WMoveresMode *mode, WRegion *reg)
462 WFrame *frame;
464 if(!OBJ_IS(reg, WFrame))
465 return;
467 frame=(WFrame*)reg;
469 /* Restore saved sizes from the beginning of the resize action */
470 if(mode->origgeom.w!=mode->geom.w){
471 frame->saved_geom.x=mode->origgeom.x;
472 frame->saved_geom.w=mode->origgeom.w;
475 if(mode->origgeom.h!=mode->geom.h){
476 frame->saved_geom.y=mode->origgeom.y;
477 frame->saved_geom.h=mode->origgeom.h;
482 bool moveresmode_do_end(WMoveresMode *mode, bool apply)
484 WRegion *reg=mode->reg;
486 assert(reg!=NULL);
487 assert(tmpmode==mode);
489 tmpmode=NULL;
491 if(XOR_RESIZE){
492 moveres_draw_rubberband(mode);
493 if(apply){
494 WRQGeomParams rq=RQGEOMPARAMS_INIT;
496 rq.geom=mode->geom;
497 rq.flags=mode->rqflags&~REGION_RQGEOM_TRYONLY;
499 region_rqgeom(reg, &rq, &mode->geom);
501 XUngrabServer(ioncore_g.dpy);
503 if(apply)
504 set_saved(mode, reg);
506 if(mode->infowin!=NULL){
507 mainloop_defer_destroy((Obj*)mode->infowin);
508 mode->infowin=NULL;
510 destroy_obj((Obj*)mode);
512 return TRUE;
516 /*}}}*/
519 /*{{{ Request and other dynfuns */
522 void region_rqgeom(WRegion *reg, const WRQGeomParams *rq,
523 WRectangle *geomret)
525 WRegion *mgr=REGION_MANAGER(reg);
527 if(mgr!=NULL){
528 if(rq->flags&REGION_RQGEOM_ABSOLUTE)
529 region_managed_rqgeom_absolute(mgr, reg, rq, geomret);
530 else
531 region_managed_rqgeom(mgr, reg, rq, geomret);
532 }else{
533 WRectangle tmp;
535 if(rq->flags&REGION_RQGEOM_ABSOLUTE)
536 region_absolute_geom_to_parent(reg, &rq->geom, &tmp);
537 else
538 tmp=rq->geom;
540 if(geomret!=NULL)
541 *geomret=tmp;
543 if(!(rq->flags&REGION_RQGEOM_TRYONLY))
544 region_fit(reg, &tmp, REGION_FIT_EXACT);
549 void rqgeomparams_from_table(WRQGeomParams *rq,
550 const WRectangle *origg, ExtlTab g)
552 rq->geom=*origg;
553 rq->flags=REGION_RQGEOM_WEAK_ALL;
555 if(extl_table_gets_i(g, "x", &(rq->geom.x)))
556 rq->flags&=~REGION_RQGEOM_WEAK_X;
557 if(extl_table_gets_i(g, "y", &(rq->geom.y)))
558 rq->flags&=~REGION_RQGEOM_WEAK_Y;
559 if(extl_table_gets_i(g, "w", &(rq->geom.w)))
560 rq->flags&=~REGION_RQGEOM_WEAK_W;
561 if(extl_table_gets_i(g, "h", &(rq->geom.h)))
562 rq->flags&=~REGION_RQGEOM_WEAK_H;
564 rq->geom.w=maxof(1, rq->geom.w);
565 rq->geom.h=maxof(1, rq->geom.h);
569 /*EXTL_DOC
570 * Attempt to resize and/or move \var{reg}. The table \var{g} is a usual
571 * geometry specification (fields \var{x}, \var{y}, \var{w} and \var{h}),
572 * but may contain missing fields, in which case, \var{reg}'s manager may
573 * attempt to leave that attribute unchanged.
575 EXTL_EXPORT_AS(WRegion, rqgeom)
576 ExtlTab region_rqgeom_extl(WRegion *reg, ExtlTab g)
578 WRQGeomParams rq=RQGEOMPARAMS_INIT;
579 WRectangle res;
581 rqgeomparams_from_table(&rq, &REGION_GEOM(reg), g);
583 region_rqgeom(reg, &rq, &res);
585 return extl_table_from_rectangle(&res);
589 void region_managed_rqgeom(WRegion *mgr, WRegion *reg,
590 const WRQGeomParams *rq,
591 WRectangle *geomret)
593 CALL_DYN(region_managed_rqgeom, mgr, (mgr, reg, rq, geomret));
597 void region_managed_rqgeom_absolute(WRegion *mgr, WRegion *reg,
598 const WRQGeomParams *rq,
599 WRectangle *geomret)
601 CALL_DYN(region_managed_rqgeom_absolute, mgr,
602 (mgr, reg, rq, geomret));
606 void region_managed_rqgeom_allow(WRegion *mgr, WRegion *reg,
607 const WRQGeomParams *rq,
608 WRectangle *geomret)
610 if(geomret!=NULL)
611 *geomret=rq->geom;
613 if(!(rq->flags&REGION_RQGEOM_TRYONLY))
614 region_fit(reg, &rq->geom, REGION_FIT_EXACT);
618 void region_managed_rqgeom_unallow(WRegion *mgr, WRegion *reg,
619 const WRQGeomParams *rq,
620 WRectangle *geomret)
622 if(geomret!=NULL)
623 *geomret=REGION_GEOM(reg);
627 void region_managed_rqgeom_absolute_default(WRegion *mgr, WRegion *reg,
628 const WRQGeomParams *rq,
629 WRectangle *geomret)
631 WRQGeomParams rq2=RQGEOMPARAMS_INIT;
633 rq2.flags=rq->flags&~REGION_RQGEOM_ABSOLUTE;
634 region_absolute_geom_to_parent(reg, &rq->geom, &rq2.geom);
636 region_managed_rqgeom(mgr, reg, &rq2, geomret);
640 bool region_managed_maximize(WRegion *mgr, WRegion *reg, int dir, int action)
642 bool ret=FALSE;
643 CALL_DYN_RET(ret, bool, region_managed_maximize, mgr, (mgr, reg, dir, action));
644 return ret;
648 void region_size_hints(WRegion *reg, WSizeHints *hints_ret)
650 sizehints_clear(hints_ret);
653 CALL_DYN(region_size_hints, reg, (reg, hints_ret));
656 if(!hints_ret->min_set){
657 hints_ret->min_width=1;
658 hints_ret->min_height=1;
660 if(!hints_ret->base_set){
661 hints_ret->base_width=0;
662 hints_ret->base_height=0;
664 if(!hints_ret->max_set){
665 hints_ret->max_width=INT_MAX;
666 hints_ret->max_height=INT_MAX;
671 void region_size_hints_correct(WRegion *reg,
672 int *wp, int *hp, bool min)
674 WSizeHints hints;
676 region_size_hints(reg, &hints);
678 sizehints_correct(&hints, wp, hp, min, FALSE);
682 int region_orientation(WRegion *reg)
684 int ret=REGION_ORIENTATION_NONE;
686 CALL_DYN_RET(ret, int, region_orientation, reg, (reg));
688 return ret;
692 /*EXTL_DOC
693 * Returns size hints for \var{reg}. The returned table always contains the
694 * fields \code{min_?}, \code{base_?} and sometimes the fields \code{max_?},
695 * \code{base_?} and \code{inc_?}, where \code{?}=\code{w}, \code{h}.
697 EXTL_SAFE
698 EXTL_EXPORT_AS(WRegion, size_hints)
699 ExtlTab region_size_hints_extl(WRegion *reg)
701 WSizeHints hints;
702 ExtlTab tab;
704 region_size_hints(reg, &hints);
706 tab=extl_create_table();
708 if(hints.base_set){
709 extl_table_sets_i(tab, "base_w", hints.base_width);
710 extl_table_sets_i(tab, "base_h", hints.base_height);
712 if(hints.min_set){
713 extl_table_sets_i(tab, "min_w", hints.min_width);
714 extl_table_sets_i(tab, "min_h", hints.min_height);
716 if(hints.max_set){
717 extl_table_sets_i(tab, "max_w", hints.max_width);
718 extl_table_sets_i(tab, "max_h", hints.max_height);
720 if(hints.inc_set){
721 extl_table_sets_i(tab, "inc_w", hints.width_inc);
722 extl_table_sets_i(tab, "inc_h", hints.height_inc);
725 return tab;
728 /*}}}*/
731 /*{{{ Restore size, maximize, shade */
734 static bool rqh(WFrame *frame, int y, int h)
736 WRQGeomParams rq=RQGEOMPARAMS_INIT;
737 WRectangle rgeom;
738 int dummy_w;
740 rq.flags=REGION_RQGEOM_VERT_ONLY;
742 rq.geom.x=REGION_GEOM(frame).x;
743 rq.geom.w=REGION_GEOM(frame).w;
744 rq.geom.y=y;
745 rq.geom.h=h;
747 dummy_w=rq.geom.w;
748 region_size_hints_correct((WRegion*)frame, &dummy_w, &(rq.geom.h), TRUE);
750 region_rqgeom((WRegion*)frame, &rq, &rgeom);
752 return (abs(rgeom.y-REGION_GEOM(frame).y)>1 ||
753 abs(rgeom.h-REGION_GEOM(frame).h)>1);
757 /*EXTL_DOC
758 * Attempt to toggle vertical maximisation of \var{frame}.
760 EXTL_EXPORT_MEMBER
761 void frame_maximize_vert(WFrame *frame)
763 WRegion *mp=REGION_MANAGER(frame);
764 int oy, oh;
766 if(frame->flags&FRAME_SHADED || frame->flags&FRAME_MAXED_VERT){
767 if(frame->flags&FRAME_SHADED)
768 frame->flags|=FRAME_SHADED_TOGGLE;
769 if(frame->flags&FRAME_SAVED_VERT){
770 if(mp!=NULL && region_managed_maximize(mp, (WRegion*)frame, VERTICAL, VERIFY))
771 region_managed_maximize(mp, (WRegion*)frame, VERTICAL, RESTORE);
772 else
773 rqh(frame, frame->saved_geom.y, frame->saved_geom.h);
775 frame->flags&=~(FRAME_MAXED_VERT|FRAME_SAVED_VERT|FRAME_SHADED_TOGGLE);
776 region_goto((WRegion*)frame);
777 return;
780 if(mp==NULL)
781 return;
783 oy=REGION_GEOM(frame).y;
784 oh=REGION_GEOM(frame).h;
786 region_managed_maximize(mp, (WRegion*)frame, VERTICAL, SAVE);
787 rqh(frame, 0, REGION_GEOM(mp).h);
788 region_managed_maximize(mp, (WRegion*)frame, VERTICAL, RM_KEEP);
790 frame->flags|=(FRAME_MAXED_VERT|FRAME_SAVED_VERT);
791 frame->saved_geom.y=oy;
792 frame->saved_geom.h=oh;
794 region_goto((WRegion*)frame);
797 static bool rqw(WFrame *frame, int x, int w)
799 WRQGeomParams rq=RQGEOMPARAMS_INIT;
800 WRectangle rgeom;
801 int dummy_h;
803 rq.flags=REGION_RQGEOM_HORIZ_ONLY;
805 rq.geom.x=x;
806 rq.geom.w=w;
807 rq.geom.y=REGION_GEOM(frame).y;
808 rq.geom.h=REGION_GEOM(frame).h;
810 dummy_h=rq.geom.h;
811 region_size_hints_correct((WRegion*)frame, &(rq.geom.w), &dummy_h, TRUE);
813 region_rqgeom((WRegion*)frame, &rq, &rgeom);
815 return (abs(rgeom.x-REGION_GEOM(frame).x)>1 ||
816 abs(rgeom.w-REGION_GEOM(frame).w)>1);
820 /*EXTL_DOC
821 * Attempt to toggle horizontal maximisation of \var{frame}.
823 EXTL_EXPORT_MEMBER
824 void frame_maximize_horiz(WFrame *frame)
826 WRegion *mp=REGION_MANAGER(frame);
827 int ox, ow;
829 if(frame->flags&FRAME_MIN_HORIZ || frame->flags&FRAME_MAXED_HORIZ){
830 if(frame->flags&FRAME_SAVED_HORIZ){
831 if(mp!=NULL && region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, VERIFY))
832 region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, RESTORE);
833 else
834 rqw(frame, frame->saved_geom.x, frame->saved_geom.w);
836 frame->flags&=~(FRAME_MAXED_HORIZ|FRAME_SAVED_HORIZ);
837 region_goto((WRegion*)frame);
838 return;
841 if(mp==NULL)
842 return;
844 ox=REGION_GEOM(frame).x;
845 ow=REGION_GEOM(frame).w;
847 region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, SAVE);
848 rqw(frame, 0, REGION_GEOM(mp).w);
849 region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, RM_KEEP);
851 frame->flags|=(FRAME_MAXED_HORIZ|FRAME_SAVED_HORIZ);
852 frame->saved_geom.x=ox;
853 frame->saved_geom.w=ow;
855 region_goto((WRegion*)frame);
860 /*}}}*/
863 /*{{{ Misc. */
866 uint region_min_h(WRegion *reg)
868 WSizeHints hints;
869 region_size_hints(reg, &hints);
870 return hints.min_height;
874 uint region_min_w(WRegion *reg)
876 WSizeHints hints;
877 region_size_hints(reg, &hints);
878 return hints.min_width;
882 void region_convert_root_geom(WRegion *reg, WRectangle *geom)
884 int rx, ry;
885 if(reg!=NULL){
886 region_rootpos(reg, &rx, &ry);
887 geom->x-=rx;
888 geom->y-=ry;
893 void region_absolute_geom_to_parent(WRegion *reg, const WRectangle *rgeom,
894 WRectangle *pgeom)
896 WRegion *parent=REGION_PARENT_REG(reg);
898 pgeom->w=rgeom->w;
899 pgeom->h=rgeom->h;
901 if(parent==NULL){
902 pgeom->x=rgeom->x;
903 pgeom->y=rgeom->y;
904 }else{
905 region_rootpos(reg, &pgeom->x, &pgeom->y);
906 pgeom->x=rgeom->x-pgeom->x;
907 pgeom->y=rgeom->y-pgeom->y;
911 /*}}}*/