~alextee/zrythm

544699ed5f06288195ce01244388cfe7c4ae0841 — Alexandros Theodotou 3 years ago d471379 cairo_optimizations
optimize cairo drawing (use ints)
M inc/utils/cairo.h => inc/utils/cairo.h +110 -40
@@ 64,50 64,39 @@ typedef struct CairoCaches
void
z_cairo_draw_selection (
  cairo_t * cr,
  double    start_x,
  double    start_y,
  double    offset_x,
  double    offset_y);
  int       start_x,
  int       start_y,
  int       offset_x,
  int       offset_y);

void
z_cairo_draw_horizontal_line (
  cairo_t * cr,
  double    y,
  double    from_x,
  double    to_x,
  int       y,
  int       from_x,
  int       to_x,
  double    alpha);

void
z_cairo_draw_vertical_line (
  cairo_t * cr,
  double    x,
  double    from_y,
  double    to_y);
  int       x,
  int       from_y,
  int       to_y);

/**
 * @param aspect Aspect ratio.
 * @param corner_radius Corner curvature radius.
 */
static inline void
void
z_cairo_rounded_rectangle (
  cairo_t * cr,
  double    x,
  double    y,
  double    width,
  double    height,
  int       x,
  int       y,
  int       width,
  int       height,
  double    aspect,
  double    corner_radius)
{
  double radius = corner_radius / aspect;
  double degrees = G_PI / 180.0;

  cairo_new_sub_path (cr);
  cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
  cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
  cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
  cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
  cairo_close_path (cr);
}
  double    corner_radius);

#define z_cairo_get_text_extents_for_widget( \
  _widget,_layout,_text,_width,_height) \


@@ 157,21 146,13 @@ z_cairo_draw_text_full (
/**
 * Draws a diamond shape.
 */
static inline void
void
z_cairo_diamond (
  cairo_t * cr,
  double    x,
  double    y,
  double    width,
  double    height)
{
  cairo_move_to (cr, x, height / 2);
  cairo_line_to (cr, width / 2, y);
  cairo_line_to (cr, width, height / 2);
  cairo_line_to (cr, width / 2, height);
  cairo_line_to (cr, x, height / 2);
  cairo_close_path (cr);
}
  int       x,
  int       y,
  int       width,
  int       height);

/**
 * Returns a surface for the icon name.


@@ 227,6 208,95 @@ z_cairo_reset_caches (
  int                height,
  cairo_t *          new_cr);

/**
 * Wrapper using integers to prevent extra
 * calculations in cairo. According to GTK devs,
 * cairo will attempt to draw details when drawing
 * non-integer coordinates.
 */
static inline void
z_cairo_move_to (
  cairo_t * cr,
  int       x,
  int       y)
{
  cairo_move_to (cr, (double) x, (double) y);
}

static inline void
z_cairo_line_to (
  cairo_t * cr,
  int       x,
  int       y)
{
  cairo_line_to (cr, (double) x, (double) y);
}

static inline void
z_cairo_rel_line_to (
  cairo_t * cr,
  int       x,
  int       y)
{
  cairo_rel_line_to (cr, (double) x, (double) y);
}

static inline void
z_cairo_rectangle (
  cairo_t * cr,
  int       x,
  int       y,
  int       width,
  int       height)
{
  cairo_rectangle (
    cr, (double) x, (double) y,
    (double) width, (double) height);
}

static inline void
z_cairo_arc (
  cairo_t * cr,
  int       xc,
  int       yc,
  int       radius,
  int       angle1,
  int       angle2)
{
  cairo_arc (
    cr, (double) xc, (double) yc,
    (double) radius, (double) angle1,
    (double) angle2);
}

static inline void
z_cairo_translate (
  cairo_t * cr,
  int       x,
  int       y)
{
  cairo_translate (cr, (double) x, (double) y);
}

static inline void
z_cairo_set_source_surface (
  cairo_t *         cr,
  cairo_surface_t * surface,
  int               x,
  int               y)
{
  cairo_set_source_surface (
    cr, surface, (double) x, (double) y);
}

static inline void
z_cairo_set_line_width (
  cairo_t * cr,
  int       width)
{
  cairo_set_line_width (cr, (double) width);
}

