24 #include <GL/freeglut.h>
34 #include "view_support.h"
45 ViewMonitor::ViewMonitor()
48 pthread_mutexattr_settype(&
mutex_attr, PTHREAD_MUTEX_RECURSIVE);
57 ViewMonitor::~ViewMonitor()
59 pthread_mutex_destroy(&
mutex);
68 static bool glut_initialized =
false;
69 static bool glew_initialized =
false;
78 static ThreadInfo* view_thread;
80 typedef int (*CTC_FUNC)(
void*);
81 static CTC_FUNC ctc_function = NULL;
82 static void* ctc_param;
83 static int ctc_result;
84 static std::map<int, View*> view_instances;
91 ViewParams(
View*
view,
int x,
int y,
int width,
int height,
const char* title) : view(view), x(x), y(y), width(width), height(height), title(title) {};
107 static void* view_thread_func(
void* param)
109 ThreadInfo* thread_info = (ThreadInfo*)param;
121 if(thread_info->should_quit)
126 if(ctc_function != NULL)
128 ctc_result = ctc_function(ctc_param);
151 static bool need_safe_call() {
return pthread_equal(view_thread->
thread, pthread_self()) == 0; }
154 static int call_in_thread(CTC_FUNC func,
void* param)
158 if(view_thread == NULL)
160 ThreadInfo* new_thread_info = NULL;
161 try { new_thread_info =
new ThreadInfo(); }
162 catch(std::bad_alloc&) {
throw Hermes::Exceptions::Exception(
"Failed to allocate structure for view thread"); }
163 int err = pthread_create(&new_thread_info->thread, NULL, view_thread_func, new_thread_info);
166 delete new_thread_info;
167 throw Hermes::Exceptions::Exception(
"Failed to create main thread, error: %d", err);
169 view_thread = new_thread_info;
180 int result = ctc_result;
189 static int set_view_title_in_thread(
void* title_pars_ptr)
191 TitleParams& title_params = *((TitleParams*)title_pars_ptr);
192 std::map<int, View*>::iterator found_view = view_instances.find(title_params.view_id);
193 if(found_view == view_instances.end())
195 throw Exceptions::Exception(
"Settings title of a view that is not registered.");
200 glutSetWindow(title_params.view_id);
201 glutSetWindowTitle(title_params.title);
212 glutInitWindowPosition(view_params.x, view_params.y);
213 glutInitWindowSize(view_params.width, view_params.height);
214 int view_id = glutCreateWindow(view_params.title);
215 glutSetWindowData(view_params.
view);
218 GLenum err = glewInit();
220 throw Exceptions::Exception(
"GLEW error: %s", glewGetErrorString(err));
221 glew_initialized =
true;
224 glutDisplayFunc(on_display_stub);
225 glutReshapeFunc(on_reshape_stub);
226 glutMotionFunc(on_mouse_move_stub);
227 glutPassiveMotionFunc(on_mouse_move_stub);
228 glutMouseFunc(on_mouse_click_stub);
229 glutKeyboardFunc(on_key_down_stub);
230 glutSpecialFunc(on_special_key_stub);
231 glutEntryFunc(on_entry_stub);
232 glutCloseFunc(on_close_stub);
235 view_instances[view_id] = view_params.
view;
238 view_params.
view->on_create(view_id);
247 std::map<int, View*>::iterator found_view = view_instances.find(params.
view_id);
248 if(found_view == view_instances.end())
250 throw Exceptions::Exception(
"Removing of a view that is not registered");
259 glutSetWindowData(NULL);
262 found_view->second->on_close();
265 glutDestroyWindow(params.
view_id);
269 view_instances.erase(found_view);
272 if(view_instances.empty())
287 static int refresh_view_in_thread(
void* view_id_ptr)
289 int view_id = *((
int*)view_id_ptr);
290 std::map<int, View*>::iterator found_view = view_instances.find(view_id);
291 if(found_view == view_instances.end())
292 throw Exceptions::Exception(
"Refreshing a view that is not registered");
295 if(found_view != view_instances.end())
297 glutSetWindow(view_id);
305 static long double_click_delay_ms = 300;
307 #define STUB_GET_VIEW() View* wnd = (View*)glutGetWindowData()
308 #define STUB_CALL(__call) STUB_GET_VIEW(); if(wnd != NULL) __call;
310 void on_display_stub(
void) { STUB_CALL( wnd->pre_display() ); }
311 void on_reshape_stub(
int width,
int height) { STUB_CALL( wnd->on_reshape(width, height) ); }
312 void on_mouse_move_stub(
int x,
int y) { STUB_CALL( wnd->on_mouse_move(x, y) ); }
313 void on_key_down_stub(
unsigned char key,
int x,
int y) { STUB_CALL( wnd->on_key_down(key, x, y) ); }
314 void on_special_key_stub(
int key,
int x,
int y) { STUB_CALL( wnd->on_special_key(key, x, y) ); }
315 void on_entry_stub(
int state) { STUB_CALL( wnd->on_entry(state) ); }
316 void on_mouse_click_stub(
int button,
int state,
int x,
int y)
323 if(state == GLUT_DOWN)
325 static double last_tick = 0;
328 if(tick - last_tick < double_click_delay_ms)
330 if(button == GLUT_LEFT_BUTTON)
331 wnd->on_left_mouse_double_click(x, y);
332 else if(button == GLUT_RIGHT_BUTTON)
333 wnd->on_right_mouse_double_click(x, y);
335 wnd->on_middle_mouse_double_click(x, y);
344 if(button == GLUT_LEFT_BUTTON)
346 if(state == GLUT_DOWN)
347 wnd->on_left_mouse_down(x, y);
349 wnd->on_left_mouse_up(x, y);
351 else if(button == GLUT_RIGHT_BUTTON)
353 if(state == GLUT_DOWN)
354 wnd->on_right_mouse_down(x, y);
356 wnd->on_right_mouse_up(x, y);
360 if(state == GLUT_DOWN)
361 wnd->on_middle_mouse_down(x, y);
363 wnd->on_middle_mouse_up(x, y);
377 RemoveParams params(glutGetWindow(),
false);
387 static const char* argv[1] = {
"x" };
390 if(!glut_initialized)
392 glutInit(&argc, (
char**) argv);
393 glut_initialized =
true;
395 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ACCUM);
396 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
400 double_click_delay_ms = GetDoubleClickTime();
416 call_in_thread(set_view_title_in_thread, ¶ms);
419 int add_view(
View* view,
int x,
int y,
int width,
int height,
const char* title)
421 ViewParams params(view, x, y, width, height, title);
425 void refresh_view(
int view_id) { call_in_thread(refresh_view_in_thread, &view_id); }
433 void force_view_thread_shutdown()
435 pthread_t current_thread;
436 bool should_wait =
false;
441 std::map<int, View*>::const_iterator iter = view_instances.begin();
442 while (iter != view_instances.end())
444 glutDestroyWindow(iter->first);
447 view_instances.clear();
450 if(view_thread != NULL)
452 current_thread = view_thread->
thread;
461 glew_initialized =
false;
462 pthread_join(current_thread, NULL);
468 pthread_t current_thread;
469 bool should_wait =
false;
473 if(view_thread != NULL)
475 current_thread = view_thread->
thread;
483 fprintf(stdout,
"%s", text); fflush(stdout);
484 pthread_join(current_thread, NULL);
492 if(view_thread != NULL)
494 fprintf(stdout,
"%s", text); fflush(stdout);