]> Pileus Git - grits/blobdiff - src/objects/grits-object.c
Add grits_object_destroy functions and fix memory leaks
[grits] / src / objects / grits-object.c
index 6abc4eb26f3ba70b3ff25a945f2af5918cd38d44..55f39754d498cf7d4f93c0ca8116d06d376effdb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
+ * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 #include <math.h>
-#include <GL/gl.h>
 
+#include "gtkgl.h"
 #include "grits-object.h"
+#include "grits-marshal.h"
 
 /* Constants */
 enum {
        SIG_ENTER,
        SIG_LEAVE,
+       SIG_CLICKED,
+       SIG_BUTTON_PRESS,
+       SIG_BUTTON_RELEASE,
+       SIG_KEY_PRESS,
+       SIG_KEY_RELEASE,
+       SIG_MOTION,
        NUM_SIGNALS,
 };
 static guint signals[NUM_SIGNALS];
@@ -45,6 +52,7 @@ static guint signals[NUM_SIGNALS];
 void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick)
 {
        GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
+
        if (!klass->draw) {
                g_warning("GritsObject: draw - Unimplemented");
                return;
@@ -54,6 +62,14 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi
        if (object->hidden)
                return;
 
+       /* Skip object with no signals when picking */
+       for (int i = 0; pick; i++) {
+               if (i == NUM_SIGNALS)
+                       return;
+               if (g_signal_has_handler_pending(object, signals[i], 0, FALSE))
+                       break;
+       }
+
        /* Support GritsTester */
        if (!GRITS_IS_OPENGL(opengl)) {
                g_debug("GritsObject: draw - drawing raw object");
@@ -61,7 +77,7 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi
                return;
        }
 
-       /* Calculae distance for LOD and horizon tests */
+       /* Calculate distance for LOD and horizon tests */
        GritsPoint *center = &object->center;
        if ((!(object->skip & GRITS_SKIP_LOD) ||
             !(object->skip & GRITS_SKIP_HORIZON)) &&
@@ -95,7 +111,7 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi
        }
 
        /* Save state, draw, restore state */
-       g_mutex_lock(opengl->sphere_lock);
+       g_mutex_lock(&opengl->sphere_lock);
        if (!(object->skip & GRITS_SKIP_STATE)) {
                glPushAttrib(GL_ALL_ATTRIB_BITS);
                glMatrixMode(GL_PROJECTION); glPushMatrix();
@@ -118,7 +134,7 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi
                glMatrixMode(GL_PROJECTION); glPopMatrix();
                glMatrixMode(GL_MODELVIEW);  glPopMatrix();
        }
-       g_mutex_unlock(opengl->sphere_lock);
+       g_mutex_unlock(&opengl->sphere_lock);
 }
 
 /**
@@ -147,42 +163,79 @@ void grits_object_hide(GritsObject *object, gboolean hidden)
 void grits_object_queue_draw(GritsObject *object)
 {
        if (object->viewer)
-               gtk_widget_queue_draw(GTK_WIDGET(object->viewer));
+               grits_viewer_queue_draw(object->viewer);
 }
 
-/* Event handling */
-void grits_object_pick_begin(GritsObject *object, GritsOpenGL *opengl)
+void grits_object_set_cursor(GritsObject *object, GdkCursorType cursor)
 {
-       object->state.picked = FALSE;
-
-       /* Check for connected signals */
-       for (int i = 0; i < NUM_SIGNALS; i++) {
-               if (g_signal_has_handler_pending(object, signals[i], 0, FALSE)) {
-                       /* Someone is watching, render the object _once_ */
-                       glPushName((guint)object);
-                       grits_object_pickdraw(object, opengl, TRUE);
-                       glPopName();
-                       return;
-               }
-       }
+       // Used by grits OpenGL
+       object->cursor = gdk_cursor_new(cursor);
+}
+
+void grits_object_destroy(GritsObject *object)
+{
+       if (object->viewer)
+               grits_viewer_remove(object->viewer, object);
+       g_object_unref(object);
 }
 
-void grits_object_pick_pointer(GritsObject *object, double x, double y)
+/* Event handling */
+void grits_object_pick(GritsObject *object, GritsOpenGL *opengl)
 {
-       object->state.picked = TRUE;
+       grits_object_pickdraw(object, opengl, TRUE);
 }
 
-void grits_object_pick_end(GritsObject *object)
+gboolean grits_object_set_pointer(GritsObject *object, GdkEvent *event, gboolean selected)
 {
-       if (object->state.picked) {
+       gboolean rval = FALSE;
+       if (selected) {
                if (!object->state.selected)
-                       g_signal_emit(object, signals[SIG_ENTER], 0);
+                       g_signal_emit(object, signals[SIG_ENTER], 0, event, &rval);
                object->state.selected = TRUE;
        } else {
                if (object->state.selected)
-                       g_signal_emit(object, signals[SIG_LEAVE], 0);
+                       g_signal_emit(object, signals[SIG_LEAVE], 0, event, &rval);
                object->state.selected = FALSE;
        }
+       return rval;
+}
+
+gboolean grits_object_event(GritsObject *object, GdkEvent *event)
+{
+       const int map[GDK_EVENT_LAST] = {
+               [GDK_BUTTON_PRESS  ] SIG_BUTTON_PRESS,
+               [GDK_2BUTTON_PRESS ] SIG_BUTTON_PRESS,
+               [GDK_3BUTTON_PRESS ] SIG_BUTTON_PRESS,
+               [GDK_BUTTON_RELEASE] SIG_BUTTON_RELEASE,
+               [GDK_KEY_PRESS     ] SIG_KEY_PRESS,
+               [GDK_KEY_RELEASE   ] SIG_KEY_RELEASE,
+               [GDK_MOTION_NOTIFY ] SIG_MOTION,
+       };
+       if (!object->state.selected)
+               return FALSE;
+       guint sig = map[event->type];
+       gboolean rval = FALSE;
+
+       /* Handle button click */
+       if (sig == SIG_BUTTON_PRESS)
+               object->state.clicking  = GRITS_CLICK_THRESHOLD;
+       if (sig == SIG_MOTION && object->state.clicking)
+               object->state.clicking -= 1;
+       if (sig == SIG_BUTTON_RELEASE && object->state.clicking)
+               g_signal_emit(object, signals[SIG_CLICKED], 0, event, &rval);
+       if (sig == SIG_BUTTON_RELEASE)
+               object->state.clicking  = 0;
+
+       /* Emit this signal */
+       if (rval == FALSE) {
+               if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE))
+                       return FALSE;
+               g_signal_emit(object, signals[sig], 0, event, &rval);
+       }
+
+       if (rval == TRUE)
+               g_debug("GritsObject: breaking chained event");
+       return rval;
 }
 
 /* GObject stuff */
