4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
12 #include <libtu/objp.h>
13 #include <libtu/minmax.h>
14 #include <libextl/extl.h>
15 #include <libmainloop/defer.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
)
45 fpts
[1].x
=rect
->x
+rect
->w
;
47 fpts
[2].x
=rect
->x
+rect
->w
;
48 fpts
[2].y
=rect
->y
+rect
->h
;
50 fpts
[3].y
=rect
->y
+rect
->h
;
54 XDrawLines(ioncore_g
.dpy
, WROOTWIN_ROOT(rw
), rw
->xor_gc
, fpts
, 5,
59 static int max_width(GrBrush
*brush
, const char *str
)
63 while(str
&& *str
!='\0'){
64 w
=grbrush_get_text_width(brush
, str
, 1);
74 static int chars_for_num(int d
)
87 static WInfoWin
*setup_moveres_display(WWindow
*parent
, int cx
, int cy
)
94 fp
.mode
=REGION_FIT_EXACT
;
100 infowin
=create_infowin(parent
, &fp
, "moveres_display");
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 */
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
;;
119 region_fitrep((WRegion
*)infowin
, NULL
, &fp
);
120 region_map((WRegion
*)infowin
);
126 static void moveres_draw_infowin(WMoveresMode
*mode
)
131 if(mode
->infowin
==NULL
)
134 buf
=INFOWIN_BUFFER(mode
->infowin
);
139 if(mode
->mode
==MOVERES_SIZE
){
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
);
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
;
169 WRootWin
*rootwin
=(mode
->reg
==NULL
171 : region_rootwin_of(mode
->reg
));
176 rgeom
.x
+=mode
->parent_rx
;
177 rgeom
.y
+=mode
->parent_ry
;
179 if(mode
->rubfn
==NULL
)
180 draw_rubberbox(rootwin
, &rgeom
);
182 mode
->rubfn(rootwin
, &rgeom
);
189 /*{{{ Move/resize mode */
192 WMoveresMode
*tmpmode
=NULL
;
196 IMPLCLASS(WMoveresMode
, Obj
, NULL
, NULL
);
199 WMoveresMode
*moveres_mode(WRegion
*reg
)
203 return ((reg
==NULL
|| tmpmode
->reg
==reg
) ? tmpmode
: NULL
);
207 WRegion
*moveresmode_target(WMoveresMode
*mode
)
213 static bool moveresmode_init(WMoveresMode
*mode
, WRegion
*reg
,
214 WDrawRubberbandFn
*rubfn
, bool cumulative
)
222 parent
=REGION_PARENT(reg
);
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
);
241 mode
->resize_cumulative
=cumulative
;
242 mode
->rqflags
=(XOR_RESIZE
? REGION_RQGEOM_TRYONLY
: 0);
244 mode
->mode
=MOVERES_SIZE
;
246 /* Get snapping geometry */
247 mgr
=REGION_MANAGER(reg
);
250 mode
->snapgeom
=REGION_GEOM(mgr
);
252 if(mgr
==(WRegion
*)parent
){
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
);
275 XGrabServer(ioncore_g
.dpy
);
276 moveres_draw_rubberband(mode
);
283 static WMoveresMode
*create_moveresmode(WRegion
*reg
,
284 WDrawRubberbandFn
*rubfn
,
287 CREATEOBJ_IMPL(WMoveresMode
, moveresmode
, (p
, reg
, rubfn
, cumulative
));
291 WMoveresMode
*region_begin_resize(WRegion
*reg
, WDrawRubberbandFn
*rubfn
,
294 WMoveresMode
*mode
=create_moveresmode(reg
, rubfn
, cumulative
);
297 mode
->mode
=MOVERES_SIZE
;
298 ioncore_change_grab_cursor(IONCORE_CURSOR_RESIZE
);
305 WMoveresMode
*region_begin_move(WRegion
*reg
, WDrawRubberbandFn
*rubfn
,
308 WMoveresMode
*mode
=create_moveresmode(reg
, rubfn
, cumulative
);
311 mode
->mode
=MOVERES_POS
;
312 ioncore_change_grab_cursor(IONCORE_CURSOR_MOVE
);
319 static void moveresmode_setorig(WMoveresMode
*mode
)
325 mode
->origgeom
=mode
->geom
;
329 static void moveresmode_do_newgeom(WMoveresMode
*mode
, WRQGeomParams
*rq
)
332 moveres_draw_rubberband(mode
);
335 rq
->flags
|=mode
->rqflags
;
336 region_rqgeom(mode
->reg
, rq
, &mode
->geom
);
339 moveres_draw_infowin(mode
);
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
,
356 int realdx1
, realdx2
, realdy1
, realdy2
;
357 WRQGeomParams rq
=RQGEOMPARAMS_INIT
;
358 int er
=ioncore_edge_resistance
;
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
;
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
);
390 sizehints_correct(&mode
->hints
, &w
, &h
, TRUE
, TRUE
);
392 /* Do not modify coordinates and sizes that were not requested to be
396 if(mode
->dx1
==mode
->dx2
){
397 if(mode
->dx1
==0 || realdx1
!=mode
->dx1
)
403 if(mode
->dx1
==0 || realdx1
!=mode
->dx1
)
406 rq
.geom
.x
+=mode
->origgeom
.w
-rq
.geom
.w
;
410 if(mode
->dy1
==mode
->dy2
){
411 if(mode
->dy1
==0 || realdy1
!=mode
->dy1
)
417 if(mode
->dy1
==0 || realdy1
!=mode
->dy1
)
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
);
433 void moveresmode_delta_resize(WMoveresMode
*mode
,
434 int dx1
, int dx2
, int dy1
, int dy2
,
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
,
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
)
464 if(!OBJ_IS(reg
, WFrame
))
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
;
487 assert(tmpmode
==mode
);
492 moveres_draw_rubberband(mode
);
494 WRQGeomParams rq
=RQGEOMPARAMS_INIT
;
497 rq
.flags
=mode
->rqflags
&~REGION_RQGEOM_TRYONLY
;
499 region_rqgeom(reg
, &rq
, &mode
->geom
);
501 XUngrabServer(ioncore_g
.dpy
);
504 set_saved(mode
, reg
);
506 if(mode
->infowin
!=NULL
){
507 mainloop_defer_destroy((Obj
*)mode
->infowin
);
510 destroy_obj((Obj
*)mode
);
519 /*{{{ Request and other dynfuns */
522 void region_rqgeom(WRegion
*reg
, const WRQGeomParams
*rq
,
525 WRegion
*mgr
=REGION_MANAGER(reg
);
528 if(rq
->flags
®ION_RQGEOM_ABSOLUTE
)
529 region_managed_rqgeom_absolute(mgr
, reg
, rq
, geomret
);
531 region_managed_rqgeom(mgr
, reg
, rq
, geomret
);
535 if(rq
->flags
®ION_RQGEOM_ABSOLUTE
)
536 region_absolute_geom_to_parent(reg
, &rq
->geom
, &tmp
);
543 if(!(rq
->flags
®ION_RQGEOM_TRYONLY
))
544 region_fit(reg
, &tmp
, REGION_FIT_EXACT
);
549 void rqgeomparams_from_table(WRQGeomParams
*rq
,
550 const WRectangle
*origg
, ExtlTab g
)
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
);
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
;
581 rqgeomparams_from_table(&rq
, ®ION_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
,
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
,
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
,
613 if(!(rq
->flags
®ION_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
,
623 *geomret
=REGION_GEOM(reg
);
627 void region_managed_rqgeom_absolute_default(WRegion
*mgr
, WRegion
*reg
,
628 const WRQGeomParams
*rq
,
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
)
643 CALL_DYN_RET(ret
, bool, region_managed_maximize
, mgr
, (mgr
, reg
, dir
, action
));
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
)
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
));
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}.
698 EXTL_EXPORT_AS(WRegion
, size_hints
)
699 ExtlTab
region_size_hints_extl(WRegion
*reg
)
704 region_size_hints(reg
, &hints
);
706 tab
=extl_create_table();
709 extl_table_sets_i(tab
, "base_w", hints
.base_width
);
710 extl_table_sets_i(tab
, "base_h", hints
.base_height
);
713 extl_table_sets_i(tab
, "min_w", hints
.min_width
);
714 extl_table_sets_i(tab
, "min_h", hints
.min_height
);
717 extl_table_sets_i(tab
, "max_w", hints
.max_width
);
718 extl_table_sets_i(tab
, "max_h", hints
.max_height
);
721 extl_table_sets_i(tab
, "inc_w", hints
.width_inc
);
722 extl_table_sets_i(tab
, "inc_h", hints
.height_inc
);
731 /*{{{ Restore size, maximize, shade */
734 static bool rqh(WFrame
*frame
, int y
, int h
)
736 WRQGeomParams rq
=RQGEOMPARAMS_INIT
;
740 rq
.flags
=REGION_RQGEOM_VERT_ONLY
;
742 rq
.geom
.x
=REGION_GEOM(frame
).x
;
743 rq
.geom
.w
=REGION_GEOM(frame
).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);
758 * Attempt to toggle vertical maximisation of \var{frame}.
761 void frame_maximize_vert(WFrame
*frame
)
763 WRegion
*mp
=REGION_MANAGER(frame
);
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
);
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
);
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
;
803 rq
.flags
=REGION_RQGEOM_HORIZ_ONLY
;
807 rq
.geom
.y
=REGION_GEOM(frame
).y
;
808 rq
.geom
.h
=REGION_GEOM(frame
).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);
821 * Attempt to toggle horizontal maximisation of \var{frame}.
824 void frame_maximize_horiz(WFrame
*frame
)
826 WRegion
*mp
=REGION_MANAGER(frame
);
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
);
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
);
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
);
866 uint
region_min_h(WRegion
*reg
)
869 region_size_hints(reg
, &hints
);
870 return hints
.min_height
;
874 uint
region_min_w(WRegion
*reg
)
877 region_size_hints(reg
, &hints
);
878 return hints
.min_width
;
882 void region_convert_root_geom(WRegion
*reg
, WRectangle
*geom
)
886 region_rootpos(reg
, &rx
, &ry
);
893 void region_absolute_geom_to_parent(WRegion
*reg
, const WRectangle
*rgeom
,
896 WRegion
*parent
=REGION_PARENT_REG(reg
);
905 region_rootpos(reg
, &pgeom
->x
, &pgeom
->y
);
906 pgeom
->x
=rgeom
->x
-pgeom
->x
;
907 pgeom
->y
=rgeom
->y
-pgeom
->y
;