Remove deprecated objects GtkAction and GtkUIManager
[pspp] / src / ui / gui / main.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2005, 2006, 2010, 2011, 2012, 2013, 2014, 2015, 2016  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "ui/gui/psppire.h"
20
21 #include <gtk/gtk.h>
22 #include <stdlib.h>
23
24 #include "language/lexer/include-path.h"
25 #include "libpspp/argv-parser.h"
26 #include "libpspp/array.h"
27 #include "libpspp/assertion.h"
28 #include "libpspp/cast.h"
29 #include "libpspp/copyleft.h"
30 #include "libpspp/str.h"
31 #include "libpspp/string-array.h"
32 #include "libpspp/version.h"
33 #include "ui/source-init-opts.h"
34 #include "ui/gui/psppire-syntax-window.h"
35 #include "ui/gui/psppire-data-window.h"
36 #include "ui/gui/psppire-output-window.h"
37
38 #include "gl/configmake.h"
39 #include "gl/progname.h"
40 #include "gl/relocatable.h"
41 #include "gl/version-etc.h"
42 #include "gl/xalloc.h"
43
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
46 #define N_(msgid) msgid
47
48
49
50 static gboolean
51 show_version_and_exit ()
52 {
53   version_etc (stdout, "psppire", PACKAGE_NAME, PACKAGE_VERSION,
54                "Ben Pfaff", "John Darrington", "Jason Stover", NULL_SENTINEL);
55
56   exit (0);
57
58   return TRUE;
59 }
60 \f
61
62
63 gboolean
64 init_prepare (GSource * source, gint * timeout_)
65 {
66   return TRUE;
67 }
68
69 gboolean
70 init_check (GSource * source)
71 {
72   return TRUE;
73 }
74
75 gboolean
76 init_dispatch (GSource * ss, GSourceFunc callback, gpointer user_data)
77 {
78   struct init_source *is = (struct init_source *) ss;
79
80   bool finished = initialize (is);
81   is->state++;
82
83   if (finished)
84     {
85       g_main_loop_quit (is->loop);
86       return FALSE;
87     }
88
89   return TRUE;
90 }
91
92 static GSourceFuncs init_funcs =
93   { init_prepare, init_check, init_dispatch, NULL };
94 \f
95
96
97 GtkWidget *wsplash;
98 gint64 start_time = 0;
99
100
101 static GtkWidget *
102 create_splash_window (void)
103 {
104   GtkWidget *sp = gtk_window_new (GTK_WINDOW_TOPLEVEL);
105
106   const gchar *filename = PKGDATADIR "/splash.png";
107   const char *relocated_filename = relocate (filename);
108   GtkWidget *l = gtk_image_new_from_file (relocated_filename);
109   if (filename != relocated_filename)
110     free (CONST_CAST (char *, relocated_filename));
111
112   gtk_container_add (GTK_CONTAINER (sp), l);
113   gtk_window_set_type_hint (GTK_WINDOW (sp),
114                             GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
115   gtk_window_set_position (GTK_WINDOW (sp), GTK_WIN_POS_CENTER);
116   gtk_window_set_skip_pager_hint (GTK_WINDOW (sp), TRUE);
117   gtk_window_set_skip_taskbar_hint (GTK_WINDOW (sp), TRUE);
118   gtk_window_set_focus_on_map (GTK_WINDOW (sp), FALSE);
119   gtk_window_set_accept_focus (GTK_WINDOW (sp), FALSE);
120
121   GdkGeometry hints;
122   hints.max_height = 100;
123   hints.max_width = 200;
124   gtk_window_set_geometry_hints (GTK_WINDOW (sp),
125                                  NULL, &hints, GDK_HINT_MAX_SIZE);
126
127
128   gtk_window_set_gravity (GTK_WINDOW (sp), GDK_GRAVITY_CENTER);
129
130   gtk_window_set_modal (GTK_WINDOW (sp), TRUE);
131   gtk_window_set_decorated (GTK_WINDOW (sp), FALSE);
132   gtk_window_set_keep_above (GTK_WINDOW (sp), TRUE);
133   gtk_widget_show_all (sp);
134   return sp;
135 }
136
137
138 static gint
139 on_local_options (GApplication * application,
140                   GVariantDict * options, gpointer user_data)
141 {
142   GVariant *b;
143
144   b =
145     g_variant_dict_lookup_value (options, "no-splash",
146                                  G_VARIANT_TYPE_BOOLEAN);
147   if (b)
148     {
149       g_variant_unref (b);
150     }
151   else
152     {
153       start_time = g_get_monotonic_time ();
154     }
155
156   return -1;
157 }
158
159
160 static void
161 on_startup (GApplication * app, gpointer ud)
162 {
163   GMainContext *context = g_main_context_new ();
164
165   if (start_time != 0)
166     {
167       wsplash = create_splash_window ();
168       gtk_application_add_window (GTK_APPLICATION (app),
169                                   GTK_WINDOW (wsplash));
170     }
171
172   GMainLoop *loop = g_main_loop_new (context, FALSE);
173
174   GSource *ss = g_source_new (&init_funcs, sizeof (struct init_source));
175
176   ((struct init_source *) ss)->loop = loop;
177   ((struct init_source *) ss)->state = 0;
178
179   g_source_set_priority (ss, G_PRIORITY_DEFAULT);
180
181   g_source_attach (ss, context);
182   g_main_loop_run (loop);
183 }
184
185
186 static void
187 post_initialise (GApplication * app)
188 {
189   register_selection_functions ();
190   psppire_output_window_setup ();
191
192   GSimpleAction *quit = g_simple_action_new ("quit", NULL);
193   g_signal_connect_swapped (quit, "activate", G_CALLBACK (psppire_quit), app);
194   g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (quit));
195 }
196
197
198 #define SPLASH_DURATION 1000
199
200 static gboolean
201 destroy_splash (gpointer ud)
202 {
203   GtkWidget *sp = GTK_WIDGET (ud);
204   gtk_widget_destroy (sp);
205   return G_SOURCE_REMOVE;
206 }
207
208 static void
209 on_activate (GApplication * app, gpointer ud)
210 {
211   post_initialise (app);
212
213   GtkWindow *x = create_data_window ();
214   gtk_window_set_transient_for (GTK_WINDOW (wsplash), GTK_WINDOW (x));
215   gtk_application_add_window (GTK_APPLICATION (app), x);
216   gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (wsplash));
217   gtk_window_set_keep_above (GTK_WINDOW (wsplash), TRUE);
218   gtk_window_present (GTK_WINDOW (wsplash));
219
220   /* Remove the splash screen after SPLASH_DURATION milliseconds */
221   gint64 elapsed_time = (g_get_monotonic_time () - start_time) / 1000;
222   if (SPLASH_DURATION - elapsed_time <= 0)
223     destroy_splash (wsplash);
224   else
225     g_timeout_add (SPLASH_DURATION - elapsed_time, destroy_splash, wsplash);
226 }
227
228
229 static void
230 on_open (GApplication * app, GFile ** files, gint n_files, gchar * hint,
231          gpointer ud)
232 {
233   post_initialise (app);
234
235   gchar *file = g_file_get_parse_name (files[0]);
236   psppire_preload_file (file);
237   g_free (file);
238 }
239
240
241 /* These are arguments which must be processed BEFORE the X server has been initialised */
242 static void
243 process_pre_start_arguments (int *argc, char ***argv)
244 {
245   GOptionEntry oe[] = {
246     {"version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
247      show_version_and_exit, "Show version information and exit", 0},
248     {NULL}
249   };
250
251   GOptionContext *oc = g_option_context_new ("");
252   g_option_context_set_help_enabled (oc, FALSE);
253   g_option_context_set_ignore_unknown_options (oc, FALSE);
254   g_option_context_add_main_entries (oc, oe, NULL);
255   g_option_context_parse (oc, argc, argv, NULL);
256 }
257
258
259 int
260 main (int argc, char *argv[])
261 {
262   GtkApplication *app =
263     gtk_application_new ("gnu.pspp", G_APPLICATION_HANDLES_OPEN);
264
265   process_pre_start_arguments (&argc, &argv);
266
267   GOptionEntry oe[] = {
268     {"no-splash", 'q', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL,
269      "Do not display the splash screen", 0},
270     {NULL}
271   };
272
273   g_application_add_main_option_entries (G_APPLICATION (app), oe);
274
275   g_signal_connect (app, "startup", G_CALLBACK (on_startup), NULL);
276   g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
277   g_signal_connect (app, "handle-local-options",
278                     G_CALLBACK (on_local_options), NULL);
279   g_signal_connect (app, "open", G_CALLBACK (on_open), NULL);
280
281   {
282     GSimpleAction *act_new_syntax = g_simple_action_new ("new-syntax", NULL);
283     g_signal_connect_swapped (act_new_syntax, "activate",
284                               G_CALLBACK (create_syntax_window), NULL);
285     g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_new_syntax));
286   }
287
288   {
289     GSimpleAction *act_new_data = g_simple_action_new ("new-data", NULL);
290     g_signal_connect_swapped (act_new_data, "activate",
291                               G_CALLBACK (create_data_window), NULL);
292     g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_new_data));
293   }
294
295   return g_application_run (G_APPLICATION (app), argc, argv);
296 }