CairoCaches *
z_cairo_caches_new (void);


M src/gui/widgets/arranger.c => src/gui/widgets/arranger.c +3 -3
@@ 126,9 126,9 @@ draw_selections (
    case UI_OVERLAY_ACTION_SELECTING:
    case UI_OVERLAY_ACTION_DELETE_SELECTING:
      z_cairo_draw_selection (
        cr, self->start_x - rect->x,
        self->start_y - rect->y,
        offset_x, offset_y);
        cr, (int) (self->start_x - rect->x),
        (int) (self->start_y - rect->y),
        (int) offset_x, (int) offset_y);
      break;
    case UI_OVERLAY_ACTION_RAMPING:
      cairo_set_source_rgba (

M src/gui/widgets/automation_mode.c => src/gui/widgets/automation_mode.c +16 -11
@@ 184,8 184,10 @@ draw_bg (
        cr, 1, 1, 1, 0.4);
      cairo_set_line_width (cr, 0.5);
      z_cairo_rounded_rectangle (
        cr, x, y, self->width, self->height,
        self->aspect, self->corner_radius);
        cr, (int) x, (int) y,
        (int) self->width, (int) self->height,
        (int) self->aspect,
        (int) self->corner_radius);
      cairo_stroke (cr);
    }



@@ 253,13 255,16 @@ draw_bg (
      if (rounded)
        {
          z_cairo_rounded_rectangle (
            cr, new_x, y, new_width, self->height,
            self->aspect, self->corner_radius);
            cr, (int) new_x, (int) y,
            (int) new_width, (int) self->height,
            (int) self->aspect,
            (int) self->corner_radius);
        }
      else
        {
          cairo_rectangle (
            cr, new_x, y, new_width, self->height);
          z_cairo_rectangle (
            cr, (int) new_x, (int) y,
            (int) new_width, (int) self->height);
        }
      cairo_fill (cr);
    }


