GtkSourceGutter - How to render icon or text on a specific line

483 Views Asked by At

I have inserted custom gtk source gutter renderer pixbuf and I want to render icon on a specific line.

The reference API states that the interface is very similar to that on GtkTreeView, but doesn't work with a tree model. So... how am I supposed to render data to a specific line if the GtkSourceGutter doesn't work with a tree model?

I checked every function in the entire library, every suggested api and child objects and nothing even hints about that.

It just doesn't make sense. The man page says that the GtkSourceGutterRendererPixbuf is used to display icon IN A CELL. Doing gtk_source_gutter_renderer_pixbuf_set_pixbuf(renderer, pixbuf); will render the icon for all cells in the gutter. And if the only way is to draw the pixbuf manually using cairo..what's the point in those renderers ?

How do I render pixbuf in a specific line using the gtksourcegutterrenderer?


enter image description here

2

There are 2 best solutions below

0
On BEST ANSWER

I personally cannot simply agree with the allegation that creating custom objects is easy. It isn't easy, not to everyone.

Mainly, because, this question is tagged c and people who don't know Object-Oriented programming might be unfamiliar with its concepts.

It is a matter of reading and practice.

So do not panic if you don't know how to, for instance create your own widget.

The easiest solution I can think of, doesn't involve creating your own renderer, but rather tell the renderer how to query rendering data.

Just connect the query-data signal on your GtkSourceGutterRenderer to a signal handler that looks like this:

G_MODULE_EXPORT void gutter_renderer_query_data (GtkSourceGutterRenderer *renderer, GtkTextIter *start, GtkTextIter *end, GtkSourceGutterRendererState state)
{
    GtkSourceView*      view    = NULL;
    GtkSourceBuffer*    buffer  = NULL;
    GSList*             marks   = NULL;
    GdkPixbuf*          pixbuf  = NULL;

    view    = GTK_SOURCE_VIEW(gtk_source_gutter_renderer_get_view(renderer));
    buffer  = GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)));

    marks   = gtk_source_buffer_get_source_marks_at_iter(buffer, start, NULL);

    if(marks != NULL)
    {
        char *category = gtk_source_mark_get_category(marks->data);

        if(!g_strcmp0(category, "CERTAIN_CATEGORY")) /* See note 1) */
            pixbuf = gtk_image_get_pixbuf(gtk_image_new_from_file("icon_file_here")); /* See note 2) */

        g_slist_free(marks);
    }

    g_object_set(G_OBJECT(renderer), "pixbuf", pixbuf, "yalign", 0.5, NULL);
}

Notes:

  1. GtkSourceMark shares the GtkSourceGutterRenderer interface so you might want to filter your other source marks, by specifying the category of a source mark that is applied to the certain line. Otherwise your custom renderer pixbuf will also be rendered left to your other source marks.

  2. You should specify the exact pixbuf you want to render internally. Doing this, you won't have to call gtk_source_gutter_renderer_pixbuf_set_pixbuf() . You let the API do the resource handling.

12
On

I haven't worked with GtkSourceView, but I can give you some clues.


How it's done by GtkSourceView's author

First of all, we need some links:

Let's start with GtkSourceGutterRendererPixbuf. From it's class_init method we find out, that it overrides only draw method. It's only purpose is to render a pixbuf or icon. Pure drawing.

However, GtkSourceGutterRenderer documentation says, that there is a query-data signal which can be used to tune Renderer's internal state. At this point we should take a look at GtkSourceGutterRendererMarks which is inherited from RendererPixbuf. It doesn't override draw, but overrides query_data. (For some reason GtkSourceGutterRendererClass is not described in the documentation. I don't know why.)

/* Read my comments. */
static void
gutter_renderer_query_data (GtkSourceGutterRenderer      *renderer,
                            GtkTextIter                  *start,
                            GtkTextIter                  *end,
                            GtkSourceGutterRendererState  state)
{
  GSList *marks;
  GdkPixbuf *pixbuf = NULL;
  
  view = GTK_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
  buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));

  marks = gtk_source_buffer_get_source_marks_at_iter (buffer,
                                                      start,
                                                      NULL);
  
  /* If there are marks, we find a pixbuf for one of them. 
   * Otherwise pixbuf is NULL. */
  if (marks != NULL)
  {
    size = measure_line_height (view);
    pixbuf = composite_marks (view, marks, size);

    g_slist_free (marks);
  }
  
  /* Now tell parent class to render certain pixbuf
   * It will render nothing if pixbuf is NULL. */
  g_object_set (G_OBJECT (renderer),
                   "pixbuf", pixbuf,
                   NULL);
}

My recommendations.

You want to draw marks at certain lines (e.g. want to highlight current debugger line). If I were you, I would have inherited from RendererPixbuf, overriden query_data and use gtk_text_iter_get_line on GtkTextIter *start. Looks like that's the bare minimum.

Feel free to ask any further questions.