19 #include <GL/freeglut.h>
29 #include "view_support.h"
41 ViewMonitor::ViewMonitor()
44 pthread_mutexattr_settype(&
mutex_attr, PTHREAD_MUTEX_RECURSIVE);
53 ViewMonitor::~ViewMonitor()
55 pthread_mutex_destroy(&
mutex);
65 static bool glut_initialized =
false;
67 static bool glew_initialized =
false;
81 typedef int(*CTC_FUNC)(
void*);
82 static CTC_FUNC ctc_function =
nullptr;
83 static void* ctc_param;
84 static int ctc_result;
86 static std::map<int, View*> view_instances;
93 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) {};
99 bool destroy_glut_window;
100 RemoveParams(
int view_id,
bool destroy_glut_window) : view_id(view_id), destroy_glut_window(destroy_glut_window) {};
106 TitleParams(
int view_id,
const char* title) : view_id(view_id), title(title) {};
110 static void* view_thread_func(
void* param)
124 if (thread_info->should_quit)
129 if (ctc_function !=
nullptr)
131 ctc_result = ctc_function(ctc_param);
132 ctc_function =
nullptr;
154 static bool need_safe_call() {
return pthread_equal(view_thread->thread, pthread_self()) == 0; }
157 static int call_in_thread(CTC_FUNC func,
void* param)
161 if (view_thread ==
nullptr)
163 ThreadInfo* new_thread_info =
nullptr;
164 try { new_thread_info =
new ThreadInfo(); }
165 catch (std::bad_alloc&) {
throw Hermes::Exceptions::Exception(
"Failed to allocate structure for view thread"); }
166 int err = pthread_create(&new_thread_info->thread,
nullptr, view_thread_func, new_thread_info);
169 delete new_thread_info;
170 throw Hermes::Exceptions::Exception(
"Failed to create main thread, error: %d", err);
172 view_thread = new_thread_info;
177 if (need_safe_call())
183 int result = ctc_result;
192 static int set_view_title_in_thread(
void* title_pars_ptr)
194 TitleParams& title_params = *((TitleParams*)title_pars_ptr);
195 std::map<int, View*>::iterator found_view = view_instances.find(title_params.view_id);
196 if (found_view == view_instances.end())
198 throw Exceptions::Exception(
"Settings title of a view that is not registered.");
203 glutSetWindow(title_params.view_id);
204 glutSetWindowTitle(title_params.title);
210 int add_view_in_thread(
void* view_pars_ptr)
212 ViewParams& view_params = *((ViewParams*)view_pars_ptr);
215 glutInitWindowPosition(view_params.x, view_params.y);
216 glutInitWindowSize(view_params.width, view_params.height);
217 int view_id = glutCreateWindow(view_params.title);
218 glutSetWindowData(view_params.view);
221 GLenum err = glewInit();
223 throw Exceptions::Exception(
"GLEW error: %s", glewGetErrorString(err));
224 glew_initialized =
true;
227 glutDisplayFunc(on_display_stub);
228 glutReshapeFunc(on_reshape_stub);
229 glutMotionFunc(on_mouse_move_stub);
230 glutPassiveMotionFunc(on_mouse_move_stub);
231 glutMouseFunc(on_mouse_click_stub);
232 glutKeyboardFunc(on_key_down_stub);
233 glutSpecialFunc(on_special_key_stub);
234 glutEntryFunc(on_entry_stub);
235 glutCloseFunc(on_close_stub);
238 view_instances[view_id] = view_params.view;
241 view_params.view->on_create(view_id);
247 int remove_view_in_thread(
void* remove_params_ptr)
249 RemoveParams& params = *(RemoveParams*)remove_params_ptr;
250 std::map<int, View*>::iterator found_view = view_instances.find(params.view_id);
251 if (found_view == view_instances.end())
253 throw Exceptions::Exception(
"Removing of a view that is not registered");
258 if (params.destroy_glut_window)
261 glutSetWindow(params.view_id);
263 glutSetWindowData(
nullptr);
266 found_view->second->on_close();
269 glutDestroyWindow(params.view_id);
273 view_instances.erase(found_view);
276 if (view_instances.empty())
278 view_thread->should_quit =
true;
279 view_thread =
nullptr;
291 static int refresh_view_in_thread(
void* view_id_ptr)
293 int view_id = *((
int*)view_id_ptr);
294 std::map<int, View*>::iterator found_view = view_instances.find(view_id);
295 if (found_view == view_instances.end())
296 throw Exceptions::Exception(
"Refreshing a view that is not registered");
299 if (found_view != view_instances.end())
301 glutSetWindow(view_id);
310 static long double_click_delay_ms = 300;
312 #define STUB_GET_VIEW() View* wnd = (View*)glutGetWindowData()
313 #define STUB_CALL(__call) STUB_GET_VIEW(); if(wnd != nullptr) __call;
315 void on_display_stub(
void) { STUB_CALL(wnd->pre_display()); }
316 void on_reshape_stub(
int width,
int height) { STUB_CALL(wnd->on_reshape(width, height)); }
317 void on_mouse_move_stub(
int x,
int y) { STUB_CALL(wnd->on_mouse_move(x, y)); }
318 void on_key_down_stub(
unsigned char key,
int x,
int y) { STUB_CALL(wnd->on_key_down(key, x, y)); }
319 void on_special_key_stub(
int key,
int x,
int y) { STUB_CALL(wnd->on_special_key(key, x, y)); }
320 void on_entry_stub(
int state) { STUB_CALL(wnd->on_entry(state)); }
321 void on_mouse_click_stub(
int button,
int state,
int x,
int y)
328 if (state == GLUT_DOWN)
330 static double last_tick = 0;
333 if (tick - last_tick < double_click_delay_ms)
335 if (button == GLUT_LEFT_BUTTON)
336 wnd->on_left_mouse_double_click(x, y);
337 else if (button == GLUT_RIGHT_BUTTON)
338 wnd->on_right_mouse_double_click(x, y);
340 wnd->on_middle_mouse_double_click(x, y);
349 if (button == GLUT_LEFT_BUTTON)
351 if (state == GLUT_DOWN)
352 wnd->on_left_mouse_down(x, y);
354 wnd->on_left_mouse_up(x, y);
356 else if (button == GLUT_RIGHT_BUTTON)
358 if (state == GLUT_DOWN)
359 wnd->on_right_mouse_down(x, y);
361 wnd->on_right_mouse_up(x, y);
365 if (state == GLUT_DOWN)
366 wnd->on_middle_mouse_down(x, y);
368 wnd->on_middle_mouse_up(x, y);
382 RemoveParams params(glutGetWindow(),
false);
383 remove_view_in_thread(¶ms);
392 static const char* argv[1] = {
"x" };
395 if (!glut_initialized)
397 glutInit(&argc, (
char**)argv);
398 glut_initialized =
true;
400 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ACCUM);
401 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
405 double_click_delay_ms = GetDoubleClickTime();
421 call_in_thread(set_view_title_in_thread, ¶ms);
424 int add_view(
View* view,
int x,
int y,
int width,
int height,
const char* title)
426 ViewParams params(view, x, y, width, height, title);
427 return call_in_thread(add_view_in_thread, ¶ms);
430 void refresh_view(
int view_id) { call_in_thread(refresh_view_in_thread, &view_id); }
435 call_in_thread(remove_view_in_thread, ¶ms);
438 void force_view_thread_shutdown()
440 pthread_t current_thread;
441 bool should_wait =
false;
446 std::map<int, View*>::const_iterator iter = view_instances.begin();
447 while (iter != view_instances.end())
449 glutDestroyWindow(iter->first);
452 view_instances.clear();
455 if (view_thread !=
nullptr)
457 current_thread = view_thread->thread;
458 view_thread->should_quit =
true;
459 view_thread =
nullptr;
466 glew_initialized =
false;
467 pthread_join(current_thread,
nullptr);
473 pthread_t current_thread;
474 bool should_wait =
false;
478 if (view_thread !=
nullptr)
480 current_thread = view_thread->thread;
488 fprintf(stdout,
"%s", text); fflush(stdout);
489 pthread_join(current_thread,
nullptr);
497 if (view_thread !=
nullptr)
499 fprintf(stdout,
"%s", text); fflush(stdout);
void refresh_view(int view_id)
Forces redisplay of a view.
void remove_view(int view_id)
Removes a view.
pthread_cond_t cond_drawing_finished
Condition used to signal that drawing has finished.
pthread_mutex_t mutex
Mutex that protects monitor.
Represents a simple visualization window.
void signal_drawing_finished()
signals drawing finished inside a protected section
Common definitions for Hermes2D.
void signal_close()
signals close inside a protected section
void leave()
leaves protected section
File containing View abstract class.
void enter()
enters protected section
ViewMonitor view_sync
synchronization between all views. Used to access OpenGL and signal a window close event and a keypre...
int add_view(View *view, int x, int y, int width, int height, const char *title)
Adds a view.
void wait_for_any_key(const char *text)
Waits for a keypress which is not processed.
void wait_keypress()
waits for keypress inside a protected section
pthread_cond_t cond_cross_thread_call
Condition used to signal a cross-thread call.
void signal_keypress()
signals keypress inside a protected section
void wait_cross_thread_call()
waits for finishing of a cross-thread call
void signal_cross_thread_call()
signals that cross-thread-call finished
static double get_tick_count()
returns a current time[in ms]
HERMES_API bool init_glut()
Initialize GLUT.
pthread_cond_t cond_close
Condition used to signal close of a window.
< A monitor used to synchronize thread in views.
void wait_for_all_views_close(const char *text)
Forces view thread to shutdown.
pthread_cond_t cond_keypress
Condition used to signal a keypress.
void set_view_title(int view_id, const char *title)
Sets title of a view.
pthread_mutexattr_t mutex_attr
Mutext attributes.
HERMES_API bool shutdown_glut()
Shutdown GLUT.