Example #1
0
bool extl_table_to_rectangle(ExtlTab tab, WRectangle *rectret)
{
    if(!extl_table_gets_i(tab, "x", &(rectret->x)) ||
       !extl_table_gets_i(tab, "y", &(rectret->y)) ||
       !extl_table_gets_i(tab, "w", &(rectret->w)) ||
       !extl_table_gets_i(tab, "h", &(rectret->h)))
       return FALSE;

    return TRUE;
}
Example #2
0
/*EXTL_DOC
 * Set module basic settings. The parameter table may contain the
 * following fields:
 * 
 * \begin{tabularx}{\linewidth}{lX}
 *  \tabhead{Field & Description}
 *  \var{scroll_amount} & Number of pixels to scroll at a time in
 *                        pointer-controlled menus when one extends
 *                        beyond a border of the screen and the pointer
 *                        touches that border. \\
 *  \var{scroll_delay}  & Time between such scrolling events in 
 *                        milliseconds.
 * \end{tabularx}
 */
EXTL_EXPORT
void mod_menu_set(ExtlTab tab)
{
    int a, t;
    
    if(extl_table_gets_i(tab, "scroll_amount", &a))
        scroll_amount=maxof(0, a);
    if(extl_table_gets_i(tab, "scroll_delay", &t))
        scroll_time=maxof(0, t);
}
Example #3
0
File: dock.c Project: dkogan/notion
static void dock_get_tile_size(WDock *dock, WRectangle *ret)
{
    ExtlTab tile_size_table;

    ret->x=0;
    ret->y=0;
    ret->w=dock_param_tile_width.dflt;
    ret->h=dock_param_tile_height.dflt;
    if(dock->brush==NULL)
        return;
    if(grbrush_get_extra(dock->brush, "tile_size", 't', &tile_size_table)){
        extl_table_gets_i(tile_size_table, dock_param_tile_width.key, &ret->w);
        extl_table_gets_i(tile_size_table, dock_param_tile_height.key, &ret->h);
        extl_unref_table(tile_size_table);
    }

}
Example #4
0
/*EXTL_DOC
 * Set parameters. Currently only \var{raise_delay} (in milliseconds)
 * is supported.
 */
