/* gcc test-focus.c -o test-focus `pkg-config gtk+-3.0 --cflags --libs` */
#include <gtk/gtk.h>

static gboolean use_image_cache = TRUE;

static GdkPixbuf *
get_pix (GtkStyleContext *context,
    const gchar *icon_name,
    gint icon_size)
{
  static GHashTable *cache = NULL;
  GtkStateFlags state;
  gchar *key;
  GtkIconInfo *icon_info;
  GdkPixbuf *pix;
  GError *error = NULL;

  if (cache == NULL)
    {
      cache = g_hash_table_new_full (g_str_hash, g_str_equal,
          g_free, g_object_unref);
    }

  state = gtk_style_context_get_state (context);
  key = g_strdup_printf ("%s-%u-%u", icon_name, icon_size, state);
  pix = g_hash_table_lookup (cache, key);
  if (pix != NULL)
    {
      g_free (key);
      return pix;
    }

  icon_info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (),
      icon_name, icon_size, 0);
  pix = gtk_icon_info_load_symbolic_for_context (icon_info, context, NULL, &error);
  g_assert_no_error (error);

  /* Takes ownership of key and pix */
  g_hash_table_insert (cache, key, pix);

  return pix;
}

static void
image_update_pixbuf (GtkWidget *image)
{
  const gchar *icon_name;
  gint icon_size;
  GdkPixbuf *pix;

  icon_name = g_object_get_data ((GObject *) image, "icon-name");
  icon_size = GPOINTER_TO_INT (g_object_get_data ((GObject *) image, "icon-size"));
  pix = get_pix (gtk_widget_get_style_context (image), icon_name, icon_size);

  gtk_image_set_from_pixbuf ((GtkImage *) image, pix);
}

static GtkWidget *
new_image (const gchar *icon_name,
    GtkIconSize icon_size)
{
  GtkWidget *image;

  if (use_image_cache)
    {
      gint size = 48;
      gint w, h;

      if (gtk_icon_size_lookup (icon_size, &w, &h))
        size = (w + h) / 2;

      image = gtk_image_new ();
      g_object_set_data ((GObject *) image, "icon-name", (gchar *) icon_name);
      g_object_set_data ((GObject *) image, "icon-size", GINT_TO_POINTER (size));
      g_signal_connect (image, "style-updated",
          G_CALLBACK (image_update_pixbuf), NULL);
      image_update_pixbuf (image);
    }
  else
    {
      image = gtk_image_new_from_icon_name (icon_name, icon_size);
    }

  return image;
}

static void
add_row (GtkWidget *grid)
{
  GtkWidget *row;
  GtkWidget *image;
  GtkWidget *align;
  GtkWidget *label;

  row = gtk_grid_new ();
  gtk_grid_attach_next_to (GTK_GRID (grid), row, NULL,
      GTK_POS_BOTTOM, 1, 1);
  gtk_widget_show (row);

  image = new_image ("avatar-default-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
  gtk_grid_attach_next_to (GTK_GRID (row), image, NULL, GTK_POS_RIGHT, 1, 1);
  gtk_widget_show (image);

  align = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_grid_attach_next_to (GTK_GRID (row), align, NULL, GTK_POS_RIGHT, 1, 1);
  gtk_widget_show (align);

  image = new_image ("user-available", GTK_ICON_SIZE_MENU);
  gtk_container_add (GTK_CONTAINER (align), image);
  gtk_widget_show (image);

  align = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_grid_attach_next_to (GTK_GRID (row), align, NULL, GTK_POS_RIGHT, 1, 1);
  gtk_widget_show (align);

  image = new_image ("phone-symbolic", GTK_ICON_SIZE_MENU);
  gtk_container_add (GTK_CONTAINER (align), image);
  gtk_widget_show (image);

  align = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_grid_attach_next_to (GTK_GRID (row), align, NULL, GTK_POS_RIGHT, 1, 1);
  gtk_widget_show (align);

  label = gtk_label_new ("Hello world");
  gtk_container_add (GTK_CONTAINER (align), label);
  gtk_widget_show (label);
}

gint
main (gint argc,
    gchar ** argv)
{
  GtkWidget *window;
  GtkWidget *sw;
  GtkWidget *grid;
  guint i;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  sw = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (window), sw);
  gtk_widget_show (sw);

  grid = gtk_grid_new ();
  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), grid);
  gtk_widget_show (grid);

  for (i = 0; i < 1000; i++)
    add_row (grid);

  gtk_widget_show (window);
  gtk_main ();
  gtk_widget_destroy (window);

  return 0;
}
