Consistency fixes
[notion.git] / ioncore / resize.c
blob5a659ce43e048394f98c4b4a3c2827dfc60be6b2
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 char *buf;
130 if(mode->infowin==NULL)
131 return;
133 buf=INFOWIN_BUFFER(mode->infowin);
135 if(buf==NULL)
136 return;
138 if(mode->mode==MOVERES_SIZE){
139 int w, h;
141 w=mode->geom.w;
142 h=mode->geom.h;
144 if(mode->hints.base_set){
145 w=MAXOF(0, w-mode->hints.base_width);
146 h=MAXOF(0, h-mode->hints.base_height);
149 if(mode->hints.inc_set){
150 w/=MAXOF(1, mode->hints.width_inc);
151 h/=MAXOF(1, mode->hints.height_inc);
154 snprintf(buf, INFOWIN_BUFFER_LEN, "%dx%d", w, h);
155 }else{
156 snprintf(buf, INFOWIN_BUFFER_LEN, "%+d %+d",
157 mode->geom.x, mode->geom.y);
160 window_draw((WWindow*)mode->infowin, TRUE);
164 static void moveres_draw_rubberband(WMoveresMode *mode)
166 WRectangle rgeom=mode->geom;
167 WRootWin *rootwin=(mode->reg==NULL
168 ? NULL
169 : region_rootwin_of(mode->reg));
171 if(rootwin==NULL)
172 return;
174 rgeom.x+=mode->parent_rx;
175 rgeom.y+=mode->parent_ry;
177 if(mode->rubfn==NULL)
178 draw_rubberbox(rootwin, &rgeom);
179 else
180 mode->rubfn(rootwin, &rgeom);
184 /*}}}*/
187 /*{{{ Move/resize mode */
190 WMoveresMode *tmpmode=NULL;
193 EXTL_EXPORT
194 IMPLCLASS(WMoveresMode, Obj, NULL, NULL);
197 WMoveresMode *moveres_mode(WRegion *reg)
199 if(tmpmode==NULL)
200 return NULL;
201 return ((reg==NULL || tmpmode->reg==reg) ? tmpmode : NULL);
205 WRegion *moveresmode_target(WMoveresMode *mode)
207 return mode->reg;
211 static bool moveresmode_init(WMoveresMode *mode, WRegion *reg,
212 WDrawRubberbandFn *rubfn, bool cumulative)
214 WWindow *parent;
215 WRegion *mgr;
217 if(tmpmode!=NULL)
218 return FALSE;
220 parent=REGION_PARENT(reg);
222 if(parent==NULL)
223 return FALSE;
225 tmpmode=mode;
227 mode->snap_enabled=FALSE;
228 region_size_hints(reg, &mode->hints);
230 region_rootpos((WRegion*)parent, &mode->parent_rx, &mode->parent_ry);
232 mode->geom=REGION_GEOM(reg);
233 mode->origgeom=REGION_GEOM(reg);
234 mode->dx1=0;
235 mode->dx2=0;
236 mode->dy1=0;
237 mode->dy2=0;
238 mode->rubfn=rubfn;
239 mode->resize_cumulative=cumulative;
240 mode->rqflags=(XOR_RESIZE ? REGION_RQGEOM_TRYONLY : 0);
241 mode->reg=reg;
242 mode->mode=MOVERES_SIZE;
244 /* Get snapping geometry */
245 mgr=REGION_MANAGER(reg);
247 if(mgr!=NULL){
248 mode->snapgeom=REGION_GEOM(mgr);
250 if(mgr==(WRegion*)parent){
251 mode->snapgeom.x=0;
252 mode->snapgeom.y=0;
253 /*mode->snap_enabled=FALSE;*/
255 mode->snap_enabled=TRUE;
258 if(!mode->hints.min_set || mode->hints.min_width<1)
259 mode->hints.min_width=1;
260 if(!mode->hints.min_set || mode->hints.min_height<1)
261 mode->hints.min_height=1;
263 /* Set up info window */
265 int x=mode->geom.x+mode->geom.w/2;
266 int y=mode->geom.y+mode->geom.h/2;
267 mode->infowin=setup_moveres_display(parent, x, y);
270 moveres_draw_infowin(mode);
272 if(XOR_RESIZE){
273 XGrabServer(ioncore_g.dpy);
274 moveres_draw_rubberband(mode);
277 return TRUE;
281 static WMoveresMode *create_moveresmode(WRegion *reg,
282 WDrawRubberbandFn *rubfn,
283 bool cumulative)
285 CREATEOBJ_IMPL(WMoveresMode, moveresmode, (p, reg, rubfn, cumulative));
289 WMoveresMode *region_begin_resize(WRegion *reg, WDrawRubberbandFn *rubfn,
290 bool cumulative)
292 WMoveresMode *mode=create_moveresmode(reg, rubfn, cumulative);
294 if(mode!=NULL){
295 mode->mode=MOVERES_SIZE;
296 ioncore_change_grab_cursor(IONCORE_CURSOR_RESIZE);
299 return mode;
303 WMoveresMode *region_begin_move(WRegion *reg, WDrawRubberbandFn *rubfn,
304 bool cumulative)
306 WMoveresMode *mode=create_moveresmode(reg, rubfn, cumulative);
308 if(mode!=NULL){
309 mode->mode=MOVERES_POS;
310 ioncore_change_grab_cursor(IONCORE_CURSOR_MOVE);
313 return mode;
317 static void moveresmode_setorig(WMoveresMode *mode)
319 mode->dx1=0;
320 mode->dx2=0;
321 mode->dy1=0;
322 mode->dy2=0;
323 mode->origgeom=mode->geom;
327 static void moveresmode_do_newgeom(WMoveresMode *mode, WRQGeomParams *rq)
329 if(XOR_RESIZE)
330 moveres_draw_rubberband(mode);
332 if(mode->reg!=NULL){
333 rq->flags|=mode->rqflags;
334 region_rqgeom(mode->reg, rq, &mode->geom);
337 moveres_draw_infowin(mode);
339 if(XOR_RESIZE)
340 moveres_draw_rubberband(mode);
344 static int clamp_up(int t, int low, int high)
346 return (t < high && t > low ? high : t);
350 static void moveresmode_delta(WMoveresMode *mode,
351 int dx1, int dx2, int dy1, int dy2,
352 WRectangle *rret)
354 int realdx1, realdx2, realdy1, realdy2;
355 WRQGeomParams rq=RQGEOMPARAMS_INIT;
356 int er=ioncore_edge_resistance;
357 int w=0, h=0;
359 realdx1=(mode->dx1+=dx1);
360 realdx2=(mode->dx2+=dx2);
361 realdy1=(mode->dy1+=dy1);
362 realdy2=(mode->dy2+=dy2);
363 rq.geom=mode->origgeom;
365 /* snap */
366 if(mode->snap_enabled){
367 WRectangle *sg=&mode->snapgeom;
369 if(mode->dx1!=0 && rq.geom.x+mode->dx1<sg->x && rq.geom.x+mode->dx1>sg->x-er)
370 realdx1=sg->x-rq.geom.x;
371 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)
372 realdx2=sg->x+sg->w-rq.geom.x-rq.geom.w;
373 if(mode->dy1!=0 && rq.geom.y+mode->dy1<sg->y && rq.geom.y+mode->dy1>sg->y-er)
374 realdy1=sg->y-rq.geom.y;
375 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)
376 realdy2=sg->y+sg->h-rq.geom.y-rq.geom.h;
379 w=MAXOF(1, mode->origgeom.w-realdx1+realdx2);
380 h=MAXOF(1, mode->origgeom.h-realdy1+realdy2);
382 if(mode->snap_enabled && mode->hints.base_set){
383 w=clamp_up(w, mode->hints.base_width-er, mode->hints.base_width);
384 h=clamp_up(h, mode->hints.base_height-er, mode->hints.base_height);
387 /* Correct size */
388 sizehints_correct(&mode->hints, &w, &h, TRUE, TRUE);
390 /* Do not modify coordinates and sizes that were not requested to be
391 * changed.
394 if(mode->dx1==mode->dx2){
395 if(mode->dx1==0 || realdx1!=mode->dx1)
396 rq.geom.x+=realdx1;
397 else
398 rq.geom.x+=realdx2;
399 }else{
400 rq.geom.w=w;
401 if(mode->dx1==0 || realdx1!=mode->dx1)
402 rq.geom.x+=realdx1;
403 else
404 rq.geom.x+=mode->origgeom.w-rq.geom.w;
408 if(mode->dy1==mode->dy2){
409 if(mode->dy1==0 || realdy1!=mode->dy1)
410 rq.geom.y+=realdy1;
411 else
412 rq.geom.y+=realdy2;
413 }else{
414 rq.geom.h=h;
415 if(mode->dy1==0 || realdy1!=mode->dy1)
416 rq.geom.y+=realdy1;
417 else
418 rq.geom.y+=mode->origgeom.h-rq.geom.h;
421 moveresmode_do_newgeom(mode, &rq);
423 if(!mode->resize_cumulative)
424 moveresmode_setorig(mode);
426 if(rret!=NULL)
427 *rret=mode->geom;
431 void moveresmode_delta_resize(WMoveresMode *mode,
432 int dx1, int dx2, int dy1, int dy2,
433 WRectangle *rret)
435 mode->mode=MOVERES_SIZE;
436 moveresmode_delta(mode, dx1, dx2, dy1, dy2, rret);
440 void moveresmode_delta_move(WMoveresMode *mode,
441 int dx, int dy, WRectangle *rret)
443 mode->mode=MOVERES_POS;
444 moveresmode_delta(mode, dx, dx, dy, dy, rret);
448 void moveresmode_rqgeom(WMoveresMode *mode, WRQGeomParams *rq,
449 WRectangle *UNUSED(rret))
451 mode->mode=MOVERES_SIZE;
452 moveresmode_do_newgeom(mode, rq);
453 moveresmode_setorig(mode);
457 /* It is ugly to do this here, but it will have to do for now... */
458 static void set_saved(WMoveresMode *mode, WRegion *reg)
460 WFrame *frame;
462 if(!OBJ_IS(reg, WFrame))
463 return;
465 frame=(WFrame*)reg;
467 /* Restore saved sizes from the beginning of the resize action */
468 if(mode->origgeom.w!=mode->geom.w){
469 frame->saved_geom.x=mode->origgeom.x;
470 frame->saved_geom.w=mode->origgeom.w;
473 if(mode->origgeom.h!=mode->geom.h){
474 frame->saved_geom.y=mode->origgeom.y;
475 frame->saved_geom.h=mode->origgeom.h;
480 bool moveresmode_do_end(WMoveresMode *mode, bool apply)
482 WRegion *reg=mode->reg;
484 assert(reg!=NULL);
485 assert(tmpmode==mode);
487 tmpmode=NULL;
489 if(XOR_RESIZE){
490 moveres_draw_rubberband(mode);
491 if(apply){
492 WRQGeomParams rq=RQGEOMPARAMS_INIT;
494 rq.geom=mode->geom;
495 rq.flags=mode->rqflags&~REGION_RQGEOM_TRYONLY;
497 region_rqgeom(reg, &rq, &mode->geom);
499 XUngrabServer(ioncore_g.dpy);
501 if(apply)
502 set_saved(mode, reg);
504 if(mode->infowin!=NULL){
505 mainloop_defer_destroy((Obj*)mode->infowin);
506 mode->infowin=NULL;
508 destroy_obj((Obj*)mode);
510 return TRUE;
514 /*}}}*/
517 /*{{{ Request and other dynfuns */
520 void region_rqgeom(WRegion *reg, const WRQGeomParams *rq,
521 WRectangle *geomret)
523 WRegion *mgr=REGION_MANAGER(reg);
525 if(mgr!=NULL){
526 if(rq->flags&REGION_RQGEOM_ABSOLUTE)
527 region_managed_rqgeom_absolute(mgr, reg, rq, geomret);
528 else
529 region_managed_rqgeom(mgr, reg, rq, geomret);
530 }else{
531 WRectangle tmp;
533 if(rq->flags&REGION_RQGEOM_ABSOLUTE)
534 region_absolute_geom_to_parent(reg, &rq->geom, &tmp);
535 else
536 tmp=rq->geom;
538 if(geomret!=NULL)
539 *geomret=tmp;
541 if(!(rq->flags&REGION_RQGEOM_TRYONLY))
542 region_fit(reg, &tmp, REGION_FIT_EXACT);
547 void rqgeomparams_from_table(WRQGeomParams *rq,
548 const WRectangle *origg, ExtlTab g)
550 rq->geom=*origg;
551 rq->flags=REGION_RQGEOM_WEAK_ALL;
553 if(extl_table_gets_i(g, "x", &(rq->geom.x)))
554 rq->flags&=~REGION_RQGEOM_WEAK_X;
555 if(extl_table_gets_i(g, "y", &(rq->geom.y)))
556 rq->flags&=~REGION_RQGEOM_WEAK_Y;
557 if(extl_table_gets_i(g, "w", &(rq->geom.w)))
558 rq->flags&=~REGION_RQGEOM_WEAK_W;
559 if(extl_table_gets_i(g, "h", &(rq->geom.h)))
560 rq->flags&=~REGION_RQGEOM_WEAK_H;
562 rq->geom.w=MAXOF(1, rq->geom.w);
563 rq->geom.h=MAXOF(1, rq->geom.h);
567 /*EXTL_DOC
568 * Attempt to resize and/or move \var{reg}. The table \var{g} is a usual
569 * geometry specification (fields \var{x}, \var{y}, \var{w} and \var{h}),
570 * but may contain missing fields, in which case, \var{reg}'s manager may
571 * attempt to leave that attribute unchanged.
573 EXTL_EXPORT_AS(WRegion, rqgeom)
574 ExtlTab region_rqgeom_extl(WRegion *reg, ExtlTab g)
576 WRQGeomParams rq=RQGEOMPARAMS_INIT;
577 WRectangle res;
579 rqgeomparams_from_table(&rq, &REGION_GEOM(reg), g);
581 region_rqgeom(reg, &rq, &res);
583 return extl_table_from_rectangle(&res);
587 void region_managed_rqgeom(WRegion *mgr, WRegion *reg,
588 const WRQGeomParams *rq,
589 WRectangle *geomret)
591 CALL_DYN(region_managed_rqgeom, mgr, (mgr, reg, rq, geomret));
595 void region_managed_rqgeom_absolute(WRegion *mgr, WRegion *reg,
596 const WRQGeomParams *rq,
597 WRectangle *geomret)
599 CALL_DYN(region_managed_rqgeom_absolute, mgr,
600 (mgr, reg, rq, geomret));
604 void region_managed_rqgeom_allow(WRegion *UNUSED(mgr), WRegion *reg,
605 const WRQGeomParams *rq,
606 WRectangle *geomret)
608 if(geomret!=NULL)
609 *geomret=rq->geom;
611 if(!(rq->flags&REGION_RQGEOM_TRYONLY))
612 region_fit(reg, &rq->geom, REGION_FIT_EXACT);
616 void region_managed_rqgeom_unallow(WRegion *UNUSED(mgr), WRegion *reg,
617 const WRQGeomParams *UNUSED(rq),
618 WRectangle *geomret)
620 if(geomret!=NULL)
621 *geomret=REGION_GEOM(reg);
625 void region_managed_rqgeom_absolute_default(WRegion *mgr, WRegion *reg,
626 const WRQGeomParams *rq,
627 WRectangle *geomret)
629 WRQGeomParams rq2=RQGEOMPARAMS_INIT;
631 rq2.flags=rq->flags&~REGION_RQGEOM_ABSOLUTE;
632 region_absolute_geom_to_parent(reg, &rq->geom, &rq2.geom);
634 region_managed_rqgeom(mgr, reg, &rq2, geomret);
638 bool region_managed_maximize(WRegion *mgr, WRegion *reg, int dir, int action)
640 bool ret=FALSE;
641 CALL_DYN_RET(ret, bool, region_managed_maximize, mgr, (mgr, reg, dir, action));
642 return ret;
646 void region_size_hints(WRegion *reg, WSizeHints *hints_ret)
648 sizehints_clear(hints_ret);
651 CALL_DYN(region_size_hints, reg, (reg, hints_ret));
654 if(!hints_ret->min_set){
655 hints_ret->min_width=1;
656 hints_ret->min_height=1;
658 if(!hints_ret->base_set){
659 hints_ret->base_width=0;
660 hints_ret->base_height=0;
662 if(!hints_ret->max_set){
663 hints_ret->max_width=INT_MAX;
664 hints_ret->max_height=INT_MAX;
669 void region_size_hints_correct(WRegion *reg,
670 int *wp, int *hp, bool min)
672 WSizeHints hints;
674 region_size_hints(reg, &hints);
676 sizehints_correct(&hints, wp, hp, min, FALSE);
680 int region_orientation(WRegion *reg)
682 int ret=REGION_ORIENTATION_NONE;
684 CALL_DYN_RET(ret, int, region_orientation, reg, (reg));
686 return ret;
690 /*EXTL_DOC
691 * Returns size hints for \var{reg}. The returned table always contains the
692 * fields \code{min_?}, \code{base_?} and sometimes the fields \code{max_?},
693 * \code{base_?} and \code{inc_?}, where \code{?}=\code{w}, \code{h}.
695 EXTL_SAFE
696 EXTL_EXPORT_AS(WRegion, size_hints)
697 ExtlTab region_size_hints_extl(WRegion *reg)
699 WSizeHints hints;
700 ExtlTab tab;
702 region_size_hints(reg, &hints);
704 tab=extl_create_table();
706 if(hints.base_set){
707 extl_table_sets_i(tab, "base_w", hints.base_width);
708 extl_table_sets_i(tab, "base_h", hints.base_height);
710 if(hints.min_set){
711 extl_table_sets_i(tab, "min_w", hints.min_width);
712 extl_table_sets_i(tab, "min_h", hints.min_height);
714 if(hints.max_set){
715 extl_table_sets_i(tab, "max_w", hints.max_width);
716 extl_table_sets_i(tab, "max_h", hints.max_height);
718 if(hints.inc_set){
719 extl_table_sets_i(tab, "inc_w", hints.width_inc);
720 extl_table_sets_i(tab, "inc_h", hints.height_inc);
723 return tab;
726 /*}}}*/
729 /*{{{ Restore size, maximize, shade */
732 static bool rqh(WFrame *frame, int y, int h)
734 WRQGeomParams rq=RQGEOMPARAMS_INIT;
735 WRectangle rgeom;
736 int dummy_w;
738 rq.flags=REGION_RQGEOM_VERT_ONLY;
740 rq.geom.x=REGION_GEOM(frame).x;
741 rq.geom.w=REGION_GEOM(frame).w;
742 rq.geom.y=y;
743 rq.geom.h=h;
745 dummy_w=rq.geom.w;
746 region_size_hints_correct((WRegion*)frame, &dummy_w, &(rq.geom.h), TRUE);
748 region_rqgeom((WRegion*)frame, &rq, &rgeom);
750 return (abs(rgeom.y-REGION_GEOM(frame).y)>1 ||
751 abs(rgeom.h-REGION_GEOM(frame).h)>1);
755 /*EXTL_DOC
756 * Attempt to toggle vertical maximisation of \var{frame}.
758 EXTL_EXPORT_MEMBER
759 void frame_maximize_vert(WFrame *frame)
761 WRegion *mp=REGION_MANAGER(frame);
762 int oy, oh;
764 if(frame->flags&FRAME_SHADED || frame->flags&FRAME_MAXED_VERT){
765 if(frame->flags&FRAME_SHADED)
766 frame->flags|=FRAME_SHADED_TOGGLE;
767 if(frame->flags&FRAME_SAVED_VERT){
768 if(mp!=NULL && region_managed_maximize(mp, (WRegion*)frame, VERTICAL, VERIFY))
769 region_managed_maximize(mp, (WRegion*)frame, VERTICAL, RESTORE);
770 else
771 rqh(frame, frame->saved_geom.y, frame->saved_geom.h);
773 frame->flags&=~(FRAME_MAXED_VERT|FRAME_SAVED_VERT|FRAME_SHADED_TOGGLE);
774 region_goto((WRegion*)frame);
775 return;
778 if(mp==NULL)
779 return;
781 oy=REGION_GEOM(frame).y;
782 oh=REGION_GEOM(frame).h;
784 region_managed_maximize(mp, (WRegion*)frame, VERTICAL, SAVE);
785 rqh(frame, 0, REGION_GEOM(mp).h);
786 region_managed_maximize(mp, (WRegion*)frame, VERTICAL, RM_KEEP);
788 frame->flags|=(FRAME_MAXED_VERT|FRAME_SAVED_VERT);
789 frame->saved_geom.y=oy;
790 frame->saved_geom.h=oh;
792 region_goto((WRegion*)frame);
795 static bool rqw(WFrame *frame, int x, int w)
797 WRQGeomParams rq=RQGEOMPARAMS_INIT;
798 WRectangle rgeom;
799 int dummy_h;
801 rq.flags=REGION_RQGEOM_HORIZ_ONLY;
803 rq.geom.x=x;
804 rq.geom.w=w;
805 rq.geom.y=REGION_GEOM(frame).y;
806 rq.geom.h=REGION_GEOM(frame).h;
808 dummy_h=rq.geom.h;
809 region_size_hints_correct((WRegion*)frame, &(rq.geom.w), &dummy_h, TRUE);
811 region_rqgeom((WRegion*)frame, &rq, &rgeom);
813 return (abs(rgeom.x-REGION_GEOM(frame).x)>1 ||
814 abs(rgeom.w-REGION_GEOM(frame).w)>1);
818 /*EXTL_DOC
819 * Attempt to toggle horizontal maximisation of \var{frame}.
821 EXTL_EXPORT_MEMBER
822 void frame_maximize_horiz(WFrame *frame)
824 WRegion *mp=REGION_MANAGER(frame);
825 int ox, ow;
827 if(frame->flags&FRAME_MIN_HORIZ || frame->flags&FRAME_MAXED_HORIZ){
828 if(frame->flags&FRAME_SAVED_HORIZ){
829 if(mp!=NULL && region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, VERIFY))
830 region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, RESTORE);
831 else
832 rqw(frame, frame->saved_geom.x, frame->saved_geom.w);
834 frame->flags&=~(FRAME_MAXED_HORIZ|FRAME_SAVED_HORIZ);
835 region_goto((WRegion*)frame);
836 return;
839 if(mp==NULL)
840 return;
842 ox=REGION_GEOM(frame).x;
843 ow=REGION_GEOM(frame).w;
845 region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, SAVE);
846 rqw(frame, 0, REGION_GEOM(mp).w);
847 region_managed_maximize(mp, (WRegion*)frame, HORIZONTAL, RM_KEEP);
849 frame->flags|=(FRAME_MAXED_HORIZ|FRAME_SAVED_HORIZ);
850 frame->saved_geom.x=ox;
851 frame->saved_geom.w=ow;
853 region_goto((WRegion*)frame);
858 /*}}}*/
861 /*{{{ Misc. */
864 uint region_min_h(WRegion *reg)
866 WSizeHints hints;
867 region_size_hints(reg, &hints);
868 return hints.min_height;
872 uint region_min_w(WRegion *reg)
874 WSizeHints hints;
875 region_size_hints(reg, &hints);
876 return hints.min_width;
880 void region_convert_root_geom(WRegion *reg, WRectangle *geom)
882 int rx, ry;
883 if(reg!=NULL){
884 region_rootpos(reg, &rx, &ry);
885 geom->x-=rx;
886 geom->y-=ry;
891 void region_absolute_geom_to_parent(WRegion *reg, const WRectangle *rgeom,
892 WRectangle *pgeom)
894 WRegion *parent=REGION_PARENT_REG(reg);
896 pgeom->w=rgeom->w;
897 pgeom->h=rgeom->h;
899 if(parent==NULL){
900 pgeom->x=rgeom->x;
901 pgeom->y=rgeom->y;
902 }else{
903 region_rootpos(reg, &pgeom->x, &pgeom->y);
904 pgeom->x=rgeom->x-pgeom->x;
905 pgeom->y=rgeom->y-pgeom->y;
909 /*}}}*/