EXTL_EXPORT
void mod_tiling_set(ExtlTab tab)
{
    int d;
    if(extl_table_gets_i(tab, "raise_delay", &d)){
        if(d>=0)
            mod_tiling_raise_delay=d;
    }
}
Example #5
0
void ioncore_set_moveres_accel(ExtlTab tab)
{
    int t_max, t_min, rd, er;
    double step, maxacc;

    if(extl_table_gets_i(tab, "kbresize_t_max", &t_max))
       actmax=(t_max>0 ? t_max : INT_MAX);
    if(extl_table_gets_i(tab, "kbresize_t_min", &t_min))
       uptmin=(t_min>0 ? t_min : INT_MAX);
    if(extl_table_gets_d(tab, "kbresize_step", &step))
       accelinc=(step>0 ? step : 1);
    if(extl_table_gets_d(tab, "kbresize_maxacc", &maxacc))
       accelmax=(maxacc>0 ? maxacc*maxacc : 1);
    if(extl_table_gets_i(tab, "kbresize_delay", &rd))
        resize_delay=MAXOF(0, rd);
    if(extl_table_gets_i(tab, "edge_resistance", &er))
        ioncore_edge_resistance=MAXOF(0, er);
}
Example #6
0
void rqgeomparams_from_table(WRQGeomParams *rq,
                             const WRectangle *origg, ExtlTab g)
{
    rq->geom=*origg;
    rq->flags=REGION_RQGEOM_WEAK_ALL;

    if(extl_table_gets_i(g, "x", &(rq->geom.x)))
       rq->flags&=~REGION_RQGEOM_WEAK_X;
    if(extl_table_gets_i(g, "y", &(rq->geom.y)))
       rq->flags&=~REGION_RQGEOM_WEAK_Y;
    if(extl_table_gets_i(g, "w", &(rq->geom.w)))
       rq->flags&=~REGION_RQGEOM_WEAK_W;
    if(extl_table_gets_i(g, "h", &(rq->geom.h)))
       rq->flags&=~REGION_RQGEOM_WEAK_H;

    rq->geom.w=MAXOF(1, rq->geom.w);
    rq->geom.h=MAXOF(1, rq->geom.h);
}
Example #7
0
/*--lowlevel routine not to be called by the user--*/
EXTL_EXPORT
WMenu *mod_menu_do_grabmenu(WMPlex *mplex, ExtlFn handler, ExtlTab tab,
                            ExtlTab param)
{
    WMenuCreateParams fnp;
    WMPlexAttachParams par;
    WMenu *menu;
    XKeyEvent *ev;
    uint state, kcb;
    bool sub;
    
    if(!ioncore_current_key(&kcb, &state, &sub))
        return NULL;
    
    if(state==0){
        WMenu *menu=mod_menu_do_menu(mplex, handler, tab, param);
        /*
        if(menu!=NULL && cycle!=extl_fn_none()){
            uint kcb, state; 
        
            menu->cycle_bindmap=region_add_cycle_bindmap((WRegion*)menu,
                                                         kcb, state, ???,
                                                         ???);
        }*/
        return menu;
    }
    
    fnp.handler=handler;
    fnp.tab=tab;
    fnp.pmenu_mode=FALSE;
    fnp.submenu_mode=FALSE;
    fnp.big_mode=extl_table_is_bool_set(param, "big");
    fnp.initial=0;
    extl_table_gets_i(param, "initial", &(fnp.initial));

    par.flags=(MPLEX_ATTACH_SWITCHTO|
               MPLEX_ATTACH_LEVEL|
               MPLEX_ATTACH_UNNUMBERED|
               MPLEX_ATTACH_SIZEPOLICY);
    par.szplcy=SIZEPOLICY_FULL_BOUNDS;
    par.level=STACKING_LEVEL_MODAL1+2;

    menu=(WMenu*)mplex_do_attach_new(mplex, &par,
                                     (WRegionCreateFn*)create_menu,
                                     (void*)&fnp); 
    
    if(menu==NULL)
        return NULL;
 
    menu->gm_kcb=kcb;
    menu->gm_state=state;
    
    ioncore_grab_establish((WRegion*)menu, grabmenu_handler, 
                           grabkilled_handler, 0);
    
    return menu;
}
Example #8
0
void de_get_border_val(uint *val, ExtlTab tab, const char *what)
{
    int g;
    
    if(extl_table_gets_i(tab, what, &g)){
        if(g>CF_BORDER_VAL_SANITY_CHECK || g<0)
            warn(TR("Border attribute %s sanity check failed."), what);
        else
            *val=g;
    }
}
Example #9
0
/*EXTL_DOC
 * Set module configuration. The following are supported:
 *
 * \begin{tabularx}{\linewidth}{lX}
 *  \tabhead{Field & Description}
 *  \var{autoshowcompl} & (boolean) Is auto-show-completions enabled?
 *      (default: true). \\
 *  \var{autoshowcompl_delay} & (integer) auto-show-completions delay
 *      in milliseconds (default: 250). \\
 *  \var{caseicompl} & (boolean) Turn some completions case-insensitive
 *      (default: false). \\
 *  \var{substrcompl} & (boolean) Complete on sub-strings in some cases
 *      (default: ftrue). \\
 * \end{tabularx}
 */
