g_error panel_set(struct widget *self,int property, glob data) { struct widget *w; g_error e; struct app_info **app; switch (property) { case PG_WP_SIZE: /* Alias 0 to our minimum rolled-up size */ e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hbar); errorcheck; if (data==0) data = w->in->split; widget_base_set(self,property,data); break; case PG_WP_SIDE: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hbar); errorcheck; switch (data) { /* Invert the side for the panelbar */ case PG_S_TOP: widget_set(w,PG_WP_SIDE,PG_S_BOTTOM); break; case PG_S_BOTTOM: widget_set(w,PG_WP_SIDE,PG_S_TOP); break; case PG_S_LEFT: widget_set(w,PG_WP_SIDE,PG_S_RIGHT); break; case PG_S_RIGHT: widget_set(w,PG_WP_SIDE,PG_S_LEFT); break; } return mkerror(ERRT_PASS,0); case PG_WP_THOBJ: DATA->bg->state = data; resizewidget(self); self->in->flags |= DIVNODE_NEED_RECALC; self->dt->flags |= DIVTREE_NEED_RECALC; break; case PG_WP_TEXT: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hlabel); errorcheck; app = appmgr_findapp(self); if (app && *app) (*app)->name = data; return widget_set(w,property,data); case PG_WP_IMAGE: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hlabel); errorcheck; return widget_set(w,property,data); case PG_WP_MARGIN: DATA->margin = data; DATA->margin_override = data >= 0; resizewidget(self); break; default: return mkerror(ERRT_PASS,0); } return success; }
/* Create an input filter to act as an adaptor between pgserver and * client-side input filters. */ g_error infilter_client_create(handle insertion, u32 accept_trigs, u32 absorb_trigs, handle *h, int owner) { struct infilter *insert_after; struct infilter **i; g_error e; /* Find the insertion point (it can be owned by anyone) */ e = rdhandle((void**)&insert_after,PG_TYPE_INFILTER,-1,insertion); errorcheck; if (insert_after) i = &insert_after->next; else i = &infilter_list; /* Insert the "adaptor" that sends events to the client */ e = infilter_insert(i, h, owner, &infilter_client_adaptor); errorcheck; (*i)->owner = owner; (*i)->accept_trigs = accept_trigs; (*i)->absorb_trigs = absorb_trigs; return success; }
void def_sprite_hide(struct sprite *spr) { static struct pgquad cr; struct divtree *dt; if (disable_output) return; if (iserror(rdhandle((void**)&dt, PG_TYPE_DIVTREE, -1, spr->dt))) return; if ( (!spr->onscreen) || (spr->ox == -1) ) return; cr.x1 = spr->x; cr.y1 = spr->y; cr.x2 = spr->x+spr->w-1; cr.y2 = spr->y+spr->h-1; /* Remove sprites above this one too */ def_sprite_hide_above(spr); /* Put back the old image */ VID(blit) (dt->display,spr->ox,spr->oy,spr->ow,spr->oh, spr->backbuffer,0,0,PG_LGOP_NONE); add_updarea(dt,spr->ox,spr->oy,spr->ow,spr->oh); spr->onscreen = 0; }
/* Rebuild function for paragraph divnodes, issued by textbox_new_par_div */ void textbox_build_par_div(struct gropctxt *c, u16 state, struct widget *self) { struct paragraph *par; struct gropnode *grops = *c->headpp; /* Retrieve the paragraph pointer from the existing gropnodes */ if (iserror(rdhandle((void**)&par,PG_TYPE_PARAGRAPH,-1,grops->next->param[0])) || !par) return; /* Text color, cursor color, cursor width */ grops->param[0] = VID(color_pgtohwr)(theme_lookup(state,PGTH_P_FGCOLOR)); par->cursor.color = grops->param[0]; par->cursor.width = theme_lookup(state,PGTH_P_CURSOR_WIDTH); /* If we're displaying to a different width, rewrap it */ if (par->width != c->r.w) { par->width = c->r.w; paragraph_wrap(par,1); } /* Set gropnode sizes */ grops->next->r.x = c->r.x; grops->next->r.y = c->r.y; grops->next->r.w = c->r.w; grops->next->r.h = c->r.h; grops->next->next->r = grops->next->r; DBG("Build, size: %d,%d,%d,%d preferred: %d,%d\n", c->r.x,c->r.y,c->r.w,c->r.h,c->owner->preferred.w,c->owner->preferred.h); }
/* A widget has requested focus... Send out the ACTIVATE and DEACTIVATE triggers, and update necessary vars */ void request_focus(struct widget *self) { handle hself = hlookup(self,NULL); struct widget *kbdfocus; /* Already focused? */ if (dts->top->focus==hself) return; kbdfocus = NULL; rdhandle((void**)&kbdfocus,PG_TYPE_WIDGET,-1,dts->top->focus); /* Deactivate the old widget, activate the new */ send_trigger(kbdfocus,PG_TRIGGER_DEACTIVATE,NULL); dts->top->focus = hself; appmgr_focus(appmgr_findapp(self)); send_trigger(self,PG_TRIGGER_ACTIVATE,NULL); /* Scroll in */ scroll_to_divnode(self->in->div); /* If there's an active hotspot cursor, move it to this widget */ if (dts->top->hotspot_cursor) { int x,y; divnode_hotspot_position(self->in->div, &x, &y); cursor_move(dts->top->hotspot_cursor,x,y,dts->top); } }
/* When the node under the cursor changes, notify the owning widget. */ void cursor_change_under(struct cursor *crsr, handle old_under) { struct widget *new_w, *old_w; new_w = NULL; rdhandle((void**)&new_w, PG_TYPE_WIDGET, -1, crsr->ctx.widget_under); old_w = NULL; rdhandle((void**)&old_w, PG_TYPE_WIDGET, -1, old_under); if (new_w == old_w) return; if (new_w) widget_set_numcursors(new_w,new_w->numcursors+1,crsr); if (old_w) widget_set_numcursors(old_w,old_w->numcursors-1,crsr); }
g_error tabpage_set(struct widget *self,int property, glob data) { struct widget *w; g_error e; /* Redirect applicable properties to the tab */ if (is_tab_property(property)) if (!iserror(rdhandle((void**)&w, PG_TYPE_WIDGET, self->owner, DATA->htab)) && w) return widget_set(w, property, data); /* Redirect applicable properties to the tab bar */ if (is_tab_bar_property(property)) if (!iserror(rdhandle((void**)&w, PG_TYPE_WIDGET, self->owner, DATA->htab_bar)) && w) return widget_set(w, property, data); return WIDGET_PARENT->set(self,property,data); }
/* Given a pg_client_trigger in network byte order this will reconstruct * the trigparam union from it, and dispatch it to the proper input filter. */ g_error infilter_client_send(union pg_client_trigger *client_trig) { union trigparam tp; int i; struct infilter *from; g_error e; memset(&tp,0,sizeof(tp)); /* Convert it all to host byte order */ for (i=0;i<(sizeof(client_trig->array)/sizeof(client_trig->array[0]));i++) client_trig->array[i] = ntohl(client_trig->array[i]); /* Reconstruct the trigparam union, depending on trigger type */ if (client_trig->content.type & PG_TRIGGERS_KEY) { tp.kbd.key = client_trig->content.u.kbd.key; tp.kbd.mods = client_trig->content.u.kbd.mods; tp.kbd.flags = client_trig->content.u.kbd.flags; tp.kbd.consume = client_trig->content.u.kbd.consume; tp.kbd.divtree = client_trig->content.u.kbd.divtree; } else if (client_trig->content.type & PG_TRIGGERS_MOUSE) { tp.mouse.x = client_trig->content.u.mouse.x; tp.mouse.y = client_trig->content.u.mouse.y; tp.mouse.btn = client_trig->content.u.mouse.btn; tp.mouse.chbtn = client_trig->content.u.mouse.chbtn; tp.mouse.pressure = client_trig->content.u.mouse.pressure; tp.mouse.is_logical = client_trig->content.u.mouse.is_logical; tp.mouse.divtree = client_trig->content.u.mouse.divtree; e = rdhandle((void**)&tp.mouse.cursor, PG_TYPE_CURSOR, -1, client_trig->content.u.mouse.cursor_handle); tp.mouse.ts_calibration = client_trig->content.u.mouse.ts_calibration; errorcheck; } else if (client_trig->content.type & PG_TRIGGER_MOTIONTRACKER) { memcpy(&tp.motion, &client_trig->content.u.motion, sizeof(tp.motion)); } /* Get the source infilter */ e = rdhandle((void**)&from,PG_TYPE_INFILTER,-1,client_trig->content.infilter_from); errorcheck; /* Send it out */ infilter_send(from, client_trig->content.type, &tp); return success; }
g_error textedit_set ( struct widget *self, int property, glob data ) { struct pgstring *text; switch (property) { case PG_WP_TEXT: if (iserror(rdhandle((void **) &text, PG_TYPE_PGSTRING, -1, (handle) data))) text = NULL; if (text) { text_backend_set_text(DATA, text); } break; case PG_WP_FONT: if (iserror(rdhandle((void **)&DATA->fd, PG_TYPE_FONTDESC,-1,data)) || !DATA->fd) return mkerror(PG_ERRT_HANDLE,44); text_backend_build(DATA, DATA->width, DATA->height); break; case PG_WP_SELECTION: if (iserror(rdhandle((void **) &text, PG_TYPE_PGSTRING, -1, (handle) data))) text = NULL; if (text) text_backend_set_selection(DATA, text); break; case PG_WP_READONLY: if (data) { SET_FLAG(DATA->flags, TEXT_WIDGET_READONLY); UNSET_FLAG(DATA->flags, TEXT_WIDGET_FLASH_ON); } else { UNSET_FLAG(DATA->flags, TEXT_WIDGET_READONLY); SET_FLAG(DATA->flags, TEXT_WIDGET_FLASH_ON); DATA->cursor_state = 1; install_timer(self, FLASHTIME_ON); } break; } return success; }
/* Iterator function for widget_find */ g_error widget_find_iterator(const void **p, void *extra) { struct widget *w = (struct widget *) (*p); const struct pgstring *str; struct widget_find_data *data = (struct widget_find_data *) extra; if (iserror(rdhandle((void**)&str,PG_TYPE_PGSTRING,-1,w->name)) || !str) return success; if (!pgstring_cmp(data->string,str)) data->result = w; return success; }
/* Get the window the cursor is in, falling back on the debug window */ static hwrbitmap magic_cursor_display(void) { struct cursor *c = cursor_get_default(); struct divtree *dt; if (!c) return VID(window_debug)(); if (iserror(rdhandle((void**)&dt, PG_TYPE_DIVTREE, -1, c->divtree))) return VID(window_debug)(); return dt->display; }
void def_sprite_update(struct sprite *spr) { struct divtree *dt; if (iserror(rdhandle((void**)&dt, PG_TYPE_DIVTREE, -1, spr->dt))) return; (*vid->sprite_hide) (spr); def_sprite_showall(); /* Also re-show the sprites we hid with protectarea */ /* Redraw */ realize_updareas(dt); }
/* Retrieve the paragraph associated with a divnode */ struct paragraph *document_get_div_par(struct divnode *div) { struct paragraph *par; /* The second gropnode refers to the paragraph, extract the handle from it */ if (!div->grop) return NULL; if (!div->grop->next) return NULL; if (iserror(rdhandle((void**)&par,PG_TYPE_PARAGRAPH,-1,div->grop->next->param[0]))) return NULL; return par; }
glob panel_get(struct widget *self,int property) { struct widget *w; g_error e; switch (property) { case PG_WP_THOBJ: return DATA->bg->state; case PG_WP_TEXT: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hlabel); errorcheck; return widget_get(w,property); case PG_WP_IMAGE: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hlabel); errorcheck; return widget_get(w,property); case PG_WP_PANELBAR: return DATA->hbar; case PG_WP_PANELBAR_LABEL: return DATA->hlabel; case PG_WP_PANELBAR_CLOSE: return DATA->hclose; case PG_WP_PANELBAR_ROTATE: return DATA->hrotate; case PG_WP_PANELBAR_ZOOM: return DATA->hzoom; case PG_WP_MARGIN: return DATA->margin; } return widget_base_get(self,property); }
glob tabpage_get(struct widget *self,int property) { struct widget *w; /* Redirect applicable properties to the tab */ if (is_tab_property(property)) if (!iserror(rdhandle((void**)&w, PG_TYPE_WIDGET, self->owner, DATA->htab)) && w) return widget_get(w, property); /* Redirect applicable properties to the tab bar */ if (is_tab_bar_property(property)) if (!iserror(rdhandle((void**)&w, PG_TYPE_WIDGET, self->owner, DATA->htab_bar)) && w) return widget_get(w, property); switch (property) { case PG_WP_TAB: return DATA->htab; case PG_WP_TAB_BAR: return DATA->htab_bar; } return WIDGET_PARENT->get(self,property); }
void panel_resize(struct widget *self) { struct widget *bar = NULL; rdhandle((void **) &bar, PG_TYPE_WIDGET, self->owner, DATA->hbar); if (DATA->margin_override) DATA->bg->split = DATA->margin; else DATA->bg->split = theme_lookup(DATA->bg->state,PGTH_P_MARGIN); self->in->div->split = theme_lookup(DATA->bg->state,PGTH_P_BORDER_SIZE); /* The minimum setting on the panelbar needs to leave room for the margin * on both sides, and the panelbar width itself. */ if (bar) widget_set(bar, PG_WP_MINIMUM, widget_get(bar, PG_WP_SIZE) + (self->in->div->split << 1)); }
/* This is used in transparent widgets - it propagates a redraw through the container the widget is in, in order to redraw the background */ void redraw_bg(struct widget *self) { struct widget *container; /* Dereference the handle */ if (iserror(rdhandle((void **)&container,PG_TYPE_WIDGET,-1, self->container)) || ! container) return; /* Flags! Redraws automatically propagate through all child nodes of the container's div. */ #ifndef CONFIG_NOPANELBAR if (container->type == PG_WIDGET_PANEL) /* Optimize for panels: don't redraw panelbar */ container->in->div->div->next->flags |= DIVNODE_NEED_REDRAW; else #endif container->in->flags |= DIVNODE_NEED_REDRAW; if ( container->dt ) container->dt->flags |= DIVTREE_NEED_REDRAW; }
void scroll_to_divnode(struct divnode *div) { s16 dx = 0,dy = 0; struct divnode *ds = div->divscroll; struct widget *w; if (!ds) return; /* If the divnode is larger or equal size to the scrolled * container, no need to scroll it in. * This fixes some confusing scroll behavior when focusing the textbox widget. */ if ( (div->r.x <= ds->calc.x && (div->r.x + div->r.w) > (ds->calc.x + ds->calc.w)) || (div->r.y <= ds->calc.y && (div->r.y + div->r.h) > (ds->calc.y + ds->calc.h)) ) return; /* Figure out how much to scroll, if any. */ if (div->r.x < ds->calc.x) dx = div->r.x - ds->calc.x; else if ( (div->r.x + div->r.w) > (ds->calc.x + ds->calc.w) ) dx = (div->r.x + div->r.w) - (ds->calc.x + ds->calc.w); if (div->r.y < ds->calc.y) dy = div->r.y - ds->calc.y; else if ( (div->r.y + div->r.h) > (ds->calc.y + ds->calc.h) ) dy = (div->r.y + div->r.h) - (ds->calc.y + ds->calc.h); /* No scrolling? */ if (!(dx || dy)) return; /* Get a pointer to the scroll bar */ if (!iserror(rdhandle((void **)&w,PG_TYPE_WIDGET,-1, ds->owner->scrollbind)) && w) { if (dx) widget_set(w,PG_WP_SCROLL_X,widget_get(w,PG_WP_SCROLL_X) + dx); if (dy) widget_set(w,PG_WP_SCROLL_Y,widget_get(w,PG_WP_SCROLL_Y) + dy); update(NULL,1); } }
/* Sends a trigger to all of a widget's children */ void r_send_trigger(struct widget *w, s32 type, union trigparam *param, int *stop,int forward) { struct widget *bar; if (!w || (*stop) > 0) return; send_trigger(w,type,param); /* Also traverse the panelbar if there is one */ if (!iserror(rdhandle((void**)&bar, PG_TYPE_WIDGET, w->owner, widget_get(w,PG_WP_PANELBAR))) && bar) { r_send_trigger(bar, type, param, stop,0); if ((*stop) > 0) return; } r_send_trigger(widget_traverse(w,PG_TRAVERSE_CHILDREN,0),type,param,stop,1); if (forward) r_send_trigger(widget_traverse(w,PG_TRAVERSE_FORWARD,1),type,param,stop,1); }
void cursor_getposition(struct cursor *crsr, int *x, int *y, struct divtree **dt) { if (!crsr) crsr = cursor_get_default(); if (!crsr) { /* Start cursors out near the top-left corner */ *x = 16; *y = 16; if (dt) *dt = dts->top; } else { *x = crsr->x; *y = crsr->y; if (dt) { if (iserror(rdhandle((void**)dt, PG_TYPE_DIVTREE, -1, crsr->divtree)) || !*dt) *dt = dts->top; } } }
g_error panelbar_set(struct widget *self,int property, glob data) { g_error e; struct widget *w; switch (property) { case PG_WP_BIND: e = rdhandle((void **)&w,PG_TYPE_WIDGET,self->owner,data); errorcheck; DATA->bindto = data; break; case PG_WP_MINIMUM: DATA->minimum = data; break; default: return mkerror(ERRT_PASS,0); } return success; }
/* Create a standard panel button. * Note that the app owns these handles, so an app may delete one or more buttons. * This means that we _must_ only refer to the buttons by their handle unless of * course we're in a callback triggered by that button. */ g_error panel_std_button(handle *h, struct widget *self, int thobj, int thobj_on, int thobj_hilight, int exev, int (*callback)(int event, struct widget *from, s32 param, int owner, const u8 *data)) { struct widget *w, *bar; g_error e; e = rdhandle((void **) &bar, PG_TYPE_WIDGET, self->owner, DATA->hbar); errorcheck; w = NULL; e = widget_derive(&w,h,PG_WIDGET_BUTTON,bar,DATA->hbar,PG_DERIVE_INSIDE,self->owner); errorcheck; w->callback = callback; w->callback_owner = self; widget_set(w, PG_WP_THOBJ_BUTTON, thobj); widget_set(w, PG_WP_THOBJ_BUTTON_ON, thobj_on); widget_set(w, PG_WP_THOBJ_BUTTON_HILIGHT, thobj_hilight); widget_set(w, PG_WP_THOBJ_BUTTON_ON_NOHILIGHT, thobj_on); widget_set(w, PG_WP_EXTDEVENTS, exev); return success; }
/* Traverse to other widgets in a given direction (PG_TRAVERSE_*) */ struct widget *widget_traverse(struct widget *w, int direction, int count) { struct widget *p; struct divnode *d; struct app_info **appinfo_p, *appinfo; switch (direction) { /* Traverse to the first child, then go forward */ case PG_TRAVERSE_CHILDREN: if (!w) return NULL; /* Make sure not only that this widget has an occupied child * attachment point, but make sure that the thing attached to it is * really the "in" connector on another widget. This is necessary to avoid * an improper result when this is called with a widget used inside another * widget as a container. */ if (!w->sub || !*w->sub || (*w->sub)->owner->in != *w->sub) return NULL; return widget_traverse((*w->sub)->owner,PG_TRAVERSE_FORWARD,count); /* Go forward by 'count' widgets */ case PG_TRAVERSE_FORWARD: for (;w && count;count--) { if (!w->out || !*w->out || (*w->out)->owner->in != *w->out) return NULL; w = (*w->out)->owner; } break; /* Go up by 'count' container levels */ case PG_TRAVERSE_CONTAINER: for (;w && count;count--) { if (iserror(rdhandle((void**) &w, PG_TYPE_WIDGET, -1, w->container))) return NULL; } break; /* Traversing backwards is harder, since there's no 'parent' pointer in the divnode */ case PG_TRAVERSE_BACKWARD: for (;w && count;count--) { /* Find a suitable subtree */ if (iserror(rdhandle((void**) &p, PG_TYPE_WIDGET, -1, w->container))) return NULL; if (p) d = p->in; else d = w->dt->head; /* Find parent divnode */ d = divnode_findparent(d, w->in); if (!d) return NULL; if (d->next != w->in) /* div child doesn't count */ return NULL; w = d->owner; } break; /* Traverse through the application list */ case PG_TRAVERSE_APP: if (w) { /* Find the appinfo structure associated with this widget */ appinfo_p = appmgr_findapp(w); if (!appinfo_p) return NULL; /* Traverse the appinfo list */ for (appinfo=*appinfo_p;appinfo && count;count--) appinfo = appinfo->next; } else { /* If they passed a 0 widget, start them off with the first app */ appinfo = applist; } /* Return the root widget */ if (!appinfo) return NULL; if (iserror(rdhandle((void**) &w, PG_TYPE_WIDGET, -1, appinfo->rootw))) return NULL; break; } return w; }
g_error widget_base_set(struct widget *w, int property, glob data) { char *str; struct divnode *maindiv = w->in->div ? w->in->div : w->in; switch (property) { /* Set the size, assuming initial split at w->in. * Calls resize handler if it exists, and sets the * appropriate flags. */ case PG_WP_SIDE: if (!VALID_SIDE(data)) return mkerror(PG_ERRT_BADPARAM,2); w->in->flags &= SIDEMASK; w->in->flags |= ((sidet)data) | DIVNODE_NEED_RECALC; resizewidget(w); w->dt->flags |= DIVTREE_NEED_RECALC; redraw_bg(w); if (w->auto_orientation) { /* Set orientation on all child widgets */ struct widget *p; p = widget_traverse(w, PG_TRAVERSE_CHILDREN, 0); while (p) { switch (data) { case PG_S_LEFT: case PG_S_RIGHT: if (w->auto_orientation & PG_AUTO_DIRECTION) widget_set(p, PG_WP_DIRECTION, PG_DIR_VERTICAL); if (w->auto_orientation & PG_AUTO_SIDE) switch (widget_get(p, PG_WP_SIDE)) { case PG_S_LEFT: widget_set(p, PG_WP_SIDE, PG_S_TOP); break; case PG_S_RIGHT: widget_set(p, PG_WP_SIDE, PG_S_BOTTOM); break; } break; case PG_S_TOP: case PG_S_BOTTOM: if (w->auto_orientation & PG_AUTO_DIRECTION) widget_set(p, PG_WP_DIRECTION, PG_DIR_HORIZONTAL); if (w->auto_orientation & PG_AUTO_SIDE) switch (widget_get(p, PG_WP_SIDE)) { case PG_S_TOP: widget_set(p, PG_WP_SIDE, PG_S_LEFT); break; case PG_S_BOTTOM: widget_set(p, PG_WP_SIDE, PG_S_RIGHT); break; } break; } p = widget_traverse(p, PG_TRAVERSE_FORWARD,1); } } break; case PG_WP_SIZE: if (data<0) { /* Automatic sizing */ w->in->flags |= DIVNODE_SIZE_AUTOSPLIT; w->dt->flags |= DIVTREE_NEED_RESIZE; } else { w->in->split = data; w->in->flags &= ~DIVNODE_SIZE_AUTOSPLIT; /* No auto resizing */ } w->in->flags |= DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_RECALC; redraw_bg(w); break; case PG_WP_SIZEMODE: w->in->flags &= ~DIVNODE_SIZE_AUTOSPLIT; /* No auto resizing */ w->in->flags &= ~PG_SZMODEMASK; w->in->flags |= data & PG_SZMODEMASK; redraw_bg(w); break; case PG_WP_SCROLL_X: if (data > w->in->child.w - w->in->r.w) data = w->in->child.w - w->in->r.w; if (data < 0) data = 0; if (maindiv->translation.x != -data) { maindiv->translation.x = -data; maindiv->flags |= DIVNODE_SCROLL_ONLY | DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_REDRAW; hotspot_free(); } maindiv->flags |= DIVNODE_DIVSCROLL | DIVNODE_EXTEND_WIDTH; break; case PG_WP_SCROLL_Y: if (data > w->in->child.h - w->in->r.h) data = w->in->child.h - w->in->r.h; if (data < 0) data = 0; if (maindiv->translation.y != -data) { maindiv->translation.y = -data; maindiv->flags |= DIVNODE_SCROLL_ONLY | DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_REDRAW; hotspot_free(); } maindiv->flags |= DIVNODE_DIVSCROLL | DIVNODE_EXTEND_HEIGHT; break; case PG_WP_NAME: if (iserror(rdhandle((void **)&str,PG_TYPE_PGSTRING,-1,data))) return mkerror(PG_ERRT_HANDLE,18); w->name = handle_canonicalize((handle) data); break; case PG_WP_PUBLICBOX: w->publicbox = data; break; case PG_WP_BIND: w->scrollbind = data; break; case PG_WP_THOBJ: maindiv->state = data; resizewidget(w); w->in->flags |= DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_RECALC; break; case PG_WP_TRIGGERMASK: w->trigger_mask = data; break; case PG_WP_HILIGHTED: { struct widget *p; // // Pass the message onto the other sub widgets // p = widget_traverse(w, PG_TRAVERSE_CHILDREN, 0); while (p) { widget_set(p, PG_WP_HILIGHTED, data); p = widget_traverse(p, PG_TRAVERSE_FORWARD,1); } } break; case PG_WP_AUTO_ORIENTATION: w->auto_orientation = data; break; default: return mkerror(PG_ERRT_BADPARAM,6); /* Unknown property */ } return success; }
void infilter_pntr_dispatch_handler(struct infilter *self, u32 trigger, union trigparam *param) { struct widget *under; int release_captured = 0; int accepted = 0; /* In order to dispatch a pointing event, it must have an associated cursor. * The normalize filter should have given us a cursor whether the driver had * one or not, but in case an event was inserted into the pipe with no cursor, * pass it on. This will usually just run the event off the end of the * filter chain, but this makes it theoretically possible for a client to pick * up the cursorless events. */ if (!param->mouse.cursor) { infilter_send(self, trigger, param); return; } /* Move the cursor */ if (trigger==PG_TRIGGER_MOVE) { int cx,cy; struct divtree *new_dt, *old_dt; /* Default to the topmost divtree, but allow the event to override */ if (iserror(rdhandle((void**)&new_dt, PG_TYPE_DIVTREE, -1, param->mouse.divtree)) || !new_dt) new_dt = dts->top; /* If the cursor is already at the destination, throw away this event */ cursor_getposition(param->mouse.cursor,&cx,&cy,&old_dt); if (cx == param->mouse.x && cy == param->mouse.y && new_dt == old_dt) return; cursor_move(param->mouse.cursor,param->mouse.x,param->mouse.y,new_dt); } inactivity_reset(); /* Read which widget is under the cursor */ under = NULL; rdhandle((void**)&under, PG_TYPE_WIDGET, -1, param->mouse.cursor->ctx.widget_under); /* If the capture_btn is released, release the capture */ if ((!(param->mouse.btn & param->mouse.cursor->ctx.capture_btn)) && param->mouse.cursor->ctx.widget_capture && param->mouse.cursor->ctx.widget_capture != param->mouse.cursor->ctx.widget_under) { struct widget *capture; if ((!iserror(rdhandle((void**)&capture, PG_TYPE_WIDGET, -1, param->mouse.cursor->ctx.widget_capture))) && capture) release_captured = send_trigger(capture,PG_TRIGGER_RELEASE,param); accepted++; param->mouse.cursor->ctx.widget_capture = 0; param->mouse.cursor->ctx.capture_btn = 0; } if (under) { /* There's an interactive widget under the cursor */ /* Keep track of the most recently clicked widget */ if (trigger==PG_TRIGGER_DOWN) { param->mouse.cursor->ctx.widget_last_clicked = param->mouse.cursor->ctx.widget_under; /* Also, allow clicks to focus applications */ appmgr_focus(appmgr_findapp(under)); } /* First send the 'raw' event, then handle the cooked ones. */ if (!release_captured) accepted += send_propagating_trigger(under,trigger,param); /* If the mouse is clicked in a widget, it 'captures' future MOVE and RELEASE events * until this button is released. */ if (trigger==PG_TRIGGER_DOWN && !param->mouse.cursor->ctx.widget_capture) { param->mouse.cursor->ctx.widget_capture = param->mouse.cursor->ctx.widget_under; param->mouse.cursor->ctx.capture_btn = param->mouse.chbtn; } } /* If a captured widget accepts PG_TRIGGER_DRAG, send it even when the * mouse is outside its divnodes. */ if (trigger==PG_TRIGGER_MOVE && param->mouse.cursor->ctx.widget_capture) { struct widget *capture; if ((!iserror(rdhandle((void**)&capture, PG_TYPE_WIDGET, -1, param->mouse.cursor->ctx.widget_capture))) && capture) accepted += send_trigger(capture,PG_TRIGGER_DRAG,param); } /* If nothing has accepted the event so far, pass it on */ if (!accepted) infilter_send(self,trigger,param); }
g_error textedit_set_font ( struct widget *self, handle font ) { return rdhandle((void **)&(DATA->fd), PG_TYPE_FONTDESC, -1, font); }
void panelbar_trigger_sprite(struct widget *self,s32 type,union trigparam *param) { bool force = 0; struct widget *boundwidget; int s; switch (type) { case PG_TRIGGER_ENTER: DATA->over = 1; break; case PG_TRIGGER_LEAVE: /* If we're dragging, the mouse didn't REALLY leave */ if (DATA->on) return; DATA->over=0; break; case PG_TRIGGER_DOWN: if (param->mouse.chbtn != 1) return; /* If we're bound to another widget (we should be) save its current size */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->oldsize = widget_get(boundwidget,PG_WP_SIZE); /* If we're not rolled up, save this as the unrolled split */ if (DATA->oldsize > DATA->minimum) DATA->unrolled = DATA->oldsize; } DATA->on = 1; DATA->x = param->mouse.x; DATA->y = param->mouse.y; DATA->draglen = 0; /* Update the screen now, so we have an up-to-date picture of the panelbar stored in DATA->s */ themeify_panelbar(self,1); VID(sprite_hideall) (); /* This line combined with the zero flag on */ update(NULL,0); /* the next gets a clean spriteless grab */ /* In case there was no release trigger (bug in input driver) */ if (DATA->s) { free_sprite(DATA->s); DATA->s = NULL; } if (DATA->sbit) { VID(bitmap_free) (DATA->sbit); DATA->sbit = NULL; } /* Allocate the new sprite */ if(iserror(new_sprite(&DATA->s,self->dt,DATA->panelbar->r.w,DATA->panelbar->r.h))) { DATA->s = NULL; return; } if (iserror(VID(bitmap_new) (&DATA->sbit,DATA->panelbar->r.w,DATA->panelbar->r.h,vid->bpp))) { free_sprite(DATA->s); DATA->s = NULL; DATA->sbit = NULL; return; } DATA->s->bitmap = &DATA->sbit; /* Grab a bitmap of the panelbar to use as the sprite */ VID(blit) (DATA->sbit,0,0,DATA->panelbar->r.w,DATA->panelbar->r.h, self->dt->display,DATA->s->x = DATA->panelbar->r.x,DATA->s->y = DATA->panelbar->r.y, PG_LGOP_NONE); /* Clip the sprite to the travel allowed by boundwidget's parent */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->s->clip_to = boundwidget->in; } return; case PG_TRIGGER_UP: case PG_TRIGGER_RELEASE: if (!DATA->on) return; if (!(param->mouse.chbtn & 1)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { s = panel_calcsplit(self,param->mouse.x,param->mouse.y, widget_get(boundwidget,PG_WP_SIDE)); if (DATA->draglen < MINDRAGLEN) { /* This was a click, not a drag */ DATA->over = 0; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); if (DATA->oldsize > DATA->minimum) /* Roll up the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->minimum); else /* Unroll the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->unrolled); } else { s += panel_effective_split(boundwidget->in); /* Save this as the new unrolled split, * Unless the user manually rolled up the panel */ if ((s-DATA->minimum) > MAXROLLUP) DATA->unrolled = s; else s = DATA->minimum; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); widget_set(boundwidget,PG_WP_SIZE,s); DATA->over = 1; } } VID(bitmap_free) (DATA->sbit); free_sprite(DATA->s); DATA->s = NULL; DATA->sbit = NULL; force = 1; /* Definitely draw the new position */ DATA->on = 0; break; case PG_TRIGGER_MOVE: case PG_TRIGGER_DRAG: if (!DATA->on) return; /* Ok, button 1 is dragging through our widget... */ if (panel_throttle(self)) return; /* Race condition prevention? * Without this, sometimes segfaults because DATA->s is NULL. * Possibly events_pending() triggered another event? */ if (!DATA->s) return; /* Determine where to blit the bar to... */ switch (self->in->flags & (~SIDEMASK)) { case PG_S_TOP: case PG_S_BOTTOM: DATA->s->x = DATA->panelbar->r.x; DATA->draglen += abs(param->mouse.y - DATA->y + DATA->panelbar->r.y - DATA->s->y); DATA->s->y = param->mouse.y - DATA->y + DATA->panelbar->r.y; break; case PG_S_LEFT: case PG_S_RIGHT: DATA->s->y = DATA->panelbar->r.y; DATA->draglen += abs(param->mouse.x - DATA->x + DATA->panelbar->r.x - DATA->s->x); DATA->s->x = param->mouse.x - DATA->x + DATA->panelbar->r.x; break; } /* Reposition sprite */ VID(sprite_update) (DATA->s); return; } themeify_panelbar(self,force); }
/* Set the video mode using the current driver. This is the implementation * of the setmode client request */ g_error video_setmode(u16 xres,u16 yres,u16 bpp,u16 flagmode,u32 flags) { g_error e; struct divtree *tree; struct sprite *spr; u8 converting_mode,oldbpp; /* Must be done first */ if (vidwrap->exitmode) { e = VID(exitmode)(); errorcheck; } /* Default values, combine flags */ if (!xres) xres = vid->xres; if (!yres) yres = vid->yres; if (!bpp) bpp = vid->bpp; switch (flagmode) { case PG_FM_ON: flags |= vid->flags; break; case PG_FM_OFF: flags = vid->flags & (~flags); break; case PG_FM_TOGGLE: flags ^= vid->flags; break; } vid->flags = flags; /* If the new bpp is different, use modeconvert/modeunconvert */ oldbpp = vid->bpp; converting_mode = (bpp != vid->bpp); if (converting_mode) { e = bitmap_iterate((handle_iterator)vid->bitmap_modeunconvert, NULL); errorcheck; e = handle_iterate(PG_TYPE_PALETTE,(handle_iterator)array_hwrtopg, NULL); errorcheck; } /* Might want to tell the driver! */ e = (*vid->setmode) (xres,yres,bpp,flags); errorcheck; /* By default logical coordinates are also physical */ vid->lxres = vid->xres; vid->lyres = vid->yres; /* Synchronize vid->display info automatically if we're using stdbitmap */ if (vid->display && vid->bitmap_getsize==def_bitmap_getsize) { if (((struct stdbitmap *)vid->display)->rend) g_free(((struct stdbitmap *)vid->display)->rend); ((struct stdbitmap *)vid->display)->freebits = 0; ((struct stdbitmap *)vid->display)->w = vid->xres; ((struct stdbitmap *)vid->display)->h = vid->yres; ((struct stdbitmap *)vid->display)->bpp = vid->bpp; } /* Reset wrapper library (before using VID macro) */ vidwrap_static = vidlib_static; vidwrap = &vidwrap_static; { /* Generate text colors table */ u32 *tc; int i; /* Default VGA 16-color palette, copied from the Linux console */ static const u32 default_palette[] = { 0x000000, 0xaa0000, 0x00aa00, 0xaaaa00, 0x0000aa, 0xaa00aa, 0x00aaaa, 0xaaaaaa, 0x555555, 0xff5555, 0x55ff55, 0xffff55, 0x5555ff, 0xff55ff, 0x55ffff, 0xffffff, }; /* Allocate space for textcolors if we haven't already */ if (!res[PGRES_DEFAULT_TEXTCOLORS]) { u32 *ptr; e = g_malloc((void**)&ptr,sizeof(u32)*17); errorcheck; ptr[0] = 16; e = mkhandle(&res[PGRES_DEFAULT_TEXTCOLORS],PG_TYPE_PALETTE,-1,(void*)ptr); errorcheck; } e = rdhandle((void **) &tc, PG_TYPE_PALETTE, -1, res[PGRES_DEFAULT_TEXTCOLORS]); errorcheck; /* Transcribe our static palette */ memcpy(tc+1, default_palette, sizeof(default_palette)); /* If we won't be doing it anyway later, go ahead and convert these to hwrcolors */ if (!converting_mode) { e = array_pgtohwr(&tc); errorcheck; } } /* Add wrapper libraries if necessary. At compile-time, support adding * 90, 180, or 270 degrees as a hardware rotation */ #ifdef CONFIG_ROTATIONBASE_90 /***** 90 degree default */ #ifdef CONFIG_ROTATE180 if (vid->flags & PG_VID_ROTATE90) { vidwrap_rotate180(vidwrap); vid->lxres = vid->xres; vid->lyres = vid->yres; } #endif #ifdef CONFIG_ROTATE270 if (vid->flags & PG_VID_ROTATE180) { vidwrap_rotate270(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #ifdef CONFIG_ROTATE if (!(vid->flags & PG_VID_ROTATEMASK)) { vidwrap_rotate90(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #else #ifdef CONFIG_ROTATIONBASE_180 /***** 180 degree default */ #ifdef CONFIG_ROTATE if (vid->flags & PG_VID_ROTATE270) { vidwrap_rotate90(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #ifdef CONFIG_ROTATE270 if (vid->flags & PG_VID_ROTATE90) { vidwrap_rotate270(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #ifdef CONFIG_ROTATE180 if (!(vid->flags & PG_VID_ROTATEMASK)) { vidwrap_rotate180(vidwrap); vid->lxres = vid->xres; vid->lyres = vid->yres; } #endif #else #ifdef CONFIG_ROTATIONBASE_270 /***** 270 degree default */ #ifdef CONFIG_ROTATE if (vid->flags & PG_VID_ROTATE180) { vidwrap_rotate90(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #ifdef CONFIG_ROTATE180 if (vid->flags & PG_VID_ROTATE270) { vidwrap_rotate180(vidwrap); vid->lxres = vid->xres; vid->lyres = vid->yres; } #endif #ifdef CONFIG_ROTATE270 if (!(vid->flags & PG_VID_ROTATEMASK)) { vidwrap_rotate270(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #else /***** 0 degree default */ #ifdef CONFIG_ROTATE if (vid->flags & PG_VID_ROTATE90) { vidwrap_rotate90(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #ifdef CONFIG_ROTATE180 if (vid->flags & PG_VID_ROTATE180) { vidwrap_rotate180(vidwrap); vid->lxres = vid->xres; vid->lyres = vid->yres; } #endif #ifdef CONFIG_ROTATE270 if (vid->flags & PG_VID_ROTATE270) { vidwrap_rotate270(vidwrap); vid->lxres = vid->yres; vid->lyres = vid->xres; } #endif #endif #endif #endif /* Should we ignore the base screen rotation for keyboard events? */ #ifdef CONFIG_ROTATIONBASE_NOKEYS vidwrap->coord_keyrotate = &def_coord_keyrotate; #ifdef CONFIG_ROTATE if (vid->flags & PG_VID_ROTATE90) vidwrap->coord_keyrotate = &rotate90_coord_keyrotate; #endif #ifdef CONFIG_ROTATE180 if (vid->flags & PG_VID_ROTATE180) vidwrap->coord_keyrotate = &rotate180_coord_keyrotate; #endif #ifdef CONFIG_ROTATE270 if (vid->flags & PG_VID_ROTATE270) vidwrap->coord_keyrotate = &rotate270_coord_keyrotate; #endif #endif /* CONFIG_ROTATIONBASE_NOKEYS */ /* Ignore the base screen rotation for pointing events? */ #ifdef CONFIG_ROTATIONBASE_NOPOINTING vidwrap->coord_physicalize = &def_coord_logicalize; vidwrap->coord_logicalize = &def_coord_logicalize; #ifdef CONFIG_ROTATE if (vid->flags & PG_VID_ROTATE90) { vidwrap->coord_physicalize = &rotate90_coord_physicalize; vidwrap->coord_logicalize = &rotate90_coord_logicalize; } #endif #ifdef CONFIG_ROTATE180 if (vid->flags & PG_VID_ROTATE180) { vidwrap->coord_physicalize = &rotate180_coord_logicalize; vidwrap->coord_logicalize = &rotate180_coord_logicalize; } #endif #ifdef CONFIG_ROTATE270 if (vid->flags & PG_VID_ROTATE270) { vidwrap->coord_physicalize = &rotate270_coord_physicalize; vidwrap->coord_logicalize = &rotate270_coord_logicalize; } #endif #endif /* CONFIG_ROTATIONBASE_NOPOINTING */ /* Since changing video modes pretty much obliterates all onscreen * sprites, and the previous location might be offscreen now, * reset the backbuffer on all sprites */ for (spr=spritelist;spr;spr=spr->next) spr->onscreen = 0; /* Resize the root divnodes of all divtrees in the dtstack */ if (dts) /* (if this is in early init, dtstack isn't here yet) */ for (tree=dts->top;tree;tree=tree->next) { tree->head->r.w = vid->lxres; tree->head->r.h = vid->lyres; tree->head->calc.w = vid->lxres; tree->head->calc.h = vid->lyres; tree->head->flags |= DIVNODE_NEED_RECALC | DIVNODE_FORCE_CHILD_RECALC | DIVNODE_NEED_REBUILD; tree->flags |= DIVTREE_NEED_RECALC | DIVTREE_ALL_REDRAW | DIVTREE_CLIP_POPUP; } /* Convert to the new color depth if necessary */ if (converting_mode) { e = bitmap_iterate((handle_iterator)vid->bitmap_modeconvert, NULL); errorcheck; e = handle_iterate(PG_TYPE_PALETTE,(handle_iterator)array_pgtohwr, NULL); errorcheck; } /* Done swtiching the mode, give the driver a shot at changing * things around */ e = VID(entermode)(); errorcheck; /* Reload things when increasing color depth */ if (oldbpp < bpp) { /* Reload any themes the server is responsible for */ e = reload_initial_themes(); errorcheck; /* FIXME: notify all clients that they can reload here */ } return success; }
void panelbar_trigger_solid(struct widget *self,s32 type,union trigparam *param) { bool force = 0; struct widget *boundwidget; int s; switch (type) { case PG_TRIGGER_ENTER: DATA->over = 1; break; case PG_TRIGGER_LEAVE: DATA->over=0; break; case PG_TRIGGER_DOWN: if (param->mouse.chbtn != 1) return; /* If we're bound to another widget (we should be) save its current size */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->oldsize = widget_get(boundwidget,PG_WP_SIZE); /* To make things easier during dragging, * get the effective split to equal the split */ widget_set(boundwidget, PG_WP_SIZEMODE, PG_SZMODE_PIXEL); widget_set(boundwidget, PG_WP_SIZE, panel_effective_split(boundwidget->in)); } DATA->on = 1; DATA->x = param->mouse.x; DATA->y = param->mouse.y; DATA->draglen = 0; break; case PG_TRIGGER_UP: case PG_TRIGGER_RELEASE: if (!DATA->on) return; if (!(param->mouse.chbtn & 1)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { if (DATA->draglen < MINDRAGLEN) { /* This was a click, not a drag */ DATA->over = 0; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); if (DATA->oldsize > DATA->minimum) /* Roll up the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->minimum); else /* Unroll the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->unrolled); update(NULL,1); } else { s = panel_effective_split(boundwidget->in); /* Save this as the new unrolled split, * Unless the user manually rolled up the panel */ if ((s-DATA->minimum) > MAXROLLUP) DATA->unrolled = s; else s = DATA->minimum; } } DATA->on = 0; break; case PG_TRIGGER_MOVE: case PG_TRIGGER_DRAG: if (!DATA->on) return; if (panel_throttle(self)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { s = panel_calcsplit(self,param->mouse.x,param->mouse.y, widget_get(boundwidget,PG_WP_SIDE)); DATA->draglen += abs(s); if (s) { s += boundwidget->in->split; /* FIXME: This isn't quite right, in solid dragging mode the panelbar * can get out of sync with the cursor when this s < DATA->minimum code * comes into effect. */ if (s < DATA->minimum) s = DATA->minimum; else { DATA->x = param->mouse.x; DATA->y = param->mouse.y; } widget_set(boundwidget, PG_WP_SIZE,s); update(NULL,1); } } return; } themeify_panelbar(self,force); }
void guru(const char *fmt, ...) { struct font_descriptor *df=NULL; char msgbuf[512]; /* Cruftee! */ char *p,*pline; char c; va_list ap; struct pgquad screenclip; static int semaphore = 0; if (!vid) return; if (semaphore) { fprintf(stderr, "GURU re-entered!\n"); return; } semaphore++; /* Format and print message */ va_start(ap,fmt); vsnprintf(msgbuf,512,fmt,ap); va_end(ap); if (!disable_output) { /* Setup */ VID(rect) (VID(window_debug)(),0,0,vid->lxres,vid->lyres,VID(color_pgtohwr)(0), PG_LGOP_NONE); rdhandle((void**)&df,PG_TYPE_FONTDESC,-1,res[PGRES_DEFAULT_FONT]); screenclip.x1 = screenclip.y1 = 0; screenclip.x2 = vid->lxres-1; screenclip.y2 = vid->lyres-1; #ifdef CONFIG_FORMAT_XBM /* Icon (if this fails, no big deal) */ { hwrbitmap icon; if (!iserror(VID(bitmap_loadxbm) (&icon,deadcomp_bits, deadcomp_width,deadcomp_height, VID(color_pgtohwr) (0xFFFF80), VID(color_pgtohwr) (0x000000)))) { VID(blit) (VID(window_debug)(),5,5,deadcomp_width,deadcomp_height, icon,0,0,PG_LGOP_NONE); VID(bitmap_free) (icon); } } #else /* To appease the below code */ # define deadcomp_width 0 #endif df->lib->draw_string(df,VID(window_debug)(),xy_to_pair(10+deadcomp_width,5), VID(color_pgtohwr)(0xFFFFFF),pgstring_tmpwrap(msgbuf), &screenclip,PG_LGOP_NONE,0); VID(update) (VID(window_debug)(),0,0,vid->lxres,vid->lyres); } #ifdef CONFIG_STDERR_GURU /* Mirror the message on stderr, prefix each line with "GURU: " */ for (c=1,pline=msgbuf;c;pline=p+1) { for (p=pline;*p && *p!='\n';p++); c=*p; *p=0; fprintf(stderr,"GURU: %s\n",pline); } #endif semaphore--; }