Updated Polish translation
[dasher.git] / Src / Gtk2 / dasher_main.cpp
blob575201c865037739d193bd815d5ed8f6636d097a
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
5 #include <cstring>
6 #include <utility>
7 #include <gdk/gdk.h>
8 #include <gdk/gdkx.h>
9 #include <glib/gi18n.h>
10 #include <gtk/gtk.h>
11 #ifdef WITH_MAEMOFULLSCREEN
12 #include <hildon-widgets/hildon-program.h>
13 #endif
14 #include <unistd.h>
16 #include "GtkDasherControl.h"
17 #include "dasher_lock_dialogue.h"
18 #ifdef WITH_MAEMO
19 #include "dasher_maemo_helper.h"
20 #endif
21 #include "dasher_main.h"
23 #include "dasher_editor.h"
24 #include "dasher_editor_internal.h"
25 #include "dasher_editor_external.h"
26 #include "math.h"
28 struct _DasherMainPrivate {
29 GtkBuilder *pXML;
30 GtkBuilder *pPrefXML;
32 // Child objects owned here
33 DasherAppSettings *pAppSettings;
34 DasherPreferencesDialogue *pPreferencesDialogue;
35 DasherEditor *pEditor;
37 CKeyboardHelper *pKeyboardHelper;
39 // Various widgets which need to be cached:
40 // GtkWidget *pBufferView;
41 GtkPaned *pDivider;
42 GtkWindow *pMainWindow;
43 GtkWidget *pToolbar;
44 GtkSpinButton *pSpeedBox;
45 GtkWidget *pAlphabetCombo;
46 GtkWidget *pStatusControl;
47 GtkWidget *pDasherWidget;
49 GtkListStore *pAlphabetList;
50 GtkAccelGroup *pAccel;
52 // Widgets used for maemo
53 #ifdef WITH_MAEMO
54 DasherMaemoHelper *pMaemoHelper;
55 #ifdef WITH_MAEMOFULLSCREEN
56 HildonProgram *pProgram;
57 HildonWindow *pHWindow;
58 #endif
59 #endif
61 // Properties of the main window
62 int iWidth;
63 int iHeight;
64 bool bWidgetsInitialised;
67 typedef struct _DasherMainPrivate DasherMainPrivate;
69 // TODO: Make sure this is actually used
70 #define DASHER_MAIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), DASHER_TYPE_MAIN, DasherMainPrivate))
72 enum {
73 REALIZED,
74 SIGNAL_NUM
77 static guint dasher_main_signals[SIGNAL_NUM] = { 0 };
79 G_DEFINE_TYPE(DasherMain, dasher_main, G_TYPE_OBJECT);
81 static void dasher_main_finalize(GObject *pObject);
83 /* Private member functions */
84 static void dasher_main_setup_window_state(DasherMain *pSelf);
85 static void dasher_main_setup_window_style(DasherMain *pSelf);
86 static void dasher_main_setup_internal_layout(DasherMain *pSelf);
87 static void dasher_main_set_window_title(DasherMain *pSelf);
89 /* ... Table based menu/toolbar commands */
90 static void dasher_main_command_import(DasherMain *pSelf);
91 static void dasher_main_command_quit(DasherMain *pSelf);
92 static void dasher_main_command_preferences(DasherMain *pSelf);
93 static void dasher_main_command_preferences_alphabet(DasherMain *pSelf);
94 static void dasher_main_command_help(DasherMain *pSelf);
95 static void dasher_main_command_about(DasherMain *pSelf);
96 static void dasher_main_command_toggle_game_mode(DasherMain*);
98 /* c.f. WRAP_CPP_CB below */
99 extern "C" void dasher_main_cb_import(GtkAction*, DasherMain*);
100 extern "C" void dasher_main_cb_quit(GtkAction*, DasherMain*);
101 extern "C" void dasher_main_cb_preferences(GtkAction*, DasherMain*);
102 extern "C" void dasher_main_cb_help(GtkAction*, DasherMain*);
103 extern "C" void dasher_main_cb_about(GtkAction*, DasherMain*);
104 extern "C" void dasher_main_cb_toggle_game_mode(GtkAction*, DasherMain*);
106 static gboolean dasher_main_speed_changed(DasherMain *pSelf);
107 static void dasher_main_alphabet_combo_changed(DasherMain *pSelf);
108 // TODO: populate speed slider
109 static void dasher_main_populate_alphabet_combo(DasherMain *pSelf);
111 /* TODO: order these in file */
112 static GtkBuilder *dasher_main_open_gui_xml(DasherMain *, const char *);
113 static void dasher_main_load_interface(DasherMain *pSelf);
114 static void dasher_main_create_preferences(DasherMain *pSelf);
115 static void dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter);
116 static void dasher_main_load_state(DasherMain *pSelf);
117 static void dasher_main_save_state(DasherMain *pSelf);
118 static void dasher_main_setup_window(DasherMain *pSelf);
119 static void dasher_main_populate_controls(DasherMain *pSelf);
120 static gint dasher_main_lookup_key(DasherMain *pSelf, guint iKeyVal);
122 /* TODO: Various functions which haven't yet been rationalised */
123 gboolean grab_focus();
125 /* ... Message handling from main window widgets */
126 extern "C" void speed_changed(GtkWidget *pWidget, gpointer user_data);
127 extern "C" void alphabet_combo_changed(GtkWidget *pWidget, gpointer pUserData);
128 extern "C" void dasher_main_cb_filename_changed(DasherEditor *pEditor, gpointer pUserData);
129 extern "C" void dasher_main_cb_buffer_changed(DasherEditor *pEditor, gpointer pUserData);
130 extern "C" void dasher_main_cb_context_changed(DasherEditor *pEditor, gpointer pUserData);
131 extern "C" gboolean dasher_main_cb_window_close(GtkWidget *pWidget, gpointer pUserData);
132 extern "C" void parameter_notification(GtkDasherControl *pDasherControl, gint iParameter, gpointer data);
134 /* ... Focus management and event forwarding */
135 extern "C" bool focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
136 extern "C" bool edit_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
137 extern "C" gboolean take_real_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data);
139 extern "C" gboolean edit_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
140 extern "C" gboolean edit_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
142 /* ... Temporary test/debug functions */
143 extern "C" gboolean test_focus_handler(GtkWidget *pWidget, GtkDirectionType iDirection, gpointer *pUserData);
145 extern "C" void handle_start_event(GtkDasherControl *pDasherControl, gpointer data);
146 extern "C" gint dasher_main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent, gpointer pUserData);
148 /* Boilerplate code */
149 static void
150 dasher_main_class_init(DasherMainClass *pClass) {
151 g_type_class_add_private(pClass, sizeof(DasherMainPrivate));
153 dasher_main_signals[REALIZED] =
154 g_signal_new("realized", G_TYPE_FROM_CLASS(pClass),
155 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
156 G_STRUCT_OFFSET(DasherMainClass, realized),
157 NULL, NULL, g_cclosure_marshal_VOID__VOID,
158 G_TYPE_NONE, 0);
160 GObjectClass *pObjectClass = (GObjectClass *)pClass;
161 pObjectClass->finalize = dasher_main_finalize;
164 static void
165 dasher_main_init(DasherMain *pDasherMain) {
166 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
168 pPrivate->pAppSettings = NULL;
169 pPrivate->pEditor = NULL;
170 pPrivate->pPreferencesDialogue = NULL;
172 pPrivate->pKeyboardHelper = new CKeyboardHelper(NULL);
174 pPrivate->bWidgetsInitialised = false;
177 static void
178 dasher_main_finalize(GObject *pObject) {
180 DasherMain *pDasherMain = DASHER_MAIN(pObject);
181 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
183 dasher_main_save_state(pDasherMain);
185 /* TODO: Does unref really do the right thing - check the whole ref counting situation */
186 // if(pPrivate->pEditor)
187 // g_object_unref(pPrivate->pEditor);
189 if(pPrivate->pPreferencesDialogue)
190 g_object_unref(pPrivate->pPreferencesDialogue);
192 if(pPrivate->pAppSettings)
193 g_object_unref(pPrivate->pAppSettings);
195 gtk_widget_destroy(GTK_WIDGET(pPrivate->pMainWindow));
197 /* TODO: Do we need to take down anything else? */
200 /* Public methods */
201 DasherMain *
202 dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
203 DasherMain *pDasherMain = (DasherMain *)(g_object_new(dasher_main_get_type(), NULL));
204 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
206 /* Create the app settings object */
207 pPrivate->pAppSettings = dasher_app_settings_new(pDasherMain, *argc, *argv);
209 /* Load the user interface from the GUI file */
210 if(pCommandLine && pCommandLine->szAppStyle) {
211 if(!strcmp(pCommandLine->szAppStyle, "traditional")) {
212 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_TRAD);
214 else if(!strcmp(pCommandLine->szAppStyle, "compose")) {
215 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_COMPOSE);
217 else if(!strcmp(pCommandLine->szAppStyle, "direct")) {
218 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_DIRECT);
220 else if(!strcmp(pCommandLine->szAppStyle, "fullscreen")) {
221 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_FULLSCREEN);
223 else {
224 g_critical("Application style %s is not supported", pCommandLine->szAppStyle);
225 return 0;
228 else {
229 // By default use traditional mode
230 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_TRAD);
233 dasher_main_load_interface(pDasherMain);
235 dasher_app_settings_set_widget(pPrivate->pAppSettings, GTK_DASHER_CONTROL(pPrivate->pDasherWidget));
238 /* TODO: This parsing code should really be tidied up */
239 if(pCommandLine && pCommandLine->szOptions) {
240 gchar **pszOptionTerms;
241 pszOptionTerms = g_strsplit(pCommandLine->szOptions, ",", 0);
243 gchar **pszCurrent = pszOptionTerms;
245 while(*pszCurrent) {
246 gchar *szJoin = g_strrstr(*pszCurrent, "=");
247 // Note to translators: This message will be output for command line errors when the "=" in --options=foo is missing.
248 const gchar *errorMessage = _("option setting is missing \"=\".");
250 if(szJoin) {
251 int iLength = szJoin - *pszCurrent;
253 gchar *szKey = g_new(gchar, iLength + 1);
254 memcpy(szKey, *pszCurrent, iLength);
255 szKey[iLength] = '\0';
257 errorMessage = dasher_app_settings_cl_set(pPrivate->pAppSettings, szKey, szJoin + 1);
259 g_free(szKey);
262 if (errorMessage) {
263 // Note to translators: This string will be output when --options= specifies an unknown option.
264 g_critical("%s: '%s', %s", _("Invalid option string specified"), *pszCurrent, errorMessage);
265 return 0;
268 ++pszCurrent;
271 g_strfreev(pszOptionTerms);
273 /* --- */
276 dasher_editor_initialise(pPrivate->pEditor, pPrivate->pAppSettings, GTK_DASHER_CONTROL(pPrivate->pDasherWidget), pPrivate->pXML, NULL);
279 dasher_main_setup_window(pDasherMain);
281 /* Create the editor */
282 gchar *szFullPath = NULL;
284 if(pCommandLine) {
285 if(pCommandLine->szFilename) {
286 if(!g_path_is_absolute(pCommandLine->szFilename)) {
287 char *cwd;
288 cwd = (char *)malloc(1024 * sizeof(char));
289 getcwd(cwd, 1024);
290 szFullPath = g_build_path("/", cwd, pCommandLine->szFilename, NULL);
292 else {
293 szFullPath = g_strdup(pCommandLine->szFilename);
298 // TODO: Fix this
299 // pPrivate->pEditor = GTK_EDITOR(
302 // dasher_editor_initialise(pPrivate->pAppSettings, pDasherMain, pPrivate->pXML, szFullPath);
304 g_free(szFullPath);
306 /* Create the preferences window */
307 dasher_main_create_preferences(pDasherMain);
309 /* Create the lock dialogue (to be removed in future versions) */
310 #ifndef WITH_MAEMO
311 dasher_lock_dialogue_new(pPrivate->pXML, pPrivate->pMainWindow);
312 #else
313 dasher_lock_dialogue_new(pPrivate->pXML, 0);
314 #endif
316 g_object_unref(pPrivate->pXML);
317 pPrivate->pXML = 0;
319 g_object_unref(pPrivate->pPrefXML);
320 pPrivate->pPrefXML = 0;
322 /* Set up various bits and pieces */
323 dasher_main_set_window_title(pDasherMain);
324 dasher_main_populate_controls(pDasherMain);
326 gtk_key_snooper_install(dasher_main_key_snooper, pDasherMain);
328 return pDasherMain;
331 static GtkBuilder *
332 dasher_main_open_gui_xml(DasherMain *pSelf, const char *szGUIFilename) {
333 GError *e = NULL;
334 GtkBuilder *xml = gtk_builder_new();
336 g_message("Opening GUI file: %s", szGUIFilename);
338 if (!gtk_builder_add_from_file(xml, szGUIFilename, &e)) {
339 g_message("Can't find GUI file: %s. Dasher is unlikely to be correctly "
340 "installed. (%s)", szGUIFilename, e->message);
341 exit(1);
344 gtk_builder_connect_signals(xml, pSelf);
346 return xml;
350 #define WRAP_CPP_CB(item) \
351 extern "C" void \
352 dasher_main_cb_##item(GtkAction *obj, DasherMain *p)\
354 dasher_main_command_##item(p);\
358 * Editor passes on the action strings to dasher_editor_command which
359 * land in dasher_editor_internal.
361 WRAP_CPP_CB(import)
362 WRAP_CPP_CB(quit)
363 WRAP_CPP_CB(preferences)
364 WRAP_CPP_CB(help)
365 WRAP_CPP_CB(about)
366 WRAP_CPP_CB(toggle_game_mode)
368 extern "C" void
369 dasher_main_cb_editor(GtkAction *obj, DasherMain *pSelf)
371 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
372 DASHER_ASSERT(pPrivate->pEditor != NULL);
373 const gchar *action = gtk_action_get_name(obj);
374 dasher_editor_command(pPrivate->pEditor, action);
377 static void
378 dasher_main_load_interface(DasherMain *pSelf) {
379 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
380 const char *szGUIFilename = NULL;
381 const char *szPrefGUIFilename = NULL;
383 #if WITH_MAEMO
384 #ifdef WITH_MAEMOFULLSCREEN
385 szGUIFilename = PROGDATA "/dashermaemofullscreen.ui";
386 #else
387 szGUIFilename = PROGDATA "/dashermaemo.ui";
388 #endif
389 szPrefGUIFilename = PROGDATA "/dashermaemo.preferences.ui";
390 #else
391 szGUIFilename = PROGDATA "/dasher.traditional.ui";
392 szPrefGUIFilename = PROGDATA "/dasher.preferences.ui";
393 #endif
395 if(!szGUIFilename) {
396 g_error("Failure to determine GUI filename");
399 pPrivate->pXML = dasher_main_open_gui_xml(pSelf, szGUIFilename);
400 pPrivate->pPrefXML = dasher_main_open_gui_xml(pSelf, szPrefGUIFilename);
402 #ifndef HAVE_GTK_SHOW_URI
403 GtkAction *helpact =
404 GTK_ACTION(gtk_builder_get_object(pPrivate->pXML, "action_help"));
405 gtk_action_set_sensitive(helpact, false);
406 gtk_action_set_visible(helpact, false);
407 #endif
409 // Save the details of some of the widgets for later
410 // pPrivate->pActionPane = gtk_builder_get_object(pPrivate->pXML, "vbox39");
411 // pPrivate->pBufferView = gtk_builder_get_object(pPrivate->pXML, "the_text_view");
412 pPrivate->pDivider = GTK_PANED(gtk_builder_get_object(pPrivate->pXML, "main_divider"));
413 // pPrivate->pEditPane = gtk_builder_get_object(pPrivate->pXML, "vbox40");
414 pPrivate->pMainWindow = GTK_WINDOW(gtk_builder_get_object(pPrivate->pXML, "window"));
415 pPrivate->pToolbar = GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "dasher_tool_bar"));
416 // pPrivate->pMenuBar = gtk_builder_get_object(pPrivate->pXML, "dasher_menu_bar");
417 pPrivate->pDasherWidget = GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "DasherControl"));
418 pPrivate->pEditor = DASHER_EDITOR(gtk_builder_get_object(pPrivate->pXML, "DasherEditor"));
419 gtk_dasher_control_set_editor(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), pPrivate->pEditor);
421 #ifndef WITH_MAEMO
422 pPrivate->pSpeedBox = GTK_SPIN_BUTTON(gtk_builder_get_object(pPrivate->pXML, "spinbutton1"));
423 pPrivate->pAlphabetCombo = GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "combobox1"));
424 pPrivate->pStatusControl = GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "hbox8"));
426 pPrivate->pAlphabetList = gtk_list_store_new(1, G_TYPE_STRING);
427 gtk_combo_box_set_model(GTK_COMBO_BOX(pPrivate->pAlphabetCombo),
428 GTK_TREE_MODEL(pPrivate->pAlphabetList));
430 GtkCellRenderer *pRenderer;
431 pRenderer = gtk_cell_renderer_text_new();
432 g_object_set(G_OBJECT(pRenderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
433 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pPrivate->pAlphabetCombo), pRenderer, true);
434 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pPrivate->pAlphabetCombo), pRenderer, "text", 0, NULL);
437 // gtk_widget_add_events(pPrivate->pDragHandle, GDK_POINTER_MOTION_MASK);
438 #else
440 #ifdef WITH_MAEMOFULLSCREEN
441 // TODO: This is horrible - no need to get it from the glade file if we're not going to use it
443 pPrivate->pProgram = HILDON_PROGRAM(hildon_program_get_instance());
444 // hildon_app_set_title(pPrivate->pApp, "Dasher");
446 pPrivate->pHWindow = HILDON_WINDOW(hildon_window_new());
447 hildon_program_add_window(pPrivate->pProgram, pPrivate->pHWindow);
449 gtk_widget_reparent(pPrivate->pInnerFrame, GTK_WIDGET(pPrivate->pHWindow));
450 // gtk_paned_set_position(GTK_PANED(window), 100);
452 /* Do menu setup */
453 GtkMenu *main_menu;
454 GtkWidget *file_menu;
455 GtkWidget *file_menu_item;
456 GtkWidget *options_menu;
457 GtkWidget *options_menu_item;
458 GtkWidget *help_menu;
459 GtkWidget *help_menu_item;
462 // main_menu = hildon_appview_get_menu(appview);
464 main_menu = GTK_MENU(gtk_menu_new());
465 file_menu = gtk_builder_get_object(pPrivate->pXML, "file_menu");
466 options_menu = gtk_builder_get_object(pPrivate->pXML, "options1_menu");
467 help_menu = gtk_builder_get_object(pPrivate->pXML, "help_menu");
468 file_menu_item = gtk_menu_item_new_with_label ("File");
469 options_menu_item = gtk_menu_item_new_with_label ("Options");
470 help_menu_item = gtk_menu_item_new_with_label ("Help");
472 g_object_ref(file_menu);
473 g_object_ref(options_menu);
474 g_object_ref(help_menu);
476 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk_builder_get_object(pPrivate->pXML, "file_menu")), NULL);
477 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk_builder_get_object(pPrivate->pXML, "options1")), NULL);
478 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk_builder_get_object(pPrivate->pXML, "help_menu")), NULL);
480 gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_menu_item),file_menu);
481 gtk_menu_item_set_submenu(GTK_MENU_ITEM(options_menu_item),options_menu);
482 gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_menu_item),help_menu);
483 gtk_menu_shell_append((GtkMenuShell *)main_menu, file_menu_item);
484 gtk_menu_shell_append((GtkMenuShell *)main_menu, options_menu_item);
485 gtk_menu_shell_append((GtkMenuShell *)main_menu, help_menu_item);
487 g_object_unref(file_menu);
488 g_object_unref(options_menu);
489 g_object_unref(help_menu);
491 hildon_program_set_common_menu(pPrivate->pProgram, main_menu);
493 gtk_widget_show_all( GTK_WIDGET( main_menu ) );
495 // /* And toolbar */
496 // GtkWidget *toolbar;
497 // toolbar = gtk_builder_get_object(pPrivate->pXML, "toolbar");
498 // g_print("Got %p\n",toolbar);
499 // gtk_widget_reparent (toolbar, appview->vbox);
501 gtk_widget_show_all(GTK_WIDGET(pPrivate->pHWindow));
503 gtk_widget_destroy(GTK_WIDGET(pPrivate->pMainWindow));
504 pPrivate->pMainWindow = pPrivate->pHWindow;
506 g_signal_connect(G_OBJECT(pPrivate->pHWindow), "delete_event", G_CALLBACK(ask_save_before_exit), NULL);
508 #endif // Maemo fullscreen
509 #endif // Maemo
511 // pPrivate->bHidden = false;
512 // pPrivate->bGrabbed = false;
514 // pPrivate->iPosition = 100; // FIXME - make this persistant
516 // TODO: Specify callbacks in glade file
517 // TODO: Rationalise focus
518 // g_signal_connect(G_OBJECT(pPrivate->pBufferView), "button-release-event", G_CALLBACK(take_real_focus), NULL);
519 // g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-press-event", G_CALLBACK(edit_key_press), NULL);
520 //g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-release-event", G_CALLBACK(edit_key_release), NULL);
522 // dasher_main_build_context_menu(pSelf);
524 // Create a Maemo helper if necessary
525 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
526 pPrivate->pMaemoHelper = dasher_maemo_helper_new(pPrivate->pMainWindow);
527 #endif
529 // Set up any non-registry-dependent options
530 #ifdef WITH_GPE
531 gtk_window_set_decorated(pPrivate->pMainWindow, false);
532 #endif
534 // Hide any widgets which aren't appropriate for this mode
535 // XXX PRLW: chances are these aren't defined in direct.ui anyway => we are
536 // hiding non-existent widgets.
538 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) == APP_STYLE_DIRECT) {
539 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "dasher_menu_bar")));
541 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_new")));
542 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_open")));
543 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_save")));
544 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_saveas")));
545 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "separatortoolitem1")));
546 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_cut")));
547 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_copy")));
548 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "tb_command_paste")));
549 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "separatortoolitem2")));
550 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "DasherEditor")));
553 // TODO: szFullPath
554 pPrivate->bWidgetsInitialised = true;
557 static void
558 dasher_main_create_preferences(DasherMain *pSelf) {
559 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
560 pPrivate->pPreferencesDialogue = dasher_preferences_dialogue_new(pPrivate->pPrefXML, pPrivate->pEditor, pPrivate->pAppSettings, pPrivate->pMainWindow);
564 * Start game mode: prompt user for the text to play with, put this in SP_GAME_TEXT_FILE;
565 * clear out any text in the dasher editor; call CDasherControl::EnterGameMode().
569 * Event handler which displays a standard GTK file dialog. The dialog allows the user
570 * to specify a text file to play game mode with.
572 * @param pButton the button that fired the event
573 * @param pWidget reference needed by GTK for callback signature
574 * @param pData pointer to a an std::pair<GtkWindow*, DasherMain*> containing references
575 * to the dialog's parent window and an instance of DasherMain
577 void show_game_file_dialog(GtkWidget *pButton, GtkWidget *pWidget, gpointer pData) {
579 std::pair<GtkWindow*, DasherMain*> *objRefs = (std::pair<GtkWindow*, DasherMain*>*)pData;
581 DasherMain *pSelf = objRefs->second;
582 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
584 GtkWidget *pFileDialog = gtk_file_chooser_dialog_new("Choose a Game Text",
585 GTK_WINDOW(objRefs->first),
586 GTK_FILE_CHOOSER_ACTION_OPEN,
587 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
588 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
589 NULL);
591 gtk_window_set_destroy_with_parent(GTK_WINDOW(pFileDialog), true);
593 if (gtk_dialog_run(GTK_DIALOG(pFileDialog)) == GTK_RESPONSE_ACCEPT) {
595 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileDialog));
597 dasher_app_settings_set_string(pPrivate->pAppSettings,
598 SP_GAME_TEXT_FILE,
599 filename);
600 gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), true);
602 gtk_widget_destroy(GTK_WIDGET(objRefs->first));
606 * Toggle game mode on and off. Toggling on causes a dialog box to be displayed
607 * welcoming the user to game mode and prompting them to specify a file to play with.
608 * Toggling off just calls LeaveGameMode().
610 * @param pSelf a reference to an instance of DasherMain
612 void dasher_main_command_toggle_game_mode(DasherMain *pSelf) {
614 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
616 if(!gtk_dasher_control_get_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget))) {
618 GtkWidget *pDialog = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
619 GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE,
620 _("Welcome to Dasher Game Mode! Game Mode is a fun way to practice entering text in Dasher. Please select a training text to play with:"));
622 GtkWidget *pDefaultButton = gtk_dialog_add_button(GTK_DIALOG(pDialog), _("Use Default"), GTK_RESPONSE_ACCEPT);
623 GtkWidget *pFileButton = gtk_dialog_add_button(GTK_DIALOG(pDialog), _("Choose File..."), 2);
624 gtk_dialog_add_button(GTK_DIALOG(pDialog), _("Cancel"), GTK_RESPONSE_REJECT);
626 //make a pair with references to the the DasherMain and parent window instances that
627 //handler will need - kind of disgusting, but looks like only way to pass multiple
628 //parameters in g_signal_connect
629 std::pair<GtkWindow*, DasherMain*> objRefs = std::make_pair(GTK_WINDOW(pDialog), pSelf);
630 //ACL surprisingly this works: the signal handler (show_game_file_dialog) is called
631 // before gtk_dialog_run returns, and the pair is in this, calling, method's stack frame,
632 // so exists until _this_ method finishes...
634 g_signal_connect(pFileButton, "button-press-event", G_CALLBACK(show_game_file_dialog),
635 (gpointer)&objRefs);
637 if (gtk_dialog_run(GTK_DIALOG(pDialog))==GTK_RESPONSE_ACCEPT) {
638 gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), true);
639 //Tick menu?
641 //have to do this check because we might have destroyed the dialog already in show_game_file_dialog
642 if(GTK_IS_WIDGET(pDialog))
643 gtk_widget_destroy(pDialog);
644 } else {
645 GtkWidget *pDialog = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
646 GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE,
647 _("Are you sure you wish to turn off game mode? All unsaved changes will be lost."));
649 GtkWidget *pNoButton = gtk_dialog_add_button(GTK_DIALOG(pDialog), GTK_STOCK_NO, GTK_RESPONSE_REJECT);
650 GtkWidget *pYesButton = gtk_dialog_add_button(GTK_DIALOG(pDialog), GTK_STOCK_YES, GTK_RESPONSE_ACCEPT);
652 if(gtk_dialog_run(GTK_DIALOG(pDialog))==GTK_RESPONSE_ACCEPT) {
653 gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), false);
655 DASHER_ASSERT(GTK_IS_WIDGET(pDialog));
656 gtk_widget_destroy(GTK_WIDGET(pDialog));
661 static void
662 dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter) {
663 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
665 switch( iParameter ) {
666 case APP_BP_SHOW_TOOLBAR:
667 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
668 gtk_widget_show(pPrivate->pToolbar);
669 else
670 gtk_widget_hide(pPrivate->pToolbar);
671 break;
672 case BP_SHOW_SLIDER: // TODO: Shouldn't be a core parmeter
673 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_SHOW_SLIDER))
674 gtk_widget_show(pPrivate->pStatusControl);
675 else
676 gtk_widget_hide(pPrivate->pStatusControl);
677 break;
678 #ifndef WITH_MAEMO
679 case LP_MAX_BITRATE:
680 gtk_spin_button_set_value(pPrivate->pSpeedBox, dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
681 break;
682 #endif
683 case SP_ALPHABET_ID:
684 dasher_main_populate_alphabet_combo(pSelf);
685 break;
686 case BP_GLOBAL_KEYBOARD:
687 dasher_main_setup_window(pSelf);
688 break;
689 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
690 case APP_LP_MAEMO_SIZE: {
691 g_message("Maemo size");
693 bool bVisible = GTK_WIDGET_VISIBLE(pPrivate->pMainWindow);
694 gtk_widget_hide(pPrivate->pMainWindow);
695 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_MAEMO_SIZE) == 0) {
696 int iWidth;
697 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
698 gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 150);
699 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWidth, 150);
700 gtk_widget_set_size_request(pPrivate->pDasherWidget, 175, -1);
702 else {
703 int iWidth;
704 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
705 gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 250);
706 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWidth, 250);
707 gtk_widget_set_size_request(pPrivate->pDasherWidget, 280, -1);
709 if(bVisible)
710 gtk_widget_show(pPrivate->pMainWindow);
711 break;
713 #endif
716 if(pPrivate->pPreferencesDialogue)
717 dasher_preferences_dialogue_handle_parameter_change(pPrivate->pPreferencesDialogue, iParameter);
719 if(pPrivate->pEditor)
720 dasher_editor_handle_parameter_change(pPrivate->pEditor, iParameter);
723 static void
724 dasher_main_load_state(DasherMain *pSelf) {
725 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
727 int iWindowWidth;
728 int iWindowHeight;
729 int iEditHeight;
731 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != APP_STYLE_COMPOSE) {
732 iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT);
733 iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH);
734 iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT);
736 else {
737 iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH);
738 iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H);
739 iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H);
742 #ifndef WITH_MAEMO
743 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWindowWidth, iWindowHeight);
744 #endif
746 gtk_paned_set_position(pPrivate->pDivider, iEditHeight);
748 pPrivate->iWidth = iWindowWidth;
749 pPrivate->iHeight = iWindowHeight;
752 int iWindowX;
753 int iWindowY;
755 iWindowX = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_X);
756 iWindowY = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_Y);
758 gtk_window_move(GTK_WINDOW(pPrivate->pMainWindow), iWindowX, iWindowY);
761 static void
762 dasher_main_save_state(DasherMain *pSelf) {
763 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
765 if(!pPrivate->bWidgetsInitialised)
766 return;
768 int iWindowWidth;
769 int iWindowHeight;
770 int iEditHeight;
772 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWindowWidth, &iWindowHeight);
773 iEditHeight = gtk_paned_get_position(pPrivate->pDivider);
775 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != APP_STYLE_COMPOSE) {
776 // APP_STYLE_DIRECT doesn't have an edit window.
777 if (dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != APP_STYLE_DIRECT)
778 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT, iEditHeight);
779 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH, iWindowWidth);
780 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT, iWindowHeight);
782 else {
783 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH, iEditHeight);
784 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H, iWindowWidth);
785 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H, iWindowHeight);
788 int iWindowX;
789 int iWindowY;
790 gtk_window_get_position(GTK_WINDOW(pPrivate->pMainWindow), &iWindowX, &iWindowY);
792 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_X, iWindowX);
793 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_Y, iWindowY);
796 void
797 dasher_main_show(DasherMain *pSelf) {
798 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
799 gtk_widget_show(GTK_WIDGET(pPrivate->pMainWindow));
802 static void
803 dasher_main_setup_window(DasherMain *pSelf) {
804 dasher_main_setup_window_style(pSelf);
805 dasher_main_setup_window_state(pSelf);
806 dasher_main_setup_internal_layout(pSelf);
808 // DasherMainPrivate *pPrivate = (DasherMainPrivate *)(pSelf->private_data);
810 // if(dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_GLOBAL_KEYBOARD))
811 // gdk_window_add_filter(0, keyboard_filter_cb, 0);
812 // else
813 // gdk_window_remove_filter(0, keyboard_filter_cb, 0);
816 static void
817 dasher_main_populate_controls(DasherMain *pSelf) {
818 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
820 // Populate the alphabet chooser
821 dasher_main_populate_alphabet_combo(pSelf);
823 // Set the value of the speed spinner
824 gtk_spin_button_set_value(pPrivate->pSpeedBox,
825 dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
828 /* Private methods */
830 /* Window state is basically size and position */
831 static void
832 dasher_main_setup_window_state(DasherMain *pSelf) {
833 dasher_main_load_state(pSelf);
835 // TODO: Setup positioning here - need to think up a policy on this
839 /* Setup the window style - this is defined to be window manager hints and the like */
840 static void
841 dasher_main_setup_window_style(DasherMain *pSelf) {
842 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
844 switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
845 case APP_STYLE_TRAD:
846 // Nothing to do
847 break;
848 case APP_STYLE_COMPOSE:
849 // Nothing to do
850 break;
851 case APP_STYLE_DIRECT:
852 // Direct mode - set always on top
853 gtk_window_set_keep_above(GTK_WINDOW(pPrivate->pMainWindow), true);
855 // Refuse focus
856 gtk_window_set_accept_focus(GTK_WINDOW(pPrivate->pMainWindow), false);
858 // Stick on all desktops
859 gtk_window_stick(GTK_WINDOW(pPrivate->pMainWindow));
860 break;
861 case APP_STYLE_FULLSCREEN:
862 // Fullscreen mode - set fullscreen
863 gtk_window_fullscreen(GTK_WINDOW(pPrivate->pMainWindow));
864 break;
865 default:
866 g_error("Inconsistent application style specified.");
870 /* Internal layout is the visibility of various widgets */
871 static void
872 dasher_main_setup_internal_layout(DasherMain *pSelf) {
873 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
875 if(pPrivate->pToolbar) {
876 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
877 gtk_widget_show(pPrivate->pToolbar);
878 else
879 gtk_widget_hide(pPrivate->pToolbar);
882 if(pPrivate->pStatusControl) {
883 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_SHOW_SLIDER))
884 gtk_widget_show(pPrivate->pStatusControl);
885 else
886 gtk_widget_hide(pPrivate->pStatusControl);
890 // TODO: Fold into setup controls?
891 static void
892 dasher_main_set_window_title(DasherMain *pSelf) {
893 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
895 const gchar *szFilename = dasher_editor_get_filename(pPrivate->pEditor);
897 // Note to translators: This is the name of the dasher program as it appears
898 // in a window title.
899 gchar * dasher = _("Dasher");
900 if(szFilename == 0) {
901 gtk_window_set_title(GTK_WINDOW(pPrivate->pMainWindow), dasher);
903 else {
904 gchar *title = g_strdup_printf("%s - %s", dasher, szFilename);
905 gtk_window_set_title(GTK_WINDOW(pPrivate->pMainWindow), title);
906 g_free (title);
910 static void
911 dasher_main_command_import(DasherMain *pSelf) {
912 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
914 GtkWidget *pFileSel = gtk_file_chooser_dialog_new(_("Select File"),
915 GTK_WINDOW(pPrivate->pMainWindow),
916 GTK_FILE_CHOOSER_ACTION_OPEN,
917 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
918 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
919 NULL);
921 #ifdef TEACH_TRAINING_HELPER_LOAD_FILE_ABOUT_URI
922 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(pFileSel), FALSE);
923 #endif
925 if(gtk_dialog_run(GTK_DIALOG(pFileSel)) == GTK_RESPONSE_ACCEPT) {
927 #ifdef TEACH_TRAINING_HELPER_LOAD_FILE_ABOUT_URI
928 gchar *szFilename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(pFileSel));
929 #else
930 gchar *szFilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSel));
931 #endif
933 gtk_dasher_control_train(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), szFilename);
935 g_free(szFilename);
938 gtk_widget_destroy(pFileSel);
941 static void dasher_main_command_quit(DasherMain *pSelf) {
942 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
944 GtkWidget *pDialogue = NULL;
946 if(dasher_editor_file_changed(pPrivate->pEditor)) {
947 // XXX PRLW: Just open the save dialogue box.
948 #if 0
949 const gchar *szFilename = dasher_editor_get_filename(pPrivate->pEditor);
951 if(szFilename) {
952 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
953 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
954 _("Do you want to save your changes to %s?\n\nYour changes will be lost if you don't save them."),
955 szFilename);
957 else {
958 #endif
959 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
960 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
961 _("Do you want to save your changes?\n\nYour changes will be lost if you don't save them."));
962 #if 0
964 #endif
966 gtk_dialog_add_buttons(GTK_DIALOG(pDialogue),
967 _("Don't save"), GTK_RESPONSE_REJECT,
968 _("Don't quit"), GTK_RESPONSE_CANCEL,
969 _("Save and quit"), GTK_RESPONSE_ACCEPT,
970 NULL);
972 switch (gtk_dialog_run(GTK_DIALOG(pDialogue))) {
973 case GTK_RESPONSE_REJECT:
974 gtk_main_quit();
975 break;
976 case GTK_RESPONSE_CANCEL:
977 gtk_widget_destroy(GTK_WIDGET(pDialogue));
978 break;
979 case GTK_RESPONSE_ACCEPT:
980 dasher_editor_command(pPrivate->pEditor, "action_save");
981 gtk_main_quit();
982 break;
985 else {
986 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
987 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
988 _("Are you sure you wish to quit?"));
990 gtk_dialog_add_buttons(GTK_DIALOG(pDialogue),
991 _("Don't quit"), GTK_RESPONSE_REJECT,
992 _("Quit"), GTK_RESPONSE_ACCEPT,
993 NULL);
995 switch (gtk_dialog_run(GTK_DIALOG(pDialogue))) {
996 case GTK_RESPONSE_REJECT:
997 gtk_widget_destroy(GTK_WIDGET(pDialogue));
998 break;
999 case GTK_RESPONSE_ACCEPT:
1000 gtk_main_quit();
1005 static void
1006 dasher_main_command_preferences(DasherMain *pSelf) {
1007 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1008 dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue, 0);
1011 static void
1012 dasher_main_command_preferences_alphabet(DasherMain *pSelf) {
1013 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1014 dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue, 1);
1017 static void
1018 dasher_main_command_help(DasherMain *pSelf) {
1019 #ifdef HAVE_GTK_SHOW_URI
1020 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1021 GdkScreen *scr;
1022 GError *err = NULL;
1024 scr = gtk_widget_get_screen(GTK_WIDGET(pPrivate->pMainWindow));
1025 if (!gtk_show_uri(scr, "ghelp:dasher", gtk_get_current_event_time(), &err)) {
1026 GtkWidget *d;
1027 d = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow),
1028 GTK_DIALOG_MODAL,
1029 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1030 "%s", _("Unable to open help file"));
1031 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(d),
1032 "%s", err->message);
1033 g_signal_connect(d, "response", G_CALLBACK(gtk_widget_destroy), NULL);
1034 gtk_window_present(GTK_WINDOW(d));
1036 g_error_free (err);
1038 #endif
1041 static void
1042 dasher_main_command_about(DasherMain *pSelf) {
1043 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1045 // In alphabetical order - please keep this in sync with the AUTHORS
1046 // file at root of the package tree
1047 const gchar *authors[] = {
1048 "Chris Ball",
1049 "Ignas Budvytis",
1050 "Peter Conlon",
1051 "Phil Cowans",
1052 "Frederik Eaton",
1053 "Behdad Esfahbod",
1054 "Matthew Garrett",
1055 "Chris Hack",
1056 "Takashi Kaburagi",
1057 "Sega Kazue",
1058 "Alan Lawrence",
1059 "David MacKay",
1060 "Iain Murray",
1061 "Martijn van Veen",
1062 "Keith Vertanen",
1063 "Hanna Wallach",
1064 "David Ward",
1065 "Patrick Welche",
1066 "Brian Williams",
1067 "Seb Wills",
1068 "Will Zou",
1069 NULL
1072 // Yeah, should really do some Gnome documentation for it...
1073 const gchar *documenters[] = {
1074 "Chris Ball",
1075 "Matthew Garrett",
1076 "David MacKay",
1077 NULL
1080 gtk_show_about_dialog(GTK_WINDOW(pPrivate->pMainWindow),
1081 "authors", authors,
1082 "comments", _("Dasher is a predictive text entry application"),
1083 "copyright", "Copyright \xC2\xA9 1998-2011 The Dasher Project",
1084 "documenters", documenters,
1085 "license", "GPL 2+",
1086 "logo-icon-name", "dasher",
1087 "translator-credits", _("translator-credits"),
1088 "version", PACKAGE_VERSION,
1089 "website", PACKAGE_URL,
1090 "wrap-license", true,
1091 NULL);
1094 static gboolean
1095 dasher_main_speed_changed(DasherMain *pSelf) {
1096 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1098 int iNewValue( static_cast<int>(round(gtk_spin_button_get_value(pPrivate->pSpeedBox) * 100)));
1100 if(dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) != iNewValue)
1101 dasher_app_settings_set_long(pPrivate->pAppSettings, LP_MAX_BITRATE, iNewValue);
1103 return true;
1106 static void
1107 dasher_main_alphabet_combo_changed(DasherMain *pSelf) {
1108 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1110 GtkTreeIter sIter;
1112 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter)) {
1113 char *szSelected;
1114 gtk_tree_model_get(GTK_TREE_MODEL(pPrivate->pAlphabetList), &sIter, 0, &szSelected, -1);
1116 if(!strcmp("More Alphabets...", szSelected)) {
1117 gtk_combo_box_set_active(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), 0);
1118 // dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue);
1119 dasher_main_command_preferences_alphabet(pSelf);
1121 else
1122 dasher_app_settings_set_string(pPrivate->pAppSettings, SP_ALPHABET_ID, szSelected);
1124 g_free(szSelected);
1128 static void
1129 dasher_main_populate_alphabet_combo(DasherMain *pSelf) {
1130 #ifndef WITH_MAEMO
1131 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1133 // Disconnect the event handler temporarily, otherwise this will
1134 // trigger alphabet changes
1136 g_signal_handlers_block_by_func(pPrivate->pAlphabetCombo, (gpointer)alphabet_combo_changed, pSelf);
1138 gtk_list_store_clear(pPrivate->pAlphabetList);
1141 GtkTreeIter sIter;
1142 const char *szValue;
1144 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_ID);
1146 if(strlen(szValue) > 0) {
1147 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1148 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1149 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter);
1152 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_1);
1153 if(strlen(szValue) > 0) {
1154 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1155 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1158 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_2);
1159 if(strlen(szValue) > 0) {
1160 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1161 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1164 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_3);
1165 if(strlen(szValue) > 0) {
1166 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1167 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1170 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_4);
1171 if(strlen(szValue) > 0) {
1172 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1173 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1176 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1177 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, "More Alphabets...", -1);
1179 g_signal_handlers_unblock_by_func(pPrivate->pAlphabetCombo, (gpointer)alphabet_combo_changed, pSelf);
1181 #endif
1184 static gint
1185 dasher_main_lookup_key(DasherMain *pSelf, guint iKeyVal) {
1186 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1188 if(pPrivate->pKeyboardHelper)
1189 return pPrivate->pKeyboardHelper->ConvertKeycode(iKeyVal);
1190 else
1191 return -1;
1195 gboolean
1196 grab_focus() {
1198 // TODO: reimplement (text view member of class)
1199 // gtk_widget_grab_focus(the_text_view);
1200 // g_bForwardKeyboard = true;
1201 return true;
1204 /* Callbacks */
1206 extern "C" void
1207 speed_changed(GtkWidget *pWidget, gpointer pUserData) {
1208 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1209 dasher_main_speed_changed(pDasherMain);
1212 extern "C" void
1213 alphabet_combo_changed(GtkWidget *pWidget, gpointer pUserData) {
1214 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1215 dasher_main_alphabet_combo_changed(pDasherMain);
1218 extern "C" void
1219 dasher_main_cb_filename_changed(DasherEditor *pEditor, gpointer pUserData) {
1220 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1221 dasher_main_set_window_title(pDasherMain);
1224 extern "C" void
1225 dasher_main_cb_buffer_changed(DasherEditor *pEditor, gpointer pUserData) {
1226 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pUserData);
1228 gtk_dasher_control_set_buffer(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_offset(pPrivate->pEditor));
1231 extern "C" void
1232 dasher_main_cb_context_changed(DasherEditor *pEditor, gpointer pUserData) {
1233 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1234 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
1236 gtk_dasher_control_set_offset(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_offset(pPrivate->pEditor));
1239 extern "C" gboolean
1240 dasher_main_cb_window_close(GtkWidget *pWidget, gpointer pUserData) {
1241 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1242 dasher_main_command_quit(pDasherMain);
1244 /* Returning true stops further propagation */
1245 return TRUE;
1248 extern "C" void
1249 parameter_notification(GtkDasherControl *pDasherControl, gint iParameter, gpointer pUserData) {
1250 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1251 dasher_main_handle_parameter_change(pDasherMain, iParameter);
1254 // TODO: Not really sure what happens here - need to sort out focus behaviour in general
1255 extern "C" bool
1256 focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
1257 return grab_focus();
1260 extern "C" bool
1261 edit_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
1262 return true;
1265 extern "C" gboolean
1266 take_real_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) {
1267 // g_bForwardKeyboard = false;
1268 return false;
1271 extern "C" gboolean
1272 edit_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
1273 // TODO: Reimplement
1275 // if(g_bForwardKeyboard) {
1276 // gboolean *returnType;
1277 // g_signal_emit_by_name(GTK_WIDGET(pPrivate->pDasherWidget), "key_press_event", event, &returnType);
1278 // return true;
1279 // }
1280 // else {
1281 // return false;
1282 // }
1284 // TODO: Check callback return functions
1285 return false;
1288 extern "C" gboolean
1289 edit_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
1290 // TODO: reimplement
1292 // if(g_bForwardKeyboard) {
1293 // gboolean *returnType;
1294 // g_signal_emit_by_name(GTK_WIDGET(pPrivate->pDasherWidget), "key_release_event", event, &returnType);
1295 // return true;
1296 // }
1297 // else {
1298 // return false;
1299 // }
1301 // TODO: Check callback return functions
1302 return false;
1305 extern "C" gboolean
1306 test_focus_handler(GtkWidget *pWidget, GtkDirectionType iDirection, gpointer *pUserData) {
1307 return FALSE;
1310 extern "C" void
1311 handle_start_event(GtkDasherControl *pDasherControl, gpointer data) {
1312 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(data);
1314 dasher_editor_grab_focus(pPrivate->pEditor);
1318 // TODO: Make this only work for children of the main window
1319 extern "C" gint
1320 dasher_main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent,
1321 gpointer pUserData) {
1322 DasherMain *pSelf = DASHER_MAIN(pUserData);
1324 gint iButton = dasher_main_lookup_key(pSelf, pEvent->keyval);
1326 if(iButton != -1) {
1327 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1329 if (pWidget == GTK_WIDGET(pPrivate->pMainWindow) ||
1330 gtk_widget_is_ancestor(pWidget, GTK_WIDGET(pPrivate->pMainWindow))) {
1331 if(pPrivate->pDasherWidget) {
1332 if(pEvent->type == GDK_KEY_PRESS)
1333 gtk_dasher_control_external_key_down(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), iButton);
1334 else
1335 gtk_dasher_control_external_key_up(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), iButton);
1338 return TRUE;
1340 else {
1341 return FALSE;
1344 else {
1345 return FALSE;
1349 // Callbacks from the Dasher widget
1351 extern "C" void
1352 handle_stop_event(GtkDasherControl *pDasherControl, gpointer data) {
1353 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(data);
1355 if(pPrivate->pEditor)
1356 dasher_editor_handle_stop(pPrivate->pEditor);
1359 // TODO: The following two should probably be made the same
1360 extern "C" void
1361 handle_request_settings(GtkDasherControl * pDasherControl, gpointer data) {
1362 // TODO: reimplement
1363 // dasher_preferences_dialogue_show(g_pPreferencesDialogue);
1366 extern "C" void
1367 gtk2_edit_delete_callback(GtkDasherControl *pDasherControl, const gchar *szText, int iOffset, gpointer user_data) {
1368 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(user_data);
1370 if(pPrivate->pEditor) {
1371 gint displaylength = g_utf8_strlen(szText, -1);
1372 dasher_editor_delete(pPrivate->pEditor, displaylength, iOffset);
1376 extern "C" void
1377 gtk2_edit_output_callback(GtkDasherControl *pDasherControl, const gchar *szText, int iOffset, gpointer user_data) {
1378 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(user_data);
1380 if(pPrivate->pEditor) {
1381 dasher_editor_output(pPrivate->pEditor, szText, iOffset);
1385 extern "C" void
1386 convert_cb(GtkDasherControl *pDasherControl, gpointer pUserData) {
1387 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pUserData);
1389 if(pPrivate->pEditor) {
1390 dasher_editor_edit_convert(pPrivate->pEditor);
1394 extern "C" void
1395 protect_cb(GtkDasherControl *pDasherControl, gpointer pUserData) {
1396 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pUserData);
1398 if(pPrivate->pEditor) {
1399 dasher_editor_edit_protect(pPrivate->pEditor);