#package Mup::EventLogger;
package EventLogger;

use Gtk2;
# gtk+ has to be initialized before we can install the override, otherwise
# it gets re-overridden.
Glib::Idle->add (sub {Gtk2::Gdk::Event->handler_set (\&event_snooper)}, FALSE);

sub setup {
}

sub teardown {
}

my %seen = ();
my @ev = ();

sub event_snooper {
	my $event = shift;
	my $type = $event->type;
	$seen{$type}++;
	$handler{$type}->($type, $event);
	Gtk2->main_do_event ($event);
}

my $seq = 'e0000000';
sub record {
	use Data::Dumper;
	#warn Dumper(\@_);
	my %e = ('type', @_);
	push @ev, \%e;
	print Data::Dumper->Dump ([\%e], [$seq++]);
}

#  struct _GdkEventAny
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#  };
#  
#  struct _GdkEventExpose
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkRectangle area;
#    GdkRegion *region;
#    gint count; /* If non-zero, how many more events follow. */
#  };
sub expose {
	my ($t, $e) = @_;			#  struct _GdkEventExpose
	record ($t,				#    GdkEventType type;
		window => $e->window,		#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		area => [ $e->area->values ],	#    GdkRectangle area;
		region => $e->region, 		#    GdkRegion *region;
		count => $e->count,		#    gint count;
	);
}
#  
#  struct _GdkEventNoExpose
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#  };
sub noexpose {
	my ($t, $e) = @_;			#  struct _GdkEventNoExpose
	record ($t,				#    GdkEventType type;
		window => $e->window,		#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
	);
}
#  
#  struct _GdkEventVisibility
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkVisibilityState state;
#  };
sub visibility {
	my ($t, $e) = @_;			#  struct _GdkEventVisibilty
	record ($t,				#    GdkEventType type;
		window => $e->window,		#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		state => $e->state,		#    GdkVisibilityState state;
	);
}
#  
#  struct _GdkEventMotion
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    guint32 time;
#    gdouble x;
#    gdouble y;
#    gdouble *axes;
#    guint state;
#    gint16 is_hint;
#    GdkDevice *device;
#    gdouble x_root, y_root;
#  };
sub motion {
	my ($t, $e) = @_;		# struct GdkEventMotion
	record ($t,			#    GdkEventType type;
		window => $e->window,	#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		time => $e->time,	#    guint32 time;
		x => $e->x,		#    gdouble x;
		y => $e->y,		#    gdouble y;
		#axes => $e->axes,	#    gdouble *axes;
		state => $e->state,	#    guint state;
		is_hint => $e->is_hint,	#    gint16 is_hint;
		#device => $e->device,	#    GdkDevice *device;
		x_root => $e->x_root,	#    gdouble x_root;
		y_root => $e->y_root,	#    gdouble y_root;
	);
}
#  
#  struct _GdkEventButton
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    guint32 time;
#    gdouble x;
#    gdouble y;
#    gdouble *axes;
#    guint state;
#    guint button;
#    GdkDevice *device;
#    gdouble x_root, y_root;
#  };
sub button {
	my ($t, $e) = @_;		# struct GdkEventButton
	record ($t,			#    GdkEventType type;
		window => $e->window,	#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		time => $e->time,	#    guint32 time;
		x => $e->x,		#    gdouble x;
		y => $e->y,		#    gdouble y;
		#axes => $e->axes,	#    gdouble *axes;
		state => $e->state,	#    guint state;
		button => $e->button,	#    guint button;
		#device => $e->device,	#    GdkDevice *device;
		x_root => $e->x_root,	#    gdouble x_root;
		y_root => $e->y_root,	#    gdouble y_root;
	);
}
#  
#  struct _GdkEventScroll
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    guint32 time;
#    gdouble x;
#    gdouble y;
#    guint state;
#    GdkScrollDirection direction;
#    GdkDevice *device;
#    gdouble x_root, y_root;
#  };
sub scroll {
	my ($t, $e) = @_;		# struct GdkEventScroll
	record ($t,			#    GdkEventType type;
		window => $e->window,	#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		time => $e->time,	#    guint32 time;
		x => $e->x,		#    gdouble x;
		y => $e->y,		#    gdouble y;
		state => $e->state,	#    guint state;
		direction => $e->direction,	#    GdkScrollDirection direction;
		#device => $e->device,	#    GdkDevice *device;
		x_root => $e->x_root,	#    gdouble x_root;
		y_root => $e->y_root,	#    gdouble y_root;
	);
}
#  
#  struct _GdkEventKey
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    guint32 time;
#    guint state;
#    guint keyval;
#    gint length;
#    gchar *string;
#    guint16 hardware_keycode;
#    guint8 group;
#  };
sub key {
	my ($t, $e) = @_;		# struct GdkEventKey
	record ($t,			#    GdkEventType type;
		window => $e->window,	#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		time => $e->time,	#    guint32 time;
		state => $e->state,	#    guint state;
		keyval => $e->keyval,	#    guint keyval;
		#length => $e->length,	#    gint length;
		#string => $e->string,	#    gchar *string;
		hardware_keycode => $e->hardware_keycode,	#    guint16 hardware_keycode;
		group => $e->group,	#    guint8 group;
	);
}
#  
#  struct _GdkEventCrossing
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkWindow *subwindow;
#    guint32 time;
#    gdouble x;
#    gdouble y;
#    gdouble x_root;
#    gdouble y_root;
#    GdkCrossingMode mode;
#    GdkNotifyType detail;
#    gboolean focus;
#    guint state;
#  };
sub crossing {
	my ($t, $e) = @_;		# struct GdkEventCrossing
	record ($t,			#    GdkEventType type;
		window => $e->window,	#    GdkWindow *window;
		send_event => $e->send_event,	#    gint8 send_event;
		subwindow => $e->subwindow,	#    GdkWindow *subwindow
		time => $e->time,	#    guint32 time;
		x => $e->x,		#    gdouble x;
		y => $e->y,		#    gdouble y;
		x_root => $e->x_root,	#    gdouble x_root;
		y_root => $e->y_root,	#    gdouble y_root;
		mode => $e->mode,	#    GdkCrossingMode mode;
		detail => $e->detail, 	#    GdkNotifyType detail;
		focus => $e->focus,	#    gboolean focus;
		state => $e->state,	#    guint state;
	);
}
#  
#  struct _GdkEventFocus
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    gint16 in;
#  };
#  
#  struct _GdkEventConfigure
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    gint x, y;
#    gint width;
#    gint height;
#  };
#  
#  struct _GdkEventProperty
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkAtom atom;
#    guint32 time;
#    guint state;
#  };
#  
#  struct _GdkEventSelection
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkAtom selection;
#    GdkAtom target;
#    GdkAtom property;
#    guint32 time;
#    GdkNativeWindow requestor;
#  };
#  
#  /* This event type will be used pretty rarely. It only is important
#     for XInput aware programs that are drawing their own cursor */
#  
#  struct _GdkEventProximity
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    guint32 time;
#    GdkDevice *device;
#  };
#  
#  struct _GdkEventClient
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkAtom message_type;
#    gushort data_format;
#    union {
#      char b[20];
#      short s[10];
#      long l[5];
#    } data;
#  };
#  
#  struct _GdkEventSetting
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkSettingAction action;
#    char *name;
#  };
#  
#  struct _GdkEventWindowState
#  {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkWindowState changed_mask;
#    GdkWindowState new_window_state;
#  };
#  
#  /* Event types for DND */
#  
#  struct _GdkEventDND {
#    GdkEventType type;
#    GdkWindow *window;
#    gint8 send_event;
#    GdkDragContext *context;
#  
#    guint32 time;
#    gshort x_root, y_root;
#  };




