/* * colloquium.c * * Copyright © 2013-2019 Thomas White * * This file is part of Colloquium. * * Colloquium is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #define _(x) gettext(x) #include #include "colloquium.h" #include "narrative_window.h" struct _colloquium { GtkApplication parent_instance; GtkBuilder *builder; char *mydir; int first_run; char *imagestore; int hidepointer; }; typedef GtkApplicationClass ColloquiumClass; G_DEFINE_TYPE(Colloquium, colloquium, GTK_TYPE_APPLICATION) static void colloquium_activate(GApplication *papp) { Colloquium *app = COLLOQUIUM(papp); if ( !app->first_run ) { Narrative *n = narrative_new(); GFile *file = g_file_new_for_uri("resource:///uk/me/bitwiz/Colloquium/default.ss"); stylesheet_set_from_file(narrative_get_stylesheet(n), file); narrative_add_empty_item(n); narrative_window_new(n, NULL, papp); g_object_unref(file); } } static void new_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { GApplication *app = vp; g_application_activate(app); } static void open_intro_doc(Colloquium *app) { GFile *file = g_file_new_for_uri("resource:///uk/me/bitwiz/Colloquium/demo.sc"); g_application_open(G_APPLICATION(app), &file, 1, ""); g_object_unref(file); } static void intro_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { GApplication *app = vp; open_intro_doc(COLLOQUIUM(app)); } void open_about_dialog(GtkWidget *parent) { GtkWidget *window; const gchar *authors[] = { "Thomas White ", NULL }; window = gtk_about_dialog_new(); gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(parent)); gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(window), "Colloquium"); gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(window), "colloquium"); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), PACKAGE_VERSION); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window), "© 2017-2019 Thomas White "); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window), /* Description of the program */ _("Narrative-based presentation system")); gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(window), GTK_LICENSE_GPL_3_0); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window), "https://www.bitwiz.me.uk/"); gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(window), "https://www.bitwiz.me.uk/"); gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors); gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(window), _("translator-credits")); g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy), NULL); gtk_widget_show_all(window); } static void quit_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { GApplication *app = vp; g_application_quit(app); } static GFile **gslist_to_array(GSList *item, int *n) { int i = 0; int len = g_slist_length(item); GFile **files = malloc(len * sizeof(GFile *)); if ( files == NULL ) return NULL; while ( item != NULL ) { if ( i == len ) { fprintf(stderr, "WTF? Too many files\n"); break; } files[i++] = item->data; item = item->next; } *n = len; return files; } static gint open_response_sig(GtkWidget *d, gint response, GApplication *papp) { if ( response == GTK_RESPONSE_ACCEPT ) { GSList *files; int n_files = 0; GFile **files_array; int i; files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(d)); files_array = gslist_to_array(files, &n_files); if ( files_array == NULL ) { fprintf(stderr, "Failed to convert file list\n"); return 0; } g_slist_free(files); g_application_open(papp, files_array, n_files, ""); for ( i=0; ifinalize(object); } static void create_config(const char *filename) { FILE *fh; fh = fopen(filename, "w"); if ( fh == NULL ) { fprintf(stderr, _("Failed to create config\n")); return; } fprintf(fh, "imagestore: %s\n", g_get_user_special_dir(G_USER_DIRECTORY_PICTURES)); fprintf(fh, "hidepointer: no\n"); fclose(fh); } static int yesno(const char *a) { if ( a == NULL ) return 0; if ( strcmp(a, "1") == 0 ) return 1; if ( strcasecmp(a, "yes") == 0 ) return 1; if ( strcasecmp(a, "true") == 0 ) return 1; if ( strcasecmp(a, "0") == 0 ) return 0; if ( strcasecmp(a, "no") == 0 ) return 0; if ( strcasecmp(a, "false") == 0 ) return 0; fprintf(stderr, "Don't understand '%s', assuming false\n", a); return 0; } static void chomp(char *s) { size_t i; if ( !s ) return; for ( i=0; iimagestore = strdup(line+12); } if ( strncmp(line, "hidepointer: ", 12) == 0 ) { app->hidepointer = yesno(line+13); } } while ( !feof(fh) ); fclose(fh); } const char *colloquium_get_imagestore(Colloquium *app) { return app->imagestore; } int colloquium_get_hidepointer(Colloquium *app) { return app->hidepointer; } static void colloquium_startup(GApplication *papp) { Colloquium *app = COLLOQUIUM(papp); const char *configdir; char *tmp; G_APPLICATION_CLASS(colloquium_parent_class)->startup(papp); g_action_map_add_action_entries(G_ACTION_MAP(app), app_entries, G_N_ELEMENTS(app_entries), app); app->builder = gtk_builder_new_from_resource("/uk/me/bitwiz/Colloquium/menus.ui"); gtk_builder_add_from_resource(app->builder, "/uk/me/bitwiz/Colloquium/windows.ui", NULL); gtk_application_set_menubar(GTK_APPLICATION(app), G_MENU_MODEL(gtk_builder_get_object(app->builder, "menubar"))); if ( gtk_application_prefers_app_menu(GTK_APPLICATION(app)) ) { /* Set the application menu only if it will be shown by the * desktop environment. All the entries are already in the * normal menus, so don't let GTK create a fallback menu in the * menu bar. */ GMenuModel *mmodel = G_MENU_MODEL(gtk_builder_get_object(app->builder, "app-menu")); gtk_application_set_app_menu(GTK_APPLICATION(app), mmodel); } configdir = g_get_user_config_dir(); app->mydir = malloc(strlen(configdir)+14); strcpy(app->mydir, configdir); strcat(app->mydir, "/colloquium"); if ( !g_file_test(app->mydir, G_FILE_TEST_IS_DIR) ) { /* Folder not created yet */ open_intro_doc(app); app->first_run = 1; if ( g_mkdir(app->mydir, S_IRUSR | S_IWUSR | S_IXUSR) ) { fprintf(stderr, _("Failed to create config folder\n")); } } /* Read config file */ tmp = malloc(strlen(app->mydir)+32); if ( tmp != NULL ) { tmp[0] = '\0'; strcat(tmp, app->mydir); strcat(tmp, "/config"); /* Create default config file if it doesn't exist */ if ( !g_file_test(tmp, G_FILE_TEST_EXISTS) ) { create_config(tmp); } read_config(tmp, app); free(tmp); } } static void colloquium_shutdown(GApplication *app) { G_APPLICATION_CLASS(colloquium_parent_class)->shutdown(app); } static void colloquium_class_init(ColloquiumClass *class) { GApplicationClass *app_class = G_APPLICATION_CLASS(class); GObjectClass *object_class = G_OBJECT_CLASS(class); app_class->startup = colloquium_startup; app_class->shutdown = colloquium_shutdown; app_class->activate = colloquium_activate; app_class->open = colloquium_open; object_class->finalize = colloquium_finalize; } static void colloquium_init(Colloquium *app) { app->imagestore = NULL; app->hidepointer = 0; } static Colloquium *colloquium_new() { Colloquium *app; g_set_application_name("Colloquium"); app = g_object_new(colloquium_get_type(), "application-id", "uk.org.bitwiz.Colloquium", "flags", G_APPLICATION_HANDLES_OPEN, "register-session", TRUE, NULL); app->first_run = 0; /* Will be updated at "startup" if appropriate */ return app; } static void show_help(const char *s) { printf(_("Syntax: %s [options] []\n\n"), s); printf(_("Narrative-based presentation system.\n\n" " -h, --help Display this help message.\n")); } int main(int argc, char *argv[]) { int c; int status; Colloquium *app; /* Long options */ const struct option longopts[] = { {"help", 0, NULL, 'h'}, {0, 0, NULL, 0} }; /* Short options */ while ((c = getopt_long(argc, argv, "h", longopts, NULL)) != -1) { switch (c) { case 'h' : show_help(argv[0]); return 0; case 0 : break; default : return 1; } } #if !GLIB_CHECK_VERSION(2,36,0) g_type_init(); #endif bindtextdomain("colloquium", LOCALEDIR); textdomain("colloquium"); app = colloquium_new(); status = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); return status; }