示例#1
0
文件: glw_bar.c 项目: Cy-4AH/showtime
static void
glw_bar_layout(glw_t *w, const glw_rctx_t *rc)
{
  glw_bar_t *gb = (void *)w;
  float r, g, b, x;

  if(w->glw_alpha < GLW_ALPHA_EPSILON)
    return;

  if(!glw_renderer_initialized(&gb->gb_gr)) {
    glw_renderer_init_quad(&gb->gb_gr);
    gb->gb_update = 1;
  }

  if(gb->gb_update) {
    gb->gb_update = 0;

    r = GLW_LERP(gb->gb_fill, gb->gb_col1[0], gb->gb_col2[0]);
    g = GLW_LERP(gb->gb_fill, gb->gb_col1[1], gb->gb_col2[1]);
    b = GLW_LERP(gb->gb_fill, gb->gb_col1[2], gb->gb_col2[2]);
    x = GLW_LERP(gb->gb_fill, -1, 1);

    glw_renderer_vtx_pos(&gb->gb_gr, 0, -1.0, -1.0, 0.0);
    glw_renderer_vtx_col(&gb->gb_gr, 0,
			 gb->gb_col1[0],
			 gb->gb_col1[1],
			 gb->gb_col1[2],
			 1.0);

    glw_renderer_vtx_pos(&gb->gb_gr, 1,  x, -1.0, 0.0);
    glw_renderer_vtx_col(&gb->gb_gr, 1, r, g, b, 1.0);


    glw_renderer_vtx_pos(&gb->gb_gr, 2,  x,  1.0, 0.0);
    glw_renderer_vtx_col(&gb->gb_gr, 2, r, g, b, 1.0);


    glw_renderer_vtx_pos(&gb->gb_gr, 3, -1.0,  1.0, 0.0);
    glw_renderer_vtx_col(&gb->gb_gr, 3,
			 gb->gb_col1[0],
			 gb->gb_col1[1],
			 gb->gb_col1[2],
			 1.0);

    glw_need_refresh(w->glw_root, 0);
  }
}
示例#2
0
static void
glw_throbber3d_render(glw_t *w, const glw_rctx_t *rc)
{
  glw_throbber3d_t *gt = (glw_throbber3d_t *)w;
  glw_rctx_t rc0, rc1;
  int i;
  glw_root_t *gr = w->glw_root;
  float a0 = w->glw_alpha * rc->rc_alpha;
  if(a0 < 0.01)
    return;

  if(!glw_renderer_initialized(&gt->renderer)) {
    glw_renderer_init(&gt->renderer, 16, 12, surfaces);

    for(i = 0; i < 16; i++) {
      glw_renderer_vtx_pos(&gt->renderer, i, pinvtx(i & 7));
      if(i < 8)
	glw_renderer_vtx_col(&gt->renderer, i, 1,1,1,1);
      else
	glw_renderer_vtx_col(&gt->renderer, i, 0.25, 0.25, 0.25, 1);
    }
  }

  rc0 = *rc;
  glw_scale_to_aspect(&rc0, 1.0);

  glw_blendmode(gr, GLW_BLEND_ADDITIVE);

#define NUMPINS 15

  for(i = 1; i < NUMPINS; i++) {
    
    float alpha = (1 - ((float)i / NUMPINS)) * rc->rc_alpha * w->glw_alpha;

    rc1 = rc0;
    glw_Rotatef(&rc1, 0.1 * gt->angle - i * ((360 / NUMPINS) / 3), 0, 1, 0);
    glw_Rotatef(&rc1,       gt->angle - i *  (360 / NUMPINS),      0, 0, 1);

    glw_renderer_draw(&gt->renderer, gr, &rc1, 
		      NULL, NULL, NULL, alpha, 0, NULL);
  }
  glw_blendmode(gr, GLW_BLEND_NORMAL);
}
示例#3
0
文件: glw_image.c 项目: Hr-/showtime
static void
glw_image_layout_alpha_edges(glw_root_t *gr, glw_rctx_t *rc, glw_image_t *gi, 
			       glw_loadable_texture_t *glt)
{
  float tex[4][2];
  float vex[4][2];

  int x, y, i = 0;

  if(gr->gr_normalized_texture_coords) {
    tex[0][0] = 0.0f;
    tex[1][0] = 0.0f + (float)gi->gi_alpha_edge / glt->glt_xs;
    tex[2][0] = glt->glt_s - (float)gi->gi_alpha_edge / glt->glt_xs;
    tex[3][0] = glt->glt_s;

    tex[0][1] = 0.0f;
    tex[1][1] = 0.0f + (float)gi->gi_alpha_edge / glt->glt_ys;
    tex[2][1] = glt->glt_t - (float)gi->gi_alpha_edge / glt->glt_ys;
    tex[3][1] = glt->glt_t;
  } else {
    tex[0][0] = 0.0f;
    tex[1][0] = gi->gi_alpha_edge;
    tex[2][0] = glt->glt_xs - gi->gi_alpha_edge;
    tex[3][0] = glt->glt_xs;

    tex[0][1] = 0.0f;
    tex[1][1] = gi->gi_alpha_edge;
    tex[2][1] = glt->glt_ys - gi->gi_alpha_edge;
    tex[3][1] = glt->glt_ys;
  }

  vex[0][0] = -1.0f;
  vex[1][0] = GLW_MIN(-1.0f + 2.0f * gi->gi_alpha_edge / rc->rc_width, 0.0f);
  vex[2][0] = GLW_MAX( 1.0f - 2.0f * gi->gi_alpha_edge / rc->rc_width, 0.0f);
  vex[3][0] = 1.0f;
    
  vex[0][1] = 1.0f;
  vex[1][1] = GLW_MAX( 1.0f - 2.0f * gi->gi_alpha_edge / rc->rc_height, 0.0f);
  vex[2][1] = GLW_MIN(-1.0f + 2.0f * gi->gi_alpha_edge / rc->rc_height, 0.0f);
  vex[3][1] = -1.0f;

  for(y = 0; y < 4; y++) {
    for(x = 0; x < 4; x++) {
      glw_renderer_vtx_pos(&gi->gi_gr, i, vex[x][0], vex[y][1], 0.0f);
      glw_renderer_vtx_st (&gi->gi_gr, i, tex[x][0], tex[y][1]);
      glw_renderer_vtx_col(&gi->gi_gr, i, 1, 1, 1, alphaborder[x][y]);
      i++;
    }
  }
}
示例#4
0
static void
glw_text_bitmap_layout(glw_t *w, const glw_rctx_t *rc)
{
  glw_text_bitmap_t *gtb = (void *)w;
  glw_root_t *gr = w->glw_root;

  gr->gr_can_externalize = 0;

  // Initialize renderers

  if(unlikely(!glw_renderer_initialized(&gtb->gtb_text_renderer)))
    glw_renderer_init_quad(&gtb->gtb_text_renderer);

  if(w->glw_class == &glw_text &&
     unlikely(!glw_renderer_initialized(&gtb->gtb_cursor_renderer)))
    glw_renderer_init_quad(&gtb->gtb_cursor_renderer);

  if(gtb->gtb_background_alpha > GLW_ALPHA_EPSILON &&
     unlikely(!glw_renderer_initialized(&gtb->gtb_cursor_renderer))) {
    glw_renderer_init_quad(&gtb->gtb_background_renderer);
    glw_renderer_vtx_pos(&gtb->gtb_background_renderer, 0, -1, -1, 0);
    glw_renderer_vtx_pos(&gtb->gtb_background_renderer, 1,  1, -1, 0);
    glw_renderer_vtx_pos(&gtb->gtb_background_renderer, 2,  1,  1, 0);
    glw_renderer_vtx_pos(&gtb->gtb_background_renderer, 3, -1,  1, 0);
  }

  // Upload texture

  image_component_t *ic = image_find_component(gtb->gtb_image, IMAGE_PIXMAP);
  if(ic != NULL) {
    glw_tex_upload(gr, &gtb->gtb_texture, ic->pm, 0);
    gtb->gtb_margin = ic->pm->pm_margin;
    image_clear_component(ic);
    gtb->gtb_need_layout = 1;
  }

  const int tex_width  = glw_tex_width(&gtb->gtb_texture);
  const int tex_height = glw_tex_height(&gtb->gtb_texture);

  ic = image_find_component(gtb->gtb_image, IMAGE_TEXT_INFO);
  image_component_text_info_t *ti = ic ? &ic->text_info : NULL;

  // Check if we need to repaint

  if(gtb->gtb_saved_width  != rc->rc_width ||
     gtb->gtb_saved_height != rc->rc_height) {

    if(ti != NULL && gtb->gtb_state == GTB_VALID) {

      if(ti->ti_flags & IMAGE_TEXT_WRAPPED)
	gtb->gtb_state = GTB_NEED_RENDER;

      if(rc->rc_width > gtb->gtb_saved_width &&
	 ti->ti_flags & IMAGE_TEXT_TRUNCATED)
	gtb->gtb_state = GTB_NEED_RENDER;

      if(gtb->gtb_flags & GTB_ELLIPSIZE) {

	if(ti->ti_flags & IMAGE_TEXT_TRUNCATED) {
	  gtb->gtb_state = GTB_NEED_RENDER;
	} else {

	  if(rc->rc_width - gtb->gtb_padding[2] - gtb->gtb_padding[0] <
	     tex_width - gtb->gtb_margin * 2)
	    gtb->gtb_state = GTB_NEED_RENDER;

	  if(rc->rc_height - gtb->gtb_padding[1] - gtb->gtb_padding[3] <
	     tex_height - gtb->gtb_margin * 2)
	    gtb->gtb_state = GTB_NEED_RENDER;
	}
      }
    }

    gtb->gtb_saved_width  = rc->rc_width;
    gtb->gtb_saved_height = rc->rc_height;
    gtb->gtb_update_cursor = 1;
    gtb->gtb_need_layout = 1;

    if(gtb->w.glw_flags2 & GLW2_DEBUG)
      printf("  textbitmap: Parent widget gives us :%d x %d ti=%p\n",
             rc->rc_width, rc->rc_height, ti);

  }

  if(ti != NULL && gtb->gtb_need_layout) {

    const int margin = gtb->gtb_margin;

    int left   =                 gtb->gtb_padding[0] - margin;
    int top    = rc->rc_height - gtb->gtb_padding[1] + margin;
    int right  = rc->rc_width  - gtb->gtb_padding[2] + margin;
    int bottom =                 gtb->gtb_padding[3] - margin;

    int text_width  = tex_width;
    int text_height = tex_height;

    float x1, y1, x2, y2;

    if(gtb->w.glw_flags2 & GLW2_DEBUG)
      printf("  textbitmap: text_width:%d left:%d right:%d margin:%d\n",
             text_width, left, right, margin);

    // Vertical
    if(text_height > top - bottom) {
      // Oversized, must cut
      text_height = top - bottom;
    } else {
      switch(w->glw_alignment) {
      case LAYOUT_ALIGN_CENTER:
      case LAYOUT_ALIGN_LEFT:
      case LAYOUT_ALIGN_RIGHT:
	bottom = (bottom + top - text_height) / 2;
	top = bottom + text_height;
	break;

      case LAYOUT_ALIGN_TOP_LEFT:
      case LAYOUT_ALIGN_TOP_RIGHT:
      case LAYOUT_ALIGN_TOP:
      case LAYOUT_ALIGN_JUSTIFIED:
	bottom = top - tex_height;
	break;

      case LAYOUT_ALIGN_BOTTOM:
      case LAYOUT_ALIGN_BOTTOM_LEFT:
      case LAYOUT_ALIGN_BOTTOM_RIGHT:
	top = bottom + tex_height;
	break;
      }
    }

    y1 = -1.0f + 2.0f * bottom / (float)rc->rc_height;
    y2 = -1.0f + 2.0f * top    / (float)rc->rc_height;



    // Horizontal
    if(text_width > right - left || ti->ti_flags & IMAGE_TEXT_TRUNCATED) {

      // Oversized, must cut

      text_width = right - left;

      if(gtb->w.glw_flags2 & GLW2_DEBUG)
        printf("  textbitmap: Oversized, must cut. Width is now %d\n",
               text_width);
#if 0
      if(!(gtb->gtb_flags & GTB_ELLIPSIZE)) {
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 0, 1,1,1,1+text_width/20);
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 1, 1,1,1,0);
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 2, 1,1,1,0);
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 3, 1,1,1,1+text_width/20);
      }
