g_error widget_derive(struct widget **w, handle *h, int type,struct widget *parent, handle hparent,int rship,int owner) { g_error e; DBG("type %d, rship %d, parent %p, owner %d\n",type,rship,parent,owner); /* Allow using this to detach widgets too. Makes sense, since this is called * by the attachwidget request handler. */ if (!parent) return widget_attach(*w, NULL, NULL, 0); switch (rship) { case PG_DERIVE_INSIDE: if (*w == NULL ) { e = widget_create(w,h, type, parent->dt, hparent, owner); errorcheck; } e = widget_attach(*w, parent->dt,parent->sub,hparent); break; case PG_DERIVE_AFTER: if ( *w == NULL ) { e = widget_create(w,h, type, parent->dt, parent->container, owner); errorcheck; } e = widget_attach(*w,parent->dt,parent->out,parent->container); break; case PG_DERIVE_BEFORE: case PG_DERIVE_BEFORE_OLD: if ( *w == NULL ) { e = widget_create(w,h, type, parent->dt, parent->container, owner); errorcheck; } e = widget_attach(*w,parent->dt,parent->where,parent->container); break; default: return mkerror(PG_ERRT_BADPARAM,22); } /* Error checking code common to all cases */ if (iserror(e)) { widget_remove(*w); errorcheck; } if ((*w)->def->post_attach) { e = (*w)->def->post_attach(*w,parent,rship); errorcheck; } return success; }
void widget_remove(struct widget *w) { struct widget *child; struct divnode **old_where; DBG("%p, type %d\n",w,w->type); /* Get out of the timer list */ remove_timer(w); /* Detach the widget from the widget tree */ old_where = w->where; widget_attach(w,NULL,NULL,0); /* Detach all children from this widget */ while ((child = widget_traverse(w,PG_TRAVERSE_CHILDREN,0)) && child->where) { DBG("removing child %p, type %d. where %p\n",child,child->type,child->where); widget_attach(child,NULL,NULL,0); } /* Note that the widget may have it's 'sub' attachment point filled even * if it doesn't have any real children, if it was used inside another widget. * We need to reattach any child divnodes this widget still has back to its insertion * point, so that they are properly deleted when the widget owning this subtree is * finished removing its component pieces. * Note that we're attaching it to the widget's former "where" attachment point, * since by this time it's been detached from the widget tree and w->where * should be NULL. */ if (w->out && *w->out && w->sub && *w->sub) { /* If this widget has two subtrees, we need to append them into just one * before we link this back into the parent's subtree. A messy process, but * cleaner than the alternative (voodoo memory management :) */ struct divnode *n; n = *w->sub; while (n->next) n = n->next; n->next = *w->out; if (old_where) *old_where = *w->sub; *w->out = *w->sub = NULL; } /* If there's only one child, link it directly */ else if (w->out && *w->out) { if (old_where) *old_where = *w->out; *w->out = NULL; } else if (w->sub && *w->sub) { if (old_where) *old_where = *w->sub; *w->sub = NULL; } /* Free the widget's private data and divnodes */ if (w->def->remove) (*w->def->remove)(w); /* Free the array of subclass data */ g_free(w->subclasses); /* Free the widget itself */ #ifdef DEBUG_KEYS num_widgets--; #endif g_free(w); }
g_error panel_install(struct widget *self) { struct widget *bar, *title; g_error e; WIDGET_ALLOC_DATA(paneldata); /* This split determines the size of the main panel area */ e = newdiv(&self->in,self); errorcheck; self->in->flags &= ~(DIVNODE_SIZE_AUTOSPLIT | DIVNODE_SIZE_RECURSIVE); self->in->flags |= PG_S_TOP; /* An optional border inside that main panel area */ e = newdiv(&self->in->div,self); errorcheck; self->in->div->flags &= ~(DIVNODE_SIZE_AUTOSPLIT | DIVNODE_SIZE_RECURSIVE); self->in->div->flags |= DIVNODE_SPLIT_BORDER; self->in->div->build = &build_panel_border; /* Create the panelbar widget */ e = widget_create(&bar,&DATA->hbar,PG_WIDGET_PANELBAR, self->dt,self->container,self->owner); errorcheck; e = widget_attach(bar,self->dt,&self->in->div->div,0); errorcheck; e = widget_set(bar,PG_WP_BIND,self->h); errorcheck; /* This draws the panel background */ e = newdiv(bar->out,self); errorcheck; DATA->bg = *bar->out; DATA->bg->flags |= DIVNODE_SPLIT_BORDER; DATA->bg->flags &= ~DIVNODE_SIZE_AUTOSPLIT; DATA->bg->build = &build_bgfill_only; DATA->bg->state = PGTH_O_PANEL; /* Set up us the container! */ self->out = &self->in->next; self->sub = &DATA->bg->div; /* Firstly, create a label widget in the panelbar to present the title */ title = NULL; e = widget_derive(&title,&DATA->hlabel,PG_WIDGET_LABEL,bar,DATA->hbar, PG_DERIVE_INSIDE,self->owner); errorcheck; widget_set(title,PG_WP_SIDE,PG_S_ALL); widget_set(title,PG_WP_THOBJ,PGTH_O_PANELBAR); /* Nextly, create the standard buttons for a panel app */ e = panel_std_button(&DATA->hzoom, self, PGTH_O_ZOOMBTN, PGTH_O_ZOOMBTN_ON, PGTH_O_ZOOMBTN_HILIGHT, PG_EXEV_TOGGLE, &panel_zoom_callback); errorcheck; e = panel_std_button(&DATA->hrotate, self, PGTH_O_ROTATEBTN, PGTH_O_ROTATEBTN_ON, PGTH_O_ROTATEBTN_HILIGHT, 0, &panel_rotate_callback); errorcheck; e = panel_std_button(&DATA->hclose, self, PGTH_O_CLOSEBTN, PGTH_O_CLOSEBTN_ON, PGTH_O_CLOSEBTN_HILIGHT, 0, &panel_close_callback); errorcheck; /* Make sure we default to our minimum rolled-up size */ widget_set(self, PG_WP_SIZE, 0); return success; }