EXTL_EXPORT
void mod_query_set(ExtlTab tab)
{
    ModQueryConfig *c=&mod_query_config;

    extl_table_gets_b(tab, "autoshowcompl", &c->autoshowcompl);
    extl_table_gets_b(tab, "caseicompl", &c->caseicompl);
    extl_table_gets_b(tab, "substrcompl", &c->substrcompl);
    
    if(extl_table_gets_i(tab, "autoshowcompl_delay",
                         &c->autoshowcompl_delay)){
        c->autoshowcompl_delay=maxof(c->autoshowcompl_delay, 0);
    }
}
Example #10
0
File: dock.c Project: dkogan/notion
static bool dock_do_attach_final(WDock *dock, WRegion *reg, void *UNUSED(unused))
{
    WDockApp *dockapp, *before_dockapp;
    WRectangle geom;
    bool draw_border=TRUE;
    int pos=INT_MAX;

    /* Create and initialise a new WDockApp struct */
    dockapp=ALLOC(WDockApp);

    if(dockapp==NULL)
        return FALSE;

    if(OBJ_IS(reg, WClientWin)){
        ExtlTab proptab=((WClientWin*)reg)->proptab;
        extl_table_gets_b(proptab, CLIENTWIN_WINPROP_BORDER, &draw_border);
        extl_table_gets_i(proptab, CLIENTWIN_WINPROP_POSITION, &pos);
    }

    dockapp->reg=reg;
    dockapp->draw_border=draw_border;
    dockapp->pos=pos;
    dockapp->tile=FALSE;

    /* Insert the dockapp at the correct relative position */
    before_dockapp=dock->dockapps;
    for(before_dockapp=dock->dockapps;
        before_dockapp!=NULL && dockapp->pos>=before_dockapp->pos;
        before_dockapp=before_dockapp->next){
    }

    if(before_dockapp!=NULL){
        LINK_ITEM_BEFORE(dock->dockapps, before_dockapp, dockapp, next, prev);
    }else{
        LINK_ITEM(dock->dockapps, dockapp, next, prev);
    }

    region_set_manager(reg, (WRegion*)dock);

    geom=REGION_GEOM(reg);
    dock_managed_rqgeom_(dock, reg,
                         REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y,
                         &geom, NULL, FALSE);

    region_map(reg);

    return TRUE;
}
Example #11
0
void ioncore_groupws_set(ExtlTab tab)
{
    char *method=NULL;
    int fpp;

    if(extl_table_gets_s(tab, "float_placement_method", &method)){
        if(strcmp(method, "udlr")==0)
            ioncore_placement_method=PLACEMENT_UDLR;
        else if(strcmp(method, "lrud")==0)
            ioncore_placement_method=PLACEMENT_LRUD;
        else if(strcmp(method, "random")==0)
            ioncore_placement_method=PLACEMENT_RANDOM;
        else
            warn(TR("Unknown placement method \"%s\"."), method);
        free(method);
    }
    if(extl_table_gets_i(tab, "float_placement_padding", &fpp))
        ioncore_placement_padding=MAXOF(0, fpp);
}
Example #12
0
bool groupws_attach_framed_extl(WGroupWS *ws, WRegion *reg, ExtlTab t)
{
    WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
    WFramedParam frp=FRAMEDPARAM_INIT;

    if(reg==NULL)
        return FALSE;

    groupattachparams_get(&ap, t, NULL);

    /* Sensible size is given in framedparams */
    if(ap.geom_set){
        ap.geom_set=0;
        ap.geom_weak_set=1;
        ap.geom_weak=0;

        frp.inner_geom_gravity_set=1;
        frp.inner_geom=ap.geom;
        frp.gravity=NorthWestGravity;
        extl_table_gets_i(t, "gravity", &frp.gravity);
    }

    return groupws_attach_framed(ws, &ap, &frp, reg);
}
Example #13
0
File: dock.c Project: dkogan/notion
EXTL_EXPORT
WDock *mod_dock_create(ExtlTab tab)
{
    char *mode=NULL;
    bool floating=FALSE;
    int screenid=0;
    WScreen *screen=NULL;
    WDock *dock=NULL;
    WRegion *stdisp=NULL;
    WMPlexSTDispInfo din;
    WFitParams fp;

    if(extl_table_gets_s(tab, "mode", &mode)){
        if(strcmp(mode, "floating")==0){
            floating=TRUE;
        }else if(strcmp(mode, "embedded")!=0){
            warn("Invalid dock mode.");
            free(mode);
            return NULL;
        }
        free(mode);
    }

    extl_table_gets_i(tab, "screen", &screenid);
    screen=ioncore_find_screen_id(screenid);
    if(screen==NULL){
        warn("Screen %d does not exist.", screenid);
        return NULL;
    }

    for(dock=docks; dock; dock=dock->dock_next){
        if(region_screen_of((WRegion*)dock)==screen){
            warn("Screen %d already has a dock. Refusing to create another.",
                 screenid);
            return NULL;
        }
    }

    if(!floating){
        mplex_get_stdisp((WMPlex*)screen, &stdisp, &din);
        if(stdisp!=NULL && !extl_table_is_bool_set(tab, "force")){
            warn("Screen %d already has an stdisp. Refusing to add embedded "
                 "dock.", screenid);
            return NULL;
        }
    }

    /* Create the dock */
    fp.mode=REGION_FIT_BOUNDS|REGION_FIT_WHATEVER;
    fp.g.x=0;
    fp.g.y=0;
    fp.g.w=1;
    fp.g.h=1;

    dock=create_dock((WWindow*)screen, &fp);

    if(dock==NULL){
        warn("Failed to create dock.");
        return NULL;
    }


    /* Get parameters */
    dock->save=FALSE;
    dock_do_set(dock, tab, FALSE);

    /* Calculate min/max size */
    dock_managed_rqgeom_(dock, NULL, 0, NULL, NULL, TRUE);

    /* Final setup */
    if(floating){
        WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
        WRegionAttachData data;

        par.flags=(MPLEX_ATTACH_UNNUMBERED
                   |MPLEX_ATTACH_SIZEPOLICY
                   |MPLEX_ATTACH_GEOM
                   |MPLEX_ATTACH_PASSIVE);

        par.geom.w=dock->min_w;
        par.geom.h=dock->min_h;
        par.geom.x=0;
        par.geom.y=0;

        mplexszplcy(dock->pos, &par.szplcy);

        if(extl_table_is_bool_set(tab, "floating_hidden"))
            par.flags|=MPLEX_ATTACH_HIDDEN;

        data.type=REGION_ATTACH_REPARENT;
        data.u.reg=(WRegion*)dock;

        if(mplex_do_attach((WMPlex*)screen, &par, &data))
            return dock;
    }else{
        mplexpos(dock->pos, &din.pos);
        din.fullsize=FALSE; /* not supported */
        if(mplex_set_stdisp((WMPlex*)screen, (WRegion*)dock, &din))
            return dock;
    }

    /* Failed to attach. */
    warn("Failed to attach dock to screen.");
    destroy_obj((Obj*)dock);
    return NULL;
}
Example #14
0
WSplit *load_splitfloat(WTiling *ws, const WRectangle *geom, ExtlTab tab)
{
    WSplit *tl=NULL, *br=NULL;
    WSplitFloat *split;
    char *dir_str;
    int dir, brs, tls;
    ExtlTab subtab;
    WRectangle tlg, brg;
    int set=0;

    set+=(extl_table_gets_i(tab, "tls", &tls)==TRUE);
    set+=(extl_table_gets_i(tab, "brs", &brs)==TRUE);
    set+=(extl_table_gets_s(tab, "dir", &dir_str)==TRUE);

    if(set!=3)
        return NULL;

    if(strcmp(dir_str, "vertical")==0){
        dir=SPLIT_VERTICAL;
    }else if(strcmp(dir_str, "horizontal")==0){
        dir=SPLIT_HORIZONTAL;
    }else{
        warn(TR("Invalid direction."));
        free(dir_str);
        return NULL;
    }
    free(dir_str);

    split=create_splitfloat(geom, ws, dir);
    if(split==NULL)
        return NULL;

    if(!extl_table_is_bool_set(tab, "tls_brs_incl_handles")){
        if(split->ssplit.dir==SPLIT_HORIZONTAL){
            tls+=split->tlpwin->bdw.right;
            brs+=split->brpwin->bdw.left;
        }else{
            tls+=split->tlpwin->bdw.bottom;
            brs+=split->brpwin->bdw.top;
        }
    }

    calc_tlg_brg(geom, tls, brs, dir, &tlg, &brg);

    splitfloat_update_handles(split, &tlg, &brg);

    if(extl_table_gets_t(tab, "tl", &subtab)){
        WRectangle g=tlg;
        splitfloat_tl_pwin_to_cnt(split, &g);
        tl=tiling_load_node(ws, &g, subtab);
        extl_unref_table(subtab);
    }

    if(extl_table_gets_t(tab, "br", &subtab)){
        WRectangle g;
        if(tl==NULL){
            g=*geom;
        }else{
            g=brg;
            splitfloat_br_pwin_to_cnt(split, &g);
        }
        br=tiling_load_node(ws, &g, subtab);
        extl_unref_table(subtab);
    }

    if(tl==NULL || br==NULL){
        destroy_obj((Obj*)split);
        if(tl!=NULL){
            split_do_resize(tl, geom, PRIMN_ANY, PRIMN_ANY, FALSE);
            return tl;
        }
        if(br!=NULL){
            split_do_resize(br, geom, PRIMN_ANY, PRIMN_ANY, FALSE);
            return br;
        }
        return NULL;
    }

    tl->parent=(WSplitInner*)split;
    br->parent=(WSplitInner*)split;

    split->ssplit.tl=tl;
    split->ssplit.br=br;

    return (WSplit*)split;
}
Example #15
0
/*EXTL_DOC
 * Set ioncore basic settings. The table \var{tab} may contain the
 * following fields.
 * 
 * \begin{tabularx}{\linewidth}{lX}
 *  \tabhead{Field & Description}
 *  \var{opaque_resize} & (boolean) Controls whether interactive move and
 *                        resize operations simply draw a rubberband during
 *                        the operation (false) or immediately affect the 
 *                        object in question at every step (true). \\
 *  \var{warp} &          (boolean) Should focusing operations move the 
 *                        pointer to the object to be focused? \\
 *  \var{warp_margin} &   (integer) Border offset in pixels to apply
 *                        to the cursor when warping. \\
 *  \var{warp_factor} &   (double[2]) X & Y factor to offset the cursor.
 *                        between 0 and 1, where 0.5 is the center. \\
 *  \var{switchto} &      (boolean) Should a managing \type{WMPlex} switch
 *                        to a newly mapped client window? \\
 *  \var{screen_notify} & (boolean) Should notification tooltips be displayed
 *                        for hidden workspaces with activity? \\
 *  \var{frame_default_index} & (string) Specifies where to add new regions
 *                        on the mutually exclusive list of a frame. One of
 *                        \codestr{last}, \codestr{next}, (for after current),
 *                        or \codestr{next-act}
 *                        (for after current and anything with activity right
 *                        after it). \\
 *  \var{dblclick_delay} & (integer) Delay between clicks of a double click.\\
 *  \var{kbresize_delay} & (integer) Delay in milliseconds for ending keyboard
 *                         resize mode after inactivity. \\
 *  \var{kbresize_t_max} & (integer) Controls keyboard resize acceleration. 
 *                         See description below for details. \\
 *  \var{kbresize_t_min} & (integer) See below. \\
 *  \var{kbresize_step} & (floating point) See below. \\
 *  \var{kbresize_maxacc} & (floating point) See below. \\
 *  \var{edge_resistance} & (integer) Resize edge resistance in pixels. \\
 *  \var{framed_transients} & (boolean) Put transients in nested frames. \\
 *  \var{float_placement_method} & (string) How to place floating frames.
 *                          One of \codestr{udlr} (up-down, then left-right), 
 *                          \codestr{lrud} (left-right, then up-down), or 
 *                          \codestr{random}. \\
 *  \var{float_placement_padding} & (integer) Pixels between frames when 
 *                          \var{float_placement_method} is \codestr{udlr} or
 *                          \codestr{lrud}. \\
 *  \var{mousefocus} & (string) Mouse focus mode: 
 *                     \codestr{disabled} or \codestr{sloppy}. \\
 *  \var{unsqueeze} & (boolean) Auto-unsqueeze transients/menus/queries/etc. \\
 *  \var{autoraise} & (boolean) Autoraise regions in groups on goto. \\
 *  \var{usertime_diff_current} & (integer) Controls switchto timeout. \\
 *  \var{usertime_diff_new} & (integer) Controls switchto timeout. \\
 *  \var{autosave_layout} & (boolean) Automatically save layout on restart and exit. \\
 *  \var{window_stacking_request} & (string) How to respond to window-stacking
 *                          requests. \codestr{ignore} to do nothing,
 *                          \codestr{activate} to set the activity flag on a
 *                          window requesting to be stacked Above. \\
 *  \var{focuslist_insert_delay} & (integer) Time (in ms) that a window must
 *                          stay focused in order to be added to the focus list.
 *                          If this value is set <=0, this logic is disabled:
 *                          the focus list is updated immediately \\
 *  \var{activity_notification_on_all_screens} & (boolean) If enabled, activity
 *                          notifiers are displayed on ALL the screens, not just
 *                          the screen that contains the window producing the
 *                          notification. This is only relevant on multi-head
 *                          setups. By default this is disabled \\
 *  \var{workspace_indicator_timeout} & (integer) If enabled, a workspace
 *                          indicator comes up at the bottom-left of the screen
 *                          when a new workspace is selected. This indicator
 *                          stays active for only as long as indicated by this
 *                          variable (in ms). Timeout values <=0 disable the
 *                          indicator altogether. This is disabled by default \\
 * \end{tabularx}
 * 
 * When a keyboard resize function is called, and at most \var{kbresize_t_max} 
 * milliseconds has passed from a previous call, acceleration factor is reset 
 * to 1.0. Otherwise, if at least \var{kbresize_t_min} milliseconds have 
 * passed from the from previous acceleration update or reset the squere root
 * of the acceleration factor is incremented by \var{kbresize_step}. The 
 * maximum acceleration factor (pixels/call modulo size hints) is given by 
 * \var{kbresize_maxacc}. The default values are (200, 50, 30, 100). 
 */