@@ -211,9 +264,10 @@ static void grits_object_class_init(GritsObjectClass *klass)
                        0,
                        NULL,
                        NULL,
-                       g_cclosure_marshal_VOID__VOID,
-                       G_TYPE_NONE,
-                       0);
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
 
        /**
         * GritsViewer::leave:
@@ -229,7 +283,123 @@ static void grits_object_class_init(GritsObjectClass *klass)
                        0,
                        NULL,
                        NULL,
-                       g_cclosure_marshal_VOID__VOID,
-                       G_TYPE_NONE,
-                       0);
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
+
+       /**
+        * GritsViewer::clicked:
+        * @object: the object.
+        *
+        * The ::clicked signal is emitted when the user clicks on the object
+        */
+       signals[SIG_CLICKED] = g_signal_new(
+                       "clicked",
+                       G_TYPE_FROM_CLASS(gobject_class),
+                       G_SIGNAL_RUN_LAST,
+                       0,
+                       NULL,
+                       NULL,
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
+
+       /**
+        * GritsViewer::button-press:
+        * @object: the object.
+        * @event:  the GdkEventButton which triggered this signal
+        *
+        * The ::button-press signal is emitted when a button (typically from a
+        * mouse) is pressed.
+        */
+       signals[SIG_BUTTON_PRESS] = g_signal_new(
+                       "button-press",
+                       G_TYPE_FROM_CLASS(gobject_class),
+                       G_SIGNAL_RUN_LAST,
+                       0,
+                       NULL,
+                       NULL,
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
+
+       /**
+        * GritsViewer::button-release:
+        * @object: the object.
+        * @event:  the GdkEventButton which triggered this signal
+        *
+        * The ::button-release signal is emitted when a button (typically from
+        * a mouse) is released.
+        */
+       signals[SIG_BUTTON_RELEASE] = g_signal_new(
+                       "button-release",
+                       G_TYPE_FROM_CLASS(gobject_class),
+                       G_SIGNAL_RUN_LAST,
+                       0,
+                       NULL,
+                       NULL,
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
+
+       /**
+        * GritsViewer::key-press:
+        * @object: the object.
+        * @event:  the GdkEventKey which triggered this signal
+        *
+        * The ::key-press signal is emitted when a key is pressed.
+        */
+       signals[SIG_KEY_PRESS] = g_signal_new(
+                       "key-press",
+                       G_TYPE_FROM_CLASS(gobject_class),
+                       G_SIGNAL_RUN_LAST,
+                       0,
+                       NULL,
+                       NULL,
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
+
+       /**
+        * GritsViewer::key-release:
+        * @object: the object.
+        * @event:  the GdkEventKey which triggered this signal
+        *
+        * The ::key-release signal is emitted when a key is released.
+        */
+       signals[SIG_KEY_RELEASE] = g_signal_new(
+                       "key-release",
+                       G_TYPE_FROM_CLASS(gobject_class),
+                       G_SIGNAL_RUN_LAST,
+                       0,
+                       NULL,
+                       NULL,
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
+
+       /**
+        * GritsViewer::motion:
+        * @object: the object.
+        * @event:  the GdkEventMotion which triggered this signal
+        *
+        * The ::motion signal is emitted the pointer moves over the object
+        */
+       signals[SIG_MOTION] = g_signal_new(
+                       "motion",
+                       G_TYPE_FROM_CLASS(gobject_class),
+                       G_SIGNAL_RUN_LAST,
+                       0,
+                       NULL,
+                       NULL,
+                       grits_cclosure_marshal_BOOLEAN__POINTER,
+                       G_TYPE_BOOLEAN,
+                       1,
+                       G_TYPE_POINTER);
 }