Update Turkish translation
[dasher.git] / Src / Gtk2 / DasherControl.cpp
blob81974d679b222aab4b60615500e30750812b6dd9
1 #include "../Common/Common.h"
2 #ifdef HAVE_CONFIG_H
3 #include <config.h>
4 #endif
6 #include <cstring>
7 #include <iostream>
8 #include "DasherControl.h"
9 #include "Timer.h"
10 #include "../DasherCore/Event.h"
11 #include "../DasherCore/ModuleManager.h"
12 #include "dasher_main.h"
13 #include "../DasherCore/GameModule.h"
14 #include "../Common/Globber.cpp"
16 #include <fcntl.h>
18 #include <gtk/gtk.h>
19 #include <gdk/gdk.h>
20 #include <gdk/gdkkeysyms.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 using namespace std;
25 // 'Private' methods (only used in this file)
26 extern "C" gint key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
27 extern "C" gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data);
28 extern "C" void realize_canvas(GtkWidget *widget, gpointer user_data);
29 extern "C" gint canvas_configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
30 extern "C" gint key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data);
31 extern "C" void canvas_destroy_event(GtkWidget *pWidget, gpointer pUserData);
32 extern "C" gboolean canvas_focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
33 #ifdef HAVE_GTK_CAIRO_SHOULD_DRAW_WINDOW
34 extern "C" gint canvas_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data);
35 #else
36 extern "C" gint canvas_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data);
37 #endif
39 static bool g_iTimeoutID = 0;
41 // CDasherControl class definitions
42 CDasherControl::CDasherControl(GtkVBox *pVBox, GtkDasherControl *pDasherControl,
43 CSettingsStore* settings)
44 : CDashIntfScreenMsgs(settings, &file_utils_) {
45 m_pScreen = NULL;
47 m_pDasherControl = pDasherControl;
48 m_pVBox = GTK_WIDGET(pVBox);
49 pClipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
50 m_pCanvas = gtk_drawing_area_new();
51 #if GTK_CHECK_VERSION (2,18,0)
52 gtk_widget_set_can_focus(m_pCanvas, TRUE);
53 #else
54 GTK_WIDGET_SET_FLAGS(m_pCanvas, GTK_CAN_FOCUS);
55 #endif
56 gtk_widget_set_double_buffered(m_pCanvas, FALSE);
58 GtkWidget *pFrame = gtk_frame_new(NULL);
59 gtk_frame_set_shadow_type(GTK_FRAME(pFrame), GTK_SHADOW_IN);
60 gtk_container_add(GTK_CONTAINER(pFrame), m_pCanvas);
62 gtk_box_pack_start(GTK_BOX(m_pVBox), pFrame, TRUE, TRUE, 0);
63 gtk_widget_show_all(GTK_WIDGET(m_pVBox));
65 // Connect callbacks - note that we need to implement the callbacks
66 // as "C" style functions and pass this as user data so they can
67 // call the object
69 g_signal_connect(m_pCanvas, "button_press_event", G_CALLBACK(button_press_event), this);
70 g_signal_connect(m_pCanvas, "button_release_event", G_CALLBACK(button_press_event), this);
71 g_signal_connect_after(m_pCanvas, "realize", G_CALLBACK(realize_canvas), this);
72 g_signal_connect(m_pCanvas, "configure_event", G_CALLBACK(canvas_configure_event), this);
73 g_signal_connect(m_pCanvas, "destroy", G_CALLBACK(canvas_destroy_event), this);
75 g_signal_connect(m_pCanvas, "key-release-event", G_CALLBACK(key_release_event), this);
76 g_signal_connect(m_pCanvas, "key_press_event", G_CALLBACK(key_press_event), this);
78 g_signal_connect(m_pCanvas, "focus_in_event", G_CALLBACK(canvas_focus_event), this);
79 #ifdef HAVE_GTK_CAIRO_SHOULD_DRAW_WINDOW
80 g_signal_connect(m_pCanvas, "draw", G_CALLBACK(canvas_draw_event), this);
81 #else
82 g_signal_connect(m_pCanvas, "expose_event", G_CALLBACK(canvas_expose_event), this);
83 #endif
85 char *home_dir = getenv("HOME");
86 char *user_data_dir = new char[strlen(home_dir) + 10];
87 sprintf(user_data_dir, "%s/.dasher/", home_dir);
88 m_user_data_dir = user_data_dir;
90 m_pScreen = new CCanvas(m_pCanvas);
91 ChangeScreen(m_pScreen);
93 //This was done in old SetupUI, i.e. the first thing in Realize().
94 // TODO: Use system defaults?
95 if(GetStringParameter(SP_DASHER_FONT) == "")
96 SetStringParameter(SP_DASHER_FONT, "Sans 10");
97 else
98 m_pScreen->SetFont(GetStringParameter(SP_DASHER_FONT));
99 Realize(get_time());
101 // m_pKeyboardHelper = new CKeyboardHelper(this);
102 // m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
105 void CDasherControl::CreateModules() {
106 CDasherInterfaceBase::CreateModules(); //create default set first
107 // Create locally cached copies of the mouse input objects, as we
108 // need to pass coordinates to them from the timer callback
109 m_pMouseInput =
110 (CDasherMouseInput *) RegisterModule(new CDasherMouseInput());
111 SetDefaultInputDevice(m_pMouseInput);
112 m_p1DMouseInput =
113 (CDasher1DMouseInput *)RegisterModule(new CDasher1DMouseInput());
114 RegisterModule(new CSocketInput(this, this));
116 #ifdef JOYSTICK
117 RegisterModule(new CDasherJoystickInput(this));
118 RegisterModule(new CDasherJoystickInputDiscrete(this));
119 #endif
121 #ifdef TILT
122 RegisterModule(new CDasherTiltInput(this));
123 #endif
127 void CDasherControl::ClearAllContext() {
128 gtk_dasher_control_clear_all_context(m_pDasherControl);
129 //SetBuffer(0); //the editor's clear method emits a "buffer_changed" signal,
130 //which does this for us automatically.
133 std::string CDasherControl::GetAllContext() {
134 return gtk_dasher_control_get_all_text(m_pDasherControl);
137 int CDasherControl::GetAllContextLenght()
139 auto text = gtk_dasher_control_get_all_text(m_pDasherControl);
140 return g_utf8_strlen(text.c_str(),-1);
143 std::string CDasherControl::GetTextAroundCursor(CControlManager::EditDistance dist) {
144 return gtk_dasher_control_get_text_around_cursor(m_pDasherControl, dist);
147 std::string CDasherControl::GetContext(unsigned int iStart, unsigned int iLength) {
148 return gtk_dasher_control_get_context(m_pDasherControl, iStart, iLength);
151 bool CDasherControl::SupportsClipboard() {
152 return true;
155 void CDasherControl::CopyToClipboard(const std::string &strText) {
156 const gchar *the_text(strText.c_str());
157 gtk_clipboard_set_text(pClipboard, the_text, strlen(the_text));
160 #ifdef WITH_SPEECH
161 bool CDasherControl::SupportsSpeech() {
162 return m_Speech.Init();
165 void CDasherControl::Speak(const std::string &strText, bool bInterrupt) {
166 string lang = GetActiveAlphabet()->GetLanguageCode();
167 m_Speech.Speak(strText, bInterrupt, lang);
169 #endif
171 CDasherControl::~CDasherControl() {
172 if(m_pMouseInput) {
173 m_pMouseInput = NULL;
176 if(m_p1DMouseInput) {
177 m_p1DMouseInput = NULL;
180 delete[] m_user_data_dir;
182 // if(m_pKeyboardHelper) {
183 // delete m_pKeyboardHelper;
184 // m_pKeyboardHelper = 0;
185 // }
188 bool CDasherControl::FocusEvent(GtkWidget *pWidget, GdkEventFocus *pEvent) {
189 if((pEvent->type == GDK_FOCUS_CHANGE) && (pEvent->in)) {
190 GdkEventFocus *focusEvent = (GdkEventFocus *) g_malloc(sizeof(GdkEventFocus));
191 gboolean *returnType;
193 focusEvent->type = GDK_FOCUS_CHANGE;
194 focusEvent->window = (GdkWindow *) m_pDasherControl;
195 focusEvent->send_event = FALSE;
196 focusEvent->in = TRUE;
198 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "focus_in_event", GTK_WIDGET(m_pDasherControl), focusEvent, NULL, &returnType);
200 return true;
203 void CDasherControl::SetFocus() {
204 gtk_widget_grab_focus(m_pCanvas);
207 GArray *CDasherControl::GetAllowedValues(int iParameter) {
208 // Glib version of the STL based core function
210 GArray *pRetVal(g_array_new(false, false, sizeof(gchar *)));
212 std::vector < std::string > vList;
213 GetPermittedValues(iParameter, vList);
215 for(std::vector < std::string >::iterator it(vList.begin()); it != vList.end(); ++it) {
216 // For internal glib reasons we need to make a variable and then
217 // pass - we can't use the iterator directly
218 const char *pTemp(it->c_str());
219 char *pTempNew = new char[strlen(pTemp) + 1];
220 strcpy(pTempNew, pTemp);
221 g_array_append_val(pRetVal, pTempNew);
224 return pRetVal;
227 void CDasherControl::RealizeCanvas(GtkWidget *pWidget) {
228 // TODO: Pointless function - call directly from C callback.
229 #ifdef DEBUG
230 std::cout << "RealizeCanvas()" << std::endl;
231 #endif
232 // Start the timer loops as everything is set up.
233 // Aim for 40 frames per second, computers are getting faster.
235 if(g_iTimeoutID == 0) {
236 g_iTimeoutID = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 25, timer_callback, this, NULL);
237 // TODO: Reimplement this (or at least reimplement some kind of status reporting)
238 //g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 5000, long_timer_callback, this, NULL);
242 int CDasherControl::CanvasConfigureEvent() {
243 GtkAllocation a;
245 #if GTK_CHECK_VERSION (2,18,0)
246 gtk_widget_get_allocation(m_pCanvas, &a);
247 #else
248 a.width = m_pCanvas->allocation.width;
249 a.height = m_pCanvas->allocation.height;
250 #endif
252 m_pScreen->resize(a.width,a.height);
253 ScreenResized(m_pScreen);
255 return 0;
258 void CDasherControl::HandleEvent(int iParameter) {
259 CDashIntfScreenMsgs::HandleEvent(iParameter);
260 switch(iParameter) {
261 case SP_DASHER_FONT:
262 m_pScreen->SetFont(GetStringParameter(SP_DASHER_FONT));
263 ScheduleRedraw();
264 break;
265 case BP_GLOBAL_KEYBOARD:
266 // TODO: reimplement
267 // if(m_pKeyboardHelper)
268 // m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
269 break;
271 // Convert events coming from the core to Glib signals.
272 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_changed", iParameter);
275 void CDasherControl::editOutput(const std::string &strText, CDasherNode *pNode) {
276 if (!GetGameModule()) //GameModule sets editbox directly
277 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_edit_insert", strText.c_str(), pNode->offset());
278 CDasherInterfaceBase::editOutput(strText, pNode);
281 void CDasherControl::editDelete(const std::string &strText, CDasherNode *pNode) {
282 if (!GetGameModule()) //GameModule sets editbox directly
283 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_edit_delete", strText.c_str(), pNode->offset());
284 CDasherInterfaceBase::editDelete(strText, pNode);
287 void CDasherControl::editConvert(CDasherNode *pNode) {
288 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_edit_convert");
289 CDasherInterfaceBase::editConvert(pNode);
292 void CDasherControl::editProtect(CDasherNode *pNode) {
293 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_edit_protect");
294 CDasherInterfaceBase::editProtect(pNode);
297 void CDasherControl::SetLockStatus(const string &strText, int iPercent) {
298 DasherLockInfo sInfo;
299 sInfo.szMessage = strText.c_str();
300 sInfo.iPercent = iPercent;
301 sInfo.time = get_time();
303 //Uniquely, the call to gtk to handle events and update the progress
304 // dialogue, also renders the canvas. So let's have a message there too...
305 CDasherInterfaceBase::SetLockStatus(strText,iPercent);
306 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_lock_info", &sInfo);
309 //TODO do we want to do something like this?
310 // ATM the only message is actually from the auto-speed control,
311 // so definitely _doesn't_ want to be modal; could introduce a boolean
312 // 'ok to interrupt user?' param to Message()?
313 //void CDasherControl::Message(const std::string &strText)
314 // GtkMessageDialog *pDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(0, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, strText.c_str()));
315 // gtk_dialog_run(GTK_DIALOG(pDialog));
316 // gtk_widget_destroy(GTK_WIDGET(pDialog));
319 unsigned int CDasherControl::ctrlMove(bool bForwards, CControlManager::EditDistance dist) {
320 return gtk_dasher_control_ctrl_move(m_pDasherControl,bForwards,dist);
323 unsigned int CDasherControl::ctrlDelete(bool bForwards, CControlManager::EditDistance dist) {
324 return gtk_dasher_control_ctrl_delete(m_pDasherControl,bForwards,dist);
327 class GtkGameModule : public CGameModule {
328 public:
329 GtkGameModule(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CDasherView *pView, CDasherModel *pModel, GtkTextBuffer *pBuffer)
330 : CGameModule(pCreator, pInterface, pView, pModel), m_pBuffer(pBuffer) {
331 m_tEntered = gtk_text_buffer_create_tag(m_pBuffer, "entered", "foreground", "#00FF00", NULL);
332 m_tWrong = gtk_text_buffer_create_tag(m_pBuffer, "wrong", "foreground", "#FF0000", "strikethrough", TRUE, NULL);
333 GtkTextIter start,end;
334 gtk_text_buffer_get_start_iter(m_pBuffer, &start);
335 m_mEntered = gtk_text_buffer_create_mark(m_pBuffer, NULL, &start, true);
336 gtk_text_buffer_get_end_iter(m_pBuffer, &end);
337 m_mTarget = gtk_text_buffer_create_mark(m_pBuffer, NULL, &end, false);
338 gtk_text_buffer_delete(m_pBuffer, &start, &end);
341 ~GtkGameModule() {
342 GtkTextTagTable *table = gtk_text_buffer_get_tag_table(m_pBuffer);
343 gtk_text_tag_table_remove(table, m_tEntered);
344 gtk_text_tag_table_remove(table, m_tWrong);
346 gtk_text_buffer_delete_mark(m_pBuffer,m_mEntered);
347 gtk_text_buffer_delete_mark(m_pBuffer,m_mTarget);
350 void ChunkGenerated() {
351 string sText;
352 for (vector<symbol>::const_iterator it=targetSyms().begin(); it!=targetSyms().end(); it++)
353 sText += m_pAlph->GetText(*it);
354 gtk_text_buffer_set_text(m_pBuffer, sText.c_str(), -1); //-1 for length = null-terminated
355 GtkTextIter start,end;
356 gtk_text_buffer_get_start_iter(m_pBuffer, &start);
357 gtk_text_buffer_move_mark(m_pBuffer, m_mEntered, &start);
358 gtk_text_buffer_move_mark(m_pBuffer, m_mTarget, &start);
359 gtk_text_buffer_get_end_iter(m_pBuffer, &end);
360 gtk_text_buffer_remove_all_tags(m_pBuffer, &start, &end);
362 void HandleEvent(const Dasher::CEditEvent *pEvt) {
363 const int iPrev(lastCorrectSym());
364 CGameModule::HandleEvent(pEvt);
365 if (iPrev==lastCorrectSym()) {
366 GtkTextIter start,end; //of "wrong" text
367 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &start, m_mEntered);
368 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &end, m_mTarget);
369 gtk_text_buffer_delete(m_pBuffer, &start, &end); //invalidates end, brings m_mEntered & m_mTarget together
370 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &start, m_mEntered);
371 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &end, m_mTarget);
372 gtk_text_buffer_insert(m_pBuffer, &start, m_strWrong.c_str(), -1); //moves m_mEntered & m_mTarget apart
373 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &start, m_mEntered);
374 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &end, m_mTarget);
375 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &end, m_mTarget);
376 gtk_text_buffer_apply_tag(m_pBuffer, m_tWrong, &start, &end);
377 } else {
378 GtkTextIter it,it2;
379 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &it, m_mEntered);
380 gtk_text_buffer_get_iter_at_mark(m_pBuffer, &it2, m_mTarget);
381 DASHER_ASSERT(gtk_text_iter_get_offset(&it) == gtk_text_iter_get_offset(&it2));
382 if (iPrev < lastCorrectSym()) {
383 //correct text added
384 DASHER_ASSERT(iPrev == lastCorrectSym()-1);
385 gtk_text_iter_forward_chars(&it2, 1);
386 gtk_text_buffer_apply_tag(m_pBuffer, m_tEntered, &it, &it2);
387 } else {
388 //correct text erased!
389 DASHER_ASSERT(iPrev == lastCorrectSym()+1);
390 gtk_text_iter_backward_chars(&it2, 1);
391 gtk_text_buffer_remove_tag(m_pBuffer, m_tEntered, &it2, &it);
393 gtk_text_buffer_move_mark(m_pBuffer, m_mEntered, &it2);
394 gtk_text_buffer_move_mark(m_pBuffer, m_mTarget, &it2);
397 void DrawText(CDasherView *pView) {}
398 private:
399 GtkTextBuffer *m_pBuffer;
400 GtkTextTag *m_tEntered, *m_tWrong;
401 GtkTextMark *m_mEntered; //just after what's been correctly entered
402 GtkTextMark *m_mTarget; //after any "wrong" text, before target; if no wrong chars, ==m_entered.
405 CGameModule *CDasherControl::CreateGameModule() {
406 if (GtkTextBuffer *buf=gtk_dasher_control_game_text_buffer(m_pDasherControl))
407 return new GtkGameModule(this, this, GetView(), m_pDasherModel, buf);
408 return CDashIntfScreenMsgs::CreateGameModule();
411 // TODO: Sort these methods out
412 void CDasherControl::ExternalKeyDown(int iKeyVal) {
413 // if(m_pKeyboardHelper) {
414 // int iButtonID(m_pKeyboardHelper->ConvertKeycode(iKeyVal));
416 // if(iButtonID != -1)
417 // KeyDown(get_time(), iButtonID);
418 // }
419 KeyDown(get_time(), iKeyVal);
422 void CDasherControl::ExternalKeyUp(int iKeyVal) {
423 // if(m_pKeyboardHelper) {
424 // int iButtonID(m_pKeyboardHelper->ConvertKeycode(iKeyVal));
426 // if(iButtonID != -1)
427 // KeyUp(get_time(), iButtonID);
428 // }
429 KeyUp(get_time(), iKeyVal);
432 int CDasherControl::TimerEvent() {
433 int x, y;
434 GdkWindow *default_root_window = gdk_get_default_root_window();
435 GdkWindow *window = gtk_widget_get_window(m_pCanvas);
437 #if GTK_CHECK_VERSION (3,0,0)
438 GdkDeviceManager *device_manager =
439 gdk_display_get_device_manager(gdk_window_get_display(window));
440 GdkDevice *pointer = gdk_device_manager_get_client_pointer(device_manager);
442 gdk_window_get_device_position(window, pointer, &x, &y, NULL);
443 #else
444 gdk_window_get_pointer(window, &x, &y, NULL);
445 #endif
446 m_pMouseInput->SetCoordinates(x, y);
448 #if GTK_CHECK_VERSION (3,0,0)
449 gdk_window_get_device_position(default_root_window, pointer, &x, &y, NULL);
450 #else
451 gdk_window_get_pointer(default_root_window, &x, &y, NULL);
452 #endif
454 int iRootWidth;
455 int iRootHeight;
457 #ifdef HAVE_GDK_WINDOW_GET_WIDTH
458 iRootWidth = gdk_window_get_width (default_root_window);
459 iRootHeight = gdk_window_get_height(default_root_window);
460 #else
461 gdk_drawable_get_size(default_root_window, &iRootWidth, &iRootHeight);
462 #endif
464 if(GetLongParameter(LP_YSCALE) < 10)
465 SetLongParameter(LP_YSCALE, 10);
467 y = (y - iRootHeight / 2);
469 m_p1DMouseInput->SetCoordinates(y, GetLongParameter(LP_YSCALE));
471 NewFrame(get_time(), false);
473 // Update our UserLog object about the current mouse position
474 CUserLogBase* pUserLog = GetUserLogPtr();
475 if (pUserLog != NULL) {
476 // We want current canvas and window coordinates so normalization
477 // is done properly with respect to the canvas.
478 GdkRectangle sWindowRect;
479 GdkRectangle sCanvasRect;
481 gdk_window_get_frame_extents(window, &sWindowRect);
483 pUserLog->AddWindowSize(sWindowRect.y,
484 sWindowRect.x,
485 sWindowRect.y + sWindowRect.height,
486 sWindowRect.x + sWindowRect.width);
488 if (m_pScreen != NULL) {
489 if (m_pScreen->GetCanvasSize(&sCanvasRect))
490 pUserLog->AddCanvasSize(sCanvasRect.y,
491 sCanvasRect.x,
492 sCanvasRect.y + sCanvasRect.height,
493 sCanvasRect.x + sCanvasRect.width);
496 int iMouseX = 0;
497 int iMouseY = 0;
498 #if GTK_CHECK_VERSION (3,0,0)
499 gdk_window_get_device_position(NULL, pointer, &iMouseX, &iMouseY, NULL);
500 #else
501 gdk_window_get_pointer(NULL, &iMouseX, &iMouseY, NULL);
502 #endif
504 // TODO: This sort of thing shouldn't be in specialised methods, move into base class somewhere
505 pUserLog->AddMouseLocationNormalized(iMouseX, iMouseY, true, GetNats());
508 return 1;
510 // See CVS for code which used to be here
513 int CDasherControl::LongTimerEvent() {
514 // std::cout << "Framerate: " << GetFramerate() << std::endl;
515 // std::cout << "Render count: " << GetRenderCount() << std::endl;
516 return 1;
519 gboolean CDasherControl::ExposeEvent() {
520 NewFrame(get_time(), true);
521 return 0;
524 void CDasherControl::Done() {
525 CDasherInterfaceBase::Done();
526 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_stop");
529 gboolean CDasherControl::ButtonPressEvent(GdkEventButton *event) {
531 // Take the focus if we click on the canvas
533 // GdkEventFocus *focusEvent = (GdkEventFocus *) g_malloc(sizeof(GdkEventFocus));
534 // gboolean *returnType;
536 // focusEvent->type = GDK_FOCUS_CHANGE;
537 // focusEvent->window = (GdkWindow *) m_pCanvas;
538 // focusEvent->send_event = FALSE;
539 // focusEvent->in = TRUE;
541 // gtk_widget_grab_focus(GTK_WIDGET(m_pCanvas));
542 // g_signal_emit_by_name(GTK_WIDGET(m_pCanvas), "focus_in_event", GTK_WIDGET(m_pCanvas), focusEvent, NULL, &returnType);
544 // No - don't take the focus - give it to the text area instead
546 //GDK uses button 1=left, 2=middle, 3=right. We want 100, 102, 101
547 int button = event->button;
548 if (button&2) button^=1;
549 if(event->type == GDK_BUTTON_PRESS)
550 KeyDown(get_time(), button+99 );
551 else if(event->type == GDK_BUTTON_RELEASE)
552 KeyUp(get_time(), button+99);
554 return false;
557 gint CDasherControl::KeyReleaseEvent(GdkEventKey *event) {
558 // TODO: This is seriously flawed - the semantics of of X11 Keyboard
559 // events mean the there's no guarantee that key up/down events will
560 // be received in pairs.
562 // if((event->keyval == GDK_Shift_L) || (event->keyval == GDK_Shift_R)) {
563 // if(event->state & GDK_CONTROL_MASK)
564 // SetLongParameter(LP_BOOSTFACTOR, 25);
565 // else
566 // SetLongParameter(LP_BOOSTFACTOR, 100);
567 // }
568 // else if((event->keyval == GDK_Control_L) || (event->keyval == GDK_Control_R)) {
569 // if(event->state & GDK_SHIFT_MASK)
570 // SetLongParameter(LP_BOOSTFACTOR, 175);
571 // else
572 // SetLongParameter(LP_BOOSTFACTOR, 100);
573 // }
574 // else {
575 // if(m_pKeyboardHelper) {
576 // int iKeyVal(m_pKeyboardHelper->ConvertKeycode(event->keyval));
578 // if(iKeyVal != -1)
579 // KeyUp(get_time(), iKeyVal);
580 // }
581 // }
583 return 0;
586 gint CDasherControl::KeyPressEvent(GdkEventKey *event) {
587 // if((event->keyval == GDK_Shift_L) || (event->keyval == GDK_Shift_R))
588 // SetLongParameter(LP_BOOSTFACTOR, 175);
589 // else if((event->keyval == GDK_Control_L) || (event->keyval == GDK_Control_R))
590 // SetLongParameter(LP_BOOSTFACTOR, 25);
591 // else {
592 // if(m_pKeyboardHelper) {
593 // int iKeyVal(m_pKeyboardHelper->ConvertKeycode(event->keyval));
595 // if(iKeyVal != -1)
596 // KeyDown(get_time(), iKeyVal);
597 // }
598 // }
599 return 0;
602 void CDasherControl::CanvasDestroyEvent() {
603 // Delete the screen
605 if(m_pScreen != NULL) {
606 delete m_pScreen;
607 m_pScreen = NULL;
611 // Tell the logging object that a new user trial is starting.
612 void CDasherControl::UserLogNewTrial()
614 CUserLogBase* pUserLog = GetUserLogPtr();
615 if (pUserLog != NULL) {
616 pUserLog->NewTrial();
620 // "C" style callbacks - these are here just because it's not possible
621 // (or at least not easy) to connect a callback directly to a C++
622 // method, so we pass a pointer to th object in the user_data field
623 // and use a wrapper function. Please do not put any functional code
624 // here.
626 extern "C" void realize_canvas(GtkWidget *widget, gpointer user_data) {
627 static_cast < CDasherControl * >(user_data)->RealizeCanvas(widget);
631 extern "C" gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) {
632 return static_cast < CDasherControl * >(data)->ButtonPressEvent(event);
635 extern "C" gint key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data) {
636 return static_cast < CDasherControl * >(data)->KeyPressEvent(event);
639 extern "C" gint canvas_configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data) {
640 return static_cast < CDasherControl * >(data)->CanvasConfigureEvent();
643 extern "C" void canvas_destroy_event(GtkWidget *pWidget, gpointer pUserData) {
644 static_cast<CDasherControl*>(pUserData)->CanvasDestroyEvent();
647 extern "C" gint key_release_event(GtkWidget *pWidget, GdkEventKey *event, gpointer pUserData) {
648 return static_cast<CDasherControl*>(pUserData)->KeyReleaseEvent(event);
651 extern "C" gboolean canvas_focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
652 return static_cast < CDasherControl * >(data)->FocusEvent(widget, event);
655 #ifdef HAVE_GTK_CAIRO_SHOULD_DRAW_WINDOW
656 extern "C" gint canvas_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) {
657 #else
658 extern "C" gint canvas_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
659 #endif
660 return ((CDasherControl*)data)->ExposeEvent();