/* gcc -g menu-button-action.c $(pkg-config --cflags --libs gtk+-3.0
   gio-2.0 glib-2.0) */

#include <gio/gio.h>
#include <glib.h>
#include <gtk/gtk.h>


#define FOO_TYPE_APPLICATION (foo_application_get_type ())

#define FOO_APPLICATION(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
   FOO_TYPE_APPLICATION, FooApplication))

#define FOO_APPLICATION_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST ((klass), \
   FOO_TYPE_APPLICATION, FooApplicationClass))

#define FOO_IS_APPLICATION(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
   FOO_TYPE_APPLICATION))

#define FOO_IS_APPLICATION_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
   FOO_TYPE_APPLICATION))

#define FOO_APPLICATION_GET_CLASS(obj) \
  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
   FOO_TYPE_APPLICATION, FooApplicationClass))

typedef struct _FooApplication      FooApplication;
typedef struct _FooApplicationClass FooApplicationClass;

struct _FooApplication
{
  GtkApplication parent_instance;
  GtkWidget *window;
};

struct _FooApplicationClass
{
  GtkApplicationClass parent_class;
};

GType                  foo_application_get_type               (void) G_GNUC_CONST;


#define FOO_TYPE_MAIN_WINDOW (foo_main_window_get_type ())

#define FOO_MAIN_WINDOW(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
   FOO_TYPE_MAIN_WINDOW, FooMainWindow))

#define FOO_MAIN_WINDOW_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST ((klass), \
   FOO_TYPE_MAIN_WINDOW, FooMainWindowClass))

#define FOO_IS_MAIN_WINDOW(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
   FOO_TYPE_MAIN_WINDOW))

#define FOO_IS_MAIN_WINDOW_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
   FOO_TYPE_MAIN_WINDOW))

#define FOO_MAIN_WINDOW_GET_CLASS(obj) \
  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
   FOO_TYPE_MAIN_WINDOW, FooMainWindowClass))

typedef struct _FooMainWindow      FooMainWindow;
typedef struct _FooMainWindowClass FooMainWindowClass;

struct _FooMainWindow
{
  GtkApplicationWindow parent_instance;
};

struct _FooMainWindowClass
{
  GtkApplicationWindowClass parent_class;
};

GType                  foo_main_window_get_type               (void) G_GNUC_CONST;


G_DEFINE_TYPE (FooApplication, foo_application, GTK_TYPE_APPLICATION);

static void
foo_application_action_toggle (GSimpleAction *simple, GVariant *parameter, gpointer user_data)
{
  GVariant *state;
  GVariant *new_state;

  state = g_action_get_state (G_ACTION (simple));
  if (state == NULL)
    return;

  new_state = g_variant_new ("b", !g_variant_get_boolean (state));
  g_action_change_state (G_ACTION (simple), new_state);
  g_variant_unref (state);
}

static void
foo_application_quit (FooApplication *self, GVariant *parameter)
{
  gtk_widget_destroy (self->window);
}

static gboolean
foo_application_timeout (gpointer user_data)
{
  FooApplication *self = FOO_APPLICATION (user_data);
  GAction *action;

  action = g_action_map_lookup_action (G_ACTION_MAP (self), "gear-menu");
  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
  g_message ("gear-menu: 1");

  return G_SOURCE_REMOVE;
}

static void
foo_application_activate (GApplication *application)
{
  FooApplication *self = FOO_APPLICATION (application);

  gtk_window_present (GTK_WINDOW (self->window));
  g_timeout_add_seconds (5, foo_application_timeout, g_object_ref (self));
}

