From 24c65a5297ebcff267415163eec06731fc170239 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Mon, 17 Aug 2015 19:00:53 +0200 Subject: [PATCH] Restore the splash screen. Re-implementat the splash screen, using functinos which are not deprecated under Gtk3. Note: This implementation does not use the gtk functions which the Gtk devs recommend for splash screens. What they forget, is that a primary purpose of a splash screen is that it should appear with the minimum of delay. gtk_init can have significant delay - hence the recommended way of doing splash screens in Gtk is self defeating. --- src/ui/gui/main.c | 292 ++++++++++++++++++++++++++++++------------- src/ui/gui/psppire.c | 122 +++++++++++------- src/ui/gui/psppire.h | 4 +- 3 files changed, 286 insertions(+), 132 deletions(-) diff --git a/src/ui/gui/main.c b/src/ui/gui/main.c index 1e59f8431f..9dd4307433 100644 --- a/src/ui/gui/main.c +++ b/src/ui/gui/main.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2004, 2005, 2006, 2010, 2011, 2012, 2013, 2014 Free Software Foundation + Copyright (C) 2004, 2005, 2006, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,6 +42,12 @@ #define _(msgid) gettext (msgid) #define N_(msgid) msgid + +GdkWindow *create_splash_window (GMainContext *context); +gboolean destroy_splash_window (gpointer ud); + + + /* Arguments to be interpreted before the X server gets initialised */ @@ -153,40 +159,6 @@ startup_option_callback (int id, void *show_splash_) NOT_REACHED (); } } - -static GtkWidget * -create_splash_window (void) -{ - GtkWidget *splash ; - GtkWidget *image; - - gtk_window_set_auto_startup_notification (FALSE); - - splash = gtk_window_new (GTK_WINDOW_POPUP); - - gtk_window_set_position (GTK_WINDOW (splash), - GTK_WIN_POS_CENTER_ALWAYS); - - gtk_window_set_type_hint (GTK_WINDOW (splash), - GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); - - image = gtk_image_new_from_file (relocate (PKGDATADIR "/splash.png")); - - gtk_container_add (GTK_CONTAINER (splash), image); - - gtk_widget_show (image); - - return splash; -} - -static gboolean -hide_splash_window (gpointer data) -{ - GtkWidget *splash = data; - gtk_widget_destroy (splash); - gtk_window_set_auto_startup_notification (TRUE); - return FALSE; -} static gboolean print_startup_time (gpointer data) @@ -199,47 +171,6 @@ print_startup_time (gpointer data) return FALSE; } -/* -static gboolean -quit_one_loop (gpointer data) -{ - gtk_main_quit (); - return FALSE; -} -*/ - -struct initialisation_parameters -{ - const char *data_file; - GtkWidget *splash_window; -}; - - -static gboolean -run_inner_loop (gpointer data) -{ - struct initialisation_parameters *ip = data; - initialize (ip->data_file); - - g_timeout_add (500, hide_splash_window, ip->splash_window); - - if (measure_startup) - { - GSource *source = g_idle_source_new (); - g_source_set_priority (source, G_PRIORITY_LOW); - g_source_set_callback (source, print_startup_time, NULL, NULL); - g_source_attach (source, NULL); - g_source_unref (source); - } - - gtk_main (); - - de_initialize (); - - return FALSE; -} - - static GMemVTable vtable = { xmalloc, @@ -278,10 +209,57 @@ remove_psn (int argc, char **argv) return argc; } + + +struct init_source +{ + GSource parent; + int state; + GMainLoop *loop; + gchar *file; +}; + + +gboolean +init_prepare (GSource *source, gint *timeout_) +{ + return TRUE; +} + + + +gboolean +init_check (GSource *source) +{ + return TRUE; +} + + +gboolean +init_dispatch (GSource *ss, + GSourceFunc callback, + gpointer user_data) +{ + struct init_source *is = (struct init_source *)ss; + + bool finished = initialize (is->file, is->state++); + + if (finished) + { + g_main_loop_quit (is->loop); + return FALSE; + } + + return TRUE; +} + +static GSourceFuncs init_funcs = {init_prepare, init_check, init_dispatch, NULL}; + + + int main (int argc, char *argv[]) { - struct initialisation_parameters init_p; gboolean show_splash = TRUE; struct argv_parser *parser; const gchar *vers; @@ -333,17 +311,161 @@ main (int argc, char *argv[]) However there shouldn't be any here because of the gtk_parse_args call above. */ gdk_init (&argc, &argv); - init_p.splash_window = create_splash_window (); - init_p.data_file = optind < argc ? argv[optind] : NULL; + GMainContext *context = g_main_context_new (); + + GdkWindow *win = show_splash ? create_splash_window (context) : NULL; + + GMainLoop *loop = g_main_loop_new (context, FALSE); + + GSource *ss = g_source_new (&init_funcs, + sizeof (struct init_source)); + + ((struct init_source *) ss)->state = 0; + + g_source_set_priority (ss, G_PRIORITY_DEFAULT); + + g_source_attach (ss, context); - // if ( show_splash ) - // gtk_widget_show (init_p.splash_window); + ((struct init_source *) ss)->loop = loop; + ((struct init_source *) ss)->file = optind < argc ? argv[optind] : NULL; + + g_source_unref (ss); - // g_idle_add (quit_one_loop, 0); + g_main_loop_run (loop); - // gtk_quit_add (0, run_inner_loop, &init_p); - run_inner_loop (&init_p); - // gtk_main (); + g_main_loop_unref (loop); + g_main_context_unref (context); + if (win) + g_timeout_add (500, destroy_splash_window, win); + + gtk_main (); + + /* Not much point in this except to check for memory leaks */ + de_initialize (); + return 0; } + + + + + +struct splash_source +{ + GSource parent; + cairo_surface_t *sfc; +}; + +void +fill_splash_window (GdkWindow *win, cairo_surface_t *sfce) +{ + cairo_t *cr = gdk_cairo_create (win); + + cairo_set_source_surface (cr, sfce, 0, 0); + + cairo_paint (cr); + cairo_destroy (cr); +} + +gboolean +splash_prepare (GSource *source, + gint *timeout_) +{ + return TRUE; +} + +gboolean +splash_check (GSource *source) +{ + return TRUE; +} + +gboolean +splash_dispatch (GSource *ss, + GSourceFunc callback, + gpointer user_data) +{ + struct splash_source *source = (struct splash_source *) ss; + + GdkEvent *e = gdk_event_get (); + if (!e) + return FALSE; + + GdkWindow *w = ((GdkEventAny *)e)->window; + + if (!w) + { + gdk_event_free (e); + return TRUE; + } + + fill_splash_window (w, source->sfc); + + gdk_window_show (w); + gdk_event_free (e); + + return TRUE; +} + + +gboolean +destroy_splash_window (gpointer ud) +{ + GdkWindow *win = GDK_WINDOW (ud); + gdk_window_withdraw (win); + gdk_display_flush (gdk_window_get_display (win)); + gdk_window_destroy (win); + + return FALSE; +} + +GSourceFuncs splash_funcs = {splash_prepare, splash_check, splash_dispatch, NULL}; + + +GdkWindow * +create_splash_window (GMainContext *context) +{ + const gchar *filename = PKGDATADIR "/splash.png"; + + const char *relocated_filename = relocate (filename); + cairo_surface_t *the_surface = + cairo_image_surface_create_from_png (relocated_filename); + + if (filename != relocated_filename) + free (CONST_CAST (char *, relocated_filename)); + + + g_return_val_if_fail (the_surface, NULL); + + int attr_mask = GDK_WA_TYPE_HINT; + GdkWindowAttr attr; + + attr.width = cairo_image_surface_get_width (the_surface); + attr.height = cairo_image_surface_get_height (the_surface); + attr.wclass = GDK_INPUT_OUTPUT; + attr.window_type = GDK_WINDOW_TOPLEVEL; + + attr.type_hint = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN; + + GdkWindow *win = gdk_window_new (NULL, &attr, attr_mask); + + gdk_window_set_events (win, GDK_EXPOSURE_MASK); + gdk_window_set_keep_above (win, TRUE); + gdk_window_show (win); + + + GSource *ss = g_source_new (&splash_funcs, + sizeof (struct splash_source)); + + ((struct splash_source *) ss)->sfc = the_surface; + g_source_set_priority (ss, G_PRIORITY_HIGH); + + g_source_attach (ss, context); + + g_source_unref (ss); + + return win; +} + + diff --git a/src/ui/gui/psppire.c b/src/ui/gui/psppire.c index 5a35b52efb..a18d332ea9 100644 --- a/src/ui/gui/psppire.c +++ b/src/ui/gui/psppire.c @@ -72,55 +72,85 @@ static gchar *local_to_filename_encoding (const char *fn); #define N_(msgid) msgid -void -initialize (const char *data_file) +bool +initialize (const char *data_file, int state) { - i18n_init (); - - preregister_widgets (); - - gsl_set_error_handler_off (); - output_engine_push (); - settings_init (); - fh_init (); - - psppire_set_lexer (NULL); - - bind_textdomain_codeset (PACKAGE, "UTF-8"); - - create_icon_factory (); - - psppire_output_window_setup (); - - journal_init (); - textdomain (PACKAGE); - - /* FIXME: This should be implemented with a GtkInterface */ - psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry); - psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view); - psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view); - psppire_selector_set_default_selection_func (PSPPIRE_TYPE_MEANS_LAYER, insert_source_row_into_layers); - - if (data_file) + switch (state) { - gchar *filename = local_to_filename_encoding (data_file); - - int retval = any_reader_detect (filename, NULL); - - /* Check to see if the file is a .sav or a .por file. If not - assume that it is a syntax file */ - if (retval == 1) - open_data_window (NULL, filename, NULL, NULL); - else if (retval == 0) - { - create_data_window (); - open_syntax_window (filename, NULL); - } - - g_free (filename); + case 0: + i18n_init (); + break; + case 1: + preregister_widgets (); + break; + case 2: + gsl_set_error_handler_off (); + break; + case 3: + output_engine_push (); + break; + case 4: + settings_init (); + break; + case 5: + fh_init (); + break; + case 6: + psppire_set_lexer (NULL); + break; + case 7: + bind_textdomain_codeset (PACKAGE, "UTF-8"); + break; + case 8: + create_icon_factory (); + break; + case 9: + psppire_output_window_setup (); + break; + case 10: + journal_init (); + break; + case 11: + textdomain (PACKAGE); + break; + case 12: + /* FIXME: This should be implemented with a GtkInterface */ + psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry); + psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view); + psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view); + psppire_selector_set_default_selection_func (PSPPIRE_TYPE_MEANS_LAYER, insert_source_row_into_layers); + break; + case 13: + { + if (data_file) + { + gchar *filename = local_to_filename_encoding (data_file); + + int retval = any_reader_detect (filename, NULL); + + /* Check to see if the file is a .sav or a .por file. If not + assume that it is a syntax file */ + if (retval == 1) + open_data_window (NULL, filename, NULL, NULL); + else if (retval == 0) + { + create_data_window (); + open_syntax_window (filename, NULL); + } + g_free (filename); + } + else + { + create_data_window (); + } + return TRUE; + } + break; + default: + return TRUE; + break; } - else - create_data_window (); + return FALSE; } diff --git a/src/ui/gui/psppire.h b/src/ui/gui/psppire.h index 8817824a9c..befbc06b53 100644 --- a/src/ui/gui/psppire.h +++ b/src/ui/gui/psppire.h @@ -17,9 +17,11 @@ #ifndef PSPPIRE_H #define PSPPIRE_H +#include + struct lexer; -void initialize (const char *data_file); +bool initialize (const char *data_file, int state); void de_initialize (void); void psppire_quit (void); -- 2.30.2