00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "vgui_gtk_adaptor.h"
00019 #include <vcl_cstdlib.h>
00020 #include <vcl_cassert.h>
00021 #include <vcl_utility.h>
00022 #include <gdk/gdkkeysyms.h>
00023 #include <gtk/gtk.h>
00024 #include <gtkgl/gtkglarea.h>
00025
00026 #include <vgui/vgui_gl.h>
00027 #include <vgui/vgui_popup_params.h>
00028 #include <vgui/internals/vgui_overlay_helper.h>
00029 #include "vgui_gtk_utils.h"
00030 #include "vgui_gtk_window.h"
00031
00032 static bool debug = false;
00033 vgui_menu vgui_gtk_adaptor::last_popup;
00034
00035 extern "C" { static gint timeout_callback(gpointer); }
00036
00037
00038
00039 vgui_gtk_adaptor::vgui_gtk_adaptor(vgui_gtk_window* win)
00040 : widget(0),
00041 win_(win),
00042 ovl_helper(0),
00043 last_mouse_x(0),
00044 last_mouse_y(0)
00045 {
00046 widget = gtk_gl_area_new_vargs(0,
00047 GDK_GL_RGBA,
00048 GDK_GL_DOUBLEBUFFER,
00049 GDK_GL_RED_SIZE, 8,
00050 GDK_GL_GREEN_SIZE, 8,
00051 GDK_GL_BLUE_SIZE, 8,
00052
00053 GDK_GL_DEPTH_SIZE,1,
00054 GDK_GL_NONE);
00055 if (!widget) {
00056 widget = gtk_gl_area_new_vargs(0,
00057 GDK_GL_RGBA,
00058 GDK_GL_DOUBLEBUFFER,
00059 GDK_GL_RED_SIZE, 5,
00060 GDK_GL_GREEN_SIZE, 6,
00061 GDK_GL_BLUE_SIZE, 5,
00062 GDK_GL_DEPTH_SIZE,1,
00063 GDK_GL_NONE);
00064 }
00065
00066 if (!widget) {
00067 widget = gtk_gl_area_new_vargs(0,
00068 GDK_GL_RGBA,
00069 GDK_GL_DOUBLEBUFFER,
00070 GDK_GL_DEPTH_SIZE,1,
00071 GDK_GL_NONE);
00072 }
00073
00074 if (!widget) {
00075 vcl_cerr << __FILE__ << " : Could not get a GL visual!\n";
00076 vcl_abort();
00077 }
00078
00079
00080
00081
00082 gtk_object_ref( GTK_OBJECT(widget) );
00083
00084 gtk_widget_set_events(widget,
00085 GDK_EXPOSURE_MASK |
00086 GDK_POINTER_MOTION_MASK |
00087 GDK_POINTER_MOTION_HINT_MASK |
00088 GDK_BUTTON_PRESS_MASK |
00089 GDK_BUTTON_RELEASE_MASK |
00090 GDK_KEY_PRESS_MASK |
00091 GDK_KEY_RELEASE_MASK |
00092 GDK_ENTER_NOTIFY_MASK |
00093 GDK_LEAVE_NOTIFY_MASK);
00094
00095 gtk_signal_connect(GTK_OBJECT(widget), "event", GTK_SIGNAL_FUNC(handle), this);
00096
00097 GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
00098
00099 redraw_requested = false;
00100 destroy_requested = false;
00101 }
00102
00103
00104 vgui_gtk_adaptor::~vgui_gtk_adaptor()
00105 {
00106 if (ovl_helper)
00107 delete ovl_helper;
00108 ovl_helper = 0;
00109
00110 glFlush();
00111 gtk_object_unref( GTK_OBJECT(widget) );
00112 widget = 0;
00113 }
00114
00115
00116 vgui_window* vgui_gtk_adaptor::get_window() const
00117 {
00118 return win_;
00119 }
00120
00121 void vgui_gtk_adaptor::swap_buffers()
00122 {
00123 make_current();
00124 gtk_gl_area_swapbuffers(GTK_GL_AREA(widget));
00125 }
00126
00127 void vgui_gtk_adaptor::make_current()
00128 {
00129 assert(gtk_gl_area_make_current(GTK_GL_AREA(widget)));
00130 }
00131
00132 void vgui_gtk_adaptor::post_redraw()
00133 {
00134 if (!redraw_requested) {
00135 redraw_requested = true;
00136 gtk_idle_add(idle_callback_for_redraw, this);
00137 }
00138 }
00139
00140 void vgui_gtk_adaptor::post_overlay_redraw()
00141 {
00142 if (!ovl_helper)
00143 ovl_helper = new vgui_overlay_helper(this);
00144 ovl_helper->post_overlay_redraw();
00145 }
00146
00147
00148 typedef struct
00149 {
00150 vgui_gtk_adaptor *adapt;
00151 int name;
00152 } vgui_gtk_adaptor_callback_data;
00153
00154
00155 void vgui_gtk_adaptor::post_timer(float timeout, int name)
00156 {
00157 vgui_gtk_adaptor_callback_data *cd = new vgui_gtk_adaptor_callback_data;
00158 cd->adapt = this;
00159 cd->name = name;
00160
00161 gint id = gtk_timeout_add(int(timeout),
00162 timeout_callback,
00163 cd);
00164
00165
00166 internal_timer i( id, (void*)cd );
00167 timers_.insert( vcl_pair<int, internal_timer>(name, i) );
00168 }
00169
00170
00171 void vgui_gtk_adaptor::kill_timer(int name)
00172 {
00173 vcl_map<int, internal_timer>::iterator it
00174 = timers_.find( name );
00175 if ( it == timers_.end() )
00176 return;
00177
00178 internal_timer timer;
00179 timer = (*it).second;
00180
00181 gtk_timeout_remove(timer.real_id_);
00182
00183 delete (vgui_gtk_adaptor_callback_data*)(timer.callback_ptr_);
00184
00185
00186 timers_.erase(it);
00187 }
00188
00189 void vgui_gtk_adaptor::post_destroy()
00190 {
00191 if (!destroy_requested) {
00192 destroy_requested = true;
00193 gtk_idle_add(idle_callback_for_destroy, this);
00194 }
00195 }
00196
00197 void vgui_gtk_adaptor::set_default_popup(vgui_menu)
00198 {
00199 vcl_cerr << "vgui_gtk_adaptor::set_default_popup\n";
00200 }
00201
00202 vgui_menu vgui_gtk_adaptor::get_popup()
00203 {
00204 vcl_cerr << "vgui_gtk_adaptor::get_popup\n";
00205 return vgui_menu();
00206 }
00207
00208 gint vgui_gtk_adaptor::handle(GtkWidget *widget,
00209 GdkEvent *gev,
00210 gpointer context)
00211 {
00212 vgui_gtk_adaptor* adaptor = (vgui_gtk_adaptor*) context;
00213
00214 bool ret_value = TRUE;
00215 if (vgui_gtk_utils::is_modifier(gev))
00216 ret_value = FALSE;
00217
00218 vgui_event event;
00219
00220 GdkEventType type = gev->type;
00221
00222 if (type==GDK_EXPOSE || type==GDK_MAP) {
00223 adaptor->draw();
00224 return TRUE;
00225 }
00226 else if (type==GDK_CONFIGURE) {
00227 adaptor->reshape();
00228 return TRUE;
00229 }
00230 else if (type==GDK_MOTION_NOTIFY) {
00231 event.type = vgui_MOTION;
00232 GdkEventMotion *e = (GdkEventMotion*)gev;
00233 if (e->is_hint) {
00234 int x,y;
00235 GdkModifierType state;
00236 gdk_window_get_pointer(e->window, &x, &y, &state);
00237 vgui_gtk_utils::set_modifiers(event, state);
00238 vgui_gtk_utils::set_coordinates(event, x, y);
00239 } else {
00240 vgui_gtk_utils::set_modifiers(event,e->state);
00241 vgui_gtk_utils::set_coordinates(event,e->x, e->y);
00242 }
00243 adaptor->last_mouse_x = event.wx;
00244 adaptor->last_mouse_y = event.wy;
00245 }
00246 else if (type==GDK_BUTTON_PRESS) {
00247 event.type = vgui_BUTTON_DOWN;
00248 GdkEventButton *e = (GdkEventButton*)gev;
00249 event.button = vgui_gtk_utils::translate_button(e->button);
00250 vgui_gtk_utils::set_modifiers(event,e->state);
00251 vgui_gtk_utils::set_coordinates(event,e->x, e->y);
00252 adaptor->last_mouse_x = event.wx;
00253 adaptor->last_mouse_y = event.wy;
00254 }
00255 else if (type==GDK_BUTTON_RELEASE) {
00256 event.type = vgui_BUTTON_UP;
00257 GdkEventButton *e = (GdkEventButton*)gev;
00258 event.button = vgui_gtk_utils::translate_button(e->button);
00259 vgui_gtk_utils::set_modifiers(event,e->state);
00260 vgui_gtk_utils::set_coordinates(event,e->x, e->y);
00261 adaptor->last_mouse_x = event.wx;
00262 adaptor->last_mouse_y = event.wy;
00263 }
00264 else if (type==GDK_KEY_PRESS) {
00265 event.type = vgui_KEY_PRESS;
00266 GdkEventKey *e = (GdkEventKey*)gev;
00267 event.set_key( vgui_gtk_utils::translate_key(e));
00268 event.ascii_char = vgui_gtk_utils::translate_key(e);
00269 vgui_gtk_utils::set_modifiers(event,e->state);
00270 event.wx = adaptor->last_mouse_x;
00271 event.wy = adaptor->last_mouse_y;
00272 }
00273 else if (type==GDK_KEY_RELEASE) {
00274 event.type = vgui_KEY_RELEASE;
00275 GdkEventKey *e = (GdkEventKey*)gev;
00276 event.set_key( vgui_gtk_utils::translate_key(e));
00277 event.ascii_char = vgui_gtk_utils::translate_key(e);
00278 vgui_gtk_utils::set_modifiers(event,e->state);
00279 event.wx = adaptor->last_mouse_x;
00280 event.wy = adaptor->last_mouse_y;
00281 }
00282 else if (type==GDK_ENTER_NOTIFY) {
00283 event.type = vgui_ENTER;
00284 gtk_widget_grab_focus(GTK_WIDGET(widget));
00285 }
00286 else if (type==GDK_LEAVE_NOTIFY) {
00287 event.type = vgui_LEAVE;
00288 }
00289 else {
00290 event.type = vgui_OTHER;
00291 }
00292
00293 if (event.type == vgui_BUTTON_DOWN &&
00294 event.button == adaptor->popup_button &&
00295 event.modifier == adaptor->popup_modifier)
00296 {
00297 GdkEventButton *bevent = (GdkEventButton *)gev;
00298
00299 GtkWidget *popup_menu = gtk_menu_new ();
00300
00301 vgui_popup_params params;
00302 params.x = event.wx;
00303 params.y = event.wy;
00304
00305
00306
00307 adaptor->last_popup = adaptor->get_total_popup(params);
00308
00309 vgui_gtk_utils::set_menu(popup_menu, adaptor->last_popup, false);
00310 gtk_menu_popup(GTK_MENU(popup_menu), 0, 0, 0, 0,
00311 bevent->button, bevent->time);
00312 return TRUE;
00313 }
00314
00315 if (debug) vcl_cerr << "vgui_event " << event << vcl_endl;
00316
00317
00318 if ( GTK_WIDGET_MAPPED(widget) ) {
00319 if (adaptor->ovl_helper)
00320 adaptor->ovl_helper->dispatch(event);
00321 else
00322 adaptor->dispatch_to_tableau(event);
00323 } else {
00324 vcl_cerr << __FILE__ << ": error: event " << event
00325 << " while GL area was not mapped\n";
00326 }
00327
00328 return ret_value;
00329 }
00330
00331
00332 void vgui_gtk_adaptor::reshape()
00333 {
00334 width = widget->allocation.width;
00335 height = widget->allocation.height;
00336
00337
00338
00339 if ( GTK_WIDGET_MAPPED(widget) ) {
00340 make_current();
00341 if (ovl_helper)
00342 ovl_helper->dispatch(vgui_RESHAPE);
00343 else
00344 dispatch_to_tableau(vgui_RESHAPE);
00345 }
00346 }
00347
00348
00349
00350
00351 void vgui_gtk_adaptor::draw()
00352 {
00353 if (debug) vcl_cerr << "vgui_gtk_adaptor::draw\n";
00354 if ( GTK_WIDGET_MAPPED(widget) ) {
00355 make_current();
00356 glDrawBuffer(GL_BACK);
00357 if (ovl_helper)
00358 ovl_helper->dispatch(vgui_DRAW);
00359 else {
00360 dispatch_to_tableau(vgui_DRAW);
00361 swap_buffers();
00362 }
00363 }
00364 }
00365
00366
00367 gint vgui_gtk_adaptor::idle_callback_for_redraw(gpointer data)
00368 {
00369 vgui_gtk_adaptor *adaptor = static_cast<vgui_gtk_adaptor*>(data);
00370
00371 adaptor->draw();
00372
00373 adaptor->redraw_requested = false;
00374
00375
00376 return FALSE;
00377 }
00378
00379
00380
00381 gint vgui_gtk_adaptor::idle_callback_for_destroy(gpointer data)
00382 {
00383 vgui_gtk_adaptor *adaptor = static_cast<vgui_gtk_adaptor*>(data);
00384
00385 adaptor->dispatch_to_tableau(vgui_DESTROY);
00386
00387 vgui_window* win = adaptor->get_window();
00388
00389
00390
00391 delete adaptor;
00392
00393
00394 if (win)
00395 delete win;
00396 else
00397 vcl_cerr << __FILE__ " : parent vgui_gtk_window is unknown, so cannot destroy!\n";
00398
00399
00400 return FALSE;
00401 }
00402
00403 extern "C" {
00404
00405 gint timeout_callback(gpointer data)
00406 {
00407 vgui_gtk_adaptor_callback_data* cd = static_cast<vgui_gtk_adaptor_callback_data*> (data);
00408 vgui_event e(vgui_TIMER);
00409 e.timer_id = cd->name;
00410 cd->adapt->dispatch_to_tableau(e);
00411
00412 delete cd;
00413
00414
00415 return FALSE;
00416 }
00417
00418 }