/*EXTL_DOC * Set important directories (the fields \var{sessiondir}, \var{searchpath} * of \var{tab}). */ EXTL_EXPORT bool ioncore_set_paths(ExtlTab tab) { char *s; if(extl_table_gets_s(tab, "userdir", &s)){ warn(TR("User directory can not be set.")); free(s); return FALSE; } if(extl_table_gets_s(tab, "sessiondir", &s)){ extl_set_sessiondir(s); free(s); return FALSE; } if(extl_table_gets_s(tab, "searchpath", &s)){ extl_set_searchpath(s); free(s); return FALSE; } return TRUE; }
static bool handle_target_winprops(WClientWin *cwin, const WManageParams *param, WScreen *scr, WPHolder **ph_ret) { char *layout=NULL, *target=NULL; WPHolder *ph=NULL; bool mgd=FALSE; if(extl_table_gets_s(cwin->proptab, "target", &target)) ph=try_target(cwin, param, target); if(ph==NULL && extl_table_gets_s(cwin->proptab, "new_group", &layout)){ ExtlTab lo=ioncore_get_layout(layout); free(layout); if(lo!=extl_table_none()){ WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT; int mask=MPLEX_ATTACH_SWITCHTO; WRegion *reg; if(param->switchto) par.flags|=MPLEX_ATTACH_SWITCHTO; /*ioncore_newly_created=(WRegion*)cwin;*/ reg=mplex_attach_new_(&scr->mplex, &par, mask, lo); extl_unref_table(lo); /*ioncore_newly_created=NULL;*/ mgd=(region_manager((WRegion*)cwin)!=NULL); if(reg!=NULL && !mgd){ if(target!=NULL) ph=try_target(cwin, param, target); if(ph==NULL){ ph=region_prepare_manage(reg, cwin, param, MANAGE_PRIORITY_NONE); if(ph==NULL) destroy_obj((Obj*)reg); } } } } if(target!=NULL) free(target); *ph_ret=ph; return mgd; }
static void calc_entry_dimens(WMenu *menu) { int i, n=extl_table_get_n(menu->tab); GrFontExtents fnte; GrBorderWidths bdw; int maxw=0; char *str; #if 0 if(extl_table_gets_s(menu->tab, title, &str)){ maxw=grbrush_get_text_width(title_brush, str, strlen(str)); free(str); } #endif for(i=1; i<=n; i++){ if(extl_table_getis(menu->tab, i, "name", 's', &str)){ int w=grbrush_get_text_width(menu->entry_brush, str, strlen(str)); if(w>maxw) maxw=w; free(str); } } grbrush_get_border_widths(menu->entry_brush, &bdw); grbrush_get_font_extents(menu->entry_brush, &fnte); menu->max_entry_w=maxw+bdw.left+bdw.right; menu->entry_h=fnte.max_height+bdw.top+bdw.bottom; menu->entry_spacing=bdw.spacing; }
static bool is_systray(WClientWin *cwin) { static Atom atom__kde_net_wm_system_tray_window_for=None; Atom actual_type=None; int actual_format; unsigned long nitems; unsigned long bytes_after; unsigned char *prop; char *dummy; bool is=FALSE; if(extl_table_gets_s(cwin->proptab, "statusbar", &dummy)){ free(dummy); return TRUE; } if(atom__kde_net_wm_system_tray_window_for==None){ atom__kde_net_wm_system_tray_window_for=XInternAtom(ioncore_g.dpy, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); } if(XGetWindowProperty(ioncore_g.dpy, cwin->win, atom__kde_net_wm_system_tray_window_for, 0, sizeof(Atom), False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop)==Success){ if(actual_type!=None){ is=TRUE; } XFree(prop); } return is; }
static WMenuEntry *preprocess_menu(ExtlTab tab, int *n_entries) { WMenuEntry *entries; ExtlTab entry; int i, n; n=extl_table_get_n(tab); *n_entries=n; if(n<=0) return NULL; entries=ALLOC_N(WMenuEntry, n); if(entries==NULL) return NULL; init_attr(); /* Initialise entries and check submenus */ for(i=1; i<=n; i++){ WMenuEntry *ent=&entries[i-1]; ent->title=NULL; ent->flags=0; gr_stylespec_init(&ent->attr); if(extl_table_geti_t(tab, i, &entry)){ char *attr; ExtlTab sub; ExtlFn fn; if(extl_table_gets_s(entry, "attr", &attr)){ gr_stylespec_load_(&ent->attr, attr, TRUE); free(attr); } if(extl_table_gets_f(entry, "submenu_fn", &fn)){ ent->flags|=WMENUENTRY_SUBMENU; extl_unref_fn(fn); }else if(extl_table_gets_t(entry, "submenu", &sub)){ ent->flags|=WMENUENTRY_SUBMENU; extl_unref_table(sub); } if(ent->flags&WMENUENTRY_SUBMENU) gr_stylespec_set(&ent->attr, GR_ATTR(submenu)); extl_unref_table(entry); } } return entries; }
static bool dock_param_extl_table_set(const WDockParam *param, ExtlTab conftab, int *ret) { char *s; if(extl_table_gets_s(conftab, param->key, &s)) return dock_param_do_set(param, s, ret); return FALSE; }
WRegion *infowin_load(WWindow *par, const WFitParams *fp, ExtlTab tab) { char *style=NULL, *text=NULL; WInfoWin *p; extl_table_gets_s(tab, "style", &style); p=create_infowin(par, fp, style); free(style); if(p==NULL) return NULL; if(extl_table_gets_s(tab, "text", &text)){ infowin_do_set_text(p, text); free(text); } return (WRegion*)p; }
static void dock_do_set(WDock *dock, ExtlTab conftab, bool resize) { char *s; bool b; bool growset=FALSE; bool posset=FALSE; bool save=FALSE; if(extl_table_gets_s(conftab, dock_param_name.key, &s)){ if(!region_set_name((WRegion*)dock, s)){ warn_obj(modname, "Can't set name to \"%s\"", s); } free(s); } if(extl_table_gets_b(conftab, "save", &save)) dock->save=save; if(dock_param_extl_table_set(&dock_param_pos, conftab, &dock->pos)) posset=TRUE; if(dock_param_extl_table_set(&dock_param_grow, conftab, &dock->grow)) growset=TRUE; if(extl_table_gets_b(conftab, dock_param_is_auto.key, &b)) dock->is_auto=b; if(resize && (growset || posset)){ WMPlex *par=OBJ_CAST(REGION_PARENT(dock), WMPlex); WRegion *stdisp=NULL; WMPlexSTDispInfo din; if(par!=NULL){ mplex_get_stdisp(par, &stdisp, &din); din.fullsize=FALSE; /* not supported. */ if(stdisp==(WRegion*)dock){ if(posset) mplexpos(dock->pos, &din.pos); if(growset){ /* Update min/max first */ dock_managed_rqgeom_(dock, NULL, 0, NULL, NULL, TRUE); } mplex_set_stdisp(par, (WRegion*)dock, &din); }else if((WRegion*)par==REGION_MANAGER(dock)){ WSizePolicy szplcy; mplexszplcy(dock->pos, &szplcy); mplex_set_szplcy(par, (WRegion*)dock, szplcy); } } dock_resize(dock); } }
bool extl_table_gets_sizepolicy(ExtlTab tab, const char *nam, WSizePolicy *szplcy) { char *tmpstr; bool ret=FALSE; if(extl_table_gets_s(tab, nam, &tmpstr)){ ret=string2sizepolicy(tmpstr, szplcy); free(tmpstr); } return ret; }
static bool get_spec(ExtlTab tab, const char *name, GrStyleSpec *spec, char **pat_ret) { char *str; bool res; if(!extl_table_gets_s(tab, name, &str)) return FALSE; res=gr_stylespec_load(spec, str); if(pat_ret==NULL) free(str); else *pat_ret=str; return res; }
void de_get_border_sides(uint *ret, ExtlTab tab) { char *style=NULL; if(!extl_table_gets_s(tab, "border_sides", &style)) return; if(strcmp(style, "all")==0) *ret=DEBORDER_ALL; else if(strcmp(style, "tb")==0) *ret=DEBORDER_TB; else if(strcmp(style, "lr")==0) *ret=DEBORDER_LR; else warn(TR("Unknown border side configuration \"%s\"."), style); free(style); }
void de_get_text_align(int *alignret, ExtlTab tab) { char *align=NULL; if(!extl_table_gets_s(tab, "text_align", &align)) return; if(strcmp(align, "left")==0) *alignret=DEALIGN_LEFT; else if(strcmp(align, "right")==0) *alignret=DEALIGN_RIGHT; else if(strcmp(align, "center")==0) *alignret=DEALIGN_CENTER; else warn(TR("Unknown text alignment \"%s\"."), align); free(align); }
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); }
void de_get_border_style(uint *ret, ExtlTab tab) { char *style=NULL; if(!extl_table_gets_s(tab, "border_style", &style)) return; if(strcmp(style, "inlaid")==0) *ret=DEBORDER_INLAID; else if(strcmp(style, "elevated")==0) *ret=DEBORDER_ELEVATED; else if(strcmp(style, "groove")==0) *ret=DEBORDER_GROOVE; else if(strcmp(style, "ridge")==0) *ret=DEBORDER_RIDGE; else warn(TR("Unknown border style \"%s\"."), style); free(style); }
static bool de_get_colour_(WRootWin *rootwin, DEColour *ret, ExtlTab tab, const char *what, DEColour substitute, DEColour inherit) { char *name=NULL; bool set=FALSE; if(extl_table_gets_s(tab, what, &name)){ if(strcmp(name, "inherit")==0){ set=de_duplicate_colour(rootwin, inherit, ret); }else{ set=de_alloc_colour(rootwin, ret, name); if(!set) warn(TR("Unable to allocate colour \"%s\"."), name); } free(name); } if(!set) de_duplicate_colour(rootwin, substitute, ret); return set; }
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; }
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; }
/*EXTL_DOC * Define a style for the root window \var{rootwin}. */ EXTL_EXPORT bool de_defstyle_rootwin(WRootWin *rootwin, const char *name, ExtlTab tab) { DEStyle *style, *based_on=NULL; char *fnt, *bss; if(name==NULL) return FALSE; style=de_create_style(rootwin, name); if(style==NULL) return FALSE; if(extl_table_gets_s(tab, "based_on", &bss)){ GrStyleSpec bs; gr_stylespec_load(&bs, bss); based_on=de_get_style(rootwin, &bs); gr_stylespec_unalloc(&bs); free(bss); }else{ based_on=de_get_style(rootwin, &style->spec); } if(based_on!=NULL){ style->based_on=based_on; based_on->usecount++; } de_get_nonfont(rootwin, style, tab); if(extl_table_gets_s(tab, "font", &fnt)){ de_load_font_for_style(style, fnt); free(fnt); }else if(based_on!=NULL && based_on->font!=NULL){ de_set_font_for_style(style, based_on->font); } if(style->font==NULL) de_load_font_for_style(style, de_default_fontname()); if(based_on!=NULL && gr_stylespec_equals(&based_on->spec, &style->spec)){ /* The new style replaces based_on, so it may be dumped. */ if(!based_on->is_fallback) destyle_dump(based_on); if(based_on->usecount==1){ uint nb=based_on->n_extra_cgrps; uint ns=style->n_extra_cgrps; /* Nothing else is using based_on: optimise and move * extra colour groups here, so that based_on can be freed. */ if(nb>0){ DEColourGroup *cgs=ALLOC_N(DEColourGroup, nb+ns); if(cgs!=NULL){ memcpy(cgs, based_on->extra_cgrps, sizeof(DEColourGroup)*nb); memcpy(cgs+nb, style->extra_cgrps, sizeof(DEColourGroup)*ns); free(style->extra_cgrps); style->extra_cgrps=cgs; style->n_extra_cgrps=nb+ns; free(based_on->extra_cgrps); based_on->extra_cgrps=NULL; based_on->n_extra_cgrps=0; } } /* style->extras_table should be none still */ style->extras_table=based_on->extras_table; based_on->extras_table=extl_table_none(); style->based_on=based_on->based_on; based_on->based_on=NULL; destyle_unref(based_on); } } filter_extras(&style->extras_table, tab); destyle_add(style); return TRUE; }
/*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; } }