+ if (!(object->skip & GRITS_SKIP_STATE)) {
+ glPopAttrib();
+ glMatrixMode(GL_PROJECTION); glPopMatrix();
+ glMatrixMode(GL_MODELVIEW); glPopMatrix();
+ }
+ g_mutex_unlock(&opengl->sphere_lock);
+}
+
+/**
+ * grits_object_draw:
+ * @object: the object
+ * @opengl: the viewer the object is being displayed in
+ *
+ * Perform any OpenGL commands necessasairy to draw the object.
+ *
+ * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be
+ * restored to the default state after the call to draw.
+ */
+void grits_object_draw(GritsObject *object, GritsOpenGL *opengl)
+{
+ grits_object_pickdraw(object, opengl, FALSE);
+}
+
+void grits_object_hide(GritsObject *object, gboolean hidden)
+{
+ GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
+ object->hidden = hidden;
+ if (klass->hide)
+ klass->hide(object, hidden);
+}
+
+void grits_object_queue_draw(GritsObject *object)
+{
+ if (object->viewer)
+ gtk_widget_queue_draw(GTK_WIDGET(object->viewer));
+}
+
+void grits_object_set_cursor(GritsObject *object, GdkCursorType cursor)
+{
+ // Used by grits OpenGL
+ object->cursor = gdk_cursor_new(cursor);
+}
+
+/* Event handling */
+void grits_object_pick(GritsObject *object, GritsOpenGL *opengl)
+{
+ grits_object_pickdraw(object, opengl, TRUE);
+}
+
+gboolean grits_object_set_pointer(GritsObject *object, GdkEvent *event, gboolean selected)
+{
+ gboolean rval = FALSE;
+ if (selected) {
+ if (!object->state.selected)
+ 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, 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 = TRUE;
+ if (sig == SIG_BUTTON_RELEASE && object->state.clicking)
+ g_signal_emit(object, signals[SIG_CLICKED], 0, event, &rval);
+ if (sig == SIG_BUTTON_RELEASE || sig == SIG_MOTION)
+ object->state.clicking = FALSE;
+
+ /* 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;