Released version 3-2015061300
[notion.git] / mod_dock / dock.c
blob224512470ada153e887dc65d31680b1cd1df43af
1 /*
2 * Ion dock module
3 * Copyright (C) 2003 Tom Payne
4 * Copyright (C) 2003 Per Olofsson
5 * Copyright (C) 2004-2009 Tuomo Valkonen
7 * by Tom Payne <ion@tompayne.org>
8 * based on code by Per Olofsson <pelle@dsv.su.se>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * $Header: /home/twp/cvsroot/twp/ion/ion-devel-dock/dock.c,v 1.17 2003/12/21 11:59:48 twp Exp $
29 /*{{{ Includes */
31 #include <limits.h>
32 #include <string.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xatom.h>
35 #include <X11/Xutil.h>
36 #include <X11/extensions/shape.h>
38 #include <libtu/objp.h>
39 #include <libtu/map.h>
40 #include <libtu/minmax.h>
41 #include <libextl/extl.h>
42 #include <libextl/readconfig.h>
43 #include <libmainloop/defer.h>
45 #include <ioncore/common.h>
46 #include <ioncore/clientwin.h>
47 #include <ioncore/eventh.h>
48 #include <ioncore/global.h>
49 #include <ioncore/manage.h>
50 #include <ioncore/names.h>
51 #include <ioncore/property.h>
52 #include <ioncore/resize.h>
53 #include <ioncore/window.h>
54 #include <ioncore/mplex.h>
55 #include <ioncore/saveload.h>
56 #include <ioncore/bindmaps.h>
57 #include <ioncore/regbind.h>
58 #include <ioncore/extlconv.h>
59 #include <ioncore/event.h>
60 #include <ioncore/resize.h>
61 #include <ioncore/sizehint.h>
62 #include <ioncore/basicpholder.h>
64 #include "exports.h"
66 /*}}}*/
69 /*{{{ Variables */
71 #include "../version.h"
73 static const char *modname="dock";
74 const char mod_dock_ion_api_version[]=NOTION_API_VERSION;
76 static WBindmap *dock_bindmap=NULL;
78 /*}}}*/
81 /*{{{ Classes */
83 INTRSTRUCT(WDockParam);
84 INTRSTRUCT(WDockApp);
85 INTRCLASS(WDock);
87 DECLSTRUCT(WDockParam){
88 const char *key;
89 const char *desc;
90 const StringIntMap *map;
91 int dflt;
94 DECLSTRUCT(WDockApp){
95 WDockApp *next, *prev;
96 WRegion *reg;
97 int pos;
98 bool draw_border;
99 bool tile;
100 WRectangle geom;
101 WRectangle tile_geom;
102 WRectangle border_geom;
105 DECLCLASS(WDock){
106 WWindow win;
107 WDock *dock_next, *dock_prev;
108 int pos, grow;
109 bool is_auto;
110 GrBrush *brush;
111 WDockApp *dockapps;
113 int min_w, min_h;
114 int max_w, max_h;
116 bool arrange_called;
117 bool save;
120 static WDock *docks=NULL;
122 /*}}}*/
125 /*{{{ Parameter conversion */
127 static void dock_param_extl_table_get(const WDockParam *param,
128 ExtlTab conftab, int value)
130 const char *s;
132 s=stringintmap_key(param->map, value, NULL);
133 if(s){
134 extl_table_sets_s(conftab, param->key, s);
140 static bool dock_param_do_set(const WDockParam *param, char *s,
141 int *ret)
143 bool changed=FALSE;
144 int i=stringintmap_value(param->map, s, -1);
145 if(i<0){
146 warn_obj(modname, "Invalid %s \"%s\"", param->desc, s);
147 }else{
148 if(*ret!=i){
149 changed=TRUE;
151 *ret=i;
153 free(s);
155 return changed;
160 static bool dock_param_extl_table_set(const WDockParam *param, ExtlTab conftab,
161 int *ret)
163 char *s;
165 if(extl_table_gets_s(conftab, param->key, &s))
166 return dock_param_do_set(param, s, ret);
168 return FALSE;
173 static bool dock_param_brush_set(const WDockParam *param, GrBrush *brush,
174 int *ret)
176 char *s;
178 if(grbrush_get_extra(brush, param->key, 's', &s))
179 return dock_param_do_set(param, s, ret);
181 return FALSE;
185 /*}}}*/
188 /*{{{ Parameter descriptions */
190 static const WDockParam dock_param_name={
191 "name",
192 "name",
193 NULL,
198 #define DOCK_HPOS_MASK 0x000f
199 #define DOCK_HPOS_LEFT 0x0000
200 #define DOCK_HPOS_CENTER 0x0001
201 #define DOCK_HPOS_RIGHT 0x0002
202 #define DOCK_VPOS_MASK 0x00f0
203 #define DOCK_VPOS_TOP 0x0000
204 #define DOCK_VPOS_MIDDLE 0x0010
205 #define DOCK_VPOS_BOTTOM 0x0020
208 static StringIntMap dock_pos_map[]={
209 {"tl", DOCK_VPOS_TOP|DOCK_HPOS_LEFT},
210 {"tc", DOCK_VPOS_TOP|DOCK_HPOS_CENTER},
211 {"tr", DOCK_VPOS_TOP|DOCK_HPOS_RIGHT},
212 {"ml", DOCK_VPOS_MIDDLE|DOCK_HPOS_LEFT},
213 {"mc", DOCK_VPOS_MIDDLE|DOCK_HPOS_CENTER},
214 {"mr", DOCK_VPOS_MIDDLE|DOCK_HPOS_RIGHT},
215 {"bl", DOCK_VPOS_BOTTOM|DOCK_HPOS_LEFT},
216 {"bc", DOCK_VPOS_BOTTOM|DOCK_HPOS_CENTER},
217 {"br", DOCK_VPOS_BOTTOM|DOCK_HPOS_RIGHT},
218 END_STRINGINTMAP
221 static WDockParam dock_param_pos={
222 "pos",
223 "dock position",
224 dock_pos_map,
225 DOCK_HPOS_LEFT|DOCK_VPOS_BOTTOM
229 enum WDockGrow{
230 DOCK_GROW_UP,
231 DOCK_GROW_DOWN,
232 DOCK_GROW_LEFT,
233 DOCK_GROW_RIGHT
236 static StringIntMap dock_grow_map[]={
237 {"up", DOCK_GROW_UP},
238 {"down", DOCK_GROW_DOWN},
239 {"left", DOCK_GROW_LEFT},
240 {"right", DOCK_GROW_RIGHT},
241 END_STRINGINTMAP
244 WDockParam dock_param_grow={
245 "grow",
246 "growth direction",
247 dock_grow_map,
248 DOCK_GROW_RIGHT
252 static const WDockParam dock_param_is_auto={
253 "is_auto",
254 "is automatic",
255 NULL,
256 TRUE
260 enum WDockOutlineStyle{
261 DOCK_OUTLINE_STYLE_NONE,
262 DOCK_OUTLINE_STYLE_ALL,
263 DOCK_OUTLINE_STYLE_EACH
266 static StringIntMap dock_outline_style_map[]={
267 {"none", DOCK_OUTLINE_STYLE_NONE},
268 {"all", DOCK_OUTLINE_STYLE_ALL},
269 {"each", DOCK_OUTLINE_STYLE_EACH},
270 END_STRINGINTMAP
273 WDockParam dock_param_outline_style={
274 "outline_style",
275 "outline style",
276 dock_outline_style_map,
277 DOCK_OUTLINE_STYLE_ALL
281 static const WDockParam dock_param_tile_width={
282 "width",
283 "tile width",
284 NULL,
288 static const WDockParam dock_param_tile_height={
289 "height",
290 "tile height",
291 NULL,
296 /*}}}*/
299 /*{{{ Misc. */
301 #define CLIENTWIN_WINPROP_POSITION "dockposition"
302 #define CLIENTWIN_WINPROP_BORDER "dockborder"
304 static WDockApp *dock_find_dockapp(WDock *dock, WRegion *reg)
306 WDockApp *dockapp;
308 for(dockapp=dock->dockapps; dockapp!=NULL; dockapp=dockapp->next){
309 if(dockapp->reg==reg){
310 return dockapp;
314 return NULL;
319 static void dock_get_outline_style(WDock *dock, int *ret)
322 *ret=dock_param_outline_style.dflt;
323 if(dock->brush!=NULL)
324 dock_param_brush_set(&dock_param_outline_style, dock->brush, ret);
328 /*}}}*/
331 /*{{{ Size calculation */
334 static void dock_get_tile_size(WDock *dock, WRectangle *ret)
336 ExtlTab tile_size_table;
338 ret->x=0;
339 ret->y=0;
340 ret->w=dock_param_tile_width.dflt;
341 ret->h=dock_param_tile_height.dflt;
342 if(dock->brush==NULL)
343 return;
344 if(grbrush_get_extra(dock->brush, "tile_size", 't', &tile_size_table)){
345 extl_table_gets_i(tile_size_table, dock_param_tile_width.key, &ret->w);
346 extl_table_gets_i(tile_size_table, dock_param_tile_height.key, &ret->h);
347 extl_unref_table(tile_size_table);
353 static void dock_get_pos_grow(WDock *dock, int *pos, int *grow)
355 WMPlex *mplex=OBJ_CAST(REGION_PARENT(dock), WMPlex);
356 WRegion *mplex_stdisp;
357 WMPlexSTDispInfo din;
359 if(mplex!=NULL){
360 mplex_get_stdisp(mplex, &mplex_stdisp, &din);
361 if(mplex_stdisp==(WRegion*)dock){
362 /* Ok, we're assigned as a status display for mplex, so
363 * get parameters from there.
365 *pos=((din.pos==MPLEX_STDISP_TL || din.pos==MPLEX_STDISP_BL)
366 ? DOCK_HPOS_LEFT
367 : DOCK_HPOS_RIGHT)
368 | ((din.pos==MPLEX_STDISP_TL || din.pos==MPLEX_STDISP_TR)
369 ? DOCK_VPOS_TOP
370 : DOCK_VPOS_BOTTOM);
371 *grow=dock->grow;
372 return;
376 *grow=dock->grow;
377 *pos=dock->pos;
382 static void dock_reshape(WDock *dock)
384 int outline_style;
386 if(!ioncore_g.shape_extension)
387 return;
389 dock_get_outline_style(dock, &outline_style);
391 switch(outline_style){
392 case DOCK_OUTLINE_STYLE_NONE:
393 case DOCK_OUTLINE_STYLE_EACH:
395 WDockApp *dockapp;
397 /* Start with an empty set */
398 XShapeCombineRectangles(ioncore_g.dpy, ((WWindow*)dock)->win,
399 ShapeBounding, 0, 0, NULL, 0, ShapeSet, 0);
401 /* Union with dockapp shapes */
402 for(dockapp=dock->dockapps; dockapp!=NULL; dockapp=dockapp->next){
403 WClientWin *cwin=OBJ_CAST(dockapp->reg, WClientWin);
404 if(outline_style==DOCK_OUTLINE_STYLE_EACH
405 && dockapp->draw_border){
406 /* Union with border shape */
407 XRectangle tile_rect;
409 tile_rect.x=dockapp->border_geom.x;
410 tile_rect.y=dockapp->border_geom.y;
411 tile_rect.width=dockapp->border_geom.w;
412 tile_rect.height=dockapp->border_geom.h;
413 XShapeCombineRectangles(ioncore_g.dpy, ((WWindow*)dock)->win,
414 ShapeBounding, 0, 0, &tile_rect, 1,
415 ShapeUnion, 0);
416 }else if(cwin!=NULL){
417 /* Union with dockapp shape */
418 int count;
419 int ordering;
421 XRectangle *rects=XShapeGetRectangles(ioncore_g.dpy, cwin->win,
422 ShapeBounding, &count,
423 &ordering);
424 if(rects!=NULL){
425 WRectangle dockapp_geom=REGION_GEOM(cwin);
426 XShapeCombineRectangles(ioncore_g.dpy, ((WWindow*)dock)->win,
427 ShapeBounding,
428 dockapp_geom.x, dockapp_geom.y,
429 rects, count, ShapeUnion, ordering);
430 XFree(rects);
435 break;
437 case DOCK_OUTLINE_STYLE_ALL:
439 WRectangle geom;
440 XRectangle rect;
442 geom=REGION_GEOM(dock);
443 rect.x=0;
444 rect.y=0;
445 rect.width=geom.w;
446 rect.height=geom.h;
447 XShapeCombineRectangles(ioncore_g.dpy, ((WWindow*)dock)->win,
448 ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
450 break;
456 static void dock_arrange_dockapps(WDock *dock, const WRectangle *bd_dockg,
457 const WDockApp *replace_this,
458 WDockApp *with_this)
460 GrBorderWidths dock_bdw, dockapp_bdw;
461 WDockApp dummy_copy, *dockapp;
462 int pos, grow, cur_coord=0;
463 WRectangle dock_geom;
465 dock->arrange_called=TRUE;
467 dock_get_pos_grow(dock, &pos, &grow);
469 /* Determine dock and dockapp border widths */
470 memset(&dock_bdw, 0, sizeof(GrBorderWidths));
471 memset(&dockapp_bdw, 0, sizeof(GrBorderWidths));
473 if(dock->brush){
474 int outline_style;
476 dock_get_outline_style(dock, &outline_style);
477 switch(outline_style){
478 case DOCK_OUTLINE_STYLE_NONE:
479 break;
480 case DOCK_OUTLINE_STYLE_ALL:
481 grbrush_get_border_widths(dock->brush, &dock_bdw);
482 dockapp_bdw.spacing=dock_bdw.spacing;
483 break;
484 case DOCK_OUTLINE_STYLE_EACH:
485 grbrush_get_border_widths(dock->brush, &dockapp_bdw);
486 break;
490 dock_geom.w=bd_dockg->w-dock_bdw.left-dock_bdw.right;
491 dock_geom.h=bd_dockg->h-dock_bdw.top-dock_bdw.bottom;
493 /* Calculate initial co-ordinate for layout algorithm */
494 switch(grow){
495 case DOCK_GROW_UP:
496 cur_coord=dock_bdw.top+dock_geom.h;
497 break;
498 case DOCK_GROW_DOWN:
499 cur_coord=dock_bdw.top;
500 break;
501 case DOCK_GROW_LEFT:
502 cur_coord=dock_bdw.left+dock_geom.w;
503 break;
504 case DOCK_GROW_RIGHT:
505 cur_coord=dock_bdw.left;
506 break;
509 /* Arrange dockapps */
510 for(dockapp=dock->dockapps; dockapp!=NULL; dockapp=dockapp->next){
511 WDockApp *da=dockapp;
513 if(replace_this!=NULL){
514 if(replace_this==dockapp){
515 da=with_this;
516 }else{
517 dummy_copy=*dockapp;
518 da=&dummy_copy;
522 /* Calculate first co-ordinate */
523 switch(grow){
524 case DOCK_GROW_UP:
525 case DOCK_GROW_DOWN:
526 switch(pos&DOCK_HPOS_MASK){
527 case DOCK_HPOS_LEFT:
528 da->border_geom.x=0;
529 break;
530 case DOCK_HPOS_CENTER:
531 da->border_geom.x=(dock_geom.w-da->border_geom.w)/2;
532 break;
533 case DOCK_HPOS_RIGHT:
534 da->border_geom.x=dock_geom.w-da->border_geom.w;
535 break;
537 da->border_geom.x+=dock_bdw.left;
538 break;
539 case DOCK_GROW_LEFT:
540 case DOCK_GROW_RIGHT:
541 switch(pos&DOCK_VPOS_MASK){
542 case DOCK_VPOS_TOP:
543 da->border_geom.y=0;
544 break;
545 case DOCK_VPOS_MIDDLE:
546 da->border_geom.y=(dock_geom.h-da->border_geom.h)/2;
547 break;
548 case DOCK_VPOS_BOTTOM:
549 da->border_geom.y=dock_geom.h-da->border_geom.h;
550 break;
552 da->border_geom.y+=dock_bdw.top;
553 break;
556 /* Calculate second co-ordinate */
557 switch(grow){
558 case DOCK_GROW_UP:
559 cur_coord-=da->border_geom.h;
560 da->border_geom.y=cur_coord;
561 cur_coord-=dockapp_bdw.spacing;
562 break;
563 case DOCK_GROW_DOWN:
564 da->border_geom.y=cur_coord;
565 cur_coord+=da->border_geom.h+dockapp_bdw.spacing;
566 break;
567 case DOCK_GROW_LEFT:
568 cur_coord-=da->border_geom.w;
569 da->border_geom.x=cur_coord;
570 cur_coord-=dockapp_bdw.spacing;
571 break;
572 case DOCK_GROW_RIGHT:
573 da->border_geom.x=cur_coord;
574 cur_coord+=da->border_geom.w+dockapp_bdw.spacing;
575 break;
578 /* Calculate tile geom */
579 da->tile_geom.x=da->border_geom.x+dockapp_bdw.left;
580 da->tile_geom.y=da->border_geom.y+dockapp_bdw.top;
582 /* Calculate dockapp geom */
583 if(da->tile){
584 da->geom.x=da->tile_geom.x+(da->tile_geom.w-da->geom.w)/2;
585 da->geom.y=da->tile_geom.y+(da->tile_geom.h-da->geom.h)/2;
586 }else{
587 da->geom.x=da->tile_geom.x;
588 da->geom.y=da->tile_geom.y;
591 if(replace_this==NULL)
592 region_fit(da->reg, &(da->geom), REGION_FIT_BOUNDS);
597 static void dock_set_minmax(WDock *dock, int grow, const WRectangle *g)
599 dock->min_w=g->w;
600 dock->min_h=g->h;
601 if(grow==DOCK_GROW_UP || grow==DOCK_GROW_DOWN){
602 dock->max_w=g->w;
603 dock->max_h=INT_MAX;
604 }else{
605 dock->max_w=INT_MAX;
606 dock->max_h=g->h;
611 static void dockapp_calc_preferred_size(WDock *dock, int grow,
612 const WRectangle *tile_size,
613 WDockApp *da)
615 int w=da->geom.w, h=da->geom.h;
617 if(grow==DOCK_GROW_UP || grow==DOCK_GROW_DOWN){
618 da->geom.w=MINOF(w, tile_size->w);
619 da->geom.h=h;
620 }else{
621 da->geom.w=w;
622 da->geom.h=MINOF(h, tile_size->h);
625 region_size_hints_correct(da->reg, &(da->geom.w), &(da->geom.h), TRUE);
630 static void dock_managed_rqgeom_(WDock *dock, WRegion *reg, int flags,
631 const WRectangle *geom, WRectangle *geomret,
632 bool just_update_minmax)
634 WDockApp *dockapp=NULL, *thisdockapp=NULL, thisdockapp_copy;
635 WRectangle dock_geom, border_dock_geom;
636 GrBorderWidths dock_bdw, dockapp_bdw;
637 int n_dockapps=0, max_w=1, max_h=1, total_w=0, total_h=0;
638 int pos, grow;
639 WRectangle tile_size;
641 /* dock_resize calls with NULL parameters. */
642 assert(reg!=NULL || (geomret==NULL && !(flags&REGION_RQGEOM_TRYONLY)));
644 dock_get_pos_grow(dock, &pos, &grow);
645 dock_get_tile_size(dock, &tile_size);
647 /* Determine dock and dockapp border widths */
648 memset(&dock_bdw, 0, sizeof(GrBorderWidths));
649 memset(&dockapp_bdw, 0, sizeof(GrBorderWidths));
651 if(dock->brush){
652 int outline_style;
654 dock_get_outline_style(dock, &outline_style);
655 switch(outline_style){
656 case DOCK_OUTLINE_STYLE_NONE:
657 break;
658 case DOCK_OUTLINE_STYLE_ALL:
659 grbrush_get_border_widths(dock->brush, &dock_bdw);
660 dockapp_bdw.spacing=dock_bdw.spacing;
661 break;
662 case DOCK_OUTLINE_STYLE_EACH:
663 grbrush_get_border_widths(dock->brush, &dockapp_bdw);
664 break;
668 /* Calculate widths and heights */
669 for(dockapp=dock->dockapps; dockapp!=NULL; dockapp=dockapp->next){
670 WDockApp *da=dockapp;
671 bool update=!(flags&REGION_RQGEOM_TRYONLY);
672 if(dockapp->reg==reg){
673 thisdockapp=dockapp;
674 if(flags&REGION_RQGEOM_TRYONLY){
675 thisdockapp_copy=*dockapp;
676 thisdockapp_copy.geom=*geom;
677 da=&thisdockapp_copy;
678 update=TRUE;
680 da->geom=*geom;
683 if(update){
684 /* Calculcate preferred size */
685 dockapp_calc_preferred_size(dock, grow, &tile_size, da);
687 /* Determine whether dockapp should be placed on a tile */
688 da->tile=da->geom.w<=tile_size.w && da->geom.h<=tile_size.h;
690 /* Calculate width and height */
691 if(da->tile){
692 da->tile_geom.w=tile_size.w;
693 da->tile_geom.h=tile_size.h;
694 }else{
695 da->tile_geom.w=da->geom.w;
696 da->tile_geom.h=da->geom.h;
699 /* Calculate border width and height */
700 da->border_geom.w=dockapp_bdw.left+da->tile_geom.w+dockapp_bdw.right;
701 da->border_geom.h=dockapp_bdw.top+da->tile_geom.h+dockapp_bdw.right;
704 /* Calculate maximum and accumulated widths and heights */
705 if(da->border_geom.w>max_w)
706 max_w=da->border_geom.w;
707 total_w+=da->border_geom.w+(n_dockapps ? dockapp_bdw.spacing : 0);
709 if(da->border_geom.h>max_h)
710 max_h=da->border_geom.h;
711 total_h+=da->border_geom.h+(n_dockapps ? dockapp_bdw.spacing : 0);
713 /* Count dockapps */
714 ++n_dockapps;
717 if(thisdockapp==NULL && reg!=NULL){
718 warn("Requesting dockapp not found.");
719 if(geomret)
720 *geomret=REGION_GEOM(reg);
721 return;
724 /* Calculate width and height of dock */
725 if(n_dockapps){
726 switch(grow){
727 case DOCK_GROW_LEFT:
728 case DOCK_GROW_RIGHT:
729 dock_geom.w=total_w;
730 dock_geom.h=max_h;
731 break;
732 case DOCK_GROW_UP:
733 case DOCK_GROW_DOWN:
734 default:
735 dock_geom.w=max_w;
736 dock_geom.h=total_h;
737 break;
739 }else{
740 dock_geom.w=tile_size.w;
741 dock_geom.h=tile_size.h;
744 border_dock_geom.x=REGION_GEOM(dock).x;
745 border_dock_geom.y=REGION_GEOM(dock).y;
746 border_dock_geom.w=dock_bdw.left+dock_geom.w+dock_bdw.right;
747 border_dock_geom.h=dock_bdw.top+dock_geom.h+dock_bdw.bottom;
749 /* Fit dock to new geom if required */
750 if(!(flags&REGION_RQGEOM_TRYONLY)){
751 WRQGeomParams rq=RQGEOMPARAMS_INIT;
753 dock_set_minmax(dock, grow, &border_dock_geom);
755 if(just_update_minmax)
756 return;
758 rq.flags=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
759 rq.geom=border_dock_geom;
761 dock->arrange_called=FALSE;
763 region_rqgeom((WRegion*)dock, &rq, NULL);
765 if(!dock->arrange_called)
766 dock_arrange_dockapps(dock, &REGION_GEOM(dock), NULL, NULL);
768 if(thisdockapp!=NULL && geomret!=NULL)
769 *geomret=thisdockapp->geom;
770 }else{
771 if(thisdockapp!=NULL && geomret!=NULL){
772 dock_arrange_dockapps(dock, &REGION_GEOM(dock),
773 thisdockapp, &thisdockapp_copy);
774 *geomret=thisdockapp_copy.geom;
779 static void dock_managed_rqgeom(WDock *dock, WRegion *reg,
780 const WRQGeomParams *rq,
781 WRectangle *geomret)
783 dock_managed_rqgeom_(dock, reg, rq->flags, &rq->geom, geomret, FALSE);
787 void dock_size_hints(WDock *dock, WSizeHints *hints)
789 hints->min_set=TRUE;
790 hints->min_width=dock->min_w;
791 hints->min_height=dock->min_h;
793 hints->max_set=TRUE;
794 hints->max_width=dock->max_w;
795 hints->max_height=dock->max_h;
799 static bool dock_fitrep(WDock *dock, WWindow *parent, const WFitParams *fp)
801 if(!window_fitrep(&(dock->win), parent, fp))
802 return FALSE;
804 dock_arrange_dockapps(dock, &(fp->g), NULL, NULL);
806 if(ioncore_g.shape_extension)
807 dock_reshape(dock);
809 return TRUE;
813 static int dock_orientation(WDock *dock)
815 return ((dock->grow==DOCK_GROW_LEFT || dock->grow==DOCK_GROW_RIGHT)
816 ? REGION_ORIENTATION_HORIZONTAL
817 : REGION_ORIENTATION_VERTICAL);
821 /*}}}*/
824 /*{{{ Drawing */
827 static void dock_draw(WDock *dock, bool complete)
829 int outline_style;
830 WRectangle g;
832 if(dock->brush==NULL)
833 return;
835 g.x=0;
836 g.y=0;
837 g.w=REGION_GEOM(dock).w;
838 g.h=REGION_GEOM(dock).h;
840 grbrush_begin(dock->brush, &g, (complete ? 0 : GRBRUSH_NO_CLEAR_OK));
842 dock_get_outline_style(dock, &outline_style);
843 switch(outline_style){
844 case DOCK_OUTLINE_STYLE_NONE:
845 break;
846 case DOCK_OUTLINE_STYLE_ALL:
848 WRectangle geom=REGION_GEOM(dock);
849 geom.x=geom.y=0;
850 grbrush_draw_border(dock->brush, &geom);
852 break;
853 case DOCK_OUTLINE_STYLE_EACH:
855 WDockApp *dockapp;
856 for(dockapp=dock->dockapps; dockapp!=NULL;
857 dockapp=dockapp->next){
858 grbrush_draw_border(dock->brush, &dockapp->tile_geom);
861 break;
864 grbrush_end(dock->brush);
868 /*EXTL_DOC
869 * Resizes and refreshes \var{dock}.
871 EXTL_EXPORT_MEMBER
872 void dock_resize(WDock *dock)
874 dock_managed_rqgeom_(dock, NULL, 0, NULL, NULL, FALSE);
875 dock_draw(dock, TRUE);
879 static void dock_brush_release(WDock *dock)
882 if(dock->brush){
883 grbrush_release(dock->brush);
884 dock->brush=NULL;
890 static void dock_brush_get(WDock *dock)
893 dock_brush_release(dock);
894 dock->brush=gr_get_brush(((WWindow*)dock)->win,
895 region_rootwin_of((WRegion*)dock),
896 "stdisp-dock");
900 static void dock_updategr(WDock *dock)
902 dock_brush_get(dock);
903 dock_resize(dock);
906 /*}}}*/
909 /*{{{ Set/get */
912 static void mplexpos(int pos, int *mpos)
914 int hp=pos&DOCK_HPOS_MASK, vp=pos&DOCK_VPOS_MASK;
915 int p;
917 p=(vp!=DOCK_VPOS_MIDDLE
918 ? (vp==DOCK_VPOS_TOP
919 ? (hp!=DOCK_HPOS_CENTER
920 ? (hp==DOCK_HPOS_RIGHT
921 ? MPLEX_STDISP_TR
922 : MPLEX_STDISP_TL)
923 : -1)
924 : (hp!=DOCK_HPOS_CENTER
925 ? (hp==DOCK_HPOS_RIGHT
926 ? MPLEX_STDISP_BR
927 : MPLEX_STDISP_BL)
928 : -1))
929 : -1);
931 if(p==-1)
932 warn("Invalid dock position while as stdisp.");
933 else
934 *mpos=p;
938 static void mplexszplcy(int pos, WSizePolicy *szplcy)
940 int hp=pos&DOCK_HPOS_MASK, vp=pos&DOCK_VPOS_MASK;
941 WSizePolicy p;
943 p=(vp!=DOCK_VPOS_MIDDLE
944 ? (vp==DOCK_VPOS_TOP
945 ? (hp!=DOCK_HPOS_CENTER
946 ? (hp==DOCK_HPOS_RIGHT
947 ? SIZEPOLICY_GRAVITY_NORTHEAST
948 : SIZEPOLICY_GRAVITY_NORTHWEST)
949 : SIZEPOLICY_GRAVITY_NORTH)
950 : (hp!=DOCK_HPOS_CENTER
951 ? (hp==DOCK_HPOS_RIGHT
952 ? SIZEPOLICY_GRAVITY_SOUTHEAST
953 : SIZEPOLICY_GRAVITY_SOUTHWEST)
954 : SIZEPOLICY_GRAVITY_SOUTH))
955 : (hp!=DOCK_HPOS_CENTER
956 ? (hp==DOCK_HPOS_RIGHT
957 ? SIZEPOLICY_GRAVITY_EAST
958 : SIZEPOLICY_GRAVITY_WEST)
959 : SIZEPOLICY_GRAVITY_CENTER));
961 *szplcy=p;
965 static void dock_do_set(WDock *dock, ExtlTab conftab, bool resize)
967 char *s;
968 bool b;
969 bool growset=FALSE;
970 bool posset=FALSE;
971 bool save=FALSE;
973 if(extl_table_gets_s(conftab, dock_param_name.key, &s)){
974 if(!region_set_name((WRegion*)dock, s)){
975 warn_obj(modname, "Can't set name to \"%s\"", s);
977 free(s);
980 if(extl_table_gets_b(conftab, "save", &save))
981 dock->save=save;
983 if(dock_param_extl_table_set(&dock_param_pos, conftab, &dock->pos))
984 posset=TRUE;
986 if(dock_param_extl_table_set(&dock_param_grow, conftab, &dock->grow))
987 growset=TRUE;
989 if(extl_table_gets_b(conftab, dock_param_is_auto.key, &b))
990 dock->is_auto=b;
992 if(resize && (growset || posset)){
993 WMPlex *par=OBJ_CAST(REGION_PARENT(dock), WMPlex);
994 WRegion *stdisp=NULL;
995 WMPlexSTDispInfo din;
997 if(par!=NULL){
998 mplex_get_stdisp(par, &stdisp, &din);
999 din.fullsize=FALSE; /* not supported. */
1000 if(stdisp==(WRegion*)dock){
1001 if(posset)
1002 mplexpos(dock->pos, &din.pos);
1003 if(growset){
1004 /* Update min/max first */
1005 dock_managed_rqgeom_(dock, NULL, 0, NULL, NULL, TRUE);
1007 mplex_set_stdisp(par, (WRegion*)dock, &din);
1008 }else if((WRegion*)par==REGION_MANAGER(dock)){
1009 WSizePolicy szplcy;
1010 mplexszplcy(dock->pos, &szplcy);
1011 mplex_set_szplcy(par, (WRegion*)dock, szplcy);
1015 dock_resize(dock);
1020 /*EXTL_DOC
1021 * Configure \var{dock}. \var{conftab} is a table of key/value pairs:
1023 * \begin{tabularx}{\linewidth}{llX}
1024 * \tabhead{Key & Values & Description}
1025 * \var{name} & string & Name of dock \\
1026 * \var{pos} & string in $\{t,m,b\}\times\{t,c,b\}$ & Dock position.
1027 * Can only be used in floating mode. \\
1028 * \var{grow} & up/down/left/right &
1029 * Growth direction where new dockapps are added. Also
1030 * sets orientation for dock when working as WMPlex status
1031 * display (see \fnref{WMPlex.set_stdisp}). \\
1032 * \var{is_auto} & bool &
1033 * Should \var{dock} automatically manage new dockapps? \\
1034 * \end{tabularx}
1036 * Any parameters not explicitly set in \var{conftab} will be left unchanged.
1038 EXTL_EXPORT_MEMBER
1039 void dock_set(WDock *dock, ExtlTab conftab)
1041 dock_do_set(dock, conftab, TRUE);
1045 static void dock_do_get(WDock *dock, ExtlTab conftab)
1047 extl_table_sets_s(conftab, dock_param_name.key,
1048 region_name((WRegion*)dock));
1049 dock_param_extl_table_get(&dock_param_pos, conftab, dock->pos);
1050 dock_param_extl_table_get(&dock_param_grow, conftab, dock->grow);
1051 extl_table_sets_b(conftab, dock_param_is_auto.key, dock->is_auto);
1052 extl_table_sets_b(conftab, "save", dock->save);
1056 /*EXTL_DOC
1057 * Get \var{dock}'s configuration table. See \fnref{WDock.set} for a
1058 * description of the table.
1060 EXTL_SAFE
1061 EXTL_EXPORT_MEMBER
1062 ExtlTab dock_get(WDock *dock)
1064 ExtlTab conftab;
1066 conftab=extl_create_table();
1067 dock_do_get(dock, conftab);
1068 return conftab;
1072 /*}}}*/
1075 /*{{{ Init/deinit */
1078 static bool dock_init(WDock *dock, WWindow *parent, const WFitParams *fp)
1080 WFitParams fp2=*fp;
1082 dock->pos=dock_param_pos.dflt;
1083 dock->grow=dock_param_grow.dflt;
1084 dock->is_auto=dock_param_is_auto.dflt;
1085 dock->brush=NULL;
1086 dock->dockapps=NULL;
1087 dock->min_w=1;
1088 dock->min_h=1;
1089 dock->max_w=1;
1090 dock->max_h=1;
1091 dock->arrange_called=FALSE;
1092 dock->save=TRUE;
1095 if(!window_init((WWindow*)dock, parent, &fp2, "WDock"))
1096 return FALSE;
1098 region_add_bindmap((WRegion*)dock, dock_bindmap);
1100 window_select_input(&(dock->win), IONCORE_EVENTMASK_CWINMGR);
1102 dock_brush_get(dock);
1104 LINK_ITEM(docks, dock, dock_next, dock_prev);
1106 return TRUE;
1110 static WDock *create_dock(WWindow *parent, const WFitParams *fp)
1112 CREATEOBJ_IMPL(WDock, dock, (p, parent, fp));
1116 static void dock_deinit(WDock *dock)
1118 while(dock->dockapps!=NULL)
1119 destroy_obj((Obj*)dock->dockapps->reg);
1121 UNLINK_ITEM(docks, dock, dock_next, dock_prev);
1123 dock_brush_release(dock);
1125 window_deinit((WWindow*) dock);
1129 EXTL_EXPORT
1130 WDock *mod_dock_create(ExtlTab tab)
1132 char *mode=NULL;
1133 bool floating=FALSE;
1134 int screenid=0;
1135 WScreen *screen=NULL;
1136 WDock *dock=NULL;
1137 WRegion *stdisp=NULL;
1138 WMPlexSTDispInfo din;
1139 WFitParams fp;
1141 if(extl_table_gets_s(tab, "mode", &mode)){
1142 if(strcmp(mode, "floating")==0){
1143 floating=TRUE;
1144 }else if(strcmp(mode, "embedded")!=0){
1145 warn("Invalid dock mode.");
1146 free(mode);
1147 return NULL;
1149 free(mode);
1152 extl_table_gets_i(tab, "screen", &screenid);
1153 screen=ioncore_find_screen_id(screenid);
1154 if(screen==NULL){
1155 warn("Screen %d does not exist.", screenid);
1156 return NULL;
1159 for(dock=docks; dock; dock=dock->dock_next){
1160 if(region_screen_of((WRegion*)dock)==screen){
1161 warn("Screen %d already has a dock. Refusing to create another.",
1162 screenid);
1163 return NULL;
1167 if(!floating){
1168 mplex_get_stdisp((WMPlex*)screen, &stdisp, &din);
1169 if(stdisp!=NULL && !extl_table_is_bool_set(tab, "force")){
1170 warn("Screen %d already has an stdisp. Refusing to add embedded "
1171 "dock.", screenid);
1172 return NULL;
1176 /* Create the dock */
1177 fp.mode=REGION_FIT_BOUNDS|REGION_FIT_WHATEVER;
1178 fp.g.x=0;
1179 fp.g.y=0;
1180 fp.g.w=1;
1181 fp.g.h=1;
1183 dock=create_dock((WWindow*)screen, &fp);
1185 if(dock==NULL){
1186 warn("Failed to create dock.");
1187 return NULL;
1191 /* Get parameters */
1192 dock->save=FALSE;
1193 dock_do_set(dock, tab, FALSE);
1195 /* Calculate min/max size */
1196 dock_managed_rqgeom_(dock, NULL, 0, NULL, NULL, TRUE);
1198 /* Final setup */
1199 if(floating){
1200 WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
1201 WRegionAttachData data;
1203 par.flags=(MPLEX_ATTACH_UNNUMBERED
1204 |MPLEX_ATTACH_SIZEPOLICY
1205 |MPLEX_ATTACH_GEOM
1206 |MPLEX_ATTACH_PASSIVE);
1208 par.geom.w=dock->min_w;
1209 par.geom.h=dock->min_h;
1210 par.geom.x=0;
1211 par.geom.y=0;
1213 mplexszplcy(dock->pos, &par.szplcy);
1215 if(extl_table_is_bool_set(tab, "floating_hidden"))
1216 par.flags|=MPLEX_ATTACH_HIDDEN;
1218 data.type=REGION_ATTACH_REPARENT;
1219 data.u.reg=(WRegion*)dock;
1221 if(mplex_do_attach((WMPlex*)screen, &par, &data))
1222 return dock;
1223 }else{
1224 mplexpos(dock->pos, &din.pos);
1225 din.fullsize=FALSE; /* not supported */
1226 if(mplex_set_stdisp((WMPlex*)screen, (WRegion*)dock, &din))
1227 return dock;
1230 /* Failed to attach. */
1231 warn("Failed to attach dock to screen.");
1232 destroy_obj((Obj*)dock);
1233 return NULL;
1237 /*}}}*/
1240 /*{{{ Toggle */
1243 /*EXTL_DOC
1244 * Toggle floating docks on \var{mplex}.
1246 EXTL_EXPORT
1247 void mod_dock_set_floating_shown_on(WMPlex *mplex, const char *how)
1249 int setpar=libtu_setparam_invert(libtu_string_to_setparam(how));
1250 WDock *dock;
1252 for(dock=docks; dock; dock=dock->dock_next){
1253 if(REGION_MANAGER(dock)==(WRegion*)mplex)
1254 mplex_set_hidden(mplex, (WRegion*)dock, setpar);
1259 /*}}}*/
1262 /*{{{ Save/load */
1265 ExtlTab dock_get_configuration(WDock *dock)
1267 ExtlTab tab;
1269 if(dock->save==FALSE)
1270 return extl_table_none();
1272 tab=region_get_base_configuration((WRegion*)dock);
1273 dock_do_get(dock, tab);
1275 return tab;
1279 WRegion *dock_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
1281 WDock *dock=create_dock(par, fp);
1282 if(dock!=NULL){
1283 dock_set(dock, tab);
1284 dock_fitrep(dock, NULL, fp);
1287 return (WRegion*)dock;
1291 /*}}}*/
1294 /*{{{ Client window management setup */
1297 static bool dock_do_attach_final(WDock *dock, WRegion *reg, void *UNUSED(unused))
1299 WDockApp *dockapp, *before_dockapp;
1300 WRectangle geom;
1301 bool draw_border=TRUE;
1302 int pos=INT_MAX;
1304 /* Create and initialise a new WDockApp struct */
1305 dockapp=ALLOC(WDockApp);
1307 if(dockapp==NULL)
1308 return FALSE;
1310 if(OBJ_IS(reg, WClientWin)){
1311 ExtlTab proptab=((WClientWin*)reg)->proptab;
1312 extl_table_gets_b(proptab, CLIENTWIN_WINPROP_BORDER, &draw_border);
1313 extl_table_gets_i(proptab, CLIENTWIN_WINPROP_POSITION, &pos);
1316 dockapp->reg=reg;
1317 dockapp->draw_border=draw_border;
1318 dockapp->pos=pos;
1319 dockapp->tile=FALSE;
1321 /* Insert the dockapp at the correct relative position */
1322 before_dockapp=dock->dockapps;
1323 for(before_dockapp=dock->dockapps;
1324 before_dockapp!=NULL && dockapp->pos>=before_dockapp->pos;
1325 before_dockapp=before_dockapp->next){
1328 if(before_dockapp!=NULL){
1329 LINK_ITEM_BEFORE(dock->dockapps, before_dockapp, dockapp, next, prev);
1330 }else{
1331 LINK_ITEM(dock->dockapps, dockapp, next, prev);
1334 region_set_manager(reg, (WRegion*)dock);
1336 geom=REGION_GEOM(reg);
1337 dock_managed_rqgeom_(dock, reg,
1338 REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y,
1339 &geom, NULL, FALSE);
1341 region_map(reg);
1343 return TRUE;
1348 static WRegion *dock_do_attach(WDock *dock, WRegionAttachData *data)
1350 WFitParams fp;
1351 dock_get_tile_size(dock, &(fp.g));
1352 fp.g.x=0;
1353 fp.g.y=0;
1354 fp.mode=REGION_FIT_WHATEVER|REGION_FIT_BOUNDS;
1356 return region_attach_helper((WRegion*)dock, (WWindow*)dock, &fp,
1357 (WRegionDoAttachFn*)dock_do_attach_final,
1358 NULL, data);
1362 /*EXTL_DOC
1363 * Attach \var{reg} to \var{dock}.
1365 EXTL_EXPORT_MEMBER
1366 bool dock_attach(WDock *dock, WRegion *reg)
1368 WRegionAttachData data;
1370 data.type=REGION_ATTACH_REPARENT;
1371 data.u.reg=reg;
1373 return (dock_do_attach(dock, &data)!=NULL);
1377 static bool dock_handle_drop(WDock *dock, int UNUSED(x), int UNUSED(y),
1378 WRegion *dropped)
1380 return dock_attach(dock, dropped);
1384 static WRegion *dock_ph_handler(WDock *dock, int UNUSED(flags), WRegionAttachData *data)
1386 return dock_do_attach(dock, data);
1390 static WPHolder *dock_managed_get_pholder(WDock *dock, WRegion *UNUSED(mgd))
1392 return (WPHolder*)create_basicpholder((WRegion*)dock,
1393 ((WBasicPHolderHandler*)
1394 dock_ph_handler));
1398 static WPHolder *dock_prepare_manage(WDock *dock, const WClientWin *UNUSED(cwin),
1399 const WManageParams *UNUSED(param),
1400 int priority)
1402 if(!MANAGE_PRIORITY_OK(priority, MANAGE_PRIORITY_LOW))
1403 return NULL;
1405 return (WPHolder*)create_basicpholder((WRegion*)dock,
1406 ((WBasicPHolderHandler*)
1407 dock_ph_handler));
1411 static void dock_managed_remove(WDock *dock, WRegion *reg)
1414 WDockApp *dockapp=dock_find_dockapp(dock, reg);
1416 if(dockapp==NULL)
1417 return;
1419 UNLINK_ITEM(dock->dockapps, dockapp, next, prev);
1420 free(dockapp);
1422 region_unset_manager(reg, (WRegion*)dock);
1424 dock_resize(dock);
1428 static bool dock_clientwin_is_dockapp(WClientWin *cwin,
1429 const WManageParams *param)
1431 bool is_dockapp=FALSE;
1433 /* First, inspect the WManageParams.dockapp parameter */
1434 if(param->dockapp){
1435 is_dockapp=TRUE;
1438 /* Second, inspect the _NET_WM_WINDOW_TYPE property */
1439 if(!is_dockapp){
1440 static Atom atom__net_wm_window_type=None;
1441 static Atom atom__net_wm_window_type_dock=None;
1442 Atom actual_type=None;
1443 int actual_format;
1444 unsigned long nitems;
1445 unsigned long bytes_after;
1446 unsigned char *prop;
1448 if(atom__net_wm_window_type==None){
1449 atom__net_wm_window_type=XInternAtom(ioncore_g.dpy,
1450 "_NET_WM_WINDOW_TYPE",
1451 False);
1453 if(atom__net_wm_window_type_dock==None){
1454 atom__net_wm_window_type_dock=XInternAtom(ioncore_g.dpy,
1455 "_NET_WM_WINDOW_TYPE_DOCK",
1456 False);
1458 if(XGetWindowProperty(ioncore_g.dpy, cwin->win, atom__net_wm_window_type,
1459 0, sizeof(Atom), False, XA_ATOM, &actual_type,
1460 &actual_format, &nitems, &bytes_after, &prop)
1461 ==Success){
1462 if(actual_type==XA_ATOM && nitems>=1
1463 && *(Atom*)prop==atom__net_wm_window_type_dock){
1464 is_dockapp=TRUE;
1466 XFree(prop);
1470 /* Third, inspect the WM_CLASS property */
1471 if(!is_dockapp){
1472 char **p;
1473 int n;
1475 p=xwindow_get_text_property(cwin->win, XA_WM_CLASS, &n);
1476 if(p!=NULL){
1477 if(n>=2 && strcmp(p[1], "DockApp")==0){
1478 is_dockapp=TRUE;
1480 XFreeStringList(p);
1484 /* Fourth, inspect the _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR property */
1485 if(!is_dockapp){
1486 static Atom atom__kde_net_wm_system_tray_window_for=None;
1487 Atom actual_type=None;
1488 int actual_format;
1489 unsigned long nitems;
1490 unsigned long bytes_after;
1491 unsigned char *prop;
1493 if(atom__kde_net_wm_system_tray_window_for==None){
1494 atom__kde_net_wm_system_tray_window_for=XInternAtom(ioncore_g.dpy,
1495 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
1496 False);
1498 if(XGetWindowProperty(ioncore_g.dpy, cwin->win,
1499 atom__kde_net_wm_system_tray_window_for, 0,
1500 sizeof(Atom), False, AnyPropertyType,
1501 &actual_type, &actual_format, &nitems,
1502 &bytes_after, &prop)==Success){
1503 if(actual_type!=None){
1504 is_dockapp=TRUE;
1506 XFree(prop);
1510 return is_dockapp;
1515 static WDock *dock_find_suitable_dock(WClientWin *cwin,
1516 const WManageParams *param)
1518 WDock *dock;
1520 for(dock=docks; dock; dock=dock->dock_next){
1521 if(!dock->is_auto)
1522 continue;
1523 if(!region_same_rootwin((WRegion*)dock, (WRegion*)cwin))
1524 continue;
1525 break;
1528 return dock;
1532 static bool clientwin_do_manage_hook(WClientWin *cwin, const WManageParams *param)
1534 WDock *dock;
1536 if(!dock_clientwin_is_dockapp(cwin, param)){
1537 return FALSE;
1540 dock=dock_find_suitable_dock(cwin, param);
1541 if(!dock){
1542 return FALSE;
1545 return region_manage_clientwin((WRegion*)dock, cwin, param,
1546 MANAGE_PRIORITY_NONE);
1550 /*}}}*/
1553 /*{{{ Module init/deinit */
1556 bool mod_dock_init()
1559 if(!ioncore_register_regclass(&CLASSDESCR(WDock),
1560 (WRegionLoadCreateFn*)dock_load)){
1561 return FALSE;
1564 if(!mod_dock_register_exports()){
1565 ioncore_unregister_regclass(&CLASSDESCR(WDock));
1566 return FALSE;
1569 dock_bindmap=ioncore_alloc_bindmap("WDock", NULL);
1570 if(dock_bindmap==NULL){
1571 warn("Unable to allocate dock bindmap.");
1572 mod_dock_unregister_exports();
1573 ioncore_unregister_regclass(&CLASSDESCR(WDock));
1576 extl_read_config("cfg_dock", NULL, TRUE);
1578 hook_add(clientwin_do_manage_alt,
1579 (WHookDummy*)clientwin_do_manage_hook);
1581 return TRUE;
1586 void mod_dock_deinit()
1588 WDock *dock;
1590 ioncore_unregister_regclass(&CLASSDESCR(WDock));
1592 hook_remove(clientwin_do_manage_alt,
1593 (WHookDummy*)clientwin_do_manage_hook);
1595 dock=docks;
1596 while(dock!=NULL){
1597 WDock *next=dock->dock_next;
1598 destroy_obj((Obj*)dock);
1599 dock=next;
1602 mod_dock_unregister_exports();
1604 if(dock_bindmap!=NULL){
1605 ioncore_free_bindmap("WDock", dock_bindmap);
1606 dock_bindmap=NULL;
1611 /*}}}*/
1614 /*{{{ WDock class description and dynfun list */
1617 static DynFunTab dock_dynfuntab[]={
1618 {window_draw, dock_draw},
1619 {region_updategr, dock_updategr},
1620 {region_managed_rqgeom, dock_managed_rqgeom},
1621 {(DynFun*)region_prepare_manage, (DynFun*)dock_prepare_manage},
1622 {region_managed_remove, dock_managed_remove},
1623 {(DynFun*)region_get_configuration, (DynFun*)dock_get_configuration},
1624 {region_size_hints, dock_size_hints},
1625 {(DynFun*)region_fitrep, (DynFun*)dock_fitrep},
1626 {(DynFun*)region_orientation, (DynFun*)dock_orientation},
1627 {(DynFun*)region_handle_drop, (DynFun*)dock_handle_drop},
1629 {(DynFun*)region_managed_get_pholder,
1630 (DynFun*)dock_managed_get_pholder},
1631 END_DYNFUNTAB
1635 EXTL_EXPORT
1636 IMPLCLASS(WDock, WWindow, dock_deinit, dock_dynfuntab);
1639 /*}}}*/