static void
recalculate_size (GtkSourceGutterRendererLines *renderer)
{
	gint num_lines;
	gint num_digits = 0;
	GtkTextBuffer *buffer;

	buffer = get_buffer (renderer);

	num_lines = gtk_text_buffer_get_line_count (buffer);

	num_digits = count_num_digits (num_lines);

	if (num_digits != renderer->priv->num_line_digits)
	{
		gchar markup[24];
		gint size;

		renderer->priv->num_line_digits = num_digits;

		num_lines = MAX (num_lines, 99);

		g_snprintf (markup, sizeof markup, "<b>%d</b>", num_lines);
		gtk_source_gutter_renderer_text_measure_markup (GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer),
		                                                markup,
		                                                &size,
		                                                NULL);

		gtk_source_gutter_renderer_set_size (GTK_SOURCE_GUTTER_RENDERER (renderer),
		                                     size);
	}
}
static void
measure_text (GtkSourceGutterRendererText *renderer,
              const gchar                 *markup,
              const gchar                 *text,
              gint                        *width,
              gint                        *height)
{
	GtkTextView *view;
	PangoLayout *layout;

	view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (renderer));

	layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);

	if (markup != NULL)
	{
		pango_layout_set_markup (layout, markup, -1);
	}
	else
	{
		pango_layout_set_text (layout, text, -1);
	}

	pango_layout_get_pixel_size (layout, width, height);

	g_object_unref (layout);
}
static void
gb_source_gutter_renderer_diff_changed (GbSourceDiff               *diff,
                                        GbSourceGutterRendererDiff *renderer)
{
   g_assert(GB_IS_SOURCE_DIFF(diff));
   g_assert(GB_IS_SOURCE_GUTTER_RENDERER_DIFF(renderer));
   gtk_source_gutter_renderer_queue_draw(GTK_SOURCE_GUTTER_RENDERER(renderer));
}
static GtkTextBuffer *
get_buffer (GtkSourceGutterRendererLines *renderer)
{
	GtkTextView *view;

	view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (renderer));

	return view != NULL ? gtk_text_view_get_buffer (view) : NULL;
}
static void
gtk_source_gutter_renderer_set_property (GObject      *object,
                                         guint         prop_id,
                                         const GValue *value,
                                         GParamSpec   *pspec)
{
	GtkSourceGutterRenderer *self = GTK_SOURCE_GUTTER_RENDERER (object);

	switch (prop_id)
	{
		case PROP_VISIBLE:
			set_visible (self, g_value_get_boolean (value));
			break;
		case PROP_XPAD:
			set_xpad (self, g_value_get_int (value));
			break;
		case PROP_YPAD:
			set_ypad (self, g_value_get_int (value));
			break;
		case PROP_XALIGN:
			set_xalign (self, g_value_get_float (value), TRUE);
			break;
		case PROP_YALIGN:
			set_yalign (self, g_value_get_float (value), TRUE);
			break;
		case PROP_ALIGNMENT_MODE:
			set_alignment_mode (self, g_value_get_enum (value));
			break;
		case PROP_VIEW:
			self->priv->view = g_value_get_object (value);
			break;
		case PROP_WINDOW_TYPE:
			self->priv->window_type = g_value_get_enum (value);
			break;
		case PROP_SIZE:
			set_size (self, g_value_get_int (value));
			break;
		case PROP_BACKGROUND_RGBA:
			set_background_color (self,
			                      g_value_get_boxed (value));
			break;
		case PROP_BACKGROUND_SET:
			set_background_color_set (self,
			                          g_value_get_boolean (value));
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
			break;
	}
}
static void
gtk_source_gutter_renderer_get_property (GObject    *object,
                                         guint       prop_id,
                                         GValue     *value,
                                         GParamSpec *pspec)
{
	GtkSourceGutterRenderer *self = GTK_SOURCE_GUTTER_RENDERER (object);

	switch (prop_id)
	{
		case PROP_VISIBLE:
			g_value_set_boolean (value, self->priv->visible);
			break;
		case PROP_XPAD:
			g_value_set_int (value, self->priv->xpad);
			break;
		case PROP_YPAD:
			g_value_set_int (value, self->priv->ypad);
			break;
		case PROP_XALIGN:
			g_value_set_float (value, self->priv->xalign);
			break;
		case PROP_YALIGN:
			g_value_set_float (value, self->priv->yalign);
			break;
		case PROP_VIEW:
			g_value_set_object (value, self->priv->view);
			break;
		case PROP_ALIGNMENT_MODE:
			g_value_set_enum (value, self->priv->alignment_mode);
			break;
		case PROP_WINDOW_TYPE:
			g_value_set_enum (value, self->priv->window_type);
			break;
		case PROP_SIZE:
			g_value_set_int (value, self->priv->size);
			break;
		case PROP_BACKGROUND_RGBA:
			g_value_set_boxed (value, &self->priv->background_color);
			break;
		case PROP_BACKGROUND_SET:
			g_value_set_boolean (value, self->priv->background_set);
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
			break;
	}
}
static void
connect_view (IdeLineChangeGutterRenderer *self)
{
  GtkTextView *view;

  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));

  if (view)
    {
      g_set_weak_pointer (&self->text_view, view);
      self->text_view_notify_buffer = g_signal_connect (self->text_view,
                                                        "notify::buffer",
                                                        G_CALLBACK (notify_buffer_cb),
                                                        self);
      connect_buffer (self);
    }
}
static void
gtk_source_gutter_renderer_dispose (GObject *object)
{
	GtkSourceGutterRenderer *renderer;

	renderer = GTK_SOURCE_GUTTER_RENDERER (object);

	set_buffer (renderer, NULL);

	if (renderer->priv->view)
	{
		_gtk_source_gutter_renderer_set_view (renderer,
		                                      NULL,
		                                      GTK_TEXT_WINDOW_PRIVATE);
	}

	G_OBJECT_CLASS (gtk_source_gutter_renderer_parent_class)->dispose (object);
}
static gint
get_last_visible_line_number (GtkSourceGutterRendererLines *lines)
{
	GtkTextView *view;
	GdkRectangle visible_rect;
	GtkTextIter iter;

	view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (lines));

	gtk_text_view_get_visible_rect (view, &visible_rect);

	gtk_text_view_get_line_at_y (view,
				     &iter,
				     visible_rect.y + visible_rect.height,
				     NULL);

	gtk_text_iter_forward_line (&iter);

	return gtk_text_iter_get_line (&iter);
}
static void
connect_style_scheme (IdeLineChangeGutterRenderer *self)
{
  GtkSourceStyleScheme *scheme;
  GtkTextBuffer *buffer;
  GtkTextView *view;

  if (!(view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self))) ||
      !(buffer = gtk_text_view_get_buffer (view)) ||
      !GTK_SOURCE_IS_BUFFER (buffer))
    return;

  scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer));

  if (!get_style_rgba (scheme, "gutter::added-line", FOREGROUND, &self->changes.add))
    gdk_rgba_parse (&self->changes.add, "#8ae234");

  if (!get_style_rgba (scheme, "gutter::changed-line", FOREGROUND, &self->changes.change))
    gdk_rgba_parse (&self->changes.change, "#fcaf3e");

  if (!get_style_rgba (scheme, "gutter::removed-line", FOREGROUND, &self->changes.remove))
    gdk_rgba_parse (&self->changes.remove, "#ef2929");
}