00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #if !defined(INCLUDED_GTKUTIL_CURSOR_H)
00023 #define INCLUDED_GTKUTIL_CURSOR_H
00024
00025 #include <glib/gmain.h>
00026 #include <gdk/gdkevents.h>
00027 #include <gtk/gtkwidget.h>
00028 #include <gtk/gtkwindow.h>
00029
00030 #include "debugging/debugging.h"
00031
00032 typedef struct _GdkCursor GdkCursor;
00033 typedef struct _GtkWidget GtkWidget;
00034 typedef struct _GtkWindow GtkWindow;
00035
00036 GdkCursor* create_blank_cursor ();
00037 void Sys_GetCursorPos (GtkWindow* window, int *x, int *y);
00038 void Sys_SetCursorPos (GtkWindow* window, int x, int y);
00039
00040 class DeferredMotion
00041 {
00042 guint m_handler;
00043 typedef void(*MotionFunction) (gdouble x, gdouble y, guint state, void* data);
00044 MotionFunction m_function;
00045 void* m_data;
00046 gdouble m_x;
00047 gdouble m_y;
00048 guint m_state;
00049
00050 static gboolean deferred (DeferredMotion* self)
00051 {
00052 self->m_handler = 0;
00053 self->m_function(self->m_x, self->m_y, self->m_state, self->m_data);
00054 return FALSE;
00055 }
00056 public:
00057 DeferredMotion (MotionFunction function, void* data) :
00058 m_handler(0), m_function(function), m_data(data)
00059 {
00060 }
00061 void motion (gdouble x, gdouble y, guint state)
00062 {
00063 m_x = x;
00064 m_y = y;
00065 m_state = state;
00066 if (m_handler == 0) {
00067 m_handler = g_idle_add((GSourceFunc) deferred, this);
00068 }
00069 }
00070
00071 static gboolean gtk_motion (GtkWidget *widget, GdkEventMotion *event, DeferredMotion* self)
00072 {
00073 self->motion(event->x, event->y, event->state);
00074 return FALSE;
00075 }
00076 };
00077
00078 class DeferredMotionDelta
00079 {
00080 int m_delta_x;
00081 int m_delta_y;
00082 guint m_motion_handler;
00083 typedef void (*MotionDeltaFunction) (int x, int y, void* data);
00084 MotionDeltaFunction m_function;
00085 void* m_data;
00086
00087 static gboolean deferred_motion (gpointer data)
00088 {
00089 reinterpret_cast<DeferredMotionDelta*> (data)->m_function(
00090 reinterpret_cast<DeferredMotionDelta*> (data)->m_delta_x,
00091 reinterpret_cast<DeferredMotionDelta*> (data)->m_delta_y,
00092 reinterpret_cast<DeferredMotionDelta*> (data)->m_data);
00093 reinterpret_cast<DeferredMotionDelta*> (data)->m_motion_handler = 0;
00094 reinterpret_cast<DeferredMotionDelta*> (data)->m_delta_x = 0;
00095 reinterpret_cast<DeferredMotionDelta*> (data)->m_delta_y = 0;
00096 return FALSE;
00097 }
00098 public:
00099 DeferredMotionDelta (MotionDeltaFunction function, void* data) :
00100 m_delta_x(0), m_delta_y(0), m_motion_handler(0), m_function(function), m_data(data)
00101 {
00102 }
00103 void flush ()
00104 {
00105 if (m_motion_handler != 0) {
00106 g_source_remove(m_motion_handler);
00107 deferred_motion(this);
00108 }
00109 }
00110 void motion_delta (int x, int y, unsigned int state)
00111 {
00112 m_delta_x += x;
00113 m_delta_y += y;
00114 if (m_motion_handler == 0) {
00115 m_motion_handler = g_idle_add(deferred_motion, this);
00116 }
00117 }
00118 };
00119
00120 class FreezePointer
00121 {
00122 unsigned int handle_motion;
00123 int recorded_x, recorded_y;
00124 typedef void (*MotionDeltaFunction) (int x, int y, unsigned int state, void* data);
00125 MotionDeltaFunction m_function;
00126 void* m_data;
00127 public:
00128 FreezePointer () :
00129 handle_motion(0), m_function(0), m_data(0)
00130 {
00131 }
00132 static gboolean motion_delta (GtkWidget *widget, GdkEventMotion *event, FreezePointer* self)
00133 {
00134 int current_x, current_y;
00135 Sys_GetCursorPos(GTK_WINDOW(widget), ¤t_x, ¤t_y);
00136 const int dx = current_x - self->recorded_x;
00137 const int dy = current_y - self->recorded_y;
00138 if (dx != 0 || dy != 0) {
00139 Sys_SetCursorPos(GTK_WINDOW(widget), self->recorded_x, self->recorded_y);
00140 self->m_function(dx, dy, event->state, self->m_data);
00141 }
00142 return FALSE;
00143 }
00144
00145 void freeze_pointer (GtkWindow* window, MotionDeltaFunction function, void* data)
00146 {
00147 ASSERT_MESSAGE(m_function == 0, "can't freeze pointer");
00148
00149 const GdkEventMask mask = static_cast<GdkEventMask> (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
00150 | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK
00151 | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
00152 | GDK_VISIBILITY_NOTIFY_MASK);
00153
00154 GdkCursor* cursor = create_blank_cursor();
00155
00156 gdk_pointer_grab(GTK_WIDGET(window)->window, TRUE, mask, 0, cursor, GDK_CURRENT_TIME);
00157 gdk_cursor_unref(cursor);
00158
00159 Sys_GetCursorPos(window, &recorded_x, &recorded_y);
00160
00161 Sys_SetCursorPos(window, recorded_x, recorded_y);
00162
00163 m_function = function;
00164 m_data = data;
00165
00166 handle_motion = g_signal_connect(G_OBJECT(window), "motion_notify_event", G_CALLBACK(motion_delta), this);
00167 }
00168
00169 void unfreeze_pointer (GtkWindow* window)
00170 {
00171 g_signal_handler_disconnect(G_OBJECT(window), handle_motion);
00172
00173 m_function = 0;
00174 m_data = 0;
00175
00176 Sys_SetCursorPos(window, recorded_x, recorded_y);
00177
00178 gdk_pointer_ungrab(GDK_CURRENT_TIME);
00179 }
00180 };
00181
00182 #endif