#endif
    } else {

      glw_renderer_vtx_col_reset(&gtb->gtb_text_renderer);

      switch(w->glw_alignment) {
      case LAYOUT_ALIGN_JUSTIFIED:
      case LAYOUT_ALIGN_CENTER:
      case LAYOUT_ALIGN_BOTTOM:
      case LAYOUT_ALIGN_TOP:
	left = (left + right - text_width) / 2;
	right = left + text_width;
	break;

      case LAYOUT_ALIGN_LEFT:
      case LAYOUT_ALIGN_TOP_LEFT:
      case LAYOUT_ALIGN_BOTTOM_LEFT:
	right = left + tex_width;
	break;

      case LAYOUT_ALIGN_RIGHT:
      case LAYOUT_ALIGN_TOP_RIGHT:
      case LAYOUT_ALIGN_BOTTOM_RIGHT:
	left = right - tex_width;
	break;
      }
    }


    x1 = -1.0f + 2.0f * left   / (float)rc->rc_width;
    x2 = -1.0f + 2.0f * right  / (float)rc->rc_width;


    const float s = text_width  / (float)tex_width;
    const float t = text_height / (float)tex_height;

    if(gtb->w.glw_flags2 & GLW2_DEBUG)
      printf("  s=%f t=%f\n", s, t);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 0, x1, y1, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 0, 0, t);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 1, x2, y1, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 1, s, t);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 2, x2, y2, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 2, s, 0);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 3, x1, y2, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 3, 0, 0);
  }

  if(w->glw_class == &glw_text && gtb->gtb_update_cursor &&
     gtb->gtb_state == GTB_VALID) {

    int i = gtb->gtb_edit_ptr;
    int left;
    float x1, y1, x2, y2;

    if(ti != NULL && ti->ti_charpos != NULL) {

      if(i < ti->ti_charposlen) {
	left  = ti->ti_charpos[i*2  ];
      } else {
	left  = ti->ti_charpos[2 * ti->ti_charposlen - 1];
      }

    } else {

      left = 0;
    }

    left  += gtb->gtb_padding[0];

    x1 = -1.0f + 2.0f * (left - 1)  / (float)rc->rc_width;
    x2 = -1.0f + 2.0f * (left    )  / (float)rc->rc_width;
    y1 = -1.0f + 2.0f * gtb->gtb_padding[3] / (float)rc->rc_height;
    y2 =  1.0f - 2.0f * gtb->gtb_padding[1] / (float)rc->rc_height;

    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 0, x1, y1, 0.0);
    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 1, x2, y1, 0.0);
    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 2, x2, y2, 0.0);
    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 3, x1, y2, 0.0);

    if(w->glw_flags2 & GLW2_DEBUG) {
      printf("Cursor updated %f %f %f %f  rect:%d,%d\n",
             x1, y1, x2, y2, rc->rc_width, rc->rc_height);
    }

    gtb->gtb_update_cursor = 0;
  }

  gtb->gtb_paint_cursor =
    gtb->gtb_flags & GTB_PERMANENT_CURSOR ||
    (w->glw_class == &glw_text && glw_is_focused(w));

  if(gtb->gtb_paint_cursor && rc->rc_alpha > GLW_ALPHA_EPSILON)
    glw_need_refresh(gr, 0);

  gtb->gtb_need_layout = 0;

  if(gtb->gtb_state == GTB_VALID && gtb->gtb_deferred_realize) {
    gtb->gtb_deferred_realize = 0;
    gtb_realize(gtb);
  }

  if(gtb->gtb_state != GTB_NEED_RENDER)
    return;

  TAILQ_INSERT_TAIL(&gr->gr_gtb_render_queue, gtb, gtb_workq_link);
  gtb->gtb_state = GTB_QUEUED_FOR_RENDERING;

  hts_cond_signal(&gr->gr_gtb_work_cond);
}
示例#5
0
static void
glw_text_bitmap_layout(glw_t *w, glw_rctx_t *rc)
{
  glw_text_bitmap_t *gtb = (void *)w;
  glw_root_t *gr = w->glw_root;
  pixmap_t *pm = gtb->gtb_pixmap;

  // Initialize renderers

  if(!glw_renderer_initialized(&gtb->gtb_text_renderer))
    glw_renderer_init_quad(&gtb->gtb_text_renderer);

  if(w->glw_class == &glw_text &&
     !glw_renderer_initialized(&gtb->gtb_cursor_renderer))
    glw_renderer_init_quad(&gtb->gtb_cursor_renderer);


  // Upload texture

  if(pm != NULL && pm->pm_pixels != NULL) {
    int fmt;

    fmt = pm->pm_type == PIXMAP_IA ? GLW_TEXTURE_FORMAT_I8A8 : GLW_TEXTURE_FORMAT_BGR32;

    glw_tex_upload(gr, &gtb->gtb_texture, pm->pm_pixels,
		   fmt, pm->pm_width, pm->pm_height, 0);

    free(pm->pm_pixels);
    pm->pm_pixels = NULL;
    gtb->gtb_need_layout = 1;
  }

  // Check if we need to repaint

  if((gtb->gtb_saved_width  != rc->rc_width || 
      gtb->gtb_saved_height != rc->rc_height)) {

    if(pm != NULL && gtb->gtb_state == GTB_VALID) {
      if(pm->pm_flags & PIXMAP_TEXT_WRAPPED)
	gtb->gtb_state = GTB_NEED_RENDER;

      if(rc->rc_width > gtb->gtb_saved_width && 
	 pm->pm_flags & PIXMAP_TEXT_TRUNCATED)
	gtb->gtb_state = GTB_NEED_RENDER;

      if(gtb->gtb_flags & GTB_ELLIPSIZE) {
	
	if(pm->pm_flags & PIXMAP_TEXT_TRUNCATED) {
	  gtb->gtb_state = GTB_NEED_RENDER;
	} else {

	  if(rc->rc_width - gtb->gtb_padding_right - gtb->gtb_padding_left <
	     pm->pm_width - pm->pm_margin * 2)
	    gtb->gtb_state = GTB_NEED_RENDER;

	  if(rc->rc_height - gtb->gtb_padding_top - gtb->gtb_padding_bottom <
	     pm->pm_height - pm->pm_margin * 2)
	    gtb->gtb_state = GTB_NEED_RENDER;
	}
      }
    }

    gtb->gtb_saved_width  = rc->rc_width;
    gtb->gtb_saved_height = rc->rc_height;
    gtb->gtb_need_layout = 1;

    if(gtb->w.glw_flags & GLW_DEBUG)
      printf("   parent widget gives us :%d x %d\n", rc->rc_width, rc->rc_height);

  }

  if(pm != NULL && gtb->gtb_need_layout) {

    int left   =                 gtb->gtb_padding_left   - pm->pm_margin;
    int top    = rc->rc_height - gtb->gtb_padding_top    + pm->pm_margin;
    int right  = rc->rc_width  - gtb->gtb_padding_right  + pm->pm_margin;
    int bottom =                 gtb->gtb_padding_bottom - pm->pm_margin;
    
    int text_width  = pm->pm_width;
    int text_height = pm->pm_height;
    
    float x1, y1, x2, y2;

    // Horizontal 
    if(text_width > right - left) {
      // Oversized, must cut
      text_width = right - left;

      if(!(gtb->gtb_flags & GTB_ELLIPSIZE)) {
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 0, 1,1,1,1+text_width/20);
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 1, 1,1,1,0);
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 2, 1,1,1,0);
	glw_renderer_vtx_col(&gtb->gtb_text_renderer, 3, 1,1,1,1+text_width/20);
      }

    } else { 

      glw_renderer_vtx_col(&gtb->gtb_text_renderer, 0, 1,1,1,1);
      glw_renderer_vtx_col(&gtb->gtb_text_renderer, 1, 1,1,1,1);
      glw_renderer_vtx_col(&gtb->gtb_text_renderer, 2, 1,1,1,1);
      glw_renderer_vtx_col(&gtb->gtb_text_renderer, 3, 1,1,1,1);

      switch(w->glw_alignment) {
      case LAYOUT_ALIGN_JUSTIFIED:
      case LAYOUT_ALIGN_CENTER:
      case LAYOUT_ALIGN_BOTTOM:
      case LAYOUT_ALIGN_TOP:
	left = (left + right - text_width) / 2;
	right = left + text_width;
	break;

      case LAYOUT_ALIGN_LEFT:
      case LAYOUT_ALIGN_TOP_LEFT:
      case LAYOUT_ALIGN_BOTTOM_LEFT:
	right = left + pm->pm_width;
	break;

      case LAYOUT_ALIGN_RIGHT:
      case LAYOUT_ALIGN_TOP_RIGHT:
      case LAYOUT_ALIGN_BOTTOM_RIGHT:
	left = right - pm->pm_width;
	break;
      }
    }

    // Vertical 
    if(text_height > top - bottom) {
      // Oversized, must cut
      text_height = top - bottom;
    } else { 
      switch(w->glw_alignment) {
      case LAYOUT_ALIGN_CENTER:
      case LAYOUT_ALIGN_LEFT:
      case LAYOUT_ALIGN_RIGHT:
	bottom = (bottom + top - text_height) / 2;
	top = bottom + text_height;
	break;

      case LAYOUT_ALIGN_TOP_LEFT:
      case LAYOUT_ALIGN_TOP_RIGHT:
      case LAYOUT_ALIGN_TOP:
      case LAYOUT_ALIGN_JUSTIFIED:
	bottom = top - pm->pm_height;
	break;

      case LAYOUT_ALIGN_BOTTOM:
      case LAYOUT_ALIGN_BOTTOM_LEFT:
      case LAYOUT_ALIGN_BOTTOM_RIGHT:
	top = bottom + pm->pm_height;
	break;
      }
    }

    x1 = -1.0f + 2.0f * left   / (float)rc->rc_width;
    y1 = -1.0f + 2.0f * bottom / (float)rc->rc_height;
    x2 = -1.0f + 2.0f * right  / (float)rc->rc_width;
    y2 = -1.0f + 2.0f * top    / (float)rc->rc_height;

    float s, t;

    if(gr->gr_normalized_texture_coords) {
      s = text_width  / (float)pm->pm_width;
      t = text_height / (float)pm->pm_height;
    } else {
      s = text_width;
      t = text_height;
    }

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 0, x1, y1, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 0, 0, t);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 1, x2, y1, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 1, s, t);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 2, x2, y2, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 2, s, 0);

    glw_renderer_vtx_pos(&gtb->gtb_text_renderer, 3, x1, y2, 0.0);
    glw_renderer_vtx_st (&gtb->gtb_text_renderer, 3, 0, 0);
  }
  
  if(w->glw_class == &glw_text && gtb->gtb_update_cursor && 
     gtb->gtb_state == GTB_VALID) {

    int i = gtb->gtb_edit_ptr;
    int left, right;
    float x1, y1, x2, y2;

    if(pm != NULL && pm->pm_charpos != NULL) {
	
      if(i < pm->pm_charposlen) {
	left  = pm->pm_charpos[i*2  ];
	right = pm->pm_charpos[i*2+1];
      } else {
	left  = pm->pm_charpos[2*pm->pm_charposlen - 1];
	right = left + 10;
      }

      left  += gtb->gtb_padding_left;
      right += gtb->gtb_padding_left;

    } else {

      left = 0;
      right = 10;
    }

    x1 = -1.0f + 2.0f * left   / (float)rc->rc_width;
    x2 = -1.0f + 2.0f * right  / (float)rc->rc_width;
    y1 = -0.9f;
    y2 =  0.9f;

    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 0, x1, y1, 0.0);
    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 1, x2, y1, 0.0);
    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 2, x2, y2, 0.0);
    glw_renderer_vtx_pos(&gtb->gtb_cursor_renderer, 3, x1, y2, 0.0);

    gtb->gtb_update_cursor = 0;
  }

  gtb->gtb_paint_cursor = w->glw_class == &glw_text && glw_is_focused(w);
  gtb->gtb_need_layout = 0;

  if(gtb->gtb_state == GTB_VALID && gtb->gtb_deferred_realize) {
    gtb->gtb_deferred_realize = 0;
    gtb_realize(gtb);
  }

  if(gtb->gtb_state != GTB_NEED_RENDER)
    return;

  TAILQ_INSERT_TAIL(&gr->gr_gtb_render_queue, gtb, gtb_workq_link);
  gtb->gtb_state = GTB_QUEUED_FOR_RENDERING;
  
  hts_cond_signal(&gr->gr_gtb_work_cond);
}