Trivial commit to keep doxygen happy
[dasher.git] / Src / Gtk2 / dasher_main.cpp
blob0813c95ce720b317324d1bc21917f5e185c19a24
1 #include "config.h"
3 #include <gdk/gdk.h>
4 #include <gdk/gdkx.h>
5 #include <glade/glade.h>
6 #include <glib/gi18n.h>
7 #include <gtk/gtk.h>
8 #ifdef WITH_MAEMOFULLSCREEN
9 #include <hildon-widgets/hildon-program.h>
10 #endif
11 #include <libgnome/libgnome.h>
13 #include "GtkDasherControl.h"
14 #include "KeyboardHelper.h"
15 #include "Preferences.h"
16 #include "dasher_lock_dialogue.h"
17 #ifdef WITH_MAEMO
18 #include "dasher_maemo_helper.h"
19 #endif
20 #include "dasher_main.h"
22 /* Static instance of singleton, USE SPARINGLY */
23 static DasherMain *g_pDasherMain = NULL;
25 // TODO: The following global variable makes control mode editing work
26 // - this needs to be sorted out properly.
27 static gboolean g_bSend = true;
29 struct _DasherMainPrivate {
30 // The glade XML file - TODO: this shouldn't be kept after interface has been loaded
31 GladeXML *pGladeXML;
33 // Child objects owned here
34 DasherAppSettings *pAppSettings;
35 DasherPreferencesDialogue *pPreferencesDialogue;
36 DasherEditor *pEditor;
38 CKeyboardHelper *pKeyboardHelper;
40 // Various widgets which need to be cached:
41 GtkWidget *pBufferView;
42 GtkWidget *pDivider;
43 GtkWidget *pMainWindow;
44 GtkWidget *pToolbar;
45 GtkWidget *pSpeedBox;
46 GtkWidget *pAlphabetCombo;
47 GtkWidget *pStatusControl;
48 GtkWidget *pDasherWidget;
50 GtkListStore *pAlphabetList;
51 GtkAccelGroup *pAccel;
52 gulong iAlphabetComboHandler;
54 // Widgets used for maemo
55 #ifdef WITH_MAEMO
56 DasherMaemoHelper *pMaemoHelper;
57 #ifdef WITH_MAEMOFULLSCREEN
58 HildonProgram *pProgram;
59 HildonWindow *pHWindow;
60 #endif
61 #endif
63 // Properties of the main window
64 int iWidth;
65 int iHeight;
66 bool bWidgetsInitialised;
69 typedef struct _DasherMainPrivate DasherMainPrivate;
71 // TODO: Make sure this is actually used
72 #define DASHER_MAIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_DASHER_MAIN, DasherMainPrivate))
74 enum {
75 REALIZED,
76 SIGNAL_NUM
79 static guint dasher_main_signals[SIGNAL_NUM] = { 0 };
81 /* Automatic command hookups */
83 typedef struct _DasherMenuCommand DasherMenuCommand;
85 struct _DasherMenuCommand {
86 GtkWidget *pWidget;
87 const gchar *szWidgetName;
88 const gchar *szCommand;
91 static DasherMenuCommand MenuCommands[] = {
92 /* Menus */
93 {NULL, "menu_command_new", "new"},
94 {NULL, "menu_command_open", "open"},
95 {NULL, "menu_command_save", "save"},
96 {NULL, "menu_command_saveas", "saveas"},
97 {NULL, "menu_command_append", "append"},
98 {NULL, "menu_command_import", "import"},
99 {NULL, "menu_command_quit", "quit"},
100 {NULL, "menu_command_cut", "cut"},
101 {NULL, "menu_command_copy", "copy"},
102 {NULL, "menu_command_copyall", "copyall"},
103 {NULL, "menu_command_paste", "paste"},
104 {NULL, "menu_command_preferences", "preferences"},
105 {NULL, "menu_command_tutorial", "tutorial"},
106 {NULL, "menu_command_help", "help"},
107 {NULL, "menu_command_about", "about"},
109 /* Toolbar */
110 {NULL, "tb_command_new", "new"},
111 {NULL, "tb_command_open", "open"},
112 {NULL, "tb_command_save", "save"},
113 {NULL, "tb_command_saveas", "saveas"},
114 {NULL, "tb_command_cut", "cut"},
115 {NULL, "tb_command_copy", "copy"},
116 {NULL, "tb_command_paste", "paste"}
119 G_DEFINE_TYPE(DasherMain, dasher_main, G_TYPE_OBJECT);
121 static void dasher_main_finalize(GObject *pObject);
123 /* Private member functions */
124 static void dasher_main_setup_window_state(DasherMain *pSelf);
125 static void dasher_main_setup_window_style(DasherMain *pSelf);
126 static void dasher_main_setup_internal_layout(DasherMain *pSelf);
127 static void dasher_main_refresh_font(DasherMain *pSelf);
128 static void dasher_main_set_filename(DasherMain *pSelf);
130 /* ... Table based menu/toolbar commands */
131 static void dasher_main_connect_menus(DasherMain *pSelf);
132 static void dasher_main_menu_command(DasherMain *pSelf, GtkWidget *pWidget);
134 static void dasher_main_command_import(DasherMain *pSelf);
135 static void dasher_main_command_quit(DasherMain *pSelf);
136 static void dasher_main_command_preferences(DasherMain *pSelf);
137 static void dasher_main_command_preferences_alphabet(DasherMain *pSelf);
138 static void dasher_main_command_tutorial(DasherMain *pSelf);
139 static void dasher_main_command_help(DasherMain *pSelf);
140 static void dasher_main_command_about(DasherMain *pself);
142 static gboolean dasher_main_speed_changed(DasherMain *pSelf);
143 static void dasher_main_alphabet_combo_changed(DasherMain *pSelf);
144 // TODO: populate speed slider
145 static void dasher_main_populate_alphabet_combo(DasherMain *pSelf);
147 /* TODO: order these in file */
148 static void dasher_main_load_interface(DasherMain *pSelf);
149 static void dasher_main_create_preferences(DasherMain *pSelf);
150 static void dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter);
151 static void dasher_main_load_state(DasherMain *pSelf);
152 static void dasher_main_save_state(DasherMain *pSelf);
153 static void dasher_main_setup_window(DasherMain *pSelf);
154 static void dasher_main_populate_controls(DasherMain *pSelf);
155 static void dasher_main_connect_control(DasherMain *pSelf);
156 static gboolean dasher_main_command(DasherMain *pSelf, const gchar *szCommand);
157 static gint dasher_main_lookup_key(DasherMain *pSelf, guint iKeyVal);
159 /* TODO: Various functions which haven't yet been rationalised */
160 gboolean grab_focus();
162 // TODO: Sort out callbacks - 1 rename, 2 check return values
164 /* Callback functions */
165 extern "C" GtkWidget *create_dasher_control(gchar *szName, gchar *szString1, gchar *szString2, gint iInt1, gint iInt2);
166 extern "C" GtkWidget *create_dasher_editor(gchar *szName, gchar *szString1, gchar *szString2, gint iInt1, gint iInt2);
168 /* ... Message handling from main window widgets */
169 extern "C" gboolean dasher_main_cb_menu_command(GtkWidget *pWidget, gpointer pUserData);
170 extern "C" gboolean speed_changed(GtkWidget *pWidget, gpointer user_data);
171 extern "C" void alphabet_combo_changed(GtkWidget *pWidget, gpointer pUserData);
172 extern "C" void dasher_main_cb_filename_changed(DasherEditor *pEditor, gpointer pUserData);
173 extern "C" void dasher_main_cb_buffer_changed(DasherEditor *pEditor, gpointer pUserData);
174 extern "C" void dasher_main_cb_context_changed(DasherEditor *pEditor, gpointer pUserData);
175 extern "C" gboolean dasher_main_cb_window_close(GtkWidget *pWidget, gpointer pUserData);
176 extern "C" void parameter_notification(GtkDasherControl *pDasherControl, gint iParameter, gpointer data);
178 /* ... Focus management and event forwarding */
179 extern "C" bool focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
180 extern "C" bool edit_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
181 extern "C" gboolean take_real_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data);
183 extern "C" gboolean edit_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
184 extern "C" gboolean edit_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
186 /* ... Temporary test/debug functions */
187 extern "C" gboolean test_focus_handler(GtkWidget *pWidget, GtkDirectionType iDirection, gpointer *pUserData);
189 extern "C" void handle_context_request(GtkDasherControl * pDasherControl, gint iOffset, gint iLength, gpointer data);
190 extern "C" void handle_control_event(GtkDasherControl *pDasherControl, gint iEvent, gpointer data);
191 extern "C" void handle_start_event(GtkDasherControl *pDasherControl, gpointer data);
192 extern "C" gint dasher_main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent, gpointer pUserData);
194 /* Boilerplate code */
195 static void
196 dasher_main_class_init(DasherMainClass *pClass) {
197 g_type_class_add_private(pClass, sizeof(DasherMainPrivate));
199 dasher_main_signals[REALIZED] = g_signal_new("realized", G_TYPE_FROM_CLASS(pClass),
200 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
201 G_STRUCT_OFFSET(DasherMainClass, realized),
202 NULL, NULL, g_cclosure_marshal_VOID__VOID,
203 G_TYPE_NONE, 0);
205 GObjectClass *pObjectClass = (GObjectClass *)pClass;
206 pObjectClass->finalize = dasher_main_finalize;
209 static void
210 dasher_main_init(DasherMain *pDasherMain) {
211 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
213 /* TODO: define log domain */
214 g_debug("Initialising DasherMain");
216 pPrivate->pAppSettings = NULL;
217 pPrivate->pEditor = NULL;
218 pPrivate->pPreferencesDialogue = NULL;
220 pPrivate->pKeyboardHelper = new CKeyboardHelper(NULL);
222 pPrivate->bWidgetsInitialised = false;
225 static void
226 dasher_main_finalize(GObject *pObject) {
227 /* TODO: Need a general overview of class finalisation */
228 g_debug("Finalizing DasherMain");
230 DasherMain *pDasherMain = DASHER_MAIN(pObject);
231 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
233 dasher_main_save_state(pDasherMain);
235 /* TODO: Does unref really do the right thing - check the whole ref counting situation */
236 if(pPrivate->pEditor)
237 g_object_unref(pPrivate->pEditor);
239 if(pPrivate->pPreferencesDialogue)
240 g_object_unref(pPrivate->pPreferencesDialogue);
242 if(pPrivate->pAppSettings)
243 g_object_unref(pPrivate->pAppSettings);
245 gtk_widget_destroy(pPrivate->pMainWindow);
247 /* TDO: Do we need to take down anything else? */
250 /* Public methods */
251 DasherMain *
252 dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
253 if(g_pDasherMain)
254 return g_pDasherMain;
255 else {
256 DasherMain *pDasherMain = (DasherMain *)(g_object_new(dasher_main_get_type(), NULL));
257 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
259 /* Create the app settings object */
260 pPrivate->pAppSettings = dasher_app_settings_new(*argc, *argv);
262 /* Load the user interface from the glade file */
263 if(pCommandLine && pCommandLine->szAppStyle) {
264 if(!strcmp(pCommandLine->szAppStyle, "traditional")) {
265 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 0);
267 else if(!strcmp(pCommandLine->szAppStyle, "compose")) {
268 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 1);
270 else if(!strcmp(pCommandLine->szAppStyle, "direct")) {
271 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 2);
273 else if(!strcmp(pCommandLine->szAppStyle, "fullscreen")) {
274 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 3);
276 else {
277 g_error("Application style %s is not supported", pCommandLine->szAppStyle);
280 else {
281 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 0);
284 dasher_main_load_interface(pDasherMain);
286 dasher_app_settings_set_widget(pPrivate->pAppSettings, GTK_DASHER_CONTROL(pPrivate->pDasherWidget));
287 dasher_editor_initialise(pPrivate->pEditor, pPrivate->pAppSettings, pDasherMain, pPrivate->pGladeXML, NULL);
290 dasher_main_setup_window(pDasherMain);
292 /* Create the editor */
293 gchar *szFullPath = NULL;
295 if(pCommandLine) {
296 if(pCommandLine->szFilename) {
297 if(!g_path_is_absolute(pCommandLine->szFilename)) {
298 char *cwd;
299 cwd = (char *)malloc(1024 * sizeof(char));
300 getcwd(cwd, 1024);
301 szFullPath = g_build_path("/", cwd, pCommandLine->szFilename, NULL);
303 else {
304 szFullPath = g_strdup(pCommandLine->szFilename);
309 // TODO: Fix this
310 // pPrivate->pEditor = GTK_EDITOR(
313 // dasher_editor_initialise(pPrivate->pAppSettings, pDasherMain, pPrivate->pGladeXML, szFullPath);
315 g_free(szFullPath);
317 g_signal_connect(pPrivate->pEditor, "filename_changed", G_CALLBACK(dasher_main_cb_filename_changed), pDasherMain);
318 g_signal_connect(pPrivate->pEditor, "buffer_changed", G_CALLBACK(dasher_main_cb_buffer_changed), pDasherMain);
319 g_signal_connect(pPrivate->pEditor, "context_changed", G_CALLBACK(dasher_main_cb_context_changed), pDasherMain);
321 /* Create the preferences window */
322 dasher_main_create_preferences(pDasherMain);
324 /* Create the lock dialogue (to be removed in future versions) */
325 #ifndef WITH_MAEMO
326 dasher_lock_dialogue_new(pPrivate->pGladeXML, GTK_WINDOW(pPrivate->pMainWindow));
327 #else
328 dasher_lock_dialogue_new(pPrivate->pGladeXML, 0);
329 #endif
331 /* Set up various bits and pieces */
332 dasher_main_set_filename(pDasherMain);
333 dasher_main_populate_controls(pDasherMain);
334 dasher_main_connect_control(pDasherMain);
336 gtk_key_snooper_install(dasher_main_key_snooper, pDasherMain);
338 /* Cache a file-wide static pointer to the singleton class */
339 g_pDasherMain = pDasherMain;
341 return pDasherMain;
345 /* Load the window interface from the glade file, and do various initialisation bits and pieces */
346 static void
347 dasher_main_load_interface(DasherMain *pSelf) {
348 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
350 const char *szGladeFilename = NULL;
352 #ifdef WITH_GPE
353 szGladeFilename = PROGDATA "/dashergpe.glade";
354 #elif WITH_MAEMO
355 #ifdef WITH_MAEMOFULLSCREEN
356 // szGladeFilename = "/var/lib/install" PROGDATA "/dashermaemofullscreen.glade";
357 szGladeFilename = PROGDATA "/dashermaemofullscreen.glade";
358 #else
359 //szGladeFilename = "/var/lib/install" PROGDATA "/dashermaemo.glade";
360 szGladeFilename = PROGDATA "/dashermaemo.glade";
361 #endif
362 #else
363 switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
364 case 0:
365 szGladeFilename = PROGDATA "/dasher.traditional.glade";
366 break;
367 case 1:
368 szGladeFilename = PROGDATA "/dasher.compose.glade";
369 break;
370 case 2:
371 szGladeFilename = PROGDATA "/dasher.direct.glade";
372 break;
373 case 3:
374 szGladeFilename = PROGDATA "/dasher.fullscreen.glade";
375 break;
376 default:
377 g_error("Inconsistent application style specified.");
379 #endif
381 if(!szGladeFilename) {
382 g_error("Failure to determine glade filename");
385 pPrivate->pGladeXML = glade_xml_new(szGladeFilename, NULL, NULL);
387 if (!pPrivate->pGladeXML) {
388 g_error("Can't find Glade file: %s. Dasher is unlikely to be correctly installed.", szGladeFilename);
391 glade_xml_signal_autoconnect(pPrivate->pGladeXML);
393 // Save the details of some of the widgets for later
394 // pPrivate->pActionPane = glade_xml_get_widget(pPrivate->pGladeXML, "vbox39");
395 pPrivate->pBufferView = glade_xml_get_widget(pPrivate->pGladeXML, "the_text_view");
396 pPrivate->pDivider = glade_xml_get_widget(pPrivate->pGladeXML, "main_divider");
397 // pPrivate->pEditPane = glade_xml_get_widget(pPrivate->pGladeXML, "vbox40");
398 pPrivate->pMainWindow = glade_xml_get_widget(pPrivate->pGladeXML, "window");
399 pPrivate->pToolbar = glade_xml_get_widget(pPrivate->pGladeXML, "toolbar");
400 // pPrivate->pMenuBar = glade_xml_get_widget(pPrivate->pGladeXML, "dasher_menu_bar");
401 pPrivate->pDasherWidget = glade_xml_get_widget(pPrivate->pGladeXML, "DasherControl");
403 #ifndef WITH_MAEMO
404 pPrivate->pSpeedBox = glade_xml_get_widget(pPrivate->pGladeXML, "spinbutton1");
405 pPrivate->pAlphabetCombo = glade_xml_get_widget(pPrivate->pGladeXML, "combobox1");
406 pPrivate->pStatusControl = glade_xml_get_widget(pPrivate->pGladeXML, "hbox8");
408 pPrivate->pAlphabetList = gtk_list_store_new(1, G_TYPE_STRING);
409 gtk_combo_box_set_model(GTK_COMBO_BOX(pPrivate->pAlphabetCombo),
410 GTK_TREE_MODEL(pPrivate->pAlphabetList));
412 GtkCellRenderer *pRenderer;
413 pRenderer = gtk_cell_renderer_text_new();
414 #if GTK_CHECK_VERSION(2,6,0)
415 g_object_set(G_OBJECT(pRenderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
416 #endif
417 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pPrivate->pAlphabetCombo), pRenderer, true);
418 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pPrivate->pAlphabetCombo), pRenderer, "text", 0, NULL);
421 // gtk_widget_add_events(pPrivate->pDragHandle, GDK_POINTER_MOTION_MASK);
422 #else
424 #ifdef WITH_MAEMOFULLSCREEN
425 // TODO: This is horrible - no need to get it from the glade file if we're not going to use it
427 pPrivate->pProgram = HILDON_PROGRAM(hildon_program_get_instance());
428 // hildon_app_set_title(pPrivate->pApp, "Dasher");
430 pPrivate->pHWindow = HILDON_WINDOW(hildon_window_new());
431 hildon_program_add_window(pPrivate->pProgram, pPrivate->pHWindow);
433 gtk_widget_reparent(pPrivate->pInnerFrame, GTK_WIDGET(pPrivate->pHWindow));
434 // gtk_paned_set_position(GTK_PANED(window), 100);
436 /* Do menu setup */
437 GtkMenu *main_menu;
438 GtkWidget *file_menu;
439 GtkWidget *file_menu_item;
440 GtkWidget *options_menu;
441 GtkWidget *options_menu_item;
442 GtkWidget *help_menu;
443 GtkWidget *help_menu_item;
446 // main_menu = hildon_appview_get_menu(appview);
448 main_menu = GTK_MENU(gtk_menu_new());
449 file_menu = glade_xml_get_widget(pPrivate->pGladeXML, "menuitem4_menu");
450 options_menu = glade_xml_get_widget(pPrivate->pGladeXML, "options1_menu");
451 help_menu = glade_xml_get_widget(pPrivate->pGladeXML, "menuitem7_menu");
452 file_menu_item = gtk_menu_item_new_with_label ("File");
453 options_menu_item = gtk_menu_item_new_with_label ("Options");
454 help_menu_item = gtk_menu_item_new_with_label ("Help");
456 g_object_ref(file_menu);
457 g_object_ref(options_menu);
458 g_object_ref(help_menu);
460 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(glade_xml_get_widget(pPrivate->pGladeXML, "menuitem4")));
461 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(glade_xml_get_widget(pPrivate->pGladeXML, "options1")));
462 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(glade_xml_get_widget(pPrivate->pGladeXML, "menuitem7")));
464 gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_menu_item),file_menu);
465 gtk_menu_item_set_submenu(GTK_MENU_ITEM(options_menu_item),options_menu);
466 gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_menu_item),help_menu);
467 gtk_menu_append(main_menu, file_menu_item);
468 gtk_menu_append(main_menu, options_menu_item);
469 gtk_menu_append(main_menu, help_menu_item);
471 g_object_unref(file_menu);
472 g_object_unref(options_menu);
473 g_object_unref(help_menu);
475 hildon_program_set_common_menu(pPrivate->pProgram, main_menu);
477 gtk_widget_show_all( GTK_WIDGET( main_menu ) );
479 // /* And toolbar */
480 // GtkWidget *toolbar;
481 // toolbar = glade_xml_get_widget(pPrivate->pGladeXML, "toolbar");
482 // g_print("Got %p\n",toolbar);
483 // gtk_widget_reparent (toolbar, appview->vbox);
485 gtk_widget_show_all(GTK_WIDGET(pPrivate->pHWindow));
487 gtk_widget_destroy(pPrivate->pMainWindow);
488 pPrivate->pMainWindow = GTK_WIDGET(pPrivate->pHWindow);
490 g_signal_connect(G_OBJECT(pPrivate->pHWindow), "delete_event", G_CALLBACK(ask_save_before_exit), NULL);
492 #endif // Maemo fullscreen
493 #endif // Maemo
495 // pPrivate->bHidden = false;
496 // pPrivate->bGrabbed = false;
498 // pPrivate->iPosition = 100; // FIXME - make this persistant
500 // TODO: Specify callbacks in glade file
501 // TODO: Rationalise focus
502 g_signal_connect(G_OBJECT(pPrivate->pBufferView), "button-release-event", G_CALLBACK(take_real_focus), NULL);
503 g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-press-event", G_CALLBACK(edit_key_press), NULL);
504 g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-release-event", G_CALLBACK(edit_key_release), NULL);
506 pPrivate->iAlphabetComboHandler = g_signal_connect(G_OBJECT(pPrivate->pAlphabetCombo), "changed", G_CALLBACK(alphabet_combo_changed), NULL);
508 // dasher_main_build_context_menu(pSelf);
510 // Create a Maemo helper if necessary
511 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
512 pPrivate->pMaemoHelper = dasher_maemo_helper_new(GTK_WINDOW(pPrivate->pMainWindow));
513 #endif
515 // Set up any non-registry-dependent options
516 #ifdef WITH_GPE
517 gtk_window_set_decorated(GTK_WINDOW(pPrivate->pMainWindow), false);
518 #endif
520 dasher_main_connect_menus(pSelf);
523 pPrivate->pEditor = DASHER_EDITOR(glade_xml_get_widget(pPrivate->pGladeXML, "DasherEditor"));
524 // TODO: szFullPath
525 pPrivate->bWidgetsInitialised = true;
528 static void
529 dasher_main_create_preferences(DasherMain *pSelf) {
530 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
531 pPrivate->pPreferencesDialogue = dasher_preferences_dialogue_new(pPrivate->pGladeXML, pPrivate->pEditor, pPrivate->pAppSettings, GTK_WINDOW(pPrivate->pMainWindow));
534 // DasherEditor *
535 // dasher_main_get_editor(DasherMain *pSelf) {
536 // DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
537 // return pPrivate->pEditor;
538 // }
540 static void
541 dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter) {
542 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
544 switch( iParameter ) {
545 case APP_BP_SHOW_TOOLBAR:
546 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
547 gtk_widget_show(pPrivate->pToolbar);
548 else
549 gtk_widget_hide(pPrivate->pToolbar);
550 break;
551 case BP_SHOW_SLIDER: // TODO: Shouldn't be a core parmeter
552 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_SHOW_SLIDER))
553 gtk_widget_show(pPrivate->pStatusControl);
554 else
555 gtk_widget_hide(pPrivate->pStatusControl);
556 break;
557 case APP_SP_EDIT_FONT:
558 // TODO: Editor should handle this directly
559 dasher_main_refresh_font(pSelf);
560 break;
561 #ifndef WITH_MAEMO
562 case LP_MAX_BITRATE:
563 gtk_spin_button_set_value(GTK_SPIN_BUTTON(pPrivate->pSpeedBox), dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
564 break;
565 #endif
566 case SP_ALPHABET_ID:
567 dasher_main_populate_alphabet_combo(pSelf);
568 break;
569 case BP_GLOBAL_KEYBOARD:
570 dasher_main_setup_window(pSelf);
571 break;
572 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
573 case APP_LP_MAEMO_SIZE: {
574 g_message("Maemo size");
576 bool bVisible = GTK_WIDGET_VISIBLE(pPrivate->pMainWindow);
577 gtk_widget_hide(pPrivate->pMainWindow);
578 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_MAEMO_SIZE) == 0) {
579 int iWidth;
580 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
581 gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 150);
582 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWidth, 150);
583 gtk_widget_set_size_request(pPrivate->pDasherWidget, 175, -1);
585 else {
586 int iWidth;
587 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
588 gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 250);
589 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWidth, 250);
590 gtk_widget_set_size_request(pPrivate->pDasherWidget, 280, -1);
592 if(bVisible)
593 gtk_widget_show(pPrivate->pMainWindow);
594 break;
596 #endif
599 // TODO: Pass into editor?
600 dasher_preferences_dialogue_handle_parameter_change(pPrivate->pPreferencesDialogue, iParameter);
603 static void
604 dasher_main_load_state(DasherMain *pSelf) {
605 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
607 int iWindowWidth;
608 int iWindowHeight;
609 int iEditHeight;
611 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != 1) {
612 iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT);
613 iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH);
614 iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT);
616 else {
617 iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH);
618 iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H);
619 iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H);
622 #ifndef WITH_MAEMO
623 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWindowWidth, iWindowHeight);
624 #endif
626 gtk_paned_set_position(GTK_PANED(pPrivate->pDivider), iEditHeight);
628 pPrivate->iWidth = iWindowWidth;
629 pPrivate->iHeight = iWindowHeight;
631 // pPrivate->iPosition = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_DOCK_POSITION);
634 static void
635 dasher_main_save_state(DasherMain *pSelf) {
636 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
638 if(!pPrivate->bWidgetsInitialised)
639 return;
641 int iWindowWidth;
642 int iWindowHeight;
643 int iEditHeight;
645 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWindowWidth, &iWindowHeight);
646 iEditHeight = gtk_paned_get_position(GTK_PANED(pPrivate->pDivider));
648 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != 1) {
649 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT, iEditHeight);
650 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH, iWindowWidth);
651 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT, iWindowHeight);
653 else {
654 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH, iEditHeight);
655 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H, iWindowWidth);
656 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H, iWindowHeight);
659 // dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_DOCK_POSITION, pPrivate->iPosition);
662 void
663 dasher_main_show(DasherMain *pSelf) {
664 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
665 gtk_widget_show(pPrivate->pMainWindow);
668 static void
669 dasher_main_setup_window(DasherMain *pSelf) {
670 dasher_main_setup_window_style(pSelf);
671 dasher_main_setup_window_state(pSelf);
672 dasher_main_setup_internal_layout(pSelf);
674 // DasherMainPrivate *pPrivate = (DasherMainPrivate *)(pSelf->private_data);
676 // if(dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_GLOBAL_KEYBOARD))
677 // gdk_window_add_filter(0, keyboard_filter_cb, 0);
678 // else
679 // gdk_window_remove_filter(0, keyboard_filter_cb, 0);
682 static void
683 dasher_main_populate_controls(DasherMain *pSelf) {
684 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
686 // Populate the alphabet chooser
687 dasher_main_populate_alphabet_combo(pSelf);
689 // Set the value of the speed spinner
690 gtk_spin_button_set_value(GTK_SPIN_BUTTON(pPrivate->pSpeedBox),
691 dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
694 static void
695 dasher_main_connect_control(DasherMain *pSelf) {
696 /* TODO: This is very much temporary - we need to think of a better
697 way of presenting application commands in a unified way */
698 #ifdef GNOME_SPEECH
699 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
701 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
702 Dasher::CControlManager::CTL_USER,
703 "Speak", -1 );
705 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
706 Dasher::CControlManager::CTL_USER,
707 Dasher::CControlManager::CTL_ROOT, -2);
710 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
711 Dasher::CControlManager::CTL_USER + 1,
712 "All", -1 );
714 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
715 Dasher::CControlManager::CTL_USER + 2,
716 "Last", -1 );
718 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
719 Dasher::CControlManager::CTL_USER + 3,
720 "Repeat", -1 );
722 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
723 Dasher::CControlManager::CTL_USER + 1,
724 Dasher::CControlManager::CTL_USER, -2);
726 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
727 -1,
728 Dasher::CControlManager::CTL_USER + 1, -2);
730 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
731 Dasher::CControlManager::CTL_USER + 2,
732 Dasher::CControlManager::CTL_USER, -2);
734 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
736 Dasher::CControlManager::CTL_USER + 2, -2);
738 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
739 Dasher::CControlManager::CTL_USER + 3,
740 Dasher::CControlManager::CTL_USER, -2);
742 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
744 Dasher::CControlManager::CTL_USER + 3, -2);
746 #endif
750 static gboolean
751 dasher_main_command(DasherMain *pSelf, const gchar *szCommand) {
752 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
754 if(!strcmp(szCommand, "import")) {
755 dasher_main_command_import(pSelf);
756 return TRUE;
759 if(!strcmp(szCommand, "quit")) {
760 dasher_main_command_quit(pSelf);
761 return TRUE;
764 if(!strcmp(szCommand, "preferences")) {
765 dasher_main_command_preferences(pSelf);
766 return TRUE;
769 if(!strcmp(szCommand, "preferences_alphabet")) {
770 dasher_main_command_preferences_alphabet(pSelf);
771 return TRUE;
774 if(!strcmp(szCommand, "tutorial")) {
775 dasher_main_command_tutorial(pSelf);
776 return TRUE;
779 if(!strcmp(szCommand, "help")) {
780 dasher_main_command_help(pSelf);
781 return TRUE;
784 if(!strcmp(szCommand, "about")) {
785 dasher_main_command_about(pSelf);
786 return TRUE;
789 if(pPrivate->pEditor)
790 return dasher_editor_command(pPrivate->pEditor, szCommand);
792 return FALSE;
795 /* Private methods */
797 /* Window state is basically size and position */
798 static void
799 dasher_main_setup_window_state(DasherMain *pSelf) {
800 dasher_main_load_state(pSelf);
802 // TODO: Setup positioning here - need to think up a policy on this
806 /* Setup the window style - this is defined to be window manager hints and the like */
807 static void
808 dasher_main_setup_window_style(DasherMain *pSelf) {
809 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
811 switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
812 case 0:
813 // Nothing to do
814 break;
815 case 1:
816 // Nothing to do
817 break;
818 case 2:
819 // Direct mode - set always on top
820 gtk_window_set_keep_above(GTK_WINDOW(pPrivate->pMainWindow), true);
822 // Refuse focus
823 gtk_window_set_accept_focus(GTK_WINDOW(pPrivate->pMainWindow), false);
824 break;
825 case 3:
826 // Fullscreen mode - set fullscreen
827 gtk_window_fullscreen(GTK_WINDOW(pPrivate->pMainWindow));
828 break;
829 default:
830 g_error("Inconsistent application style specified.");
834 /* Internal layout is the visibility of various widgets */
835 static void
836 dasher_main_setup_internal_layout(DasherMain *pSelf) {
837 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
839 if(pPrivate->pToolbar) {
840 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
841 gtk_widget_show(pPrivate->pToolbar);
842 else
843 gtk_widget_hide(pPrivate->pToolbar);
846 if(pPrivate->pStatusControl) {
847 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_SHOW_SLIDER))
848 gtk_widget_show(pPrivate->pStatusControl);
849 else
850 gtk_widget_hide(pPrivate->pStatusControl);
853 dasher_main_refresh_font(pSelf);
856 static void
857 dasher_main_refresh_font(DasherMain *pSelf) {
858 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
860 dasher_editor_handle_font(pPrivate->pEditor,
861 dasher_app_settings_get_string(pPrivate->pAppSettings, APP_SP_EDIT_FONT));
864 // TODO: Fold into setup controls?
865 static void
866 dasher_main_set_filename(DasherMain *pSelf) {
867 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
869 const gchar *szFilename = dasher_editor_get_filename(pPrivate->pEditor);
871 if(szFilename == 0) {
872 gtk_window_set_title(GTK_WINDOW(pPrivate->pMainWindow), "Dasher");
874 else {
875 // TODO: Prepend 'Dasher - ' to filename?
876 gtk_window_set_title(GTK_WINDOW(pPrivate->pMainWindow), szFilename);
880 static void
881 dasher_main_connect_menus(DasherMain *pSelf) {
882 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
884 int iNumItems = sizeof(MenuCommands) / sizeof(DasherMenuCommand);
886 for(int i(0); i < iNumItems; ++i) {
887 GtkWidget *pWidget;
889 pWidget = glade_xml_get_widget(pPrivate->pGladeXML, MenuCommands[i].szWidgetName);
891 MenuCommands[i].pWidget = pWidget;
893 // TODO: Check that these are the right signals to connect to
894 if(pWidget)
895 if(GTK_IS_MENU_ITEM(pWidget))
896 g_signal_connect(G_OBJECT(pWidget), "activate", G_CALLBACK(dasher_main_cb_menu_command), pSelf);
897 else
898 g_signal_connect(G_OBJECT(pWidget), "clicked", G_CALLBACK(dasher_main_cb_menu_command), pSelf);
902 static void
903 dasher_main_menu_command(DasherMain *pSelf, GtkWidget *pWidget) {
904 int iNumItems = sizeof(MenuCommands) / sizeof(DasherMenuCommand);
906 for(int i(0); i < iNumItems; ++i) {
907 if(MenuCommands[i].pWidget == pWidget) {
908 dasher_main_command(pSelf, MenuCommands[i].szCommand);
909 return;
914 static void
915 dasher_main_command_import(DasherMain *pSelf) {
916 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
918 GtkWidget *pFileSel = gtk_file_chooser_dialog_new(_("Select File"),
919 GTK_WINDOW(pPrivate->pMainWindow),
920 GTK_FILE_CHOOSER_ACTION_OPEN,
921 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
922 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
923 NULL);
925 #ifdef GNOME_LIBS
926 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(pFileSel), FALSE);
927 #endif
929 if(gtk_dialog_run(GTK_DIALOG(pFileSel)) == GTK_RESPONSE_ACCEPT) {
931 #ifdef GNOME_LIBS
932 gchar *szFilename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(pFileSel));
933 #else
934 gchar *szFilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSel));
935 #endif
937 gtk_dasher_control_train(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), szFilename);
939 g_free(szFilename);
942 gtk_widget_destroy(pFileSel);
945 static void dasher_main_command_quit(DasherMain *pSelf) {
946 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
948 GtkWidget *pDialogue = NULL;
950 if(dasher_editor_file_changed(pPrivate->pEditor)) {
951 const gchar *szFilename = dasher_editor_get_filename(pPrivate->pEditor);
953 if(szFilename) {
954 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
955 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
956 _("Do you want to save your changes to %s?\n\nYour changes will be lost if you don't save them."),
957 szFilename);
959 else {
960 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
961 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
962 _("Do you want to save your changes?\n\nYour changes will be lost if you don't save them."));
965 gtk_dialog_add_buttons(GTK_DIALOG(pDialogue),
966 _("Don't save"), GTK_RESPONSE_REJECT,
967 _("Don't quit"), GTK_RESPONSE_CANCEL,
968 _("Save and quit"), GTK_RESPONSE_ACCEPT,
969 NULL);
971 switch (gtk_dialog_run(GTK_DIALOG(pDialogue))) {
972 case GTK_RESPONSE_REJECT:
973 // write_to_file(); // FIXME - REIMPLEMENT
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 gtk_widget_destroy(GTK_WIDGET(pDialogue));
981 // write_to_file(); // FIXME - REIMPLEMENT
982 // save_file_and_quit(NULL, NULL);
985 else {
986 // It should be noted that write_to_file merely saves the new text to the training
987 // file rather than saving it to a file of the user's choice
989 // FIXME - REIMPLEMENT
991 // write_to_file();
993 gtk_main_quit();
997 static void
998 dasher_main_command_preferences(DasherMain *pSelf) {
999 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1000 dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue, 0);
1003 static void
1004 dasher_main_command_preferences_alphabet(DasherMain *pSelf) {
1005 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1006 dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue, 1);
1009 static void
1010 dasher_main_command_tutorial(DasherMain *pSelf) {
1011 // TODO: Implement this
1014 static void
1015 dasher_main_command_help(DasherMain *pSelf) {
1016 // TODO: Need to disable the menu if gnome libs aren't present (or get rid of without gnome option)
1017 #ifdef GNOME_LIBS
1018 gnome_help_display_desktop(NULL, "dasher", "dasher", NULL, NULL);
1019 #endif
1022 static void
1023 dasher_main_command_about(DasherMain *pSelf) {
1024 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1026 #if (defined GNOME_LIBS) || (GTK_CHECK_VERSION(2,6,0))
1028 // In alphabetical order
1029 const gchar *authors[] = {
1030 "Chris Ball",
1031 "Ignas Budvytis",
1032 "Phil Cowans",
1033 "Frederik Eaton",
1034 "Behdad Esfahbod",
1035 "Matthew Garrett",
1036 "Chris Hack",
1037 "David MacKay",
1038 "Iain Murray",
1039 "Takashi Kaburagi",
1040 "Keith Vertanen",
1041 "Hanna Wallach",
1042 "David Ward",
1043 "Brian Williams",
1044 "Seb Wills",
1045 "Will Zou",
1046 NULL
1049 // Yeah, should really do some Gnome documentation for it...
1050 const gchar *documenters[] = {
1051 "Chris Ball",
1052 "Matthew Garrett",
1053 "David MacKay",
1054 NULL
1057 #if GTK_CHECK_VERSION(2,6,0)
1058 gtk_show_about_dialog(GTK_WINDOW(pPrivate->pMainWindow),
1059 "authors", authors,
1060 "comments", _("Dasher is a predictive text entry application"),
1061 "copyright", "Copyright \xC2\xA9 1998-2007 The Dasher Project",
1062 "documenters", documenters,
1063 "license", "GPL 2+",
1064 "logo-icon-name", "dasher",
1065 "translator-credits", _("translator-credits"),
1066 "version", VERSION,
1067 "website", "http://www.dasher.org.uk/",
1068 "wrap-license", true,
1069 NULL);
1070 #else
1071 gchar *translator_credits = _("translator-credits");
1073 GtkWidget *about = gnome_about_new (_("Dasher"),
1074 PACKAGE_VERSION,
1075 "Copyright The Dasher Project\n",
1076 _("Dasher is a predictive text entry application"),
1077 (const char **)authors,
1078 (const char **)documenters,
1079 strcmp (translator_credits, "translator-credits") != 0 ? (const char *)translator_credits : NULL,
1080 NULL);
1082 gtk_window_set_transient_for (GTK_WINDOW(about), GTK_WINDOW(pPrivate->pMainWindow));
1083 // g_signal_connect (G_OBJECT (about), "destory", G_CALLBACK (gtk_widget_destroyed), &about);
1084 gtk_widget_show(about);
1086 #endif
1088 #else
1089 // EAT UGLY ABOUT BOX, PHILISTINE
1090 GtkWidget *label, *button;
1091 char *tmp;
1093 GtkWidget *about = gtk_dialog_new();
1095 gtk_dialog_set_has_separator(GTK_DIALOG(about), FALSE);
1096 gtk_window_set_title(GTK_WINDOW(about), "About Dasher");
1098 tmp = g_strdup_printf("Dasher Version %s ", VERSION);
1099 label = gtk_label_new(tmp);
1100 gtk_widget_show(label);
1101 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), label, FALSE, FALSE, 0);
1103 label = gtk_label_new("http://www.dasher.org.uk/");
1104 gtk_widget_show(label);
1105 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), label, FALSE, FALSE, 0);
1107 label = gtk_label_new("Copyright The Dasher Project");
1108 gtk_widget_show(label);
1109 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), label, TRUE, TRUE, 0);
1111 button = gtk_button_new_from_stock(GTK_STOCK_OK);
1112 gtk_widget_show(button);
1113 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), button, FALSE, FALSE, 0);
1114 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(about));
1116 gtk_widget_show(about);
1117 #endif
1120 static gboolean
1121 dasher_main_speed_changed(DasherMain *pSelf) {
1122 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1124 int iNewValue( static_cast<int>(round(gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(pPrivate->pSpeedBox)) * 100)));
1126 if(dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) != iNewValue)
1127 dasher_app_settings_set_long(pPrivate->pAppSettings, LP_MAX_BITRATE, iNewValue);
1129 return true;
1132 static void
1133 dasher_main_alphabet_combo_changed(DasherMain *pSelf) {
1134 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1136 GtkTreeIter sIter;
1138 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter);
1140 const char *szSelected;
1141 gtk_tree_model_get(GTK_TREE_MODEL(pPrivate->pAlphabetList), &sIter, 0, &szSelected, -1);
1143 if(!strcmp("More Alphabets...", szSelected)) {
1144 gtk_combo_box_set_active(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), 0);
1145 // dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue);
1146 dasher_main_command(pSelf, "preferences_alphabet");
1148 else
1149 dasher_app_settings_set_string(pPrivate->pAppSettings, SP_ALPHABET_ID, szSelected);
1152 static void
1153 dasher_main_populate_alphabet_combo(DasherMain *pSelf) {
1154 #ifndef WITH_MAEMO
1155 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1157 // Disconnect the event handler temporarily, otherwise this will
1158 // trigger alphabet changes
1160 g_signal_handler_block(pPrivate->pAlphabetCombo, pPrivate->iAlphabetComboHandler);
1162 gtk_list_store_clear(pPrivate->pAlphabetList);
1165 GtkTreeIter sIter;
1166 const char *szValue;
1168 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_ID);
1170 if(strlen(szValue) > 0) {
1171 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1172 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1173 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter);
1176 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_1);
1177 if(strlen(szValue) > 0) {
1178 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1179 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1182 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_2);
1183 if(strlen(szValue) > 0) {
1184 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1185 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1188 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_3);
1189 if(strlen(szValue) > 0) {
1190 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1191 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1194 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_4);
1195 if(strlen(szValue) > 0) {
1196 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1197 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1200 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1201 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, "More Alphabets...", -1);
1203 g_signal_handler_unblock(pPrivate->pAlphabetCombo, pPrivate->iAlphabetComboHandler);
1205 #endif
1208 static gint
1209 dasher_main_lookup_key(DasherMain *pSelf, guint iKeyVal) {
1210 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1212 if(pPrivate->pKeyboardHelper)
1213 return pPrivate->pKeyboardHelper->ConvertKeycode(iKeyVal);
1214 else
1215 return -1;
1219 gboolean
1220 grab_focus() {
1222 // TODO: reimplement (text view member of class)
1223 // gtk_widget_grab_focus(the_text_view);
1224 // g_bForwardKeyboard = true;
1225 return true;
1228 /* Callbacks */
1230 extern "C" GtkWidget *
1231 create_dasher_control(gchar *szName, gchar *szString1, gchar *szString2, gint iInt1, gint iInt2) {
1232 GtkWidget *pDasherControl = gtk_dasher_control_new();
1234 #ifdef WITH_MAEMO
1235 // TODO: Do this in glade file?
1236 gtk_widget_set_size_request(pDasherControl, 175, -1);
1237 #endif
1239 return pDasherControl;
1242 extern "C" GtkWidget *
1243 create_dasher_editor(gchar *szName, gchar *szString1, gchar *szString2, gint iInt1, gint iInt2) {
1244 return GTK_WIDGET(dasher_editor_new());
1247 extern "C" gboolean
1248 dasher_main_cb_menu_command(GtkWidget *pWidget, gpointer pUserData) {
1249 dasher_main_menu_command((DasherMain *)pUserData, pWidget);
1251 return FALSE; // TODO: Scheck semantics of return value
1254 extern "C" gboolean
1255 speed_changed(GtkWidget *pWidget, gpointer user_data) {
1256 if(g_pDasherMain)
1257 return dasher_main_speed_changed(g_pDasherMain);
1259 // TODO: Check callback return functions
1260 return false;
1263 extern "C" void
1264 alphabet_combo_changed(GtkWidget *pWidget, gpointer pUserData) {
1265 if(g_pDasherMain)
1266 dasher_main_alphabet_combo_changed(g_pDasherMain);
1269 extern "C" void
1270 dasher_main_cb_filename_changed(DasherEditor *pEditor, gpointer pUserData) {
1271 dasher_main_set_filename(DASHER_MAIN(pUserData));
1274 extern "C" void
1275 dasher_main_cb_buffer_changed(DasherEditor *pEditor, gpointer pUserData) {
1276 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1277 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
1279 gtk_dasher_control_set_buffer(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_offset(pPrivate->pEditor));
1282 extern "C" void
1283 dasher_main_cb_context_changed(DasherEditor *pEditor, gpointer pUserData) {
1284 if(!g_bSend)
1285 return;
1287 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1288 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
1290 gtk_dasher_control_set_offset(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_offset(pPrivate->pEditor));
1293 extern "C" gboolean
1294 dasher_main_cb_window_close(GtkWidget *pWidget, gpointer pUserData) {
1295 dasher_main_command(g_pDasherMain, "quit");
1297 /* Returning true stops further propagation */
1298 return TRUE;
1301 extern "C" void
1302 parameter_notification(GtkDasherControl *pDasherControl, gint iParameter, gpointer data) {
1303 if(g_pDasherMain)
1304 dasher_main_handle_parameter_change(g_pDasherMain, iParameter);
1307 // TODO: Not really sure what happens here - need to sort out focus behaviour in general
1308 extern "C" bool
1309 focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
1310 return grab_focus();
1313 extern "C" bool
1314 edit_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
1315 return true;
1318 extern "C" gboolean
1319 take_real_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) {
1320 // g_bForwardKeyboard = false;
1321 return false;
1324 extern "C" gboolean
1325 edit_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
1326 // TODO: Reimplement
1328 // if(g_bForwardKeyboard) {
1329 // gboolean *returnType;
1330 // g_signal_emit_by_name(GTK_OBJECT(pPrivate->pDasherWidget), "key_press_event", event, &returnType);
1331 // return true;
1332 // }
1333 // else {
1334 // return false;
1335 // }
1337 // TODO: Check callback return functions
1338 return false;
1341 extern "C" gboolean
1342 edit_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
1343 // TODO: reimplement
1345 // if(g_bForwardKeyboard) {
1346 // gboolean *returnType;
1347 // g_signal_emit_by_name(GTK_OBJECT(pPrivate->pDasherWidget), "key_release_event", event, &returnType);
1348 // return true;
1349 // }
1350 // else {
1351 // return false;
1352 // }
1354 // TODO: Check callback return functions
1355 return false;
1358 extern "C" gboolean
1359 test_focus_handler(GtkWidget *pWidget, GtkDirectionType iDirection, gpointer *pUserData) {
1360 return FALSE;
1363 extern "C" void
1364 handle_context_request(GtkDasherControl * pDasherControl, gint iOffset, gint iLength, gpointer data) {
1365 if(!g_pDasherMain)
1366 return;
1368 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(g_pDasherMain);
1370 if(!pPrivate->pEditor || !pPrivate->pDasherWidget)
1371 return;
1373 gtk_dasher_control_set_context(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_context(pPrivate->pEditor, iOffset, iLength));
1376 extern "C" void
1377 handle_control_event(GtkDasherControl *pDasherControl, gint iEvent, gpointer data) {
1378 if(!g_pDasherMain)
1379 return;
1381 /* TODO: replace this with something a little more sensible */
1383 switch(iEvent) {
1384 case Dasher::CControlManager::CTL_USER + 1:
1385 dasher_main_command(g_pDasherMain, "speakall");
1386 return;
1387 case Dasher::CControlManager::CTL_USER + 2:
1388 dasher_main_command(g_pDasherMain, "speaklast");
1389 return;
1390 case Dasher::CControlManager::CTL_USER + 3:
1391 dasher_main_command(g_pDasherMain, "speakrepeat");
1392 return;
1393 default:
1394 break;
1398 // TODO: This is a horrible hack here to make the release work!
1400 g_bSend = false;
1402 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(g_pDasherMain);
1403 dasher_editor_handle_control(pPrivate->pEditor, iEvent);
1405 gtk_dasher_control_set_control_offset(GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
1406 dasher_editor_get_offset(pPrivate->pEditor));
1408 g_bSend = true;
1409 // ---
1413 extern "C" void
1414 handle_start_event(GtkDasherControl *pDasherControl, gpointer data) {
1415 if(!g_pDasherMain)
1416 return;
1418 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(g_pDasherMain);
1420 dasher_editor_grab_focus(pPrivate->pEditor);
1424 // TODO: Make this only work for children of the main window
1425 extern "C" gint
1426 dasher_main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent, gpointer pUserData) {
1427 DasherMain *pSelf = DASHER_MAIN(pUserData);
1429 gint iButton = dasher_main_lookup_key(pSelf, pEvent->keyval);
1431 if(iButton != -1) {
1432 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1434 if(gdk_window_get_toplevel(pEvent->window) == pPrivate->pMainWindow->window) {
1435 if(pPrivate->pDasherWidget) {
1436 if(pEvent->type == GDK_KEY_PRESS)
1437 gtk_dasher_control_external_key_down(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), iButton);
1438 else
1439 gtk_dasher_control_external_key_up(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), iButton);
1442 return TRUE;
1444 else {
1445 return FALSE;
1448 else {
1449 return FALSE;