11 #include <glib/gi18n.h>
13 #ifdef WITH_MAEMOFULLSCREEN
14 #include <hildon-widgets/hildon-program.h>
18 #include "GtkDasherControl.h"
19 #include "dasher_lock_dialogue.h"
21 #include "dasher_maemo_helper.h"
23 #include "dasher_main.h"
25 #include "dasher_editor.h"
28 #include "dasher_main_private.h"
29 #include "XmlSettingsStore.h"
30 #include "FileUtils.h"
37 static guint dasher_main_signals
[SIGNAL_NUM
] = { 0 };
39 G_DEFINE_TYPE(DasherMain
, dasher_main
, G_TYPE_OBJECT
);
41 static void dasher_main_finalize(GObject
*pObject
);
43 /* Private member functions */
44 static void dasher_main_setup_window_state(DasherMain
*pSelf
);
45 static void dasher_main_setup_window_style(DasherMain
*pSelf
);
46 static void dasher_main_setup_internal_layout(DasherMain
*pSelf
);
47 static void dasher_main_set_window_title(DasherMain
*pSelf
);
49 /* ... Table based menu/toolbar commands */
50 static void dasher_main_command_import(DasherMain
*pSelf
);
51 static void dasher_main_command_quit(DasherMain
*pSelf
);
52 static void dasher_main_command_preferences(DasherMain
*pSelf
);
53 static void dasher_main_command_preferences_alphabet(DasherMain
*pSelf
);
54 static void dasher_main_command_help(DasherMain
*pSelf
);
55 static void dasher_main_command_about(DasherMain
*pSelf
);
56 static void dasher_main_command_toggle_direct_mode(DasherMain
*);
57 static void dasher_main_command_toggle_game_mode(DasherMain
*);
59 /* c.f. WRAP_CPP_CB below */
60 extern "C" void dasher_main_cb_import(GtkAction
*, DasherMain
*);
61 extern "C" void dasher_main_cb_quit(GtkAction
*, DasherMain
*);
62 extern "C" void dasher_main_cb_preferences(GtkAction
*, DasherMain
*);
63 extern "C" void dasher_main_cb_help(GtkAction
*, DasherMain
*);
64 extern "C" void dasher_main_cb_about(GtkAction
*, DasherMain
*);
65 extern "C" void dasher_main_cb_toggle_direct_mode(GtkAction
*, DasherMain
*);
66 extern "C" void dasher_main_cb_toggle_game_mode(GtkAction
*, DasherMain
*);
68 static gboolean
dasher_main_speed_changed(DasherMain
*pSelf
);
69 static void dasher_main_alphabet_combo_changed(DasherMain
*pSelf
);
70 // TODO: populate speed slider
71 static void dasher_main_populate_alphabet_combo(DasherMain
*pSelf
);
73 /* TODO: order these in file */
74 static GtkBuilder
*dasher_main_open_gui_xml(DasherMain
*, const char *);
75 static void dasher_main_load_interface(DasherMain
*pSelf
);
76 static void dasher_main_create_preferences(DasherMain
*pSelf
);
77 static void dasher_main_handle_parameter_change(DasherMain
*pSelf
, int iParameter
);
78 static void dasher_main_load_state(DasherMain
*pSelf
);
79 static void dasher_main_save_state(DasherMain
*pSelf
);
80 static void dasher_main_setup_window(DasherMain
*pSelf
);
81 static void dasher_main_populate_controls(DasherMain
*pSelf
);
82 static gint
dasher_main_lookup_key(DasherMain
*pSelf
, guint iKeyVal
);
84 /* TODO: Various functions which haven't yet been rationalised */
85 gboolean
grab_focus();
87 /* ... Message handling from main window widgets */
88 extern "C" void speed_changed(GtkWidget
*pWidget
, gpointer user_data
);
89 extern "C" void alphabet_combo_changed(GtkWidget
*pWidget
, gpointer pUserData
);
90 extern "C" void dasher_main_cb_filename_changed(DasherEditor
*pEditor
, gpointer pUserData
);
91 extern "C" void dasher_main_cb_buffer_changed(DasherEditor
*pEditor
, gpointer pUserData
);
92 extern "C" void dasher_main_cb_context_changed(DasherEditor
*pEditor
, gpointer pUserData
);
93 extern "C" gboolean
dasher_main_cb_window_close(GtkWidget
*pWidget
, GdkEvent
*event
, gpointer pUserData
);
94 extern "C" void parameter_notification(GtkDasherControl
*pDasherControl
, gint iParameter
, gpointer data
);
96 /* ... Focus management and event forwarding */
97 extern "C" bool focus_in_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
);
98 extern "C" bool edit_focus_in_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
);
99 extern "C" gboolean
take_real_focus(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer user_data
);
101 extern "C" gboolean
edit_key_press(GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
);
102 extern "C" gboolean
edit_key_release(GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
);
104 /* ... Temporary test/debug functions */
105 extern "C" gboolean
test_focus_handler(GtkWidget
*pWidget
, GtkDirectionType iDirection
, gpointer
*pUserData
);
107 extern "C" void handle_start_event(GtkDasherControl
*pDasherControl
, gpointer data
);
108 extern "C" gint
dasher_main_key_snooper(GtkWidget
*pWidget
, GdkEventKey
*pEvent
, gpointer pUserData
);
110 /* Boilerplate code */
112 dasher_main_class_init(DasherMainClass
*pClass
) {
113 g_type_class_add_private(pClass
, sizeof(DasherMainPrivate
));
115 dasher_main_signals
[REALIZED
] =
116 g_signal_new("realized", G_TYPE_FROM_CLASS(pClass
),
117 (GSignalFlags
)(G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
),
118 G_STRUCT_OFFSET(DasherMainClass
, realized
),
119 NULL
, NULL
, g_cclosure_marshal_VOID__VOID
,
122 GObjectClass
*pObjectClass
= (GObjectClass
*)pClass
;
123 pObjectClass
->finalize
= dasher_main_finalize
;
127 dasher_main_init(DasherMain
*pDasherMain
) {
128 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pDasherMain
);
130 pPrivate
->pAppSettings
= NULL
;
131 pPrivate
->pEditor
= NULL
;
132 pPrivate
->pPreferencesDialogue
= NULL
;
134 pPrivate
->pKeyboardHelper
= new CKeyboardHelper(NULL
);
136 pPrivate
->bWidgetsInitialised
= false;
140 dasher_main_finalize(GObject
*pObject
) {
142 DasherMain
*pDasherMain
= DASHER_MAIN(pObject
);
143 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pDasherMain
);
145 pPrivate
->pAppSettings
->UnregisterParameterChangeCallback(pPrivate
->parameter_callback_id_
);
147 /* TODO: Does unref really do the right thing - check the whole ref counting situation */
148 // if(pPrivate->pEditor)
149 // g_object_unref(pPrivate->pEditor);
151 if(pPrivate
->pPreferencesDialogue
)
152 g_object_unref(pPrivate
->pPreferencesDialogue
);
154 if(pPrivate
->pAppSettings
)
155 g_object_unref(pPrivate
->pAppSettings
);
157 gtk_widget_destroy(GTK_WIDGET(pPrivate
->pMainWindow
));
159 /* TODO: Do we need to take down anything else? */
162 class XmlErrorDisplay
: public CMessageDisplay
{
164 void Message(const std::string
&strText
, bool bInterrupt
) override
{
165 // TODO: decide if a pop-up dialog should be shown instead.
166 fputs(strText
.c_str(), stderr
);
173 dasher_main_new(int *argc
, char ***argv
, SCommandLine
*pCommandLine
) {
174 DasherMain
*pDasherMain
= (DasherMain
*)(g_object_new(dasher_main_get_type(), NULL
));
175 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pDasherMain
);
176 string configFileName
= "settings.xml";
177 if (pCommandLine
->szConfigFile
!= nullptr) {
178 configFileName
= "settings.";
179 configFileName
+= pCommandLine
->szConfigFile
;
180 configFileName
+= ".xml";
182 static XmlErrorDisplay display
;
183 // TODO Pass that instance of fileutils to DasherControl, instead of creating new one.
184 static FileUtils fileUtils
;
185 auto settings
= new Dasher::XmlSettingsStore(configFileName
, &fileUtils
, &display
);
187 // Save the defaults if needed.
190 DasherAppSettings::Create(settings
);
191 pPrivate
->pAppSettings
= DasherAppSettings::Get();
192 pPrivate
->parameter_callback_id_
=
193 pPrivate
->pAppSettings
->RegisterParameterChangeCallback(
194 std::bind(dasher_main_handle_parameter_change
, pDasherMain
, std::placeholders::_1
));
196 /* Load the user interface from the GUI file */
197 if(pCommandLine
&& pCommandLine
->szAppStyle
) {
198 if(!strcmp(pCommandLine
->szAppStyle
, "traditional")) {
199 pPrivate
->pAppSettings
->SetLong(APP_LP_STYLE
, APP_STYLE_TRAD
);
201 else if(!strcmp(pCommandLine
->szAppStyle
, "compose")) {
202 pPrivate
->pAppSettings
->SetLong(APP_LP_STYLE
, APP_STYLE_COMPOSE
);
204 else if(!strcmp(pCommandLine
->szAppStyle
, "direct")) {
205 pPrivate
->pAppSettings
->SetLong(APP_LP_STYLE
, APP_STYLE_DIRECT
);
207 else if(!strcmp(pCommandLine
->szAppStyle
, "fullscreen")) {
208 pPrivate
->pAppSettings
->SetLong(APP_LP_STYLE
, APP_STYLE_FULLSCREEN
);
211 g_critical("Application style %s is not supported", pCommandLine
->szAppStyle
);
216 dasher_main_load_interface(pDasherMain
);
218 pPrivate
->pAppSettings
->SetWidget(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
));
221 /* TODO: This parsing code should really be tidied up */
222 if(pCommandLine
&& pCommandLine
->szOptions
) {
223 gchar
**pszOptionTerms
;
224 pszOptionTerms
= g_strsplit(pCommandLine
->szOptions
, ",", 0);
226 gchar
**pszCurrent
= pszOptionTerms
;
229 gchar
*szJoin
= g_strrstr(*pszCurrent
, "=");
230 // Note to translators: This message will be output for command line errors when the "=" in --options=foo is missing.
231 const gchar
*errorMessage
= _("option setting is missing \"=\".");
234 int iLength
= szJoin
- *pszCurrent
;
236 gchar
*szKey
= g_new(gchar
, iLength
+ 1);
237 memcpy(szKey
, *pszCurrent
, iLength
);
238 szKey
[iLength
] = '\0';
240 errorMessage
= pPrivate
->pAppSettings
->ClSet(szKey
, szJoin
+ 1);
246 // Note to translators: This string will be output when --options= specifies an unknown option.
247 g_critical("%s: '%s', %s", _("Invalid option string specified"), *pszCurrent
, errorMessage
);
254 g_strfreev(pszOptionTerms
);
259 dasher_editor_initialise(pPrivate
->pEditor
, pPrivate
->pAppSettings
, GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), pPrivate
->pXML
, NULL
);
262 dasher_main_setup_window(pDasherMain
);
264 /* Create the editor */
265 gchar
*szFullPath
= NULL
;
268 if(pCommandLine
->szFilename
) {
269 if(!g_path_is_absolute(pCommandLine
->szFilename
)) {
271 cwd
= (char *)malloc(1024 * sizeof(char));
273 szFullPath
= g_build_path("/", cwd
, pCommandLine
->szFilename
, NULL
);
276 szFullPath
= g_strdup(pCommandLine
->szFilename
);
282 // pPrivate->pEditor = GTK_EDITOR(
285 // dasher_editor_initialise(pPrivate->pAppSettings, pDasherMain, pPrivate->pXML, szFullPath);
289 /* Create the preferences window */
290 dasher_main_create_preferences(pDasherMain
);
292 /* Create the lock dialogue (to be removed in future versions) */
294 dasher_lock_dialogue_new(pPrivate
->pXML
, pPrivate
->pMainWindow
);
296 dasher_lock_dialogue_new(pPrivate
->pXML
, 0);
299 /* Set up various bits and pieces */
300 dasher_main_set_window_title(pDasherMain
);
301 dasher_main_populate_controls(pDasherMain
);
303 gtk_key_snooper_install(dasher_main_key_snooper
, pDasherMain
);
309 dasher_main_open_gui_xml(DasherMain
*pSelf
, const char *szGUIFilename
) {
311 GtkBuilder
*xml
= gtk_builder_new();
313 g_message("Opening GUI file: %s", szGUIFilename
);
315 if (!gtk_builder_add_from_file(xml
, szGUIFilename
, &e
)) {
316 g_message("Can't find GUI file: %s. Dasher is unlikely to be correctly "
317 "installed. (%s)", szGUIFilename
, e
->message
);
321 gtk_builder_connect_signals(xml
, pSelf
);
327 #define WRAP_CPP_CB(item) \
329 dasher_main_cb_##item(GtkAction *obj, DasherMain *p)\
331 dasher_main_command_##item(p);\
335 * Editor passes on the action strings to dasher_editor_command which
336 * land in dasher_editor.
340 WRAP_CPP_CB(preferences
)
343 WRAP_CPP_CB(toggle_direct_mode
)
344 WRAP_CPP_CB(toggle_game_mode
)
347 dasher_main_cb_editor(GtkAction
*obj
, DasherMain
*pSelf
)
349 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
350 DASHER_ASSERT(pPrivate
->pEditor
!= NULL
);
351 const gchar
*action
= gtk_action_get_name(obj
);
352 dasher_editor_command(pPrivate
->pEditor
, action
);
356 dasher_main_load_interface(DasherMain
*pSelf
) {
357 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
358 const char *szGUIFilename
= NULL
;
359 const char *szPrefGUIFilename
= NULL
;
362 #ifdef WITH_MAEMOFULLSCREEN
363 szGUIFilename
= PROGDATA
"/dashermaemofullscreen.ui";
365 szGUIFilename
= PROGDATA
"/dashermaemo.ui";
367 szPrefGUIFilename
= PROGDATA
"/dashermaemo.preferences.ui";
369 szGUIFilename
= PROGDATA
"/dasher.traditional.ui";
370 szPrefGUIFilename
= PROGDATA
"/dasher.preferences.ui";
374 g_error("Failure to determine GUI filename");
377 pPrivate
->pXML
= dasher_main_open_gui_xml(pSelf
, szGUIFilename
);
378 pPrivate
->pPrefXML
= dasher_main_open_gui_xml(pSelf
, szPrefGUIFilename
);
380 #ifndef HAVE_GTK_SHOW_URI
382 GTK_ACTION(gtk_builder_get_object(pPrivate
->pXML
, "action_help"));
383 gtk_action_set_sensitive(helpact
, false);
384 gtk_action_set_visible(helpact
, false);
387 // Save the details of some of the widgets for later
388 // pPrivate->pActionPane = gtk_builder_get_object(pPrivate->pXML, "vbox39");
389 // pPrivate->pBufferView = gtk_builder_get_object(pPrivate->pXML, "the_text_view");
390 pPrivate
->pDivider
= GTK_PANED(gtk_builder_get_object(pPrivate
->pXML
, "main_divider"));
391 // pPrivate->pEditPane = gtk_builder_get_object(pPrivate->pXML, "vbox40");
392 pPrivate
->pMainWindow
= GTK_WINDOW(gtk_builder_get_object(pPrivate
->pXML
, "window"));
393 pPrivate
->pToolbar
= GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "dasher_tool_bar"));
394 // pPrivate->pMenuBar = gtk_builder_get_object(pPrivate->pXML, "dasher_menu_bar");
395 pPrivate
->pDasherWidget
= GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "DasherControl"));
396 pPrivate
->pEditor
= DASHER_EDITOR(gtk_builder_get_object(pPrivate
->pXML
, "DasherEditor"));
397 gtk_dasher_control_set_editor(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), pPrivate
->pEditor
);
400 pPrivate
->pSpeedBox
= GTK_SPIN_BUTTON(gtk_builder_get_object(pPrivate
->pXML
, "spinbutton1"));
401 pPrivate
->pAlphabetCombo
= GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "combobox1"));
402 pPrivate
->pStatusControl
= GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "hbox8"));
404 pPrivate
->pAlphabetList
= gtk_list_store_new(1, G_TYPE_STRING
);
405 gtk_combo_box_set_model(GTK_COMBO_BOX(pPrivate
->pAlphabetCombo
),
406 GTK_TREE_MODEL(pPrivate
->pAlphabetList
));
408 GtkCellRenderer
*pRenderer
;
409 pRenderer
= gtk_cell_renderer_text_new();
410 g_object_set(G_OBJECT(pRenderer
), "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
411 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pPrivate
->pAlphabetCombo
), pRenderer
, true);
412 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pPrivate
->pAlphabetCombo
), pRenderer
, "text", 0, NULL
);
415 // gtk_widget_add_events(pPrivate->pDragHandle, GDK_POINTER_MOTION_MASK);
418 #ifdef WITH_MAEMOFULLSCREEN
419 // TODO: This is horrible - no need to get it from the glade file if we're not going to use it
421 pPrivate
->pProgram
= HILDON_PROGRAM(hildon_program_get_instance());
422 // hildon_app_set_title(pPrivate->pApp, "Dasher");
424 pPrivate
->pHWindow
= HILDON_WINDOW(hildon_window_new());
425 hildon_program_add_window(pPrivate
->pProgram
, pPrivate
->pHWindow
);
427 gtk_widget_reparent(pPrivate
->pInnerFrame
, GTK_WIDGET(pPrivate
->pHWindow
));
428 // gtk_paned_set_position(GTK_PANED(window), 100);
432 GtkWidget
*file_menu
;
433 GtkWidget
*file_menu_item
;
434 GtkWidget
*options_menu
;
435 GtkWidget
*options_menu_item
;
436 GtkWidget
*help_menu
;
437 GtkWidget
*help_menu_item
;
440 // main_menu = hildon_appview_get_menu(appview);
442 main_menu
= GTK_MENU(gtk_menu_new());
443 file_menu
= gtk_builder_get_object(pPrivate
->pXML
, "file_menu");
444 options_menu
= gtk_builder_get_object(pPrivate
->pXML
, "options1_menu");
445 help_menu
= gtk_builder_get_object(pPrivate
->pXML
, "help_menu");
446 file_menu_item
= gtk_menu_item_new_with_label ("File");
447 options_menu_item
= gtk_menu_item_new_with_label ("Options");
448 help_menu_item
= gtk_menu_item_new_with_label ("Help");
450 g_object_ref(file_menu
);
451 g_object_ref(options_menu
);
452 g_object_ref(help_menu
);
454 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk_builder_get_object(pPrivate
->pXML
, "file_menu")), NULL
);
455 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk_builder_get_object(pPrivate
->pXML
, "options1")), NULL
);
456 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk_builder_get_object(pPrivate
->pXML
, "help_menu")), NULL
);
458 gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_menu_item
),file_menu
);
459 gtk_menu_item_set_submenu(GTK_MENU_ITEM(options_menu_item
),options_menu
);
460 gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_menu_item
),help_menu
);
461 gtk_menu_shell_append((GtkMenuShell
*)main_menu
, file_menu_item
);
462 gtk_menu_shell_append((GtkMenuShell
*)main_menu
, options_menu_item
);
463 gtk_menu_shell_append((GtkMenuShell
*)main_menu
, help_menu_item
);
465 g_object_unref(file_menu
);
466 g_object_unref(options_menu
);
467 g_object_unref(help_menu
);
469 hildon_program_set_common_menu(pPrivate
->pProgram
, main_menu
);
471 gtk_widget_show_all( GTK_WIDGET( main_menu
) );
474 // GtkWidget *toolbar;
475 // toolbar = gtk_builder_get_object(pPrivate->pXML, "toolbar");
476 // g_print("Got %p\n",toolbar);
477 // gtk_widget_reparent (toolbar, appview->vbox);
479 gtk_widget_show_all(GTK_WIDGET(pPrivate
->pHWindow
));
481 gtk_widget_destroy(GTK_WIDGET(pPrivate
->pMainWindow
));
482 pPrivate
->pMainWindow
= pPrivate
->pHWindow
;
484 g_signal_connect(G_OBJECT(pPrivate
->pHWindow
), "delete_event", G_CALLBACK(ask_save_before_exit
), NULL
);
486 #endif // Maemo fullscreen
489 // pPrivate->bHidden = false;
490 // pPrivate->bGrabbed = false;
492 // pPrivate->iPosition = 100; // FIXME - make this persistant
494 // TODO: Specify callbacks in glade file
495 // TODO: Rationalise focus
496 // g_signal_connect(G_OBJECT(pPrivate->pBufferView), "button-release-event", G_CALLBACK(take_real_focus), NULL);
497 // g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-press-event", G_CALLBACK(edit_key_press), NULL);
498 //g_signal_connect(G_OBJECT(pPrivate->pBufferView), "key-release-event", G_CALLBACK(edit_key_release), NULL);
500 // dasher_main_build_context_menu(pSelf);
502 // Create a Maemo helper if necessary
503 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
504 pPrivate
->pMaemoHelper
= dasher_maemo_helper_new(pPrivate
->pMainWindow
);
507 // Set up any non-registry-dependent options
509 gtk_window_set_decorated(pPrivate
->pMainWindow
, false);
512 // Hide any widgets which aren't appropriate for this mode
513 if(pPrivate
->pAppSettings
->GetLong(APP_LP_STYLE
) == APP_STYLE_DIRECT
) {
514 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "DasherEditor")));
518 pPrivate
->bWidgetsInitialised
= true;
522 dasher_main_create_preferences(DasherMain
*pSelf
) {
523 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
524 pPrivate
->pPreferencesDialogue
= dasher_preferences_dialogue_new(pPrivate
->pPrefXML
, pPrivate
->pEditor
, pPrivate
->pAppSettings
, pPrivate
->pMainWindow
);
528 * Start game mode: prompt user for the text to play with, put this in SP_GAME_TEXT_FILE;
529 * clear out any text in the dasher editor; call CDasherControl::EnterGameMode().
531 * Event handler which displays a standard GTK file dialog. The dialog allows the user
532 * to specify a text file to play game mode with.
534 * @param pButton the button that fired the event
535 * @param pWidget reference needed by GTK for callback signature
536 * @param pData pointer to a an std::pair<GtkWindow*, DasherMain*> containing references
537 * to the dialog's parent window and an instance of DasherMain
539 void show_game_file_dialog(GtkWidget
*pButton
, GtkWidget
*pWidget
, gpointer pData
) {
541 std::pair
<GtkWindow
*, DasherMain
*> *objRefs
= (std::pair
<GtkWindow
*, DasherMain
*>*)pData
;
543 DasherMain
*pSelf
= objRefs
->second
;
544 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
546 GtkWidget
*pFileDialog
= gtk_file_chooser_dialog_new("Choose a Game Text",
547 GTK_WINDOW(objRefs
->first
),
548 GTK_FILE_CHOOSER_ACTION_OPEN
,
549 _("_Cancel"), GTK_RESPONSE_CANCEL
,
550 _("_Open"), GTK_RESPONSE_ACCEPT
,
553 gtk_window_set_destroy_with_parent(GTK_WINDOW(pFileDialog
), true);
555 if (gtk_dialog_run(GTK_DIALOG(pFileDialog
)) == GTK_RESPONSE_ACCEPT
) {
557 char *filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileDialog
));
559 pPrivate
->pAppSettings
->SetString(SP_GAME_TEXT_FILE
, filename
);
560 gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), true);
562 gtk_widget_destroy(GTK_WIDGET(objRefs
->first
));
565 void dasher_main_command_toggle_direct_mode(DasherMain
*pSelf
) {
566 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
568 // Question of style: we could hide/show in
569 // dasher_main_handle_parameter_change()
570 if (pPrivate
->pAppSettings
->GetLong(APP_LP_STYLE
) == APP_STYLE_DIRECT
) {
571 // Opposite of direct mode
572 gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "DasherEditor")));
573 gtk_window_set_keep_above(GTK_WINDOW(pPrivate
->pMainWindow
), false);
574 gtk_window_set_accept_focus(GTK_WINDOW(pPrivate
->pMainWindow
), true);
575 gtk_window_unstick(GTK_WINDOW(pPrivate
->pMainWindow
));
576 pPrivate
->pAppSettings
->SetLong(APP_LP_STYLE
, APP_STYLE_TRAD
);
579 gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate
->pXML
, "DasherEditor")));
580 // Direct mode - set always on top
581 gtk_window_set_keep_above(GTK_WINDOW(pPrivate
->pMainWindow
), true);
583 gtk_window_set_accept_focus(GTK_WINDOW(pPrivate
->pMainWindow
), false);
584 // Stick on all desktops
585 gtk_window_stick(GTK_WINDOW(pPrivate
->pMainWindow
));
586 pPrivate
->pAppSettings
->SetLong(APP_LP_STYLE
, APP_STYLE_DIRECT
);
589 dasher_editor_toggle_direct_mode(pPrivate
->pEditor
);
593 * Toggle game mode on and off. Toggling on causes a dialog box to be displayed
594 * welcoming the user to game mode and prompting them to specify a file to play with.
595 * Toggling off just calls LeaveGameMode().
597 * @param pSelf a reference to an instance of DasherMain
599 void dasher_main_command_toggle_game_mode(DasherMain
*pSelf
) {
601 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
603 if(!gtk_dasher_control_get_game_mode(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
))) {
605 GtkWidget
*pDialog
= gtk_message_dialog_new(GTK_WINDOW(pPrivate
->pMainWindow
), GTK_DIALOG_MODAL
,
606 GTK_MESSAGE_OTHER
, GTK_BUTTONS_NONE
,
607 _("Welcome to Dasher Game Mode! Game Mode is a fun way to practice entering text in Dasher. Please select a training text to play with:"));
609 gtk_dialog_add_button(GTK_DIALOG(pDialog
), _("Use Default"), GTK_RESPONSE_ACCEPT
);
610 GtkWidget
*pFileButton
= gtk_dialog_add_button(GTK_DIALOG(pDialog
), _("Choose File..."), 2);
611 gtk_dialog_add_button(GTK_DIALOG(pDialog
), _("Cancel"), GTK_RESPONSE_REJECT
);
613 //make a pair with references to the the DasherMain and parent window instances that
614 //handler will need - kind of disgusting, but looks like only way to pass multiple
615 //parameters in g_signal_connect
616 std::pair
<GtkWindow
*, DasherMain
*> objRefs
= std::make_pair(GTK_WINDOW(pDialog
), pSelf
);
617 //ACL surprisingly this works: the signal handler (show_game_file_dialog) is called
618 // before gtk_dialog_run returns, and the pair is in this, calling, method's stack frame,
619 // so exists until _this_ method finishes...
621 g_signal_connect(pFileButton
, "button-press-event", G_CALLBACK(show_game_file_dialog
),
624 if (gtk_dialog_run(GTK_DIALOG(pDialog
))==GTK_RESPONSE_ACCEPT
) {
625 gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), true);
628 //have to do this check because we might have destroyed the dialog already in show_game_file_dialog
629 if(GTK_IS_WIDGET(pDialog
))
630 gtk_widget_destroy(pDialog
);
632 GtkWidget
*pDialog
= gtk_message_dialog_new(GTK_WINDOW(pPrivate
->pMainWindow
), GTK_DIALOG_MODAL
,
633 GTK_MESSAGE_OTHER
, GTK_BUTTONS_NONE
,
634 _("Are you sure you wish to turn off game mode? All unsaved changes will be lost."));
636 gtk_dialog_add_button(GTK_DIALOG(pDialog
), _("No"), GTK_RESPONSE_REJECT
);
637 gtk_dialog_add_button(GTK_DIALOG(pDialog
), _("Yes"), GTK_RESPONSE_ACCEPT
);
639 if(gtk_dialog_run(GTK_DIALOG(pDialog
))==GTK_RESPONSE_ACCEPT
) {
640 gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), false);
642 DASHER_ASSERT(GTK_IS_WIDGET(pDialog
));
643 gtk_widget_destroy(GTK_WIDGET(pDialog
));
649 dasher_main_handle_parameter_change(DasherMain
*pSelf
, int iParameter
) {
650 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
652 switch( iParameter
) {
653 case APP_BP_SHOW_TOOLBAR
:
654 if( pPrivate
->pAppSettings
->GetBool(APP_BP_SHOW_TOOLBAR
))
655 gtk_widget_show(pPrivate
->pToolbar
);
657 gtk_widget_hide(pPrivate
->pToolbar
);
659 case APP_BP_SHOW_STATUSBAR
:
660 if (pPrivate
->pAppSettings
->GetBool(APP_BP_SHOW_STATUSBAR
))
661 gtk_widget_show(pPrivate
->pStatusControl
);
663 gtk_widget_hide(pPrivate
->pStatusControl
);
667 gtk_spin_button_set_value(pPrivate
->pSpeedBox
, pPrivate
->pAppSettings
->GetLong(LP_MAX_BITRATE
) / 100.0);
671 dasher_main_populate_alphabet_combo(pSelf
);
673 case BP_GLOBAL_KEYBOARD
:
674 dasher_main_setup_window(pSelf
);
676 #if defined WITH_MAEMO && !defined WITH_MAEMOFULLSCREEN
677 case APP_LP_MAEMO_SIZE
: {
678 g_message("Maemo size");
680 bool bVisible
= GTK_WIDGET_VISIBLE(pPrivate
->pMainWindow
);
681 gtk_widget_hide(pPrivate
->pMainWindow
);
682 if(pPrivate
->pAppSettings
->GetLong(APP_LP_MAEMO_SIZE
) == 0) {
684 gtk_window_get_size(GTK_WINDOW(pPrivate
->pMainWindow
), &iWidth
, NULL
);
685 gtk_widget_set_size_request(pPrivate
->pMainWindow
, -1, 150);
686 gtk_window_resize(GTK_WINDOW(pPrivate
->pMainWindow
), iWidth
, 150);
687 gtk_widget_set_size_request(pPrivate
->pDasherWidget
, 175, -1);
691 gtk_window_get_size(GTK_WINDOW(pPrivate
->pMainWindow
), &iWidth
, NULL
);
692 gtk_widget_set_size_request(pPrivate
->pMainWindow
, -1, 250);
693 gtk_window_resize(GTK_WINDOW(pPrivate
->pMainWindow
), iWidth
, 250);
694 gtk_widget_set_size_request(pPrivate
->pDasherWidget
, 280, -1);
697 gtk_widget_show(pPrivate
->pMainWindow
);
703 if(pPrivate
->pPreferencesDialogue
)
704 dasher_preferences_dialogue_handle_parameter_change(pPrivate
->pPreferencesDialogue
, iParameter
);
706 if(pPrivate
->pEditor
)
707 dasher_editor_handle_parameter_change(pPrivate
->pEditor
, iParameter
);
711 dasher_main_load_state(DasherMain
*pSelf
) {
712 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
714 int iEditSize
= pPrivate
->pAppSettings
->GetLong(APP_LP_EDIT_SIZE
);
715 int iWindowWidth
= pPrivate
->pAppSettings
->GetLong(APP_LP_SCREEN_WIDTH
);
716 int iWindowHeight
= pPrivate
->pAppSettings
->GetLong(APP_LP_SCREEN_HEIGHT
);
719 gtk_window_resize(GTK_WINDOW(pPrivate
->pMainWindow
), iWindowWidth
, iWindowHeight
);
722 gtk_paned_set_position(pPrivate
->pDivider
, iEditSize
);
724 pPrivate
->iWidth
= iWindowWidth
;
725 pPrivate
->iHeight
= iWindowHeight
;
731 iWindowX
= pPrivate
->pAppSettings
->GetLong(APP_LP_X
);
732 iWindowY
= pPrivate
->pAppSettings
->GetLong(APP_LP_Y
);
734 gtk_window_move(GTK_WINDOW(pPrivate
->pMainWindow
), iWindowX
, iWindowY
);
738 dasher_main_save_state(DasherMain
*pSelf
) {
739 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
741 if(!pPrivate
->bWidgetsInitialised
)
747 gtk_window_get_size(GTK_WINDOW(pPrivate
->pMainWindow
), &iWindowWidth
, &iWindowHeight
);
748 int iEditSize
= gtk_paned_get_position(pPrivate
->pDivider
);
750 // APP_STYLE_DIRECT doesn't have an edit window.
751 if (pPrivate
->pAppSettings
->GetLong(APP_LP_STYLE
) != APP_STYLE_DIRECT
)
752 pPrivate
->pAppSettings
->SetLong(APP_LP_EDIT_SIZE
, iEditSize
);
753 pPrivate
->pAppSettings
->SetLong(APP_LP_SCREEN_WIDTH
, iWindowWidth
);
754 pPrivate
->pAppSettings
->SetLong(APP_LP_SCREEN_HEIGHT
, iWindowHeight
);
758 gtk_window_get_position(GTK_WINDOW(pPrivate
->pMainWindow
), &iWindowX
, &iWindowY
);
760 pPrivate
->pAppSettings
->SetLong(APP_LP_X
, iWindowX
);
761 pPrivate
->pAppSettings
->SetLong(APP_LP_Y
, iWindowY
);
765 dasher_main_show(DasherMain
*pSelf
) {
766 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
767 gtk_widget_show(GTK_WIDGET(pPrivate
->pMainWindow
));
771 dasher_main_setup_window(DasherMain
*pSelf
) {
772 dasher_main_setup_window_style(pSelf
);
773 dasher_main_setup_window_state(pSelf
);
774 dasher_main_setup_internal_layout(pSelf
);
776 // DasherMainPrivate *pPrivate = (DasherMainPrivate *)(pSelf->private_data);
778 // if(dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_GLOBAL_KEYBOARD))
779 // gdk_window_add_filter(0, keyboard_filter_cb, 0);
781 // gdk_window_remove_filter(0, keyboard_filter_cb, 0);
785 dasher_main_populate_controls(DasherMain
*pSelf
) {
786 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
788 // Populate the alphabet chooser
789 dasher_main_populate_alphabet_combo(pSelf
);
791 // Set the value of the speed spinner
792 gtk_spin_button_set_value(pPrivate
->pSpeedBox
,
793 pPrivate
->pAppSettings
->GetLong(LP_MAX_BITRATE
) / 100.0);
796 /* Private methods */
798 /* Window state is basically size and position */
800 dasher_main_setup_window_state(DasherMain
*pSelf
) {
801 dasher_main_load_state(pSelf
);
803 // TODO: Setup positioning here - need to think up a policy on this
807 /* Setup the window style - this is defined to be window manager hints and the like */
809 dasher_main_setup_window_style(DasherMain
*pSelf
) {
810 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
812 switch(pPrivate
->pAppSettings
->GetLong(APP_LP_STYLE
)) {
816 case APP_STYLE_COMPOSE
:
819 case APP_STYLE_DIRECT
:
820 // Direct mode - set always on top
821 gtk_window_set_keep_above(GTK_WINDOW(pPrivate
->pMainWindow
), true);
824 gtk_window_set_accept_focus(GTK_WINDOW(pPrivate
->pMainWindow
), false);
826 // Stick on all desktops
827 gtk_window_stick(GTK_WINDOW(pPrivate
->pMainWindow
));
829 case APP_STYLE_FULLSCREEN
:
830 // Fullscreen mode - set fullscreen
831 gtk_window_fullscreen(GTK_WINDOW(pPrivate
->pMainWindow
));
834 g_error("Inconsistent application style specified.");
838 /* Internal layout is the visibility of various widgets */
840 dasher_main_setup_internal_layout(DasherMain
*pSelf
) {
841 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
843 if(pPrivate
->pToolbar
) {
844 if(pPrivate
->pAppSettings
->GetBool(APP_BP_SHOW_TOOLBAR
))
845 gtk_widget_show(pPrivate
->pToolbar
);
847 gtk_widget_hide(pPrivate
->pToolbar
);
850 if(pPrivate
->pStatusControl
) {
851 if (pPrivate
->pAppSettings
->GetBool(APP_BP_SHOW_STATUSBAR
))
852 gtk_widget_show(pPrivate
->pStatusControl
);
854 gtk_widget_hide(pPrivate
->pStatusControl
);
858 // TODO: Fold into setup controls?
860 dasher_main_set_window_title(DasherMain
*pSelf
) {
861 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
863 const gchar
*szFilename
= dasher_editor_get_filename(pPrivate
->pEditor
);
865 // Note to translators: This is the name of the dasher program as it appears
866 // in a window title.
867 gchar
* dasher
= _("Dasher");
868 if(szFilename
== 0) {
869 gtk_window_set_title(GTK_WINDOW(pPrivate
->pMainWindow
), dasher
);
872 gchar
*title
= g_strdup_printf("%s - %s", dasher
, szFilename
);
873 gtk_window_set_title(GTK_WINDOW(pPrivate
->pMainWindow
), title
);
879 dasher_main_command_import(DasherMain
*pSelf
) {
880 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
882 GtkWidget
*pFileSel
= gtk_file_chooser_dialog_new(_("Select File"),
883 GTK_WINDOW(pPrivate
->pMainWindow
),
884 GTK_FILE_CHOOSER_ACTION_OPEN
,
885 _("_Open"), GTK_RESPONSE_ACCEPT
,
886 _("_Cancel"), GTK_RESPONSE_CANCEL
,
889 #ifdef TEACH_TRAINING_HELPER_LOAD_FILE_ABOUT_URI
890 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(pFileSel
), FALSE
);
893 if(gtk_dialog_run(GTK_DIALOG(pFileSel
)) == GTK_RESPONSE_ACCEPT
) {
895 #ifdef TEACH_TRAINING_HELPER_LOAD_FILE_ABOUT_URI
896 gchar
*szFilename
= gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(pFileSel
));
898 gchar
*szFilename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSel
));
901 gtk_dasher_control_train(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), szFilename
);
906 gtk_widget_destroy(pFileSel
);
909 static void dasher_main_command_quit(DasherMain
*pSelf
) {
910 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
912 GtkWidget
*pDialogue
= NULL
;
913 dasher_main_save_state(pSelf
);
914 if(dasher_editor_file_changed(pPrivate
->pEditor
)) {
915 // XXX PRLW: Just open the save dialogue box.
917 const gchar
*szFilename
= dasher_editor_get_filename(pPrivate
->pEditor
);
920 pDialogue
= gtk_message_dialog_new(GTK_WINDOW(pPrivate
->pMainWindow
), GTK_DIALOG_MODAL
,
921 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
922 _("Do you want to save your changes to %s?\n\nYour changes will be lost if you don't save them."),
927 pDialogue
= gtk_message_dialog_new(GTK_WINDOW(pPrivate
->pMainWindow
), GTK_DIALOG_MODAL
,
928 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
929 _("Do you want to save your changes?\n\nYour changes will be lost if you don't save them."));
934 gtk_dialog_add_buttons(GTK_DIALOG(pDialogue
),
935 _("Quit without saving"), GTK_RESPONSE_REJECT
,
936 _("Don't quit"), GTK_RESPONSE_CANCEL
,
937 _("Save and quit"), GTK_RESPONSE_ACCEPT
,
940 switch (gtk_dialog_run(GTK_DIALOG(pDialogue
))) {
941 case GTK_RESPONSE_REJECT
:
944 case GTK_RESPONSE_CANCEL
:
945 gtk_widget_destroy(GTK_WIDGET(pDialogue
));
947 case GTK_RESPONSE_ACCEPT
:
948 dasher_editor_command(pPrivate
->pEditor
, "action_save");
954 pDialogue
= gtk_message_dialog_new(GTK_WINDOW(pPrivate
->pMainWindow
), GTK_DIALOG_MODAL
,
955 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
956 _("Are you sure you wish to quit?"));
958 gtk_dialog_add_buttons(GTK_DIALOG(pDialogue
),
959 _("Don't quit"), GTK_RESPONSE_REJECT
,
960 _("Quit"), GTK_RESPONSE_ACCEPT
,
963 switch (gtk_dialog_run(GTK_DIALOG(pDialogue
))) {
964 case GTK_RESPONSE_REJECT
:
965 gtk_widget_destroy(GTK_WIDGET(pDialogue
));
967 case GTK_RESPONSE_ACCEPT
:
974 dasher_main_command_preferences(DasherMain
*pSelf
) {
975 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
976 dasher_preferences_dialogue_show(pPrivate
->pPreferencesDialogue
, 0);
980 dasher_main_command_preferences_alphabet(DasherMain
*pSelf
) {
981 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
982 dasher_preferences_dialogue_show(pPrivate
->pPreferencesDialogue
, 1);
986 dasher_main_command_help(DasherMain
*pSelf
) {
987 #ifdef HAVE_GTK_SHOW_URI
988 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
992 scr
= gtk_widget_get_screen(GTK_WIDGET(pPrivate
->pMainWindow
));
993 if (!gtk_show_uri(scr
, "ghelp:dasher", gtk_get_current_event_time(), &err
)) {
995 d
= gtk_message_dialog_new(GTK_WINDOW(pPrivate
->pMainWindow
),
997 GTK_MESSAGE_ERROR
, GTK_BUTTONS_CLOSE
,
998 "%s", _("Unable to open help file"));
999 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(d
),
1000 "%s", err
->message
);
1001 g_signal_connect(d
, "response", G_CALLBACK(gtk_widget_destroy
), NULL
);
1002 gtk_window_present(GTK_WINDOW(d
));
1010 dasher_main_command_about(DasherMain
*pSelf
) {
1011 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
1013 // In alphabetical order - please keep this in sync with the AUTHORS
1014 // file at root of the package tree
1015 const gchar
*authors
[] = {
1040 // Yeah, should really do some Gnome documentation for it...
1041 const gchar
*documenters
[] = {
1048 gtk_show_about_dialog(GTK_WINDOW(pPrivate
->pMainWindow
),
1050 "comments", _("Dasher is a predictive text entry application"),
1051 "copyright", "Copyright \xC2\xA9 1998-2011 The Dasher Project",
1052 "documenters", documenters
,
1053 "license", "GPL 2+",
1054 "logo-icon-name", "dasher",
1055 "translator-credits", _("translator-credits"),
1056 "version", PACKAGE_VERSION
,
1057 "website", PACKAGE_URL
,
1058 "wrap-license", true,
1063 dasher_main_speed_changed(DasherMain
*pSelf
) {
1064 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
1066 int iNewValue( static_cast<int>(round(gtk_spin_button_get_value(pPrivate
->pSpeedBox
) * 100)));
1068 if(pPrivate
->pAppSettings
->GetLong(LP_MAX_BITRATE
) != iNewValue
)
1069 pPrivate
->pAppSettings
->SetLong(LP_MAX_BITRATE
, iNewValue
);
1075 dasher_main_alphabet_combo_changed(DasherMain
*pSelf
) {
1076 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
1080 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pPrivate
->pAlphabetCombo
), &sIter
)) {
1082 gtk_tree_model_get(GTK_TREE_MODEL(pPrivate
->pAlphabetList
), &sIter
, 0, &szSelected
, -1);
1084 if(!strcmp("More Alphabets...", szSelected
)) {
1085 gtk_combo_box_set_active(GTK_COMBO_BOX(pPrivate
->pAlphabetCombo
), 0);
1086 // dasher_preferences_dialogue_show(pPrivate->pPreferencesDialogue);
1087 dasher_main_command_preferences_alphabet(pSelf
);
1090 pPrivate
->pAppSettings
->SetString(SP_ALPHABET_ID
, szSelected
);
1097 dasher_main_populate_alphabet_combo(DasherMain
*pSelf
) {
1099 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
1101 // Disconnect the event handler temporarily, otherwise this will
1102 // trigger alphabet changes
1104 g_signal_handlers_block_by_func(pPrivate
->pAlphabetCombo
, (gpointer
)alphabet_combo_changed
, pSelf
);
1106 gtk_list_store_clear(pPrivate
->pAlphabetList
);
1110 const char *szValue
;
1112 szValue
= pPrivate
->pAppSettings
->GetString(SP_ALPHABET_ID
).c_str();
1114 if(strlen(szValue
) > 0) {
1115 gtk_list_store_append(pPrivate
->pAlphabetList
, &sIter
);
1116 gtk_list_store_set(pPrivate
->pAlphabetList
, &sIter
, 0, szValue
, -1);
1117 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pPrivate
->pAlphabetCombo
), &sIter
);
1120 szValue
= pPrivate
->pAppSettings
->GetString(SP_ALPHABET_1
).c_str();
1121 if(strlen(szValue
) > 0) {
1122 gtk_list_store_append(pPrivate
->pAlphabetList
, &sIter
);
1123 gtk_list_store_set(pPrivate
->pAlphabetList
, &sIter
, 0, szValue
, -1);
1126 szValue
= pPrivate
->pAppSettings
->GetString(SP_ALPHABET_2
).c_str();
1127 if(strlen(szValue
) > 0) {
1128 gtk_list_store_append(pPrivate
->pAlphabetList
, &sIter
);
1129 gtk_list_store_set(pPrivate
->pAlphabetList
, &sIter
, 0, szValue
, -1);
1132 szValue
= pPrivate
->pAppSettings
->GetString(SP_ALPHABET_3
).c_str();
1133 if(strlen(szValue
) > 0) {
1134 gtk_list_store_append(pPrivate
->pAlphabetList
, &sIter
);
1135 gtk_list_store_set(pPrivate
->pAlphabetList
, &sIter
, 0, szValue
, -1);
1138 szValue
= pPrivate
->pAppSettings
->GetString(SP_ALPHABET_4
).c_str();
1139 if(strlen(szValue
) > 0) {
1140 gtk_list_store_append(pPrivate
->pAlphabetList
, &sIter
);
1141 gtk_list_store_set(pPrivate
->pAlphabetList
, &sIter
, 0, szValue
, -1);
1144 gtk_list_store_append(pPrivate
->pAlphabetList
, &sIter
);
1145 gtk_list_store_set(pPrivate
->pAlphabetList
, &sIter
, 0, "More Alphabets...", -1);
1147 g_signal_handlers_unblock_by_func(pPrivate
->pAlphabetCombo
, (gpointer
)alphabet_combo_changed
, pSelf
);
1153 dasher_main_lookup_key(DasherMain
*pSelf
, guint iKeyVal
) {
1154 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
1156 if(pPrivate
->pKeyboardHelper
)
1157 return pPrivate
->pKeyboardHelper
->ConvertKeycode(iKeyVal
);
1166 // TODO: reimplement (text view member of class)
1167 // gtk_widget_grab_focus(the_text_view);
1168 // g_bForwardKeyboard = true;
1175 speed_changed(GtkWidget
*pWidget
, gpointer pUserData
) {
1176 DasherMain
*pDasherMain
= DASHER_MAIN(pUserData
);
1177 dasher_main_speed_changed(pDasherMain
);
1181 alphabet_combo_changed(GtkWidget
*pWidget
, gpointer pUserData
) {
1182 DasherMain
*pDasherMain
= DASHER_MAIN(pUserData
);
1183 dasher_main_alphabet_combo_changed(pDasherMain
);
1187 dasher_main_cb_filename_changed(DasherEditor
*pEditor
, gpointer pUserData
) {
1188 DasherMain
*pDasherMain
= DASHER_MAIN(pUserData
);
1189 dasher_main_set_window_title(pDasherMain
);
1193 dasher_main_cb_buffer_changed(DasherEditor
*pEditor
, gpointer pUserData
) {
1194 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pUserData
);
1196 gtk_dasher_control_set_buffer(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), dasher_editor_get_offset(pPrivate
->pEditor
));
1200 dasher_main_cb_context_changed(DasherEditor
*pEditor
, gpointer pUserData
) {
1201 DasherMain
*pDasherMain
= DASHER_MAIN(pUserData
);
1202 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pDasherMain
);
1204 gtk_dasher_control_set_offset(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), dasher_editor_get_offset(pPrivate
->pEditor
));
1208 dasher_main_cb_window_close(GtkWidget
*pWidget
, GdkEvent
*event
, gpointer pUserData
) {
1209 DasherMain
*pDasherMain
= DASHER_MAIN(pUserData
);
1210 dasher_main_command_quit(pDasherMain
);
1212 /* Returning true stops further propagation */
1217 parameter_notification(GtkDasherControl
*pDasherControl
, gint iParameter
, gpointer pUserData
) {
1218 DasherMain
*pDasherMain
= DASHER_MAIN(pUserData
);
1219 dasher_main_handle_parameter_change(pDasherMain
, iParameter
);
1222 // TODO: Not really sure what happens here - need to sort out focus behaviour in general
1224 focus_in_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
) {
1225 return grab_focus();
1229 edit_focus_in_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
) {
1234 take_real_focus(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer user_data
) {
1235 // g_bForwardKeyboard = false;
1240 edit_key_press(GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
) {
1241 // TODO: Reimplement
1243 // if(g_bForwardKeyboard) {
1244 // gboolean *returnType;
1245 // g_signal_emit_by_name(GTK_WIDGET(pPrivate->pDasherWidget), "key_press_event", event, &returnType);
1252 // TODO: Check callback return functions
1257 edit_key_release(GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
) {
1258 // TODO: reimplement
1260 // if(g_bForwardKeyboard) {
1261 // gboolean *returnType;
1262 // g_signal_emit_by_name(GTK_WIDGET(pPrivate->pDasherWidget), "key_release_event", event, &returnType);
1269 // TODO: Check callback return functions
1274 test_focus_handler(GtkWidget
*pWidget
, GtkDirectionType iDirection
, gpointer
*pUserData
) {
1279 handle_start_event(GtkDasherControl
*pDasherControl
, gpointer data
) {
1280 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(data
);
1282 dasher_editor_grab_focus(pPrivate
->pEditor
);
1286 // TODO: Make this only work for children of the main window
1288 dasher_main_key_snooper(GtkWidget
*pWidget
, GdkEventKey
*pEvent
,
1289 gpointer pUserData
) {
1290 DasherMain
*pSelf
= DASHER_MAIN(pUserData
);
1292 gint iButton
= dasher_main_lookup_key(pSelf
, pEvent
->keyval
);
1295 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pSelf
);
1297 if (pWidget
== GTK_WIDGET(pPrivate
->pMainWindow
) ||
1298 gtk_widget_is_ancestor(pWidget
, GTK_WIDGET(pPrivate
->pMainWindow
))) {
1299 if(pPrivate
->pDasherWidget
) {
1300 if(pEvent
->type
== GDK_KEY_PRESS
)
1301 gtk_dasher_control_external_key_down(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), iButton
);
1303 gtk_dasher_control_external_key_up(GTK_DASHER_CONTROL(pPrivate
->pDasherWidget
), iButton
);
1317 // Callbacks from the Dasher widget
1320 handle_stop_event(GtkDasherControl
*pDasherControl
, gpointer data
) {
1321 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(data
);
1323 if(pPrivate
->pEditor
)
1324 dasher_editor_handle_stop(pPrivate
->pEditor
);
1327 // TODO: The following two should probably be made the same
1329 handle_request_settings(GtkDasherControl
* pDasherControl
, gpointer data
) {
1330 // TODO: reimplement
1331 // dasher_preferences_dialogue_show(g_pPreferencesDialogue);
1335 gtk2_edit_delete_callback(GtkDasherControl
*pDasherControl
, const gchar
*szText
, int iOffset
, gpointer user_data
) {
1336 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(user_data
);
1338 if(pPrivate
->pEditor
) {
1339 gint displaylength
= g_utf8_strlen(szText
, -1);
1340 dasher_editor_delete(pPrivate
->pEditor
, displaylength
, iOffset
);
1345 gtk2_edit_output_callback(GtkDasherControl
*pDasherControl
, const gchar
*szText
, int iOffset
, gpointer user_data
) {
1346 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(user_data
);
1348 if(pPrivate
->pEditor
) {
1349 dasher_editor_output(pPrivate
->pEditor
, szText
, iOffset
);
1354 convert_cb(GtkDasherControl
*pDasherControl
, gpointer pUserData
) {
1355 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pUserData
);
1357 if(pPrivate
->pEditor
) {
1358 dasher_editor_edit_convert(pPrivate
->pEditor
);
1363 protect_cb(GtkDasherControl
*pDasherControl
, gpointer pUserData
) {
1364 DasherMainPrivate
*pPrivate
= DASHER_MAIN_GET_PRIVATE(pUserData
);
1366 if(pPrivate
->pEditor
) {
1367 dasher_editor_edit_protect(pPrivate
->pEditor
);