static void
foo_application_startup (GApplication *application)
{
  FooApplication *self = FOO_APPLICATION (application);
  GSimpleAction *action;
  GVariant *state;
  const gchar *gear_menu_accels[2] = {"F10", NULL};
  const gchar *quit_accels[2] = {"<Primary>q", NULL};

  G_APPLICATION_CLASS (foo_application_parent_class)->startup (application);

  state = g_variant_new ("b", FALSE);
  action = g_simple_action_new_stateful ("gear-menu", NULL, state);
  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
  g_signal_connect (action, "activate", G_CALLBACK (foo_application_action_toggle), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (action));
  g_object_unref (action);

  action = g_simple_action_new ("quit", NULL);
  g_signal_connect_swapped (action, "activate", G_CALLBACK (foo_application_quit), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (action));
  g_object_unref (action);

  gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.quit", quit_accels);
  gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.gear-menu", gear_menu_accels);

  self->window = g_object_new (FOO_TYPE_MAIN_WINDOW,
                               "application", application,
                               NULL);
}

static void
foo_application_dispose (GObject *object)
{
  FooApplication *self = FOO_APPLICATION (object);
  G_OBJECT_CLASS (foo_application_parent_class)->dispose (object);
}

static void
foo_application_init (FooApplication *self)
{
}

static void
foo_application_class_init (FooApplicationClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GApplicationClass *application_class = G_APPLICATION_CLASS (class);

  object_class->dispose = foo_application_dispose;
  application_class->activate = foo_application_activate;
  application_class->startup = foo_application_startup;
}


G_DEFINE_TYPE (FooMainWindow, foo_main_window, GTK_TYPE_APPLICATION_WINDOW);

static const gchar *preview_menu =
"<interface>"
"  <menu id='preview-menu'>"
"   <section>"
"      <item>"
"        <attribute name='action'>app.quit</attribute>"
"        <attribute name='label'>Quit</attribute>"
"      </item>"
"    </section>"
"  </menu>"
"</interface>";

static void
foo_main_window_dispose (GObject *object)
{
  FooMainWindow *self = FOO_MAIN_WINDOW (object);
  G_OBJECT_CLASS (foo_main_window_parent_class)->dispose (object);
}

static void
foo_main_window_init (FooMainWindow *self)
{
  GApplication *app;
  GAction *action;
  GMenuModel *menu;
  GtkBuilder *builder;
  GtkWidget *button;
  GtkWidget *grid;
  GtkWidget *label;

  app = g_application_get_default ();
  action = g_action_map_lookup_action (G_ACTION_MAP (app), "gear-menu");
  g_message ("gear-menu: %d", g_action_get_enabled (action));

  grid = gtk_grid_new ();
  gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
  gtk_container_add (GTK_CONTAINER (self), grid);

  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, preview_menu, -1, NULL);

  menu = G_MENU_MODEL (gtk_builder_get_object (builder, "preview-menu"));

  button = g_object_new (GTK_TYPE_MENU_BUTTON,
                         "action-name", "app.gear-menu",
                         "menu-model", menu,
                         NULL);
  /* gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), menu); */
  /* gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "app.gear-menu"); */
  gtk_container_add (GTK_CONTAINER (grid), button);

  g_object_unref (builder);

  label = gtk_label_new ("Foo Foo Foo Foo");
  gtk_container_add (GTK_CONTAINER (grid), label);

  label = gtk_label_new ("Bar Bar Bar Bar");
  gtk_container_add (GTK_CONTAINER (grid), label);

  label = gtk_label_new ("Baz Baz Baz Baz");
  gtk_container_add (GTK_CONTAINER (grid), label);

  gtk_widget_show_all (GTK_WIDGET (self));
}

static void
foo_main_window_class_init (FooMainWindowClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->dispose = foo_main_window_dispose;
}

static GtkWidget *
foo_main_window_new (GtkApplication *application)
{
  return g_object_new (FOO_TYPE_MAIN_WINDOW,
                       "application", application,
                       NULL);
}


gint
main (gint argc, gchar *argv[])
{
  GApplication *app;
  gint exit_status;

  app = g_object_new (FOO_TYPE_APPLICATION,
                       "application-id", "org.gnome.Foo",
                       NULL);
  exit_status = g_application_run (app, argc, argv);
  g_object_unref (app);

  return exit_status;
}
