Bug fixed in DnD.
[gliv.git] / src / main.c
blob5be3b73c7d696cee3d4c39828b1b68066a0d0c50
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@yahoo.fr>
21 /********************
22 * Main source file *
23 ********************/
25 #include <unistd.h> /* close(), dup(), dup2(), STDERR_FILENO */
26 #include <stdlib.h> /* exit() */
27 #include <gtk/gtkgl.h>
29 #include "gliv.h"
30 #include "main.h"
31 #include "cmdline.h"
32 #include "options.h"
33 #include "gliv_image.h"
34 #include "rcfile.h"
35 #include "files_list.h"
36 #include "messages.h"
37 #include "windows.h"
38 #include "ipc.h"
40 rt_struct *rt;
41 options_struct *options;
42 gliv_image *current_image = NULL;
43 GtkWidget *gl_widget;
44 GtkMenuBar *menu_bar;
47 * This is borrowed from gtk+-2, without the gtk_grab_notify() calls.
48 * They slow down things a lot when the images menus are built with many files.
50 GtkWindowGroup *_gtk_window_get_group(GtkWindow * window)
52 if (window && window->group)
53 return window->group;
54 else {
55 static GtkWindowGroup *default_group = NULL;
57 if (!default_group)
58 default_group = gtk_window_group_new();
60 return default_group;
64 static GtkWindowGroup *gtk_main_get_window_group(GtkWidget * widget)
66 GtkWidget *toplevel = NULL;
68 if (widget)
69 toplevel = gtk_widget_get_toplevel(widget);
71 if (toplevel && GTK_IS_WINDOW(toplevel))
72 return _gtk_window_get_group(GTK_WINDOW(toplevel));
73 else
74 return _gtk_window_get_group(NULL);
77 void gtk_grab_add(GtkWidget * widget)
79 GtkWindowGroup *group;
81 g_return_if_fail(widget != NULL);
83 if (!GTK_WIDGET_HAS_GRAB(widget) && GTK_WIDGET_IS_SENSITIVE(widget)) {
84 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_GRAB);
86 group = gtk_main_get_window_group(widget);
88 g_object_ref(widget);
89 group->grabs = g_slist_prepend(group->grabs, widget);
91 /* gtk_grab_notify (group, widget, FALSE); */
95 void gtk_grab_remove(GtkWidget * widget)
97 GtkWindowGroup *group;
99 g_return_if_fail(widget != NULL);
101 if (GTK_WIDGET_HAS_GRAB(widget)) {
102 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_GRAB);
104 group = gtk_main_get_window_group(widget);
105 group->grabs = g_slist_remove(group->grabs, widget);
107 g_object_unref(widget);
109 /* gtk_grab_notify (group, widget, TRUE); */
113 void destroy_ggo_inputs(struct gengetopt_args_info *ggo)
115 gint i;
117 for (i = 0; i < ggo->inputs_num; i++)
118 g_free(ggo->inputs[i]);
120 g_free(ggo->inputs);
121 ggo->inputs = NULL;
122 ggo->inputs_num = 0;
125 void destroy_ggo_flags(struct gengetopt_args_info *ggo)
127 g_free(ggo->menu_arg);
128 g_free(ggo->client_arg);
129 g_free(ggo->alpha_checks_arg);
130 g_free(ggo->build_menus_arg);
131 g_free(ggo->force_load_arg);
132 g_free(ggo->full_screen_arg);
133 g_free(ggo->glivrc_arg);
134 g_free(ggo->info_arg);
135 g_free(ggo->loop_arg);
136 g_free(ggo->scale_down_arg);
137 g_free(ggo->maximize_arg);
138 g_free(ggo->make_fit_arg);
139 g_free(ggo->mnemonics_arg);
140 g_free(ggo->scrollbars_arg);
141 g_free(ggo->mipmap_arg);
142 g_free(ggo->recursive_arg);
143 g_free(ggo->sort_arg);
144 g_free(ggo->shuffle_arg);
145 g_free(ggo->thumbnails_arg);
146 g_free(ggo->dither_arg);
147 g_free(ggo->resize_win_arg);
148 g_free(ggo->slide_show_arg);
149 g_free(ggo->zoom_pointer_arg);
150 g_free(ggo->null_arg);
151 g_free(ggo->one_image_arg);
152 g_free(ggo->no_center_arg);
155 /* May exit :) */
156 gboolean get_on_off(const gchar * str)
158 if (str == NULL)
159 return TRUE;
161 while (*str == '=' || *str == ' ')
162 str++;
164 if (g_str_equal(str, "on"))
165 return TRUE;
167 if (g_str_equal(str, "off"))
168 return FALSE;
170 ERROR_MSG(_("Command line flags should be on or off, not %s\n"), str);
171 quit(1);
174 typedef struct {
175 gboolean given;
176 gboolean *flag;
177 gchar *str;
178 gboolean not;
179 } ggo_flag;
181 typedef struct {
182 gboolean given;
183 gint *opt_val;
184 gint value;
185 gint minimum;
186 } ggo_int;
188 static void fill_options(struct gengetopt_args_info *ggo)
190 ggo_flag flags[] = {
191 /* *INDENT-OFF* */
192 { ggo->full_screen_given, &options->fullscreen, ggo->full_screen_arg, 0 },
193 { ggo->scale_down_given, &options->scaledown, ggo->scale_down_arg, 0 },
194 { ggo->maximize_given, &options->maximize, ggo->maximize_arg, 0 },
195 { ggo->zoom_pointer_given, &options->zoom_pointer, ggo->zoom_pointer_arg, 0 },
196 { ggo->dither_given, &options->dither, ggo->dither_arg, 0 },
197 { ggo->force_load_given, &options->force, ggo->force_load_arg, 0 },
198 { ggo->mipmap_given, &options->mipmap, ggo->mipmap_arg, 0 },
199 { ggo->build_menus_given, &options->build_menus, ggo->build_menus_arg, 1 },
200 { ggo->mnemonics_given, &options->mnemonics, ggo->mnemonics_arg, 1 },
201 { ggo->menu_given, &options->menu_bar, ggo->menu_arg, 1 },
202 { ggo->info_given, &options->status_bar, ggo->info_arg, 1 },
203 { ggo->scrollbars_given, &options->scrollbars, ggo->scrollbars_arg, 1 },
204 { ggo->alpha_checks_given, &options->alpha_checks, ggo->alpha_checks_arg, 1 },
205 { ggo->loop_given, &options->loop, ggo->loop_arg, 0 },
206 { ggo->one_image_given, &options->one_image, ggo->one_image_arg, 0 },
207 { ggo->thumbnails_given, &options->thumbnails, ggo->thumbnails_arg, 1 },
208 { ggo->slide_show_given, &options->start_show, ggo->slide_show_arg, 0 },
209 { ggo->resize_win_given, &options->resize_win, ggo->resize_win_arg, 1 },
210 { ggo->make_fit_given, &options->maximize, ggo->make_fit_arg, 0 },
211 { ggo->make_fit_given, &options->scaledown, ggo->make_fit_arg, 0 },
212 { ggo->no_center_given, &options->no_center, ggo->no_center_arg, 0 },
213 { FALSE, NULL, NULL, }
214 /* *INDENT-ON* */
217 ggo_int ints[] = {
218 /* *INDENT-OFF* */
219 { ggo->delay_given, &options->delay, ggo->delay_arg, 0 },
220 { ggo->history_given, &options->history_size, ggo->history_arg, -1 },
221 { ggo->duration_given, &options->duration, ggo->duration_arg, 0 },
222 { ggo->fps_given, &options->fps, ggo->fps_arg, -1 },
223 { FALSE, NULL, FALSE, 0 }
224 /* *INDENT-ON* */
227 ggo_flag *flag;
228 ggo_int *opt_int;
230 for (flag = flags; flag->flag != NULL; flag++)
231 if (flag->given) {
232 *flag->flag = get_on_off(flag->str);
233 if (flag->not)
234 *flag->flag ^= TRUE;
237 for (opt_int = ints; opt_int->opt_val != NULL; opt_int++)
238 if (opt_int->given && opt_int->value >= opt_int->minimum)
239 *opt_int->opt_val = opt_int->value;
242 #define FLAG_ON(flag) (flag##_given && get_on_off(flag##_arg))
244 static void init_args(gint argc, gchar ** argv)
246 struct gengetopt_args_info ggo;
247 options_struct *rc_file;
249 /* Command line (some flags only). */
251 if (cmdline_parser(argc, argv, &ggo) != 0)
252 quit(1);
254 if (FLAG_ON(ggo.sort) && FLAG_ON(ggo.shuffle)) {
255 g_printerr(_("Cannot sort and shuffle at the same time\n"));
256 quit(1);
259 if (FLAG_ON(ggo.client) && connect_server(argc, argv))
260 /* Successfully reused a GLiv window. */
261 quit(0);
263 /* Configuration file. */
264 rc_file = load_rc(!FLAG_ON(ggo.glivrc));
265 options = g_memdup(rc_file, sizeof(options_struct));
267 /* Command line (remaining options). */
268 fill_options(&ggo);
270 rt = g_new(rt_struct, 1);
272 rt->cursor_hidden = FALSE;
273 rt->help = FALSE;
274 rt->alpha_checks_changed = TRUE;
275 rt->scr_width = gdk_screen_width();
276 rt->scr_height = gdk_screen_height();
278 if (FLAG_ON(ggo.null)) {
279 read_null_filenames(FLAG_ON(ggo.recursive), FLAG_ON(ggo.shuffle),
280 FLAG_ON(ggo.sort));
282 insert_after_current(ggo.inputs, ggo.inputs_num,
283 FLAG_ON(ggo.recursive),
284 FLAG_ON(ggo.shuffle), FLAG_ON(ggo.sort), TRUE);
286 } else if (ggo.inputs_num > 0)
287 /* There are filenames on the command line. */
288 init_list(ggo.inputs, ggo.inputs_num,
289 FLAG_ON(ggo.recursive),
290 FLAG_ON(ggo.shuffle), FLAG_ON(ggo.sort));
292 destroy_ggo_inputs(&ggo);
293 destroy_ggo_flags(&ggo);
297 * We call cmdline_parser() a first time to quickly exit if --help or --version
298 * was given. We do the real work after the next call in init_args(), after
299 * gtk_init() removed the gtk arguments.
301 * We temporarily close stderr because unknown and gtk arguments are handled
302 * afterwards.
304 static void check_quick_exit(gint argc, gchar ** argv)
306 struct gengetopt_args_info ggo;
307 gint fd;
309 /* Silence stderr. */
310 fd = dup(STDERR_FILENO);
311 close(STDERR_FILENO);
313 cmdline_parser(argc, argv, &ggo);
315 /* Restore stderr. */
316 dup2(fd, STDERR_FILENO);
317 close(fd);
319 destroy_ggo_inputs(&ggo);
320 destroy_ggo_flags(&ggo);
323 G_GNUC_NORETURN void quit(gint code)
325 exit(code);
328 gboolean gui_quit(void)
330 GtkMessageDialog *dialog;
331 gchar *msg;
333 if (options->confirm_quit == FALSE)
334 quit(0);
336 msg = _("Do you really want to quit GLiv?");
338 dialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(get_current_window(),
339 GTK_DIALOG_MODAL,
340 GTK_MESSAGE_QUESTION,
341 GTK_BUTTONS_YES_NO,
342 "%s", msg));
344 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
346 set_hide_cursor_enabled(FALSE);
347 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
348 quit(0);
350 gtk_widget_destroy(GTK_WIDGET(dialog));
351 set_hide_cursor_enabled(TRUE);
352 return TRUE;
355 gint main(gint argc, gchar ** argv)
357 check_quick_exit(argc, argv);
359 /* i18n */
360 #ifdef ENABLE_NLS
361 gtk_set_locale();
362 #ifdef LOCALEDIR
363 bindtextdomain(PACKAGE, LOCALEDIR);
364 #endif
365 textdomain(PACKAGE);
366 bind_textdomain_codeset(PACKAGE, "UTF-8");
367 #endif
369 g_thread_init(NULL);
370 gtk_init(&argc, &argv);
371 gtk_gl_init(&argc, &argv);
373 init_args(argc, argv);
375 create_windows();
376 start_server();
378 gtk_main();
380 return 0;