コード例 #1
0
ファイル: if_hotspot.c プロジェクト: UIKit0/picogui
/* This is the 'high level' hotspot function that will usually be called
 * by the widget code.
 *
 * It rebuilds the hotspot graph from the current divtree if necessary, finds
 * the hotspot closest to the mouse pointer, traverses the hotspot graph in
 * the indicated direction, and finds the new mouse pointer position.
 *
 * The direction is a HOTSPOT_* constant
 */
void hotspot_traverse(short direction) {
  struct hotspot *p;
  int x,y;
  struct divtree *dt;

  /* rebuild the graph */
  if (!hotspotlist) {
    hotspot_build(dts->top->head,NULL);
    if (popup_toolbar_passthrough())
      hotspot_build(dts->root->head,appmgr_nontoolbar_area());
    hotspot_graph();
  }

  /* Create the hotspotnav cursor if it doesn't exist */
  if (!dts->top->hotspot_cursor)
    if (iserror(cursor_new(&dts->top->hotspot_cursor,NULL,-1)))
      return;

  /* Find the current node 
   */
  cursor_getposition(dts->top->hotspot_cursor,&x,&y,&dt);
  p = hotspot_closest(x,y);

  if (!p)
    return;

  /* If the closest node isn't really that close, just warp to
   * that closest node. Otherwise, traverse. 
   *
   * NOTE: We used to test whether the hotspot cursor was within
   * the same divnode as the hotspot, but now that the hotspot cursor
   * is separate from all driver-controlled cursors we can do an
   * exact match.
   */
  if (x==p->x && y==p->y) {
    /* traverse */
    p = p->graph[direction];
    if (!p)
      return;
  }

  /* Make sure the divnode is scrolled in and focused now */
  if (p->div)
    request_focus(p->div->owner);

  /* Warp the hotspot cursor to the new hotspot location */
  cursor_move(dts->top->hotspot_cursor,p->x,p->y,dt);
}
コード例 #2
0
ファイル: cursor.c プロジェクト: UIKit0/picogui
void cursor_widgetunder(struct cursor *crsr) {
  int x,y;
  struct divnode *div;
  struct divtree *dt;

  cursor_getposition(crsr, &x, &y, &dt);
  div = dt->head;

  /* If there are popups and they're all in the nontoolbar area,
   * we can pass toolbar's events through to the bottom layer in the dtstack
   */
  if (popup_toolbar_passthrough()) {
    struct divnode *ntb = appmgr_nontoolbar_area();
    if (ntb) {
      if (x < ntb->r.x ||
	  y < ntb->r.y ||
	  x >= ntb->r.x+ntb->r.w ||
	  y >= ntb->r.y+ntb->r.h) {
	
	/* Get a widget from the bottom layer, with the toolbars */
	div = dts->root->head;
      }
    }
  }
 
  /* recursively determine the widget/divnode under the cursor */
  crsr->ctx.div_under = NULL;
  crsr->ctx.deepest_div = NULL;
  r_cursor_widgetunder(crsr,div,x,y);

  /* Save the widget associated with the divnode we're under */
  if (crsr->ctx.div_under) {
    crsr->ctx.widget_under = hlookup(crsr->ctx.div_under->owner,NULL);

    /* Also change the cursor theme */
    cursor_set_theme(crsr, widget_get(crsr->ctx.div_under->owner,PG_WP_THOBJ));
  }
  else {
    crsr->ctx.widget_under = 0;

    /* Default cursor theme */
    cursor_set_theme(crsr, PGTH_O_DEFAULT);
  }
}
コード例 #3
0
ファイル: widget.c プロジェクト: scanlime/picogui
/* Set the number of cursors occupying the widget, and send any appropriate
 * triggers due to the change.
 */
