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_gtk2_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 <gdk/gdkgl.h>
00025 #include <gtk/gtkgl.h>
00026
00027 #include <vgui/vgui_gl.h>
00028 #include <vgui/vgui_popup_params.h>
00029 #include <vgui/internals/vgui_overlay_helper.h>
00030 #include "vgui_gtk2_utils.h"
00031 #include "vgui_gtk2_window.h"
00032 #include <vcl_iostream.h>
00033
00034 vgui_menu vgui_gtk2_adaptor::last_popup;
00035
00036 extern "C" {
00037 static gint timeout_callback(gpointer);
00038 }
00039
00040
00041
00042 vgui_gtk2_adaptor::vgui_gtk2_adaptor(vgui_gtk2_window* win)
00043 : idle_request_posted_(false),
00044 widget(0),
00045 win_(win),
00046 ovl_helper(0),
00047 last_mouse_x(0),
00048 last_mouse_y(0)
00049 {
00050
00051
00052
00053 GdkGLConfig* glconfig = gdk_gl_config_new_by_mode (GdkGLConfigMode(GDK_GL_MODE_RGB |
00054 GDK_GL_MODE_DEPTH |
00055 GDK_GL_MODE_DOUBLE));
00056 if (glconfig == 0)
00057 {
00058 g_print ("*** Cannot find the double-buffered visual.\n");
00059 g_print ("*** Trying single-buffered visual.\n");
00060
00061
00062 glconfig = gdk_gl_config_new_by_mode(GdkGLConfigMode(GDK_GL_MODE_RGB |
00063 GDK_GL_MODE_DEPTH));
00064 if (glconfig == 0)
00065 {
00066 g_print ("*** No appropriate OpenGL-capable visual found.\n");
00067 vcl_abort();
00068 }
00069 }
00070
00071 widget = gtk_drawing_area_new ();
00072
00073
00074 if (!widget)
00075 {
00076 vcl_cerr << __FILE__ << " : Could not get a GL widget!\n";
00077 vcl_abort();
00078 }
00079
00080
00081 if ( !gtk_widget_set_gl_capability(widget,
00082 glconfig,
00083 0 ,
00084 TRUE,
00085 GDK_GL_RGBA_TYPE) )
00086 {
00087 vcl_cerr << __FILE__ << " : Could not set GL capability!\n";
00088 vcl_abort();
00089 }
00090
00091
00092
00093
00094 gtk_object_ref( GTK_OBJECT(widget) );
00095
00096 gtk_widget_set_events(widget,
00097 GDK_EXPOSURE_MASK |
00098 GDK_POINTER_MOTION_MASK |
00099 GDK_POINTER_MOTION_HINT_MASK |
00100 GDK_BUTTON_PRESS_MASK |
00101 GDK_BUTTON_RELEASE_MASK |
00102 GDK_KEY_PRESS_MASK |
00103 GDK_KEY_RELEASE_MASK |
00104 GDK_ENTER_NOTIFY_MASK |
00105 GDK_LEAVE_NOTIFY_MASK);
00106
00107 #if 0
00108 gtk_signal_connect(GTK_OBJECT(widget), "event", GTK_SIGNAL_FUNC(handle), this);
00109 #else
00110 gtk_signal_connect(GTK_OBJECT(widget), "configure_event", GTK_SIGNAL_FUNC(handle_configure), this);
00111 gtk_signal_connect(GTK_OBJECT(widget), "expose_event", GTK_SIGNAL_FUNC(handle_draw), this);
00112 gtk_signal_connect(GTK_OBJECT(widget), "map_event", GTK_SIGNAL_FUNC(handle_draw), this);
00113 gtk_signal_connect(GTK_OBJECT(widget), "motion_notify_event", GTK_SIGNAL_FUNC(handle_motion_notify), this);
00114 gtk_signal_connect(GTK_OBJECT(widget), "button_press_event", GTK_SIGNAL_FUNC(handle_button), this);
00115 gtk_signal_connect(GTK_OBJECT(widget), "button_release_event", GTK_SIGNAL_FUNC(handle_button), this);
00116 gtk_signal_connect(GTK_OBJECT(widget), "key_press_event", GTK_SIGNAL_FUNC(handle_key), this);
00117 gtk_signal_connect(GTK_OBJECT(widget), "key_release_event", GTK_SIGNAL_FUNC(handle_key), this);
00118 gtk_signal_connect(GTK_OBJECT(widget), "enter_notify_event", GTK_SIGNAL_FUNC(handle_enter_leave), this);
00119 gtk_signal_connect(GTK_OBJECT(widget), "leave_notify_event", GTK_SIGNAL_FUNC(handle_enter_leave), this);
00120 #endif
00121 GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
00122
00123 redraw_requested = false;
00124 destroy_requested = false;
00125 }
00126
00127
00128 vgui_gtk2_adaptor::~vgui_gtk2_adaptor()
00129 {
00130 if (ovl_helper)
00131 delete ovl_helper;
00132 ovl_helper = 0;
00133
00134 glFlush();
00135 gtk_object_unref( GTK_OBJECT(widget) );
00136 widget = 0;
00137 }
00138
00139
00140 vgui_window* vgui_gtk2_adaptor::get_window() const
00141 {
00142 return win_;
00143 }
00144
00145 void vgui_gtk2_adaptor::swap_buffers()
00146 {
00147 make_current();
00148 gdk_gl_drawable_swap_buffers (gtk_widget_get_gl_drawable(widget));
00149 }
00150
00151 void vgui_gtk2_adaptor::make_current()
00152 {
00153 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
00154 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
00155 assert( gldrawable );
00156 gdk_gl_drawable_make_current(gldrawable, glcontext);
00157 }
00158
00159 void vgui_gtk2_adaptor::post_redraw()
00160 {
00161 if (!redraw_requested)
00162 {
00163 redraw_requested = true;
00164 gtk_idle_add(idle_callback_for_redraw, this);
00165 }
00166 }
00167
00168 void vgui_gtk2_adaptor::post_overlay_redraw()
00169 {
00170 if (!ovl_helper)
00171 ovl_helper = new vgui_overlay_helper(this);
00172 ovl_helper->post_overlay_redraw();
00173 }
00174
00175 void vgui_gtk2_adaptor::post_idle_request()
00176 {
00177 if (!idle_request_posted_){
00178 idle_request_posted_ = true;
00179 g_idle_add(idle_callback_for_tableaux, this);
00180 }
00181 }
00182
00183
00184 typedef struct
00185 {
00186 vgui_gtk2_adaptor *adapt;
00187 int name;
00188 } vgui_gtk2_adaptor_callback_data;
00189
00190
00191 void vgui_gtk2_adaptor::post_timer(float timeout, int name)
00192 {
00193 vgui_gtk2_adaptor_callback_data *cd = new vgui_gtk2_adaptor_callback_data;
00194 cd->adapt = this;
00195 cd->name = name;
00196
00197 gint id = gtk_timeout_add(int(timeout),
00198 timeout_callback,
00199 cd);
00200
00201
00202 internal_timer i( id, (void*)cd );
00203 timers_.insert( vcl_pair<int, internal_timer>(name, i) );
00204 }
00205
00206
00207 void vgui_gtk2_adaptor::kill_timer(int name)
00208 {
00209 vcl_map<int, internal_timer>::iterator it
00210 = timers_.find( name );
00211 if ( it == timers_.end() )
00212 return;
00213
00214 internal_timer timer;
00215 timer = (*it).second;
00216
00217 gtk_timeout_remove(timer.real_id_);
00218
00219 delete (vgui_gtk2_adaptor_callback_data*)(timer.callback_ptr_);
00220
00221
00222 timers_.erase(it);
00223 }
00224
00225 void vgui_gtk2_adaptor::post_destroy()
00226 {
00227 if (!destroy_requested)
00228 {
00229 destroy_requested = true;
00230 gtk_idle_add(idle_callback_for_destroy, this);
00231 }
00232 }
00233
00234 void vgui_gtk2_adaptor::set_default_popup(vgui_menu)
00235 {
00236 #ifdef DEBUG
00237 vcl_cerr << "vgui_gtk2_adaptor::set_default_popup\n";
00238 #endif
00239 }
00240
00241 vgui_menu vgui_gtk2_adaptor::get_popup()
00242 {
00243 #ifdef DEBUG
00244 vcl_cerr << "vgui_gtk2_adaptor::get_popup\n";
00245 #endif
00246 return vgui_menu();
00247 }
00248
00249 gint vgui_gtk2_adaptor::handle_configure(
00250 GtkWidget *widget,
00251 GdkEvent *gev,
00252 gpointer context)
00253 {
00254 vgui_gtk2_adaptor* adaptor = (vgui_gtk2_adaptor*) context;
00255
00256
00257
00258 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
00259 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
00260 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
00261 return FALSE;
00262 gdk_gl_drawable_gl_end (gldrawable);
00263
00264 adaptor->reshape();
00265 return TRUE;
00266 }
00267
00268 gint vgui_gtk2_adaptor::handle_draw(
00269 GtkWidget *widget,
00270 GdkEvent *gev,
00271 gpointer context)
00272 {
00273 vgui_gtk2_adaptor* adaptor = (vgui_gtk2_adaptor*) context;
00274 adaptor->draw();
00275 return TRUE;
00276 }
00277
00278 gint vgui_gtk2_adaptor::handle_motion_notify(
00279 GtkWidget *widget,
00280 GdkEvent *gev,
00281 gpointer context)
00282 {
00283 vgui_gtk2_adaptor* adaptor = (vgui_gtk2_adaptor*) context;
00284 vgui_event event;
00285
00286 event.type = vgui_MOTION;
00287 GdkEventMotion *e = (GdkEventMotion*)gev;
00288 if (e->is_hint)
00289 {
00290 int x,y;
00291 GdkModifierType state;
00292 gdk_window_get_pointer(e->window, &x, &y, &state);
00293 vgui_gtk2_utils::set_modifiers(event, state);
00294 vgui_gtk2_utils::set_coordinates(event, x, y);
00295 }
00296 else
00297 {
00298 vgui_gtk2_utils::set_modifiers(event,e->state);
00299 vgui_gtk2_utils::set_coordinates(event,e->x, e->y);
00300 }
00301 adaptor->last_mouse_x = event.wx;
00302 adaptor->last_mouse_y = event.wy;
00303
00304 return handle(event, widget, gev, context);
00305 }
00306
00307
00308 gint vgui_gtk2_adaptor::handle_button(
00309 GtkWidget *widget,
00310 GdkEvent *gev,
00311 gpointer context)
00312 {
00313 vgui_gtk2_adaptor* adaptor = (vgui_gtk2_adaptor*) context;
00314 vgui_event event;
00315 GdkEventType type = gev->type;
00316
00317 if (type==GDK_BUTTON_PRESS)
00318 event.type = vgui_BUTTON_DOWN;
00319 else if (type==GDK_BUTTON_RELEASE)
00320 event.type = vgui_BUTTON_UP;
00321 GdkEventButton *e = (GdkEventButton*)gev;
00322 event.button = vgui_gtk2_utils::translate_button(e->button);
00323 vgui_gtk2_utils::set_modifiers(event,e->state);
00324 vgui_gtk2_utils::set_coordinates(event,e->x, e->y);
00325 adaptor->last_mouse_x = event.wx;
00326 adaptor->last_mouse_y = event.wy;
00327
00328 if (event.type == vgui_BUTTON_DOWN &&
00329 event.button == adaptor->popup_button &&
00330 event.modifier == adaptor->popup_modifier)
00331 {
00332 GdkEventButton *bevent = (GdkEventButton *)gev;
00333
00334 GtkWidget *popup_menu = gtk_menu_new ();
00335
00336 vgui_popup_params params;
00337 params.x = event.wx;
00338 params.y = event.wy;
00339
00340
00341
00342 adaptor->last_popup = adaptor->get_total_popup(params);
00343
00344 vgui_gtk2_utils::set_menu(popup_menu, adaptor->last_popup, false);
00345 gtk_menu_popup(GTK_MENU(popup_menu), 0, 0, 0, 0,
00346 bevent->button, bevent->time);
00347 return TRUE;
00348 }
00349
00350 return handle(event, widget, gev, context);
00351 }
00352
00353 gint vgui_gtk2_adaptor::handle_key(
00354 GtkWidget *widget,
00355 GdkEvent *gev,
00356 gpointer context)
00357 {
00358 vgui_gtk2_adaptor* adaptor = (vgui_gtk2_adaptor*) context;
00359 vgui_event event;
00360 GdkEventType type = gev->type;
00361
00362 if (type==GDK_KEY_PRESS)
00363 event.type = vgui_KEY_PRESS;
00364 else if (type==GDK_KEY_RELEASE)
00365 event.type = vgui_KEY_RELEASE;
00366 GdkEventKey *e = (GdkEventKey*)gev;
00367 event.set_key( vgui_gtk2_utils::translate_key(e));
00368 event.ascii_char = vgui_gtk2_utils::translate_key(e);
00369 vgui_gtk2_utils::set_modifiers(event,e->state);
00370 event.wx = adaptor->last_mouse_x;
00371 event.wy = adaptor->last_mouse_y;
00372
00373 return handle(event, widget, gev, context);
00374 }
00375
00376 gint vgui_gtk2_adaptor::handle_enter_leave(
00377 GtkWidget *widget,
00378 GdkEvent *gev,
00379 gpointer context)
00380 {
00381 vgui_event event;
00382 GdkEventType type = gev->type;
00383
00384 if (type==GDK_ENTER_NOTIFY)
00385 {
00386 event.type = vgui_ENTER;
00387 gtk_widget_grab_focus(GTK_WIDGET(widget));
00388 }
00389 else if (type==GDK_LEAVE_NOTIFY)
00390 {
00391 event.type = vgui_LEAVE;
00392 }
00393
00394 return handle(event, widget, gev, context);
00395 }
00396
00397 gint vgui_gtk2_adaptor::handle(const vgui_event &event,
00398 GtkWidget *widget,
00399 GdkEvent *gev,
00400 gpointer context)
00401 {
00402 vgui_gtk2_adaptor* adaptor = (vgui_gtk2_adaptor*) context;
00403
00404 bool ret_value = TRUE;
00405 if (vgui_gtk2_utils::is_modifier(gev))
00406 ret_value = FALSE;
00407
00408 #ifdef DEBUG
00409 vcl_cerr << "vgui_event " << event << '\n';
00410 #endif
00411
00412
00413 if ( GTK_WIDGET_MAPPED(widget) )
00414 {
00415 if (adaptor->ovl_helper)
00416 adaptor->ovl_helper->dispatch(event);
00417 else
00418 adaptor->dispatch_to_tableau(event);
00419 }
00420 else
00421 vcl_cerr << __FILE__ << ": error: event " << event
00422 << " while GL area was not mapped\n";
00423
00424 return ret_value;
00425 }
00426
00427
00428 void vgui_gtk2_adaptor::reshape()
00429 {
00430 width = widget->allocation.width;
00431 height = widget->allocation.height;
00432
00433
00434
00435 if ( GTK_WIDGET_MAPPED(widget) )
00436 {
00437 make_current();
00438 if (ovl_helper)
00439 ovl_helper->dispatch(vgui_RESHAPE);
00440 else
00441 dispatch_to_tableau(vgui_RESHAPE);
00442 }
00443 }
00444
00445 bool vgui_gtk2_adaptor::do_idle()
00446 {
00447 if ( idle_request_posted_ )
00448 idle_request_posted_ = dispatch_to_tableau( vgui_event( vgui_IDLE ) );
00449 return idle_request_posted_;
00450 }
00451
00452
00453
00454 void vgui_gtk2_adaptor::draw()
00455 {
00456 #ifdef DEBUG
00457 vcl_cerr << "vgui_gtk2_adaptor::draw\n";
00458 #endif
00459 if ( GTK_WIDGET_MAPPED(widget) )
00460 {
00461 make_current();
00462 glDrawBuffer(GL_BACK);
00463 if (ovl_helper)
00464 ovl_helper->dispatch(vgui_DRAW);
00465 else
00466 {
00467 dispatch_to_tableau(vgui_DRAW);
00468 swap_buffers();
00469 }
00470 }
00471 }
00472
00473
00474 gint vgui_gtk2_adaptor::idle_callback_for_tableaux(gpointer data)
00475 {
00476 vgui_gtk2_adaptor *adaptor = static_cast<vgui_gtk2_adaptor*>(data);
00477
00478 return adaptor->do_idle();
00479 }
00480
00481
00482 gint vgui_gtk2_adaptor::idle_callback_for_redraw(gpointer data)
00483 {
00484 vgui_gtk2_adaptor *adaptor = static_cast<vgui_gtk2_adaptor*>(data);
00485
00486 adaptor->draw();
00487
00488 adaptor->redraw_requested = false;
00489
00490
00491 return FALSE;
00492 }
00493
00494
00495
00496 gint vgui_gtk2_adaptor::idle_callback_for_destroy(gpointer data)
00497 {
00498 vgui_gtk2_adaptor *adaptor = static_cast<vgui_gtk2_adaptor*>(data);
00499
00500 adaptor->dispatch_to_tableau(vgui_DESTROY);
00501
00502 vgui_window* win = adaptor->get_window();
00503
00504
00505 if (win)
00506 delete win;
00507 else
00508 vcl_cerr << __FILE__ " : parent vgui_gtk2_window is unknown, so cannot destroy!\n";
00509
00510
00511
00512 delete adaptor;
00513
00514
00515 return FALSE;
00516 }
00517
00518 extern "C" {
00519 gint timeout_callback(gpointer data)
00520 {
00521 vgui_gtk2_adaptor_callback_data* cd = static_cast<vgui_gtk2_adaptor_callback_data*> (data);
00522 vgui_event e(vgui_TIMER);
00523 e.timer_id = cd->name;
00524 cd->adapt->dispatch_to_tableau(e);
00525
00526
00527 return true;
00528 }
00529 }