sub _default { my ($t, $e) = @_; record ($t, ev => $e, time => $e->time); }

our %handler = (
    'nothing' => \&_default,
    'delete' => \&_default,
    'destroy' => \&_default,
    'expose' => \&expose,
    'motion-notify' => \&motion,
    'button-press' => \&button,
    '2button-press' => \&button,
    '3button-press' => \&button,
    'button-release' => \&button,
    'key-press' => \&key,
    'key-release' => \&key,
    'enter-notify' => \&crossing,
    'leave-notify' => \&crossing,
    'focus-change' => \&_default,
    'configure' => \&_default,
    'map' => \&_default,
    'unmap' => \&_default,
    'property-notify' => \&_default,
    'selection-clear' => \&_default,
    'selection-request' => \&_default,
    'selection-notify' => \&_default,
    'proximity-in' => \&_default,
    'proximity-out' => \&_default,
    'drag-enter' => \&_default,
    'drag-leave' => \&_default,
    'drag-motion' => \&_default,
    'drag-status' => \&_default,
    'drop-start' => \&_default,
    'drop-finished' => \&_default,
    'client-event' => \&_default,
    'visibility-notify' => \&_default,
    'no-expose' => \&_default,
    'scroll' => \&scroll,
    'window-state' => \&_default,
    'setting' => \&_default,
);



END {
	#use Data::Dumper;
	print map{ "$seen{$_}\t$_\n" } sort {$seen{$a} <=> $seen{$b}} keys %seen;
	#print Dumper(\@ev);
}

1;