void widget_set_numcursors(struct widget *self, int num, struct cursor *crsr) {
  union trigparam param;

  /* Don't let our puny little u8 roll over if something else f***s up */
  if (num < 0)
    num = 0;

  cursor_getposition(crsr, &param.mouse.x, &param.mouse.y, NULL);
  param.mouse.btn = crsr->prev_buttons;
  param.mouse.chbtn = 0;
  param.mouse.cursor = crsr;

  if (self->numcursors && !num)
    send_trigger(self,PG_TRIGGER_LEAVE,&param);

  if (!self->numcursors && num)
    send_trigger(self,PG_TRIGGER_ENTER,&param);  

  self->numcursors = num;
}
コード例 #4
0
ファイル: cursor.c プロジェクト: UIKit0/picogui
g_error cursor_new(struct cursor **crsr, handle *h, int owner) {
  g_error e;
  struct cursor *c;
  handle c_h;

  /* Allocate cursor */
  e = g_malloc((void**)&c, sizeof(struct cursor));
  errorcheck;
  memset(c,0,sizeof(struct cursor));

  /* Default at the screen center */
  cursor_getposition(NULL,&c->x, &c->y,NULL);

  /* Add to list */
  c->next = cursor_list;
  cursor_list = c;

  /* Allocate the sprite */
  e = cursor_set_theme(c, PGTH_O_DEFAULT);
  errorcheck;

  /* Give the cursor a handle. We always use pointers to
   * reference cursors internal to pgserver, but when passing
   * events to and from a client we must refer to the cursor
   * using only this handle.
   */
  e = mkhandle(&c_h, PG_TYPE_CURSOR, owner, c);
  errorcheck;

  if (crsr)
    *crsr = c;
  if (h)
    *h = c_h;

  return success;
}
コード例 #5
0
ファイル: if_pntr_dispatch.c プロジェクト: scanlime/picogui
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);
}
コード例 #6
0
ファイル: if_pntr_normalize.c プロジェクト: scanlime/picogui
void infilter_pntr_normalize_handler(struct infilter *self, u32 trigger, union trigparam *param) {
  int x,y, oldbtn, newbtn;
  static struct cursor *cursor_global_invisible;

  /* If we have pointer events with no cursor, assign them our invisible global
   * cursor so that it can collect context information that we'll need for dispatch.
   */
  if (!param->mouse.cursor) {
    if (!cursor_global_invisible) {
      if (iserror(cursor_new(&cursor_global_invisible,NULL,-1)))
	return;
      cursor_global_invisible->sprite->visible = 0;
    }
    param->mouse.cursor = cursor_global_invisible;
  }

  if (trigger != PG_TRIGGER_SCROLLWHEEL) {
    
    /* Get physical cursor position for use later */
    cursor_getposition(param->mouse.cursor, &x, &y,NULL);
    if (!param->mouse.is_logical) {
      /* Normal rotation handling */
      VID(coord_physicalize)(&x,&y);
    }
    
    /* Convert relative motion to absolute motion.
     * We have to be careful about which coordinate system the input is in.
     */
    if (trigger==PG_TRIGGER_PNTR_RELATIVE) {
      trigger = PG_TRIGGER_PNTR_STATUS;
      param->mouse.x += x;
      param->mouse.y += y;
      if (param->mouse.is_logical)
	VID(coord_physicalize)(&x,&y);
      param->mouse.is_logical = 0;
    }
    
    /* Convert absolute motion to individual events
     */
    if (trigger==PG_TRIGGER_PNTR_STATUS) {
      /* Save the old/new button state too, since it may be modified by other
       * input filters when we do infilter_send. Remember that this is all working
       * with the same trigparam structure, and just repassing it after changing
       * the type :)
       */
      newbtn = param->mouse.btn;
      oldbtn = param->mouse.cursor->prev_buttons;
      
      if (newbtn & ~oldbtn)
	trigger = PG_TRIGGER_DOWN;
      else if (oldbtn & ~newbtn)
	trigger = PG_TRIGGER_UP;
      else
	trigger = PG_TRIGGER_MOVE;
    }
    
    /* If we're moving the cursor and this isn't a MOVE event, generate one
     */
    if ((param->mouse.x != x || param->mouse.y != y) && trigger!=PG_TRIGGER_MOVE) {
      union trigparam moveparam = *param;
      moveparam.mouse.btn = param->mouse.cursor->prev_buttons;
      infilter_send(self,PG_TRIGGER_MOVE,&moveparam);
    }
  }    

  /* Detect changes in buttons, and store that along with the event
   */
  param->mouse.chbtn = param->mouse.btn ^ param->mouse.cursor->prev_buttons;
  param->mouse.cursor->prev_buttons = param->mouse.btn;

  /* Resend it (we might have changed the trigger type) */
  infilter_send(self,trigger,param);
}
コード例 #7
0
ファイル: cursor.c プロジェクト: UIKit0/picogui
g_error cursor_set_theme(struct cursor *crsr, int thobj) {
  hwrbitmap *bitmap,*mask;
  s16 w,h;
  bool redisplay;
  g_error e;

  crsr->thobj = thobj;
  
  /* Read the cursor bitmap and bitmask. Note that if the cursor is rectangular
   * or it uses an alpha channel the mask will be NULL.
   */

  e = rdhandlep((void***)&bitmap,PG_TYPE_BITMAP,-1,theme_lookup(thobj,PGTH_P_CURSORBITMAP));
  errorcheck;

  mask = NULL;
  e = rdhandlep((void***)&mask,PG_TYPE_BITMAP,-1,theme_lookup(thobj,PGTH_P_CURSORBITMASK));
  errorcheck;

  if (crsr->sprite && bitmap==crsr->sprite->bitmap && mask==crsr->sprite->mask)
    return success;

  /* If there's no bitmap yet, it's early in init and the default cursor
   * hasn't been created yet. Skip this all.
   */
  if (!bitmap)
    return success;

  VID(bitmap_getsize) (*bitmap,&w,&h);
  
  /* Insert the new bitmaps, resize/create the sprite if necessary */

  redisplay = crsr->sprite && crsr->sprite->onscreen;
  if (redisplay)
    VID(sprite_hide) (crsr->sprite);

  /* Update the hotspot before cursor_move */
  crsr->hotspot_x = theme_lookup(thobj,PGTH_P_CRSRHOTSPOT_X);
  crsr->hotspot_y = theme_lookup(thobj,PGTH_P_CRSRHOTSPOT_Y);

  if (!crsr->sprite) {
    int x,y;
    struct divtree *dt;

    /* Get the default position */
    cursor_getposition(crsr,&x,&y,&dt);

    /* Create a new sprite (default hidden, as per description in input.h) */
    e = new_sprite(&crsr->sprite,dt,w,h);
    errorcheck;
    crsr->sprite->visible = 0;
    
    /* Set the bitmap up, and move it */
    crsr->sprite->bitmap = bitmap;
    crsr->sprite->mask = mask;
    cursor_move(crsr, x,y, dt);
  }
  else {

    /* Since we're not creating a new sprite, we might need to move the hotspot
     */
    crsr->sprite->x = crsr->x - crsr->hotspot_x;
    crsr->sprite->y = crsr->y - crsr->hotspot_y;

    if ( (w!=crsr->sprite->w) || (h!=crsr->sprite->h) ) {
      /* Resize an existing sprite 
       */
      VID(bitmap_free) (crsr->sprite->backbuffer);
      e = VID(bitmap_new) (&crsr->sprite->backbuffer,w,h,vid->bpp);
      errorcheck;
      crsr->sprite->w = w;
      crsr->sprite->h = h;
    }

    crsr->sprite->bitmap = bitmap;
    crsr->sprite->mask = mask;
  }    

  /* If the cursor has an alpha channel, set the LGOP accordingly */
  if (w && h && (VID(getpixel)(*bitmap,0,0) & PGCF_ALPHA))
    crsr->sprite->lgop = PG_LGOP_ALPHA;
  else
    crsr->sprite->lgop = PG_LGOP_NONE;
  
  if (redisplay)
    VID(sprite_show)(crsr->sprite);
  
  /* Whether it was onscreen or not, show it at the next convenient opportunity */
  crsr->sprite->visible = 1;

  return success;
}