@@ 325,13 330,13 @@ automation_mode_widget_draw (
      PangoLayout * layout = self->layout;
      cairo_set_source_rgba (
        cr, 1, 1, 1, 1);
      cairo_move_to (
      z_cairo_move_to (
        cr,
        x + AUTOMATION_MODE_HPADDING +
        (int) (x + AUTOMATION_MODE_HPADDING +
          i * (2 * AUTOMATION_MODE_HPADDING) +
          total_text_widths,
        (y + self->height / 2) -
          self->text_heights[i] / 2);
          total_text_widths),
        (int) ((y + self->height / 2) -
          self->text_heights[i] / 2));
      char mode_str[400];
      if (i == AUTOMATION_MODE_RECORD)
        {

M src/gui/widgets/custom_button.c => src/gui/widgets/custom_button.c +12 -8
@@ 111,10 111,12 @@ draw_bg (
    {
      cairo_set_source_rgba (
        cr, 1, 1, 1, 0.4);
      cairo_set_line_width (cr, 0.5);
      cairo_set_line_width (cr, 1);
      z_cairo_rounded_rectangle (
        cr, x, y, self->size, self->size,
        self->aspect, self->corner_radius);
        cr, (int) x, (int) y,
        (int) self->size, (int) self->size,
        (int) self->aspect,
        (int) self->corner_radius);
      cairo_stroke (cr);
    }



@@ 143,8 145,9 @@ draw_bg (
  self->last_color = c;

  z_cairo_rounded_rectangle (
    cr, x, y, width, self->size, self->aspect,
    self->corner_radius);
    cr, (int) x, (int) y, (int) width,
    (int) self->size, (int) self->aspect,
    (int) self->corner_radius);
  cairo_fill (cr);
}



@@ 205,9 208,10 @@ custom_button_widget_draw_with_text (
  /* draw text */
  cairo_set_source_rgba (
    cr, 1, 1, 1, 1);
  cairo_move_to (
    cr, x + self->size + 2,
    (y + self->size / 2) - self->text_height / 2);
  z_cairo_move_to (
    cr, (int) (x + self->size + 2),
    (int)
    ((y + self->size / 2) - self->text_height / 2));
  PangoLayout * layout = self->layout;
  pango_layout_set_text (
    layout, self->text, -1);

M src/gui/widgets/midi_note.c => src/gui/widgets/midi_note.c +18 -15
@@ 109,9 109,10 @@ draw_midi_note_bg (
    }

  z_cairo_rounded_rectangle (
    cr, draw_x, full_rect->y - arr_rect->y,
    draw_width, full_rect->height, 1.0,
    full_rect->height / 8.0f);
    cr, (int) draw_x,
    (int) (full_rect->y - arr_rect->y),
    (int) draw_width, (int) full_rect->height, 1,
    (int) (full_rect->height / 8.0f));
  /*cairo_rectangle (*/
    /*cr, draw_x, full_rect->y - rect->y,*/
    /*draw_width, full_rect->height);*/


@@ 202,10 203,10 @@ midi_note_draw (
      if (PIANO_ROLL->drum_mode)
        {
          z_cairo_diamond (
            cr, draw_rect.x - arr_rect->x,
            draw_rect.y - arr_rect->y,
            draw_rect.width,
            draw_rect.height);
            cr, (int) (draw_rect.x - arr_rect->x),
            (int) (draw_rect.y - arr_rect->y),
            (int) draw_rect.width,
            (int) draw_rect.height);
        }
      else
        {


@@ 232,9 233,10 @@ midi_note_draw (
      if (PIANO_ROLL->drum_mode)
        {
          z_cairo_diamond (
            cr, draw_rect.x - arr_rect->x,
            draw_rect.y - arr_rect->y,
            draw_rect.width, draw_rect.height);
            cr, (int) (draw_rect.x - arr_rect->x),
            (int) (draw_rect.y - arr_rect->y),
            (int) draw_rect.width,
            (int) draw_rect.height);
        }
      else
        {


@@ 275,12 277,13 @@ midi_note_draw (
      recreate_pango_layouts (
        self,
        MIN (full_rect.width, 400));
      cairo_move_to (
      z_cairo_move_to (
        cr,
        REGION_NAME_BOX_PADDING +
          (full_rect.x - arr_rect->x),
        fontsize_ratio * REGION_NAME_BOX_PADDING +
          (full_rect.y - arr_rect->y));
        (int) (REGION_NAME_BOX_PADDING +
          (full_rect.x - arr_rect->x)),
        (int)
        (fontsize_ratio * REGION_NAME_BOX_PADDING +
          (full_rect.y - arr_rect->y)));
      PangoLayout * layout = self->layout;
      z_cairo_draw_text (
        cr,

M src/gui/widgets/region.c => src/gui/widgets/region.c +84 -76
@@ 169,10 169,11 @@ draw_background (
    }

  z_cairo_rounded_rectangle (
    cr, vis_offset_x - added_x_pre_padding, 0,
    vis_width + added_x_pre_padding +
      added_x_post_padding,
    full_height, 1.0, 4.0);
    cr, (int) (vis_offset_x - added_x_pre_padding),
    0,
    (int) (vis_width + added_x_pre_padding +
      added_x_post_padding),
    (int) full_height, 1, 4);

  /* clip this path so all drawing afterwards will
   * be confined inside it. preserve so we can


@@ 239,7 240,7 @@ draw_loop_points (
  double dashes[] = { 5 };
  cairo_set_dash (
    cr, dashes, 1, 0);
  cairo_set_line_width (cr, 1);
  z_cairo_set_line_width (cr, 1);

  ArrangerObject * obj =
    (ArrangerObject *) self;


@@ 283,10 284,10 @@ draw_loop_points (
    {
      gdk_cairo_set_source_rgba (
        cr, &UI_COLORS->bright_green);
      cairo_move_to (
        cr, x_px, 0);
      cairo_line_to (
        cr, x_px, full_height);
      z_cairo_move_to (
        cr, (int) x_px, 0);
      z_cairo_line_to (
        cr, (int) x_px, (int) full_height);
      cairo_stroke (cr);
    }



@@ 313,10 314,10 @@ draw_loop_points (
        {
          cairo_set_source_rgba (
            cr, 0, 0, 0, 1.0);
          cairo_move_to (
            cr, x_px, 0);
          cairo_line_to (
            cr, x_px, full_height);
          z_cairo_move_to (
            cr, (int) x_px, 0);
          z_cairo_line_to (
            cr, (int) x_px, (int) full_height);
          cairo_stroke (cr);
        }
    }


@@ 487,12 488,12 @@ draw_midi_region (
                          (draw_y - y_start),
                      (vis_offset_y + vis_height) -
                        draw_y);
                  cairo_rectangle (
                  z_cairo_rectangle (
                    cr,
                    draw_x,
                    draw_y,
                    draw_width,
                    draw_height);
                    (int) draw_x,
                    (int) draw_y,
                    (int) draw_width,
                    (int) draw_height);
                  cairo_fill (cr);
                }
            }


@@ 635,9 636,9 @@ draw_chord_region (
              x_end *= (double) full_width;

              /* draw */
              cairo_rectangle (
                cr, x_start, 0,
                12.0, full_height);
              z_cairo_rectangle (
                cr, (int) x_start, 0,
                12, (int) full_height);
              cairo_fill (cr);

              cairo_set_source_rgba (


@@ 797,10 798,10 @@ draw_automation_region (
                  x_start_real < full_width)
                {
                  int padding = 1;
                  cairo_rectangle (
                  z_cairo_rectangle (
                    cr,
                    x_start_real - padding,
                    y_start_real - padding,
                    (int) (x_start_real - padding),
                    (int) (y_start_real - padding),
                    2 * padding,
                    2 * padding);
                  cairo_fill (cr);


@@ 816,8 817,8 @@ draw_automation_region (
                  double ac_width =
                    fabs (x_end - x_start);
                  ac_width *= full_width;
                    cairo_set_line_width (
                      cr, 2.0);
                    z_cairo_set_line_width (
                      cr, 2);
                  for (double k =
                         MAX (x_start_real, 0.0);
                       k < (x_start_real) +


@@ 855,12 856,14 @@ draw_automation_region (
                      if (math_doubles_equal (
                            k, 0.0))
                        {
                          cairo_move_to (
                            cr, new_x, new_y);
                          z_cairo_move_to (
                            cr, (int) new_x,
                            (int) new_y);
                        }

                      cairo_line_to (
                        cr, new_x, new_y);
                      z_cairo_line_to (
                        cr, (int) new_x,
                        (int) new_y);
                    }
                  cairo_stroke (cr);
                }


@@ 890,7 893,7 @@ draw_fades (
  /* set color */
  cairo_set_source_rgba (
    cr, 0.2, 0.2, 0.2, 0.6);
  cairo_set_line_width (cr, 3);
  z_cairo_set_line_width (cr, 3);

  int vis_offset_x =
    draw_rect->x - full_rect->x;


@@ 946,23 949,26 @@ draw_fades (
          /* if start */
          if (i == vis_start_px)
            {
              cairo_move_to (
                cr, i - rect->x, val * full_height);
              z_cairo_move_to (
                cr,
                (int) (i - rect->x),
                (int) (val * full_height));
            }

          cairo_rel_line_to (
          z_cairo_rel_line_to (
            cr, 1,
            (next_val - val) * full_height);
            (int) ((next_val - val) * full_height));

          /* if end */
          if (i == vis_fade_in_px)
            {
              /* paint a gradient in the faded out
               * part */
              cairo_rel_line_to (
                cr, 0, next_val - full_height);
              cairo_rel_line_to (
                cr, - i, 0);
              z_cairo_rel_line_to (
                cr, 0,
                (int) (next_val - full_height));
              z_cairo_rel_line_to (
                cr, (int) (- i), 0);
              cairo_close_path (cr);
              cairo_fill (cr);
            }


@@ 1011,23 1017,24 @@ draw_fades (
          /* if start, move only */
          if (i == visible_fade_out_px)
            {
              cairo_move_to (
                cr, i, val * full_height);
              z_cairo_move_to (
                cr, (int) i,
                (int) (val * full_height));
            }

          cairo_rel_line_to (
          z_cairo_rel_line_to (
            cr, 1,
            (next_val - val) * full_height);
            (int) ((next_val - val) * full_height));

          /* if end, draw */
          if (i == visible_end_px)
            {
              /* paint a gradient in the faded out
               * part */
              cairo_rel_line_to (
                cr, 0, - full_height);
              cairo_rel_line_to (
                cr, - i, 0);
              z_cairo_rel_line_to (
                cr, 0, (int) (- full_height));
              z_cairo_rel_line_to (
                cr, (int) (- i), 0);
              cairo_close_path (cr);
              cairo_fill (cr);
            }


@@ 1040,11 1047,11 @@ draw_fades (
 */
static void
draw_audio_region (
  ZRegion *       self,
  cairo_t *      cr,
  GdkRectangle * rect,
  GdkRectangle * full_rect,
  GdkRectangle * draw_rect,
  ZRegion *         self,
  cairo_t *         cr,
  GdkRectangle *    rect,
  GdkRectangle *    full_rect,
  GdkRectangle *    draw_rect,
  RegionCounterpart counterpart)
{
  /*g_message ("drawing audio region");*/


@@ 1107,8 1114,8 @@ draw_audio_region (
  /*Position tmp;*/
  /*position_from_frames (&tmp, curr_frames);*/
  /*position_print (&tmp);*/
  for (double i = local_start_x + 0.5;
       i < (double) local_end_x; i += 0.5)
  for (double i = local_start_x + 1;
       i < (double) local_end_x; i += 1)
    {
      curr_frames = (long) (multiplier * i);
      /* current single channel frames */


@@ 1148,8 1155,8 @@ draw_audio_region (
            }
        }
#define DRAW_VLINE(cr,x,from_y,to_y) \
  cairo_move_to (cr, x, from_y); \
  cairo_line_to (cr, x, to_y)
  z_cairo_move_to (cr, (int) x, (int) from_y); \
  z_cairo_line_to (cr, (int) x, (int) to_y)

      /* normalize */
      min = (min + 1.f) / 2.f;


@@ 1173,7 1180,7 @@ draw_audio_region (
          DRAW_VLINE (
            cr,
            /* x */
            i - 0.5,
            (int) (i - 0.5),
            /* from y */
            local_min_y,
            /* to y */


@@ 1249,21 1256,22 @@ draw_name (
  double radius = REGION_NAME_BOX_CURVINESS / 1.0;
  double degrees = G_PI / 180.0;
  cairo_new_sub_path (cr);
  cairo_move_to (
  z_cairo_move_to (
    cr,
    (pangorect.width + REGION_NAME_PADDING_R),
    (int) (pangorect.width + REGION_NAME_PADDING_R),
    0);
  int black_box_height =
    pangorect.height + 2 * REGION_NAME_BOX_PADDING;
  cairo_arc (
  z_cairo_arc (
    cr,
    (pangorect.width + REGION_NAME_PADDING_R) -
      radius,
    black_box_height - radius, radius,
    0 * degrees, 90 * degrees);
  cairo_line_to (
    cr, 0, black_box_height);
  cairo_line_to (
    (int)
    ((pangorect.width + REGION_NAME_PADDING_R) -
      radius),
    (int) (black_box_height - radius), (int) radius,
    0 * degrees, (int) (90 * degrees));
  z_cairo_line_to (
    cr, 0, (int) black_box_height);
  z_cairo_line_to (
    cr, 0, 0);
  cairo_close_path (cr);
  cairo_fill (cr);


@@ 1271,10 1279,10 @@ draw_name (
  /* draw text */
  cairo_set_source_rgba (
    cr, 1, 1, 1, 1);
  cairo_move_to (
  z_cairo_move_to (
    cr,
    REGION_NAME_BOX_PADDING,
    REGION_NAME_BOX_PADDING);
    (int) REGION_NAME_BOX_PADDING,
    (int) REGION_NAME_BOX_PADDING);
  pango_cairo_show_layout (cr, layout);
}



@@ 1334,10 1342,10 @@ region_draw (
        obj, rect, &full_rect, &draw_rect);

      /* translate to the full rect */
      cairo_translate (
      z_cairo_translate (
        cr,
        full_rect.x - rect->x,
        full_rect.y - rect->y);
        (int) (full_rect.x - rect->x),
        (int) (full_rect.y - rect->y));

      if (i == REGION_COUNTERPART_MAIN)
        {


@@ 1427,15 1435,15 @@ region_draw (

          int x = draw_rect.x - full_rect.x;
          int y = draw_rect.y - full_rect.y;
          cairo_translate (cr, x, y);
          z_cairo_translate (cr, x, y);
          if (MW_TIMELINE->action ==
                UI_OVERLAY_ACTION_STRETCHING_R)
            {
              cairo_scale (
                cr, self->stretch_ratio, 1);
            }
          cairo_set_source_surface (
            cr, obj->cached_surface[i], 0.0, 0.0);
          z_cairo_set_source_surface (
            cr, obj->cached_surface[i], 0, 0);
          cairo_paint (cr);

          cairo_restore (cr);

M src/gui/widgets/ruler.c => src/gui/widgets/ruler.c +75 -53
@@ 192,9 192,11 @@ draw_regions (
  px_end =
    ui_pos_to_px_editor (
      &region_obj->end_pos, 1);
  cairo_rectangle (
    cr, px_start - rect->x, - rect->y,
    px_end - px_start, height / 4.0);
  z_cairo_rectangle (
    cr, (int) (px_start - rect->x),
    (int) (- rect->y),
    (int) (px_end - px_start),
    (int) (height / 4.0));
  cairo_fill (cr);

  /* draw its transient if copy-moving TODO */


@@ 207,9 209,11 @@ draw_regions (
      px_end =
        ui_pos_to_px_editor (
          &region_obj->end_pos, 1);
      cairo_rectangle (
        cr, px_start - rect->x, - rect->y,
        px_end - px_start, height / 4.0);
      z_cairo_rectangle (
        cr, (int) (px_start - rect->x),
        (int) (- rect->y),
        (int) (px_end - px_start),
        (int) (height / 4.0));
      cairo_fill (cr);
    }



@@ 241,9 245,12 @@ draw_regions (
          px_end =
            ui_pos_to_px_editor (
              &other_region_obj->end_pos, 1);
          cairo_rectangle (
            cr, px_start - rect->x, - rect->y,
            px_end - px_start, height / 4.0);
          z_cairo_rectangle (
            cr,
            (int) (px_start - rect->x),
            (int) (- rect->y),
            (int) (px_end - px_start),
            (int) (height / 4.0));
          cairo_fill (cr);
        }
    }


@@ 307,13 314,17 @@ draw_loop_start (
        rect->x + rect->width)
    {
      cairo_set_source_rgb (cr, 0, 0.9, 0.7);
      cairo_set_line_width (cr, 2);
      cairo_move_to (
        cr, dr.x - rect->x, dr.y);
      cairo_line_to (
        cr, dr.x - rect->x, dr.y + dr.height);
      cairo_line_to (
        cr, (dr.x + dr.width) - rect->x, dr.y);
      z_cairo_set_line_width (cr, 2);
      z_cairo_move_to (
        cr, (int) (dr.x - rect->x),
        (int) (dr.y));
      z_cairo_line_to (
        cr, (int) (dr.x - rect->x),
        (int) (dr.y + dr.height));
      z_cairo_line_to (
        cr,
        (int) ((dr.x + dr.width) - rect->x),
        (int) (dr.y));
      cairo_fill (cr);
    }
}


@@ 379,13 390,16 @@ draw_loop_end (
        rect->x + rect->width)
    {
      cairo_set_source_rgb (cr, 0, 0.9, 0.7);
      cairo_set_line_width (cr, 2);
      cairo_move_to (cr, dr.x - rect->x, dr.y);
      cairo_line_to (
        cr, (dr.x + dr.width) - rect->x, dr.y);
      cairo_line_to (
        cr, (dr.x + dr.width) - rect->x,
        dr.y + dr.height);
      z_cairo_set_line_width (cr, 2);
      z_cairo_move_to (
        cr,
        (int) (dr.x - rect->x), (int) dr.y);
      z_cairo_line_to (
        cr, (int) ((dr.x + dr.width) - rect->x),
        (int) (dr.y));
      z_cairo_line_to (
        cr, (int) ((dr.x + dr.width) - rect->x),
        (int) (dr.y + dr.height));
      cairo_fill (cr);
    }
}


@@ 467,14 481,17 @@ draw_cue_point (
        {
          cairo_set_source_rgb (cr, 0, 0.6, 0.9);
        }
      cairo_set_line_width (cr, 2);
      cairo_move_to (
        cr, dr.x - rect->x, dr.y);
      cairo_line_to (
        cr, (dr.x + dr.width) - rect->x,
        dr.y + dr.height / 2);
      cairo_line_to (
        cr, dr.x - rect->x, dr.y + dr.height);
      z_cairo_set_line_width (cr, 2);
      z_cairo_move_to (
        cr, (int) (dr.x - rect->x), (int) dr.y);
      z_cairo_line_to (
        cr,
        (int) ((dr.x + dr.width) - rect->x),
        (int) (dr.y + dr.height / 2));
      z_cairo_line_to (
        cr,
        (int) (dr.x - rect->x),
        (int) (dr.y + dr.height));
      cairo_fill (cr);
    }
}


@@ 530,12 547,17 @@ draw_playhead (

      cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
      cairo_set_line_width (cr, 2);
      cairo_move_to (cr, dr.x - rect->x, dr.y);
      cairo_line_to (
        cr, (dr.x + dr.width / 2) - rect->x,
        dr.y + dr.height);
      cairo_line_to (
        cr, (dr.x + dr.width) - rect->x, dr.y);
      z_cairo_move_to (
        cr, (int) (dr.x - rect->x),
        (int) dr.y);
      z_cairo_line_to (
        cr,
        (int) ((dr.x + dr.width / 2) - rect->x),
        (int) (dr.y + dr.height));
      z_cairo_line_to (
        cr,
        (int) ((dr.x + dr.width) - rect->x),
        (int) dr.y);
      cairo_fill (cr);
    }
}


@@ 615,7 637,7 @@ ruler_draw_cb (
      else
        cairo_set_source_rgba (
          cr_to_use, 0.5, 0.5, 0.5, 0.25);
      cairo_set_line_width (cr_to_use, 2);
      z_cairo_set_line_width (cr_to_use, 2);

      /* if transport loop start is within the
       * screen */


@@ 625,10 647,10 @@ ruler_draw_cb (
          /* draw the loop start line */
          double x =
            (start_px - rect.x);
          cairo_move_to (
            cr_to_use, x, 0);
          cairo_line_to (
            cr_to_use, x, rect.height);
          z_cairo_move_to (
            cr_to_use, (int) x, 0);
          z_cairo_line_to (
            cr_to_use, (int) x, (int) rect.height);
          cairo_stroke (cr_to_use);
        }
      /* if transport loop end is within the


@@ 639,10 661,10 @@ ruler_draw_cb (
          /* draw the loop end line */
          double x =
            (end_px - rect.x);
          cairo_move_to (
            cr_to_use, x, 0);
          cairo_line_to (
            cr_to_use, x, rect.height);
          z_cairo_move_to (
            cr_to_use, (int) x, 0);
          z_cairo_line_to (
            cr_to_use, (int) x, (int) rect.height);
          cairo_stroke (cr_to_use);
        }



@@ 667,11 689,11 @@ ruler_draw_cb (

      double loop_start_local_x =
        MAX (0, start_px - rect.x);
      cairo_rectangle (
      z_cairo_rectangle (
        cr_to_use,
        loop_start_local_x, 0,
        end_px - MAX (rect.x, start_px),
        rect.height);
        (int) loop_start_local_x, 0,
        (int) (end_px - MAX (rect.x, start_px)),
        (int) (rect.height));
      cairo_set_source (cr_to_use, pat);
      cairo_fill (cr_to_use);
      cairo_pattern_destroy (pat);


@@ 885,9 907,9 @@ ruler_draw_cb (
          /* fill */
          cairo_set_source_rgba (
            cr_to_use, 1, 1, 1, 0.27);
          cairo_rectangle (
            cr_to_use, dr.x, dr.y,
            dr.width, dr.height);
          z_cairo_rectangle (
            cr_to_use, (int) dr.x, (int) dr.y,
            (int) dr.width, (int) dr.height);
          cairo_fill (cr_to_use);

          /* draw edges */

M src/utils/cairo.c => src/utils/cairo.c +77 -15
@@ 26,17 26,17 @@
void
z_cairo_draw_selection (
  cairo_t * cr,
  double    start_x,
  double    start_y,
  double    offset_x,
  double    offset_y)
  int       start_x,
  int       start_y,
  int       offset_x,
  int       offset_y)
{
  cairo_set_source_rgba (cr, 0.9, 0.9, 0.9, 1.0);
  cairo_rectangle (
  z_cairo_rectangle (
    cr, start_x, start_y, offset_x, offset_y);
  cairo_stroke (cr);
  cairo_set_source_rgba (cr, 0.3, 0.3, 0.3, 0.3);
  cairo_rectangle (
  z_cairo_rectangle (
    cr, start_x, start_y, offset_x, offset_y);
  cairo_fill (cr);
}


@@ 44,13 44,13 @@ z_cairo_draw_selection (
void
z_cairo_draw_horizontal_line (
  cairo_t * cr,
  double    y,
  double    from_x,
  double    to_x,
  int       y,
  int       from_x,
  int       to_x,
  double    alpha)
{
  cairo_set_source_rgba (cr, 0.7, 0.7, 0.7, alpha);
  cairo_set_line_width (cr, 0.5);
  cairo_set_line_width (cr, 1);
  cairo_move_to (cr, from_x, y);
  cairo_line_to (cr, to_x, y);
  cairo_stroke (cr);


@@ 59,9 59,9 @@ z_cairo_draw_horizontal_line (
void
z_cairo_draw_vertical_line (
  cairo_t * cr,
  double    x,
  double    from_y,
  double    to_y)
  int       x,
  int       from_y,
  int       to_y)
{
  cairo_move_to (cr, x, from_y);
  cairo_line_to (cr, x, to_y);


@@ 123,6 123,68 @@ z_cairo_create_pango_layout_from_description (
}

/**
 * Draws a diamond shape.
 */
void
z_cairo_diamond (
  cairo_t * cr,
  int       x,
  int       y,
  int       width,
  int       height)
{
  z_cairo_move_to (cr, x, (int) (height / 2));
  z_cairo_line_to (cr, (int) (width / 2), y);
  z_cairo_line_to (cr, width, height / 2);
  z_cairo_line_to (cr, width / 2, height);
  z_cairo_line_to (cr, x, height / 2);
  cairo_close_path (cr);
}

/**
 * @param aspect Aspect ratio.
 * @param corner_radius Corner curvature radius.
 */
void
z_cairo_rounded_rectangle (
  cairo_t * cr,
  int       x,
  int       y,
  int       width,
  int       height,
  double    aspect,
  double    corner_radius)
{
  double radius = corner_radius / aspect;
  double degrees = G_PI / 180.0;

  cairo_new_sub_path (cr);
  z_cairo_arc (
    cr, (int) (x + width - radius),
    (int) (y + radius),
    (int) radius, (int) (-90 * degrees),
    0 * degrees);
  z_cairo_arc (
    cr,
    (int) (x + width - radius),
    (int) (y + height - radius),
    (int) radius, 0 * degrees,
    (int) (90 * degrees));
  z_cairo_arc (
    cr,
    (int) (x + radius),
    (int) (y + height - radius),
    (int) radius,
    (int) (90 * degrees), (int) (180 * degrees));
  z_cairo_arc (
    cr,
    (int) (x + radius),
    (int) (y + radius), (int) radius,
    (int) (180 * degrees), (int) (270 * degrees));
  cairo_close_path (cr);
}

/**
 * Creates a PangoLayout to be cached in widgets
 * based on the given settings.
 */


@@ 188,12 250,12 @@ z_cairo_draw_text_full (
{
  g_return_if_fail (
    cr && layout && widget && text);
  cairo_translate (cr, start_x, start_y);
  z_cairo_translate (cr, start_x, start_y);

  pango_layout_set_markup (layout, text, -1);
  pango_cairo_show_layout (cr, layout);

  cairo_translate (cr, - start_x, - start_y);
  z_cairo_translate (cr, - start_x, - start_y);
}

/**