/* 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); } }
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; }
/* 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; }
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); }