EXTL_EXPORT
void ioncore_set(ExtlTab tab)
{
    int dd;
    char *tmp;
    ExtlFn fn;
    
    extl_table_gets_b(tab, "opaque_resize", &(ioncore_g.opaque_resize));
    extl_table_gets_b(tab, "warp", &(ioncore_g.warp_enabled));
    extl_table_gets_i(tab, "warp_margin", &(ioncore_g.warp_margin));
    extl_table_gets_d(tab, "warp_factor_x", &(ioncore_g.warp_factor[0]));
    extl_table_gets_d(tab, "warp_factor_y", &(ioncore_g.warp_factor[1]));
    extl_table_gets_b(tab, "switchto", &(ioncore_g.switchto_new));
    extl_table_gets_b(tab, "screen_notify", &(ioncore_g.screen_notify));
    extl_table_gets_b(tab, "framed_transients", &(ioncore_g.framed_transients));
    extl_table_gets_b(tab, "unsqueeze", &(ioncore_g.unsqueeze_enabled));
    extl_table_gets_b(tab, "autoraise", &(ioncore_g.autoraise));
    extl_table_gets_b(tab, "autosave_layout", &(ioncore_g.autosave_layout));

    if(extl_table_gets_s(tab, "window_stacking_request", &tmp)){
        ioncore_g.window_stacking_request=stringintmap_value(win_stackrq, 
                                                         tmp,
                                                         ioncore_g.window_stacking_request);
        free(tmp);
    }
    
    if(extl_table_gets_s(tab, "frame_default_index", &tmp)){
        ioncore_g.frame_default_index=stringintmap_value(frame_idxs, 
                                                         tmp,
                                                         ioncore_g.frame_default_index);
        free(tmp);
    }

    if(extl_table_gets_s(tab, "mousefocus", &tmp)){
        if(strcmp(tmp, "disabled")==0)
            ioncore_g.no_mousefocus=TRUE;
        else if(strcmp(tmp, "sloppy")==0)
            ioncore_g.no_mousefocus=FALSE;
        free(tmp);
    }
    
    if(extl_table_gets_i(tab, "dblclick_delay", &dd))
        ioncore_g.dblclick_delay=MAXOF(0, dd);

    if(extl_table_gets_i(tab, "usertime_diff_current", &dd))
        ioncore_g.usertime_diff_current=MAXOF(0, dd);

    if(extl_table_gets_i(tab, "usertime_diff_new", &dd))
        ioncore_g.usertime_diff_new=MAXOF(0, dd);

    if(extl_table_gets_i(tab, "focuslist_insert_delay", &dd))
        ioncore_g.focuslist_insert_delay=MAXOF(0, dd);

    if(extl_table_gets_i(tab, "workspace_indicator_timeout", &dd))
        ioncore_g.workspace_indicator_timeout=MAXOF(0, dd);

    extl_table_gets_b(tab, "activity_notification_on_all_screens",
                      &(ioncore_g.activity_notification_on_all_screens));

    ioncore_set_moveres_accel(tab);
    
    ioncore_groupws_set(tab);
    
    /* Internal -- therefore undocumented above */
    if(extl_table_gets_f(tab, "_get_winprop", &fn)){
        if(get_winprop_fn_set)
            extl_unref_fn(get_winprop_fn);
        get_winprop_fn=fn;
        get_winprop_fn_set=TRUE;
    }
    
    if(extl_table_gets_f(tab, "_get_layout", &fn)){
        if(get_layout_fn_set)
            extl_unref_fn(get_layout_fn);
        get_layout_fn=fn;
        get_layout_fn_set=TRUE;
    }
    
}