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