Preparing for release A few fixes before code freeze
[dasher.git] / Src / Gtk2 / dasher_main.cpp
blobe9e73eb7857bbc9ed9c7a2a3a70a4666e0df7c2e
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 struct _DasherMainPrivate {
26 // The glade XML file - TODO: this shouldn't be kept after interface has been loaded
27 GladeXML *pGladeXML;
29 // Child objects owned here
30 DasherAppSettings *pAppSettings;
31 DasherPreferencesDialogue *pPreferencesDialogue;
32 DasherEditor *pEditor;
34 CKeyboardHelper *pKeyboardHelper;
36 // Various widgets which need to be cached:
37 GtkWidget *pBufferView;
38 GtkWidget *pDivider;
39 GtkWidget *pMainWindow;
40 GtkWidget *pToolbar;
41 GtkWidget *pSpeedBox;
42 GtkWidget *pAlphabetCombo;
43 GtkWidget *pStatusControl;
44 GtkWidget *pDasherWidget;
46 GtkListStore *pAlphabetList;
47 GtkAccelGroup *pAccel;
48 gulong iAlphabetComboHandler;
50 // Widgets used for maemo
51 #ifdef WITH_MAEMO
52 DasherMaemoHelper *pMaemoHelper;
53 #ifdef WITH_MAEMOFULLSCREEN
54 HildonProgram *pProgram;
55 HildonWindow *pHWindow;
56 #endif
57 #endif
59 // Properties of the main window
60 int iWidth;
61 int iHeight;
62 bool bWidgetsInitialised;
65 typedef struct _DasherMainPrivate DasherMainPrivate;
67 // TODO: Make sure this is actually used
68 #define DASHER_MAIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_DASHER_MAIN, DasherMainPrivate))
70 enum {
71 REALIZED,
72 SIGNAL_NUM
75 static guint dasher_main_signals[SIGNAL_NUM] = { 0 };
77 /* Automatic command hookups */
79 typedef struct _DasherMenuCommand DasherMenuCommand;
81 struct _DasherMenuCommand {
82 GtkWidget *pWidget;
83 const gchar *szWidgetName;
84 const gchar *szCommand;
87 static DasherMenuCommand MenuCommands[] = {
88 /* Menus */
89 {NULL, "menu_command_new", "new"},
90 {NULL, "menu_command_open", "open"},
91 {NULL, "menu_command_save", "save"},
92 {NULL, "menu_command_saveas", "saveas"},
93 {NULL, "menu_command_append", "append"},
94 {NULL, "menu_command_import", "import"},
95 {NULL, "menu_command_quit", "quit"},
96 {NULL, "menu_command_cut", "cut"},
97 {NULL, "menu_command_copy", "copy"},
98 {NULL, "menu_command_copyall", "copyall"},
99 {NULL, "menu_command_paste", "paste"},
100 {NULL, "menu_command_preferences", "preferences"},
101 {NULL, "menu_command_tutorial", "tutorial"},
102 {NULL, "menu_command_help", "help"},
103 {NULL, "menu_command_about", "about"},
105 /* Toolbar */
106 {NULL, "tb_command_new", "new"},
107 {NULL, "tb_command_open", "open"},
108 {NULL, "tb_command_save", "save"},
109 {NULL, "tb_command_saveas", "saveas"},
110 {NULL, "tb_command_cut", "cut"},
111 {NULL, "tb_command_copy", "copy"},
112 {NULL, "tb_command_paste", "paste"}
115 G_DEFINE_TYPE(DasherMain, dasher_main, G_TYPE_OBJECT);
117 static void dasher_main_finalize(GObject *pObject);
119 /* Private member functions */
120 static void dasher_main_setup_window_state(DasherMain *pSelf);
121 static void dasher_main_setup_window_style(DasherMain *pSelf);
122 static void dasher_main_setup_internal_layout(DasherMain *pSelf);
123 static void dasher_main_refresh_font(DasherMain *pSelf);
124 static void dasher_main_set_filename(DasherMain *pSelf);
126 /* ... Table based menu/toolbar commands */
127 static void dasher_main_connect_menus(DasherMain *pSelf);
128 static void dasher_main_menu_command(DasherMain *pSelf, GtkWidget *pWidget);
130 static void dasher_main_command_import(DasherMain *pSelf);
131 static void dasher_main_command_quit(DasherMain *pSelf);
132 static void dasher_main_command_preferences(DasherMain *pSelf);
133 static void dasher_main_command_preferences_alphabet(DasherMain *pSelf);
134 static void dasher_main_command_tutorial(DasherMain *pSelf);
135 static void dasher_main_command_help(DasherMain *pSelf);
136 static void dasher_main_command_about(DasherMain *pself);
138 static gboolean dasher_main_speed_changed(DasherMain *pSelf);
139 static void dasher_main_alphabet_combo_changed(DasherMain *pSelf);
140 // TODO: populate speed slider
141 static void dasher_main_populate_alphabet_combo(DasherMain *pSelf);
143 /* TODO: order these in file */
144 static void dasher_main_load_interface(DasherMain *pSelf);
145 static void dasher_main_create_preferences(DasherMain *pSelf);
146 static void dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter);
147 static void dasher_main_load_state(DasherMain *pSelf);
148 static void dasher_main_save_state(DasherMain *pSelf);
149 static void dasher_main_setup_window(DasherMain *pSelf);
150 static void dasher_main_populate_controls(DasherMain *pSelf);
151 static void dasher_main_connect_control(DasherMain *pSelf);
152 static gboolean dasher_main_command(DasherMain *pSelf, const gchar *szCommand);
153 static gint dasher_main_lookup_key(DasherMain *pSelf, guint iKeyVal);
155 /* TODO: Various functions which haven't yet been rationalised */
156 gboolean grab_focus();
158 // TODO: Sort out callbacks - 1 rename, 2 check return values
160 /* Callback functions */
161 extern "C" GtkWidget *create_dasher_control(gchar *szName, gchar *szString1, gchar *szString2, gint iInt1, gint iInt2);
163 /* ... Message handling from main window widgets */
164 extern "C" gboolean dasher_main_cb_menu_command(GtkWidget *pWidget, gpointer pUserData);
165 extern "C" gboolean speed_changed(GtkWidget *pWidget, gpointer user_data);
166 extern "C" void alphabet_combo_changed(GtkWidget *pWidget, gpointer pUserData);
167 extern "C" void dasher_main_cb_filename_changed(DasherEditor *pEditor, gpointer pUserData);
168 extern "C" void dasher_main_cb_buffer_changed(DasherEditor *pEditor, gpointer pUserData);
169 extern "C" void dasher_main_cb_context_changed(DasherEditor *pEditor, gpointer pUserData);
170 extern "C" gboolean dasher_main_cb_window_close(GtkWidget *pWidget, gpointer pUserData);
171 extern "C" void parameter_notification(GtkDasherControl *pDasherControl, gint iParameter, gpointer data);
173 /* ... Focus management and event forwarding */
174 extern "C" bool focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
175 extern "C" bool edit_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data);
176 extern "C" gboolean take_real_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data);
178 extern "C" gboolean edit_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
179 extern "C" gboolean edit_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
181 /* ... Temporary test/debug functions */
182 extern "C" gboolean test_focus_handler(GtkWidget *pWidget, GtkDirectionType iDirection, gpointer *pUserData);
184 extern "C" void handle_context_request(GtkDasherControl * pDasherControl, gint iOffset, gint iLength, gpointer data);
185 extern "C" void handle_control_event(GtkDasherControl *pDasherControl, gint iEvent, gpointer data);
186 extern "C" void handle_start_event(GtkDasherControl *pDasherControl, gpointer data);
187 extern "C" gint dasher_main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent, gpointer pUserData);
189 /* Boilerplate code */
190 static void
191 dasher_main_class_init(DasherMainClass *pClass) {
192 g_type_class_add_private(pClass, sizeof(DasherMainPrivate));
194 dasher_main_signals[REALIZED] = g_signal_new("realized", G_TYPE_FROM_CLASS(pClass),
195 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
196 G_STRUCT_OFFSET(DasherMainClass, realized),
197 NULL, NULL, g_cclosure_marshal_VOID__VOID,
198 G_TYPE_NONE, 0);
200 GObjectClass *pObjectClass = (GObjectClass *)pClass;
201 pObjectClass->finalize = dasher_main_finalize;
204 static void
205 dasher_main_init(DasherMain *pDasherMain) {
206 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
208 /* TODO: define log domain */
209 g_debug("Initialising DasherMain");
211 pPrivate->pAppSettings = NULL;
212 pPrivate->pEditor = NULL;
213 pPrivate->pPreferencesDialogue = NULL;
215 pPrivate->pKeyboardHelper = new CKeyboardHelper(NULL);
217 pPrivate->bWidgetsInitialised = false;
220 static void
221 dasher_main_finalize(GObject *pObject) {
222 /* TODO: Need a general overview of class finalisation */
223 g_debug("Finalizing DasherMain");
225 DasherMain *pDasherMain = DASHER_MAIN(pObject);
226 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
228 dasher_main_save_state(pDasherMain);
230 /* TODO: Does unref really do the right thing - check the whole ref counting situation */
231 if(pPrivate->pEditor)
232 g_object_unref(pPrivate->pEditor);
234 if(pPrivate->pPreferencesDialogue)
235 g_object_unref(pPrivate->pPreferencesDialogue);
237 if(pPrivate->pAppSettings)
238 g_object_unref(pPrivate->pAppSettings);
240 gtk_widget_destroy(pPrivate->pMainWindow);
242 /* TDO: Do we need to take down anything else? */
245 /* Public methods */
246 DasherMain *
247 dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
248 if(g_pDasherMain)
249 return g_pDasherMain;
250 else {
251 DasherMain *pDasherMain = (DasherMain *)(g_object_new(dasher_main_get_type(), NULL));
252 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
254 /* Create the app settings object */
255 pPrivate->pAppSettings = dasher_app_settings_new(*argc, *argv);
257 /* Load the user interface from the glade file */
258 if(pCommandLine && pCommandLine->szAppStyle) {
259 if(!strcmp(pCommandLine->szAppStyle, "traditional")) {
260 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 0);
262 else if(!strcmp(pCommandLine->szAppStyle, "compose")) {
263 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 1);
265 else if(!strcmp(pCommandLine->szAppStyle, "direct")) {
266 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 2);
268 else if(!strcmp(pCommandLine->szAppStyle, "fullscreen")) {
269 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 3);
271 else {
272 g_error("Application style %s is not supported", pCommandLine->szAppStyle);
275 else {
276 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 0);
279 dasher_main_load_interface(pDasherMain);
281 dasher_app_settings_set_widget(pPrivate->pAppSettings, GTK_DASHER_CONTROL(pPrivate->pDasherWidget));
282 dasher_main_setup_window(pDasherMain);
284 /* Create the editor */
285 gchar *szFullPath = NULL;
287 if(pCommandLine) {
288 if(pCommandLine->szFilename) {
289 if(!g_path_is_absolute(pCommandLine->szFilename)) {
290 char *cwd;
291 cwd = (char *)malloc(1024 * sizeof(char));
292 getcwd(cwd, 1024);
293 szFullPath = g_build_path("/", cwd, pCommandLine->szFilename, NULL);
295 else {
296 szFullPath = g_strdup(pCommandLine->szFilename);
301 pPrivate->pEditor = dasher_editor_new(pPrivate->pAppSettings, pDasherMain, pPrivate->pGladeXML, szFullPath);
303 g_free(szFullPath);
305 g_signal_connect(pPrivate->pEditor, "filename_changed", G_CALLBACK(dasher_main_cb_filename_changed), pDasherMain);
306 g_signal_connect(pPrivate->pEditor, "buffer_changed", G_CALLBACK(dasher_main_cb_buffer_changed), pDasherMain);
307 g_signal_connect(pPrivate->pEditor, "context_changed", G_CALLBACK(dasher_main_cb_context_changed), pDasherMain);
309 /* Create the preferences window */
310 dasher_main_create_preferences(pDasherMain);
312 /* Create the lock dialogue (to be removed in future versions) */
313 #ifndef WITH_MAEMO
314 dasher_lock_dialogue_new(pPrivate->pGladeXML, GTK_WINDOW(pPrivate->pMainWindow));
315 #else
316 dasher_lock_dialogue_new(pPrivate->pGladeXML, 0);
317 #endif
319 /* Set up various bits and pieces */
320 dasher_main_set_filename(pDasherMain);
321 dasher_main_populate_controls(pDasherMain);
322 dasher_main_connect_control(pDasherMain);
324 gtk_key_snooper_install(dasher_main_key_snooper, pDasherMain);
326 /* Cache a file-wide static pointer to the singleton class */
327 g_pDasherMain = pDasherMain;
329 return pDasherMain;
333 /* Load the window interface from the glade file, and do various initialisation bits and pieces */
334 static void
335 dasher_main_load_interface(DasherMain *pSelf) {
336 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
338 const char *szGladeFilename = NULL;
340 #ifdef WITH_GPE
341 szGladeFilename = PROGDATA "/dashergpe.glade";
342 #elif WITH_MAEMO
343 #ifdef WITH_MAEMOFULLSCREEN
344 // szGladeFilename = "/var/lib/install" PROGDATA "/dashermaemofullscreen.glade";
345 szGladeFilename = PROGDATA "/dashermaemofullscreen.glade";
346 #else
347 //szGladeFilename = "/var/lib/install" PROGDATA "/dashermaemo.glade";
348 szGladeFilename = PROGDATA "/dashermaemo.glade";
349 #endif
350 #else
351 switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
352 case 0:
353 szGladeFilename = PROGDATA "/dasher.traditional.glade";
354 break;
355 case 1:
356 szGladeFilename = PROGDATA "/dasher.compose.glade";
357 break;
358 case 2:
359 szGladeFilename = PROGDATA "/dasher.direct.glade";
360 break;
361 case 3:
362 szGladeFilename = PROGDATA "/dasher.fullscreen.glade";
363 break;
364 default:
365 g_error("Inconsistent application style specified.");
367 #endif
369 if(!szGladeFilename) {
370 g_error("Failure to determine glade filename");
373 pPrivate->pGladeXML = glade_xml_new(szGladeFilename, NULL, NULL);
375 if (!pPrivate->pGladeXML) {
376 g_error("Can't find Glade file: %s. Dasher is unlikely to be correctly installed.", szGladeFilename);
379 glade_xml_signal_autoconnect(pPrivate->pGladeXML);
381 // Save the details of some of the widgets for later
382 // pPrivate->pActionPane = glade_xml_get_widget(pPrivate->pGladeXML, "vbox39");
383 pPrivate->pBufferView = glade_xml_get_widget(pPrivate->pGladeXML, "the_text_view");
384 pPrivate->pDivider = glade_xml_get_widget(pPrivate->pGladeXML, "main_divider");
385 // pPrivate->pEditPane = glade_xml_get_widget(pPrivate->pGladeXML, "vbox40");
386 pPrivate->pMainWindow = glade_xml_get_widget(pPrivate->pGladeXML, "window");
387 pPrivate->pToolbar = glade_xml_get_widget(pPrivate->pGladeXML, "toolbar");
388 // pPrivate->pMenuBar = glade_xml_get_widget(pPrivate->pGladeXML, "dasher_menu_bar");
389 pPrivate->pDasherWidget = glade_xml_get_widget(pPrivate->pGladeXML, "DasherControl");
391 #ifndef WITH_MAEMO
392 pPrivate->pSpeedBox = glade_xml_get_widget(pPrivate->pGladeXML, "spinbutton1");
393 pPrivate->pAlphabetCombo = glade_xml_get_widget(pPrivate->pGladeXML, "combobox1");
394 pPrivate->pStatusControl = glade_xml_get_widget(pPrivate->pGladeXML, "hbox8");
396 pPrivate->pAlphabetList = gtk_list_store_new(1, G_TYPE_STRING);
397 gtk_combo_box_set_model(GTK_COMBO_BOX(pPrivate->pAlphabetCombo),
398 GTK_TREE_MODEL(pPrivate->pAlphabetList));
400 GtkCellRenderer *pRenderer;
401 pRenderer = gtk_cell_renderer_text_new();
402 #if GTK_CHECK_VERSION(2,6,0)
403 g_object_set(G_OBJECT(pRenderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
404 #endif
405 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pPrivate->pAlphabetCombo), pRenderer, true);
406 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pPrivate->pAlphabetCombo), pRenderer, "text", 0, NULL);
409 // gtk_widget_add_events(pPrivate->pDragHandle, GDK_POINTER_MOTION_MASK);
410 #else
412 #ifdef WITH_MAEMOFULLSCREEN
413 // TODO: This is horrible - no need to get it from the glade file if we're not going to use it
415 pPrivate->pProgram = HILDON_PROGRAM(hildon_program_get_instance());
416 // hildon_app_set_title(pPrivate->pApp, "Dasher");
418 pPrivate->pHWindow = HILDON_WINDOW(hildon_window_new());
419 hildon_program_add_window(pPrivate->pProgram, pPrivate->pHWindow);
421 gtk_widget_reparent(pPrivate->pInnerFrame, GTK_WIDGET(pPrivate->pHWindow));
422 // gtk_paned_set_position(GTK_PANED(window), 100);
424 /* Do menu setup */
425 GtkMenu *main_menu;
426 GtkWidget *file_menu;
427 GtkWidget *file_menu_item;
428 GtkWidget *options_menu;
429 GtkWidget *options_menu_item;
430 GtkWidget *help_menu;
431 GtkWidget *help_menu_item;
434 // main_menu = hildon_appview_get_menu(appview);
436 main_menu = GTK_MENU(gtk_menu_new());
437 file_menu = glade_xml_get_widget(pPrivate->pGladeXML, "menuitem4_menu");
438 options_menu = glade_xml_get_widget(pPrivate->pGladeXML, "options1_menu");
439 help_menu = glade_xml_get_widget(pPrivate->pGladeXML, "menuitem7_menu");
440 file_menu_item = gtk_menu_item_new_with_label ("File");
441 options_menu_item = gtk_menu_item_new_with_label ("Options");
442 help_menu_item = gtk_menu_item_new_with_label ("Help");
444 g_object_ref(file_menu);
445 g_object_ref(options_menu);
446 g_object_ref(help_menu);
448 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(glade_xml_get_widget(pPrivate->pGladeXML, "menuitem4")));
449 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(glade_xml_get_widget(pPrivate->pGladeXML, "options1")));
450 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(glade_xml_get_widget(pPrivate->pGladeXML, "menuitem7")));
452 gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_menu_item),file_menu);
453 gtk_menu_item_set_submenu(GTK_MENU_ITEM(options_menu_item),options_menu);
454 gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_menu_item),help_menu);
455 gtk_menu_append(main_menu, file_menu_item);
456 gtk_menu_append(main_menu, options_menu_item);
457 gtk_menu_append(main_menu, help_menu_item);
459 g_object_unref(file_menu);
460 g_object_unref(options_menu);
461 g_object_unref(help_menu);
463 hildon_program_set_common_menu(pPrivate->pProgram, main_menu);
465 gtk_widget_show_all( GTK_WIDGET( main_menu ) );
467 // /* And toolbar */
468 // GtkWidget *toolbar;
469 // toolbar = glade_xml_get_widget(pPrivate->pGladeXML, "toolbar");
470 // g_print("Got %p\n",toolbar);
471 // gtk_widget_reparent (toolbar, appview->vbox);
473 gtk_widget_show_all(GTK_WIDGET(pPrivate->pHWindow));
475 gtk_widget_destroy(pPrivate->pMainWindow);
476 pPrivate->pMainWindow = GTK_WIDGET(pPrivate->pHWindow);
478 g_signal_connect(G_OBJECT(pPrivate->pHWindow), "delete_event", G_CALLBACK(ask_save_before_exit), NULL);
480 #endif // Maemo fullscreen
481 #endif // Maemo
483 // pPrivate->bHidden = false;
484 // pPrivate->bGrabbed = false;
486 // pPrivate->iPosition = 100; // FIXME - make this persistant
488 // TODO: Specify callbacks in glade file
489 // TODO: Rationalise focus
490 g_signal_connect(G_OBJECT(pPrivate->pBufferView), "button-release-event", G_CALLBACK(take_real_focus), NULL);
491 g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-press-event", G_CALLBACK(edit_key_press), NULL);
492 g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-release-event", G_CALLBACK(edit_key_release), NULL);
494 pPrivate->iAlphabetComboHandler = g_signal_connect(G_OBJECT(pPrivate->pAlphabetCombo), "changed", G_CALLBACK(alphabet_combo_changed), NULL);
496 // dasher_main_build_context_menu(pSelf);
498 // Create a Maemo helper if necessary
499 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
500 pPrivate->pMaemoHelper = dasher_maemo_helper_new(GTK_WINDOW(pPrivate->pMainWindow));
501 #endif
503 // Set up any non-registry-dependent options
504 #ifdef WITH_GPE
505 gtk_window_set_decorated(GTK_WINDOW(pPrivate->pMainWindow), false);
506 #endif
508 dasher_main_connect_menus(pSelf);
510 pPrivate->bWidgetsInitialised = true;
513 static void
514 dasher_main_create_preferences(DasherMain *pSelf) {
515 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
516 pPrivate->pPreferencesDialogue = dasher_preferences_dialogue_new(pPrivate->pGladeXML, pPrivate->pEditor, pPrivate->pAppSettings, GTK_WINDOW(pPrivate->pMainWindow));
519 // DasherEditor *
520 // dasher_main_get_editor(DasherMain *pSelf) {
521 // DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
522 // return pPrivate->pEditor;
523 // }
525 static void
526 dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter) {
527 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
529 switch( iParameter ) {
530 case APP_BP_SHOW_TOOLBAR:
531 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
532 gtk_widget_show(pPrivate->pToolbar);
533 else
534 gtk_widget_hide(pPrivate->pToolbar);
535 break;
536 case BP_SHOW_SLIDER: // TODO: Shouldn't be a core parmeter
537 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_SHOW_SLIDER))
538 gtk_widget_show(pPrivate->pStatusControl);
539 else
540 gtk_widget_hide(pPrivate->pStatusControl);
541 break;
542 case APP_SP_EDIT_FONT:
543 dasher_main_refresh_font(pSelf);
544 break;
545 #ifndef WITH_MAEMO
546 case LP_MAX_BITRATE:
547 gtk_spin_button_set_value(GTK_SPIN_BUTTON(pPrivate->pSpeedBox), dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
548 break;
549 #endif
550 case SP_ALPHABET_ID:
551 dasher_main_populate_alphabet_combo(pSelf);
552 break;
553 case BP_GLOBAL_KEYBOARD:
554 dasher_main_setup_window(pSelf);
555 break;
556 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
557 case APP_LP_MAEMO_SIZE: {
558 g_message("Maemo size");
560 bool bVisible = GTK_WIDGET_VISIBLE(pPrivate->pMainWindow);
561 gtk_widget_hide(pPrivate->pMainWindow);
562 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_MAEMO_SIZE) == 0) {
563 int iWidth;
564 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
565 gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 150);
566 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWidth, 150);
567 gtk_widget_set_size_request(pPrivate->pDasherWidget, 175, -1);
569 else {
570 int iWidth;
571 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
572 gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 250);
573 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWidth, 250);
574 gtk_widget_set_size_request(pPrivate->pDasherWidget, 280, -1);
576 if(bVisible)
577 gtk_widget_show(pPrivate->pMainWindow);
578 break;
580 #endif
583 // TODO: Pass into editor?
584 dasher_preferences_dialogue_handle_parameter_change(pPrivate->pPreferencesDialogue, iParameter);
587 static void
588 dasher_main_load_state(DasherMain *pSelf) {
589 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
591 int iWindowWidth;
592 int iWindowHeight;
593 int iEditHeight;
595 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != 1) {
596 iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT);
597 iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH);
598 iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT);
600 else {
601 iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH);
602 iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H);
603 iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H);
606 #ifndef WITH_MAEMO
607 gtk_window_resize(GTK_WINDOW(pPrivate->pMainWindow), iWindowWidth, iWindowHeight);
608 #endif
610 gtk_paned_set_position(GTK_PANED(pPrivate->pDivider), iEditHeight);
612 pPrivate->iWidth = iWindowWidth;
613 pPrivate->iHeight = iWindowHeight;
615 // pPrivate->iPosition = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_DOCK_POSITION);
618 static void
619 dasher_main_save_state(DasherMain *pSelf) {
620 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
622 if(!pPrivate->bWidgetsInitialised)
623 return;
625 int iWindowWidth;
626 int iWindowHeight;
627 int iEditHeight;
629 gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWindowWidth, &iWindowHeight);
630 iEditHeight = gtk_paned_get_position(GTK_PANED(pPrivate->pDivider));
632 if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != 1) {
633 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT, iEditHeight);
634 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH, iWindowWidth);
635 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT, iWindowHeight);
637 else {
638 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH, iEditHeight);
639 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H, iWindowWidth);
640 dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H, iWindowHeight);
643 // dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_DOCK_POSITION, pPrivate->iPosition);
646 void
647 dasher_main_show(DasherMain *pSelf) {
648 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
649 gtk_widget_show(pPrivate->pMainWindow);
652 static void
653 dasher_main_setup_window(DasherMain *pSelf) {
654 dasher_main_setup_window_style(pSelf);
655 dasher_main_setup_window_state(pSelf);
656 dasher_main_setup_internal_layout(pSelf);
658 // DasherMainPrivate *pPrivate = (DasherMainPrivate *)(pSelf->private_data);
660 // if(dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_GLOBAL_KEYBOARD))
661 // gdk_window_add_filter(0, keyboard_filter_cb, 0);
662 // else
663 // gdk_window_remove_filter(0, keyboard_filter_cb, 0);
666 static void
667 dasher_main_populate_controls(DasherMain *pSelf) {
668 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
670 // Populate the alphabet chooser
671 dasher_main_populate_alphabet_combo(pSelf);
673 // Set the value of the speed spinner
674 gtk_spin_button_set_value(GTK_SPIN_BUTTON(pPrivate->pSpeedBox),
675 dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
678 static void
679 dasher_main_connect_control(DasherMain *pSelf) {
680 /* TODO: This is very much temporary - we need to think of a better
681 way of presenting application commands in a unified way */
682 #ifdef GNOME_SPEECH
683 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
685 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
686 Dasher::CControlManager::CTL_USER,
687 "Speak", -1 );
689 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
690 Dasher::CControlManager::CTL_USER,
691 Dasher::CControlManager::CTL_ROOT, -2);
694 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
695 Dasher::CControlManager::CTL_USER + 1,
696 "All", -1 );
698 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
699 Dasher::CControlManager::CTL_USER + 2,
700 "Last", -1 );
702 gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
703 Dasher::CControlManager::CTL_USER + 3,
704 "Repeat", -1 );
706 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
707 Dasher::CControlManager::CTL_USER + 1,
708 Dasher::CControlManager::CTL_USER, -2);
710 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
711 -1,
712 Dasher::CControlManager::CTL_USER + 1, -2);
714 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
715 Dasher::CControlManager::CTL_USER + 2,
716 Dasher::CControlManager::CTL_USER, -2);
718 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
720 Dasher::CControlManager::CTL_USER + 2, -2);
722 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
723 Dasher::CControlManager::CTL_USER + 3,
724 Dasher::CControlManager::CTL_USER, -2);
726 gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pPrivate->pDasherWidget),
728 Dasher::CControlManager::CTL_USER + 3, -2);
730 #endif
734 static gboolean
735 dasher_main_command(DasherMain *pSelf, const gchar *szCommand) {
736 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
738 if(!strcmp(szCommand, "import")) {
739 dasher_main_command_import(pSelf);
740 return TRUE;
743 if(!strcmp(szCommand, "quit")) {
744 dasher_main_command_quit(pSelf);
745 return TRUE;
748 if(!strcmp(szCommand, "preferences")) {
749 dasher_main_command_preferences(pSelf);
750 return TRUE;
753 if(!strcmp(szCommand, "preferences_alphabet")) {
754 dasher_main_command_preferences_alphabet(pSelf);
755 return TRUE;
758 if(!strcmp(szCommand, "tutorial")) {
759 dasher_main_command_tutorial(pSelf);
760 return TRUE;
763 if(!strcmp(szCommand, "help")) {
764 dasher_main_command_help(pSelf);
765 return TRUE;
768 if(!strcmp(szCommand, "about")) {
769 dasher_main_command_about(pSelf);
770 return TRUE;
773 if(pPrivate->pEditor)
774 return dasher_editor_command(pPrivate->pEditor, szCommand);
776 return FALSE;
779 /* Private methods */
781 /* Window state is basically size and position */
782 static void
783 dasher_main_setup_window_state(DasherMain *pSelf) {
784 dasher_main_load_state(pSelf);
786 // TODO: Setup positioning here - need to think up a policy on this
790 /* Setup the window style - this is defined to be window manager hints and the like */
791 static void
792 dasher_main_setup_window_style(DasherMain *pSelf) {
793 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
795 switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
796 case 0:
797 // Nothing to do
798 break;
799 case 1:
800 // Nothing to do
801 break;
802 case 2:
803 // Direct mode - set always on top
804 gtk_window_set_keep_above(GTK_WINDOW(pPrivate->pMainWindow), true);
806 // Refuse focus
807 gtk_window_set_accept_focus(GTK_WINDOW(pPrivate->pMainWindow), false);
808 break;
809 case 3:
810 // Fullscreen mode - set fullscreen
811 gtk_window_fullscreen(GTK_WINDOW(pPrivate->pMainWindow));
812 break;
813 default:
814 g_error("Inconsistent application style specified.");
818 /* Internal layout is the visibility of various widgets */
819 static void
820 dasher_main_setup_internal_layout(DasherMain *pSelf) {
821 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
823 if(pPrivate->pToolbar) {
824 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
825 gtk_widget_show(pPrivate->pToolbar);
826 else
827 gtk_widget_hide(pPrivate->pToolbar);
830 if(pPrivate->pStatusControl) {
831 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_SHOW_SLIDER))
832 gtk_widget_show(pPrivate->pStatusControl);
833 else
834 gtk_widget_hide(pPrivate->pStatusControl);
837 dasher_main_refresh_font(pSelf);
840 static void
841 dasher_main_refresh_font(DasherMain *pSelf) {
842 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
844 const gchar *szFontName = dasher_app_settings_get_string(pPrivate->pAppSettings, APP_SP_EDIT_FONT);
845 PangoFontDescription *pFD = pango_font_description_from_string(szFontName);
847 if(strcmp(szFontName, "")) {
848 gtk_widget_modify_font(pPrivate->pBufferView, pFD);
852 // TODO: Fold into setup controls?
853 static void
854 dasher_main_set_filename(DasherMain *pSelf) {
855 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
857 const gchar *szFilename = dasher_editor_get_filename(pPrivate->pEditor);
859 if(szFilename == 0) {
860 gtk_window_set_title(GTK_WINDOW(pPrivate->pMainWindow), "Dasher");
862 else {
863 // TODO: Prepend 'Dasher - ' to filename?
864 gtk_window_set_title(GTK_WINDOW(pPrivate->pMainWindow), szFilename);
868 static void
869 dasher_main_connect_menus(DasherMain *pSelf) {
870 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
872 int iNumItems = sizeof(MenuCommands) / sizeof(DasherMenuCommand);
874 for(int i(0); i < iNumItems; ++i) {
875 GtkWidget *pWidget;
877 pWidget = glade_xml_get_widget(pPrivate->pGladeXML, MenuCommands[i].szWidgetName);
879 MenuCommands[i].pWidget = pWidget;
881 // TODO: Check that these are the right signals to connect to
882 if(pWidget)
883 if(GTK_IS_MENU_ITEM(pWidget))
884 g_signal_connect(G_OBJECT(pWidget), "activate", G_CALLBACK(dasher_main_cb_menu_command), pSelf);
885 else
886 g_signal_connect(G_OBJECT(pWidget), "clicked", G_CALLBACK(dasher_main_cb_menu_command), pSelf);
890 static void
891 dasher_main_menu_command(DasherMain *pSelf, GtkWidget *pWidget) {
892 int iNumItems = sizeof(MenuCommands) / sizeof(DasherMenuCommand);
894 for(int i(0); i < iNumItems; ++i) {
895 if(MenuCommands[i].pWidget == pWidget) {
896 dasher_main_command(pSelf, MenuCommands[i].szCommand);
897 return;
902 static void
903 dasher_main_command_import(DasherMain *pSelf) {
904 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
906 GtkWidget *pFileSel = gtk_file_chooser_dialog_new(_("Select File"),
907 GTK_WINDOW(pPrivate->pMainWindow),
908 GTK_FILE_CHOOSER_ACTION_OPEN,
909 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
910 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
911 NULL);
913 #ifdef GNOME_LIBS
914 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(pFileSel), FALSE);
915 #endif
917 if(gtk_dialog_run(GTK_DIALOG(pFileSel)) == GTK_RESPONSE_ACCEPT) {
919 #ifdef GNOME_LIBS
920 gchar *szFilename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(pFileSel));
921 #else
922 gchar *szFilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSel));
923 #endif
925 gtk_dasher_control_train(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), szFilename);
927 g_free(szFilename);
930 gtk_widget_destroy(pFileSel);
933 static void dasher_main_command_quit(DasherMain *pSelf) {
934 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
936 GtkWidget *pDialogue = NULL;
938 if(dasher_editor_file_changed(pPrivate->pEditor)) {
939 const gchar *szFilename = dasher_editor_get_filename(pPrivate->pEditor);
941 if(szFilename) {
942 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
943 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
944 _("Do you want to save your changes to %s?\n\nYour changes will be lost if you don't save them."),
945 szFilename);
947 else {
948 pDialogue = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL,
949 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
950 _("Do you want to save your changes?\n\nYour changes will be lost if you don't save them."));
953 gtk_dialog_add_buttons(GTK_DIALOG(pDialogue),
954 _("Don't save"), GTK_RESPONSE_REJECT,
955 _("Don't quit"), GTK_RESPONSE_CANCEL,
956 _("Save and quit"), GTK_RESPONSE_ACCEPT,
957 NULL);
959 switch (gtk_dialog_run(GTK_DIALOG(pDialogue))) {
960 case GTK_RESPONSE_REJECT:
961 // write_to_file(); // FIXME - REIMPLEMENT
962 gtk_main_quit();
963 break;
964 case GTK_RESPONSE_CANCEL:
965 gtk_widget_destroy(GTK_WIDGET(pDialogue));
966 break;
967 case GTK_RESPONSE_ACCEPT:
968 gtk_widget_destroy(GTK_WIDGET(pDialogue));
969 // write_to_file(); // FIXME - REIMPLEMENT
970 // save_file_and_quit(NULL, NULL);
973 else {
974 // It should be noted that write_to_file merely saves the new text to the training
975 // file rather than saving it to a file of the user's choice
977 // FIXME - REIMPLEMENT
979 // write_to_file();
981 gtk_main_quit();
985 static void
986 dasher_main_command_preferences(DasherMain *pSelf) {
987 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
988 dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue, 0);
991 static void
992 dasher_main_command_preferences_alphabet(DasherMain *pSelf) {
993 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
994 dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue, 1);
997 static void
998 dasher_main_command_tutorial(DasherMain *pSelf) {
999 // TODO: Implement this
1002 static void
1003 dasher_main_command_help(DasherMain *pSelf) {
1004 // TODO: Need to disable the menu if gnome libs aren't present (or get rid of without gnome option)
1005 #ifdef GNOME_LIBS
1006 gnome_help_display_desktop(NULL, "dasher", "dasher", NULL, NULL);
1007 #endif
1010 static void
1011 dasher_main_command_about(DasherMain *pSelf) {
1012 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1014 #if (defined GNOME_LIBS) || (GTK_CHECK_VERSION(2,6,0))
1016 // In alphabetical order
1017 const gchar *authors[] = {
1018 "Chris Ball",
1019 "Ignas Budvytis",
1020 "Phil Cowans",
1021 "Frederik Eaton",
1022 "Behdad Esfahbod",
1023 "Matthew Garrett",
1024 "Chris Hack",
1025 "David MacKay",
1026 "Iain Murray",
1027 "Takashi Kaburagi",
1028 "Keith Vertanen",
1029 "Hanna Wallach",
1030 "David Ward",
1031 "Brian Williams",
1032 "Seb Wills",
1033 "Will Zou",
1034 NULL
1037 // Yeah, should really do some Gnome documentation for it...
1038 const gchar *documenters[] = {
1039 "Chris Ball",
1040 "Matthew Garrett",
1041 "David MacKay",
1042 NULL
1045 #if GTK_CHECK_VERSION(2,6,0)
1046 gtk_show_about_dialog(GTK_WINDOW(pPrivate->pMainWindow),
1047 "authors", authors,
1048 "comments", _("Dasher is a predictive text entry application"),
1049 "copyright", "Copyright \xC2\xA9 1998-2007 The Dasher Project",
1050 "documenters", documenters,
1051 "license", "GPL 2+",
1052 "logo-icon-name", "dasher",
1053 "translator-credits", _("translator-credits"),
1054 "version", VERSION,
1055 "website", "http://www.dasher.org.uk/",
1056 "wrap-license", true,
1057 NULL);
1058 #else
1059 gchar *translator_credits = _("translator-credits");
1061 GtkWidget *about = gnome_about_new (_("Dasher"),
1062 PACKAGE_VERSION,
1063 "Copyright The Dasher Project\n",
1064 _("Dasher is a predictive text entry application"),
1065 (const char **)authors,
1066 (const char **)documenters,
1067 strcmp (translator_credits, "translator-credits") != 0 ? (const char *)translator_credits : NULL,
1068 NULL);
1070 gtk_window_set_transient_for (GTK_WINDOW(about), GTK_WINDOW(pPrivate->pMainWindow));
1071 // g_signal_connect (G_OBJECT (about), "destory", G_CALLBACK (gtk_widget_destroyed), &about);
1072 gtk_widget_show(about);
1074 #endif
1076 #else
1077 // EAT UGLY ABOUT BOX, PHILISTINE
1078 GtkWidget *label, *button;
1079 char *tmp;
1081 GtkWidget *about = gtk_dialog_new();
1083 gtk_dialog_set_has_separator(GTK_DIALOG(about), FALSE);
1084 gtk_window_set_title(GTK_WINDOW(about), "About Dasher");
1086 tmp = g_strdup_printf("Dasher Version %s ", VERSION);
1087 label = gtk_label_new(tmp);
1088 gtk_widget_show(label);
1089 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), label, FALSE, FALSE, 0);
1091 label = gtk_label_new("http://www.dasher.org.uk/");
1092 gtk_widget_show(label);
1093 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), label, FALSE, FALSE, 0);
1095 label = gtk_label_new("Copyright The Dasher Project");
1096 gtk_widget_show(label);
1097 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), label, TRUE, TRUE, 0);
1099 button = gtk_button_new_from_stock(GTK_STOCK_OK);
1100 gtk_widget_show(button);
1101 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->vbox), button, FALSE, FALSE, 0);
1102 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(about));
1104 gtk_widget_show(about);
1105 #endif
1108 static gboolean
1109 dasher_main_speed_changed(DasherMain *pSelf) {
1110 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1112 int iNewValue( static_cast<int>(round(gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(pPrivate->pSpeedBox)) * 100)));
1114 if(dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) != iNewValue)
1115 dasher_app_settings_set_long(pPrivate->pAppSettings, LP_MAX_BITRATE, iNewValue);
1117 return true;
1120 static void
1121 dasher_main_alphabet_combo_changed(DasherMain *pSelf) {
1122 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1124 GtkTreeIter sIter;
1126 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter);
1128 const char *szSelected;
1129 gtk_tree_model_get(GTK_TREE_MODEL(pPrivate->pAlphabetList), &sIter, 0, &szSelected, -1);
1131 if(!strcmp("More Alphabets...", szSelected)) {
1132 gtk_combo_box_set_active(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), 0);
1133 // dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue);
1134 dasher_main_command(pSelf, "preferences_alphabet");
1136 else
1137 dasher_app_settings_set_string(pPrivate->pAppSettings, SP_ALPHABET_ID, szSelected);
1140 static void
1141 dasher_main_populate_alphabet_combo(DasherMain *pSelf) {
1142 #ifndef WITH_MAEMO
1143 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1145 // Disconnect the event handler temporarily, otherwise this will
1146 // trigger alphabet changes
1148 g_signal_handler_block(pPrivate->pAlphabetCombo, pPrivate->iAlphabetComboHandler);
1150 gtk_list_store_clear(pPrivate->pAlphabetList);
1153 GtkTreeIter sIter;
1154 const char *szValue;
1156 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_ID);
1158 if(strlen(szValue) > 0) {
1159 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1160 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
1161 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter);
1164 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_1);
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_2);
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 szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_3);
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_4);
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 gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
1189 gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, "More Alphabets...", -1);
1191 g_signal_handler_unblock(pPrivate->pAlphabetCombo, pPrivate->iAlphabetComboHandler);
1193 #endif
1196 static gint
1197 dasher_main_lookup_key(DasherMain *pSelf, guint iKeyVal) {
1198 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1200 if(pPrivate->pKeyboardHelper)
1201 return pPrivate->pKeyboardHelper->ConvertKeycode(iKeyVal);
1202 else
1203 return -1;
1207 gboolean
1208 grab_focus() {
1210 // TODO: reimplement (text view member of class)
1211 // gtk_widget_grab_focus(the_text_view);
1212 // g_bForwardKeyboard = true;
1213 return true;
1216 /* Callbacks */
1218 extern "C" GtkWidget *
1219 create_dasher_control(gchar *szName, gchar *szString1, gchar *szString2, gint iInt1, gint iInt2) {
1220 GtkWidget *pDasherControl = gtk_dasher_control_new();
1222 #ifdef WITH_MAEMO
1223 // TODO: Do this in glade file?
1224 gtk_widget_set_size_request(pDasherControl, 175, -1);
1225 #endif
1227 return pDasherControl;
1230 extern "C" gboolean
1231 dasher_main_cb_menu_command(GtkWidget *pWidget, gpointer pUserData) {
1232 dasher_main_menu_command((DasherMain *)pUserData, pWidget);
1234 return FALSE; // TODO: Scheck semantics of return value
1237 extern "C" gboolean
1238 speed_changed(GtkWidget *pWidget, gpointer user_data) {
1239 if(g_pDasherMain)
1240 return dasher_main_speed_changed(g_pDasherMain);
1242 // TODO: Check callback return functions
1243 return false;
1246 extern "C" void
1247 alphabet_combo_changed(GtkWidget *pWidget, gpointer pUserData) {
1248 if(g_pDasherMain)
1249 dasher_main_alphabet_combo_changed(g_pDasherMain);
1252 extern "C" void
1253 dasher_main_cb_filename_changed(DasherEditor *pEditor, gpointer pUserData) {
1254 dasher_main_set_filename(DASHER_MAIN(pUserData));
1257 extern "C" void
1258 dasher_main_cb_buffer_changed(DasherEditor *pEditor, gpointer pUserData) {
1259 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1260 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
1262 gtk_dasher_control_set_buffer(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_offset(pPrivate->pEditor));
1265 extern "C" void
1266 dasher_main_cb_context_changed(DasherEditor *pEditor, gpointer pUserData) {
1267 DasherMain *pDasherMain = DASHER_MAIN(pUserData);
1268 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
1270 gtk_dasher_control_set_offset(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_offset(pPrivate->pEditor));
1273 extern "C" gboolean
1274 dasher_main_cb_window_close(GtkWidget *pWidget, gpointer pUserData) {
1275 dasher_main_command(g_pDasherMain, "quit");
1277 /* Returning true stops further propagation */
1278 return TRUE;
1281 extern "C" void
1282 parameter_notification(GtkDasherControl *pDasherControl, gint iParameter, gpointer data) {
1283 if(g_pDasherMain)
1284 dasher_main_handle_parameter_change(g_pDasherMain, iParameter);
1287 // TODO: Not really sure what happens here - need to sort out focus behaviour in general
1288 extern "C" bool
1289 focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
1290 return grab_focus();
1293 extern "C" bool
1294 edit_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
1295 return true;
1298 extern "C" gboolean
1299 take_real_focus(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) {
1300 // g_bForwardKeyboard = false;
1301 return false;
1304 extern "C" gboolean
1305 edit_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
1306 // TODO: Reimplement
1308 // if(g_bForwardKeyboard) {
1309 // gboolean *returnType;
1310 // g_signal_emit_by_name(GTK_OBJECT(pPrivate->pDasherWidget), "key_press_event", event, &returnType);
1311 // return true;
1312 // }
1313 // else {
1314 // return false;
1315 // }
1317 // TODO: Check callback return functions
1318 return false;
1321 extern "C" gboolean
1322 edit_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
1323 // TODO: reimplement
1325 // if(g_bForwardKeyboard) {
1326 // gboolean *returnType;
1327 // g_signal_emit_by_name(GTK_OBJECT(pPrivate->pDasherWidget), "key_release_event", event, &returnType);
1328 // return true;
1329 // }
1330 // else {
1331 // return false;
1332 // }
1334 // TODO: Check callback return functions
1335 return false;
1338 extern "C" gboolean
1339 test_focus_handler(GtkWidget *pWidget, GtkDirectionType iDirection, gpointer *pUserData) {
1340 return FALSE;
1343 extern "C" void
1344 handle_context_request(GtkDasherControl * pDasherControl, gint iOffset, gint iLength, gpointer data) {
1345 if(!g_pDasherMain)
1346 return;
1348 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(g_pDasherMain);
1350 if(!pPrivate->pEditor || !pPrivate->pDasherWidget)
1351 return;
1353 gtk_dasher_control_set_context(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), dasher_editor_get_context(pPrivate->pEditor, iOffset, iLength));
1356 extern "C" void
1357 handle_control_event(GtkDasherControl *pDasherControl, gint iEvent, gpointer data) {
1358 if(!g_pDasherMain)
1359 return;
1361 /* TODO: replace this with something a little more sensible */
1363 switch(iEvent) {
1364 case Dasher::CControlManager::CTL_USER + 1:
1365 dasher_main_command(g_pDasherMain, "speakall");
1366 break;
1367 case Dasher::CControlManager::CTL_USER + 2:
1368 dasher_main_command(g_pDasherMain, "speaklast");
1369 break;
1370 case Dasher::CControlManager::CTL_USER + 3:
1371 dasher_main_command(g_pDasherMain, "speakrepeat");
1372 break;
1373 default:
1374 break;
1378 extern "C" void
1379 handle_start_event(GtkDasherControl *pDasherControl, gpointer data) {
1380 if(!g_pDasherMain)
1381 return;
1383 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(g_pDasherMain);
1385 dasher_editor_grab_focus(pPrivate->pEditor);
1389 // TODO: Make this only work for children of the main window
1390 extern "C" gint
1391 dasher_main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent, gpointer pUserData) {
1392 DasherMain *pSelf = DASHER_MAIN(pUserData);
1394 gint iButton = dasher_main_lookup_key(pSelf, pEvent->keyval);
1396 if(iButton != -1) {
1397 DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
1399 if(gdk_window_get_toplevel(pEvent->window) == pPrivate->pMainWindow->window) {
1400 if(pPrivate->pDasherWidget) {
1401 if(pEvent->type == GDK_KEY_PRESS)
1402 gtk_dasher_control_external_key_down(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), iButton);
1403 else
1404 gtk_dasher_control_external_key_up(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), iButton);
1407 return TRUE;
1409 else {
1410 return FALSE;
1413 else {
1414 return FALSE;