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

#ifdef G_OS_WIN32
  #include <windows.h>
  #include <psapi.h>
#endif

void
print_memory (char *event_name)
{
#ifdef G_OS_WIN32
  static gboolean started = FALSE;
  static gint64 start;
  HANDLE hProc;
  PROCESS_MEMORY_COUNTERS_EX pmc;

  if (started == FALSE)
    {
      started = TRUE;
      start = g_get_monotonic_time ();
    }

  hProc = GetCurrentProcess ();
  GetProcessMemoryInfo (hProc, (PROCESS_MEMORY_COUNTERS *) &pmc, sizeof(pmc));
  CloseHandle (hProc);

  g_print ("!!!!!%"G_GINT64_FORMAT"\t%u\t%u\t%s\n", g_get_monotonic_time () - start,
                                                    (unsigned int) pmc.WorkingSetSize,
                                                    (unsigned int) pmc.PrivateUsage,
                                                    event_name);
#else
  #error "Please implement print_memory () for your operating system."
#endif
}

gboolean
print_memory_event_cb (GtkWidget *widget,
                       GdkEvent  *event,
                       gpointer   user_data)
{
  print_memory ((char *) user_data);
  return FALSE;
}

gboolean
print_memory_timeout_cb (gpointer user_data)
{
  print_memory ((char *) user_data);
  return TRUE;
}

gboolean
queue_draw (gpointer user_data)
{
  gtk_widget_queue_draw (GTK_WIDGET (user_data));
  return TRUE;
}

int
main (int argc,
      char *argv[])
{
  GtkWidget *window = NULL;
//  GtkWidget *label = NULL;
//  GtkWidget *box = NULL;
//  GtkWidget *entry = NULL;

  g_print ("!!!!!time\tworkingset\tprivate\tevent\n");
  gtk_init(&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
  gtk_widget_add_events(GTK_WIDGET (window), GDK_BUTTON_PRESS_MASK |
                                             GDK_BUTTON_RELEASE_MASK |
                                             GDK_ENTER_NOTIFY_MASK |
                                             GDK_EXPOSURE_MASK |
                                             GDK_FOCUS_CHANGE_MASK |
                                             GDK_KEY_PRESS_MASK |
                                             GDK_KEY_RELEASE_MASK |
                                             GDK_LEAVE_NOTIFY_MASK |
                                             GDK_POINTER_MOTION_MASK |
                                             GDK_PROPERTY_CHANGE_MASK |
                                             GDK_PROXIMITY_IN_MASK |
                                             GDK_PROXIMITY_OUT_MASK |
                                             GDK_VISIBILITY_NOTIFY_MASK |
                                             GDK_STRUCTURE_MASK);
  g_signal_connect (window, "button-press-event", G_CALLBACK (print_memory_event_cb), &"button-press-event");
  g_signal_connect (window, "button-release-event", G_CALLBACK (print_memory_event_cb), &"button-release-event");
  g_signal_connect (window, "configure-event", G_CALLBACK (print_memory_event_cb), &"configure-event");
  g_signal_connect (window, "damage-event", G_CALLBACK (print_memory_event_cb), &"damage-event");
  g_signal_connect (window, "delete-event", G_CALLBACK (print_memory_event_cb), &"delete-event");
  g_signal_connect (window, "destroy-event", G_CALLBACK (print_memory_event_cb), &"destroy-event");
  g_signal_connect (window, "enter-notify-event", G_CALLBACK (print_memory_event_cb), &"enter-notify-event");
  g_signal_connect (window, "expose-event", G_CALLBACK (print_memory_event_cb), &"expose-event");
  g_signal_connect (window, "focus-in-event", G_CALLBACK (print_memory_event_cb), &"focus-in-event");
  g_signal_connect (window, "focus-out-event", G_CALLBACK (print_memory_event_cb), &"focus-out-event");
  g_signal_connect (window, "grab-broken-event", G_CALLBACK (print_memory_event_cb), &"grab-broken-event");
  g_signal_connect (window, "key-press-event", G_CALLBACK (print_memory_event_cb), &"key-press-event");
  g_signal_connect (window, "key-release-event", G_CALLBACK (print_memory_event_cb), &"key-release-event");
  g_signal_connect (window, "leave-notify-event", G_CALLBACK (print_memory_event_cb), &"leave-notify-event");
  g_signal_connect (window, "map-event", G_CALLBACK (print_memory_event_cb), &"map-event");
  g_signal_connect (window, "motion-notify-event", G_CALLBACK (print_memory_event_cb), &"motion-notify-event");
  g_signal_connect (window, "no-expose-event", G_CALLBACK (print_memory_event_cb), &"no-expose-event");
  g_signal_connect (window, "property-notify-event", G_CALLBACK (print_memory_event_cb), &"property-notify-event");
  g_signal_connect (window, "proximity-in-event", G_CALLBACK (print_memory_event_cb), &"proximity-in-event");
  g_signal_connect (window, "proximity-out-event", G_CALLBACK (print_memory_event_cb), &"proximity-out-event");
  g_signal_connect (window, "scroll-event", G_CALLBACK (print_memory_event_cb), &"scroll-event");
  g_signal_connect (window, "selection-clear-event", G_CALLBACK (print_memory_event_cb), &"selection-clear-event");
  g_signal_connect (window, "selection-notify-event", G_CALLBACK (print_memory_event_cb), &"selection-notify-event");
  g_signal_connect (window, "selection-request-event", G_CALLBACK (print_memory_event_cb), &"selection-request-event");
  g_signal_connect (window, "unmap-event", G_CALLBACK (print_memory_event_cb), &"unmap-event");
  g_signal_connect (window, "visibility-notify-event", G_CALLBACK (print_memory_event_cb), &"visibility-notify-event");
  g_signal_connect (window, "window-state-event", G_CALLBACK (print_memory_event_cb), &"window-state-event");
  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);

//  box = gtk_vbox_new (FALSE, 4);
//  gtk_container_add (GTK_CONTAINER (window), box);
//  label = gtk_label_new ("Test");
//  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
//  entry = gtk_entry_new ();
//  gtk_box_pack_end (GTK_BOX (box), entry, TRUE, TRUE, 0);
  gtk_widget_show_all (window);

  g_timeout_add(1000, queue_draw, (gpointer)window);
  g_timeout_add(10, print_memory_timeout_cb, "<timeout>");

  gtk_main();

  return 0;
}
