Rename the hash table to thumbs_hash_table.
[gliv.git] / src / windows.c
blobd81330a033c9a1a94d47f61348af395c5213d0b6
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 * The top level widgets *
23 *************************/
25 #include <gdk/gdkx.h> /* gdk_net_wm_supports() */
27 #include "gliv.h"
28 #include "windows.h"
29 #include "options.h"
30 #include "gliv_image.h"
31 #include "callbacks.h"
32 #include "messages.h"
33 #include "math_floats.h"
34 #include "str_utils.h"
35 #include "matrix.h"
36 #include "scrollbars.h"
37 #include "gl_widget.h"
38 #include "menus.h"
40 extern rt_struct *rt;
41 extern options_struct *options;
42 extern gliv_image *current_image;
43 extern GtkWidget *gl_widget;
44 extern GtkMenuBar *menu_bar;
46 /* What is in the window. */
47 static GtkVBox *widgets;
49 static GtkWindow *main_window;
50 static GtkWindow *fs_window;
52 /* The main status bar and its subdivisions. */
53 static GtkHBox *status_bar;
54 static GtkEntry *entry_ident;
55 static GtkEntry *entry_size;
56 static GtkEntry *entry_state;
59 * Called when resizing the window because the image changed or a
60 * widget has been toggled.
62 void resize_window(gint width, gint height, gboolean force)
64 if (options->resize_win == FALSE && force == FALSE)
65 return;
67 if (width < 0)
68 width = rt->wid_size->width;
70 if (height < 0)
71 height = rt->wid_size->height;
73 width = MAX(width, 320);
74 height = MAX(height, 240);
77 * First, we let GTK resize the window around the
78 * width x height widget,
80 gtk_widget_set_size_request(gl_widget, width, height);
81 gtk_window_resize(main_window, width, height);
83 process_events();
85 /* then, we make the widget downsizable. */
86 gtk_widget_set_size_request(gl_widget, 1, 1);
89 void show_dialog(GtkWidget * widget, const gchar * name)
91 /* In windowed mode we let the WM choose the position. */
92 if (options->fullscreen)
93 gtk_window_set_position(GTK_WINDOW(widget), GTK_WIN_POS_MOUSE);
95 if (name != NULL)
96 gtk_window_set_title(GTK_WINDOW(widget), name);
98 gtk_widget_show_all(widget);
101 /* To add an entry in the status bar. */
102 static GtkEntry *add_entry(gboolean grow, const gchar * init)
104 GtkEntry *entry;
106 entry = GTK_ENTRY(gtk_entry_new());
107 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
108 gtk_box_pack_start(GTK_BOX(status_bar), GTK_WIDGET(entry), grow, TRUE, 0);
110 /* We don't want the blinking cursor. */
111 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(entry), GTK_CAN_FOCUS);
113 gtk_entry_set_text(entry, init);
115 return entry;
118 static void create_status_bar(void)
120 status_bar = GTK_HBOX(gtk_hbox_new(FALSE, 0));
122 entry_ident = add_entry(TRUE, _("No image loaded"));
123 entry_size = add_entry(FALSE, _("width x height"));
124 entry_state = add_entry(FALSE, _("zoom% (angle)"));
127 void set_loading_entry(const gchar * filename)
129 static gchar *old_ident = NULL;
131 if (filename == NULL) {
132 /* Revert to the previous text without the loading information. */
133 gtk_entry_set_text(entry_ident, old_ident);
134 g_free(old_ident);
135 } else {
136 /* Add a loading information. */
137 gchar *new_ident;
139 old_ident = gtk_editable_get_chars(GTK_EDITABLE(entry_ident), 0, -1);
141 new_ident = g_strconcat(old_ident, " ", _("loading"), ":",
142 filename_to_utf8(filename), NULL);
144 gtk_entry_set_text(entry_ident, new_ident);
145 g_free(new_ident);
148 if (options->status_bar) {
149 /* Make sure the widget is updated now. */
150 gtk_widget_queue_draw(GTK_WIDGET(status_bar));
151 gdk_window_process_updates(GTK_WIDGET(status_bar)->window, TRUE);
155 /* Returns TRUE if the widget has been toggled. */
156 gboolean toggle_widget(GtkWidget * widget, gboolean * flag)
158 if (*flag == FALSE)
159 /* Show. */
160 gtk_widget_show(widget);
161 else
162 /* Hide. */
163 gtk_widget_hide(widget);
165 *flag ^= TRUE;
167 if (options->fullscreen == FALSE)
168 resize_window(-1, -1, FALSE);
170 return TRUE;
173 void toggle_menu_bar(void)
175 toggle_widget(GTK_WIDGET(menu_bar), &options->menu_bar);
178 void toggle_status_bar(void)
180 toggle_widget(GTK_WIDGET(status_bar), &options->status_bar);
183 /* To take into account the new filename, zoom, angle, symmetry. */
184 void update_status_bar(void)
186 gchar *size_str, *state_str;
187 const gchar *sym;
188 gfloat zoom, angle;
190 if (current_image == NULL)
191 return;
193 if (current_image->ident != NULL) {
194 /* Filename and dimensions status, only the first time. */
195 gtk_entry_set_text(entry_ident, current_image->ident);
196 gtk_editable_set_position(GTK_EDITABLE(entry_ident), 0);
198 size_str = g_strdup_printf("%dx%d",
199 current_image->width, current_image->height);
200 gtk_entry_set_text(entry_size, size_str);
201 g_free(size_str);
204 /* The state */
206 zoom = get_matrix_zoom() * 100.0;
207 angle = get_matrix_angle() * 180.0 / PI;
208 sym = is_matrix_symmetry()? " /" : "";
210 /* We don't want -0.000 */
211 if (float_equal(angle, 0.0))
212 angle = 0.0;
214 state_str = g_strdup_printf(_("%.3f%% (%.3f deg%s)"), zoom, angle, sym);
215 gtk_entry_set_text(entry_state, state_str);
217 g_free(state_str);
220 /* Does the WM support the EWMH protocol? */
221 static gboolean has_net_wm(void)
223 return gdk_net_wm_supports(gdk_atom_intern("_NET_WM_STATE_FULLSCREEN",
224 FALSE));
228 * On the first map, all widgets are shown, we have to hide
229 * those that are not requested.
231 static gboolean first_map(void)
233 if (options->menu_bar == FALSE)
234 gtk_widget_hide(GTK_WIDGET(menu_bar));
236 if (options->status_bar == FALSE)
237 gtk_widget_hide(GTK_WIDGET(status_bar));
239 if (options->scrollbars == FALSE)
240 hide_scrollbars();
242 if (options->fullscreen && has_net_wm())
243 toggle_fullscreen(TRUE);
245 return FALSE;
248 void create_windows(void)
250 GtkWindow *first_window;
251 GtkAccelGroup *accel_group;
252 GtkHBox *hbox;
255 * The main window: seen when not in fullscreen,
256 * or when using the NET WM protocol.
258 main_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
259 gtk_window_set_title(main_window, "GLiv");
260 install_callbacks(main_window);
262 /* The window seen in fullscreen mode. */
263 fs_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
264 gtk_window_set_title(fs_window, _("GLiv in fullscreen"));
266 /* Make it fullscreen. */
267 gtk_window_move(fs_window, 0, 0);
268 gtk_window_set_default_size(fs_window, rt->scr_width, rt->scr_height);
269 gtk_window_set_decorated(fs_window, FALSE);
270 install_callbacks(fs_window);
272 /* The widgets. */
273 create_gl_widget();
274 accel_group = create_menus();
275 create_status_bar();
277 /* Bind keyboard accelerators to windows. */
278 gtk_window_add_accel_group(main_window, accel_group);
279 gtk_window_add_accel_group(fs_window, accel_group);
281 /* Collection. */
282 widgets = GTK_VBOX(gtk_vbox_new(FALSE, 0));
284 /* The menu bar on the top. */
285 gtk_box_pack_start(GTK_BOX(widgets), GTK_WIDGET(menu_bar), FALSE, FALSE, 0);
287 /* The OpenGL widget and the vertical scrollbar under the menu bar. */
288 hbox = GTK_HBOX(gtk_hbox_new(FALSE, 0));
289 gtk_box_pack_start_defaults(GTK_BOX(hbox), gl_widget);
290 gtk_box_pack_start(GTK_BOX(hbox), get_new_scrollbar(FALSE), FALSE, FALSE,
292 gtk_box_pack_start_defaults(GTK_BOX(widgets), GTK_WIDGET(hbox));
294 /* The horizontal scrollbar under them. */
295 gtk_box_pack_start(GTK_BOX(widgets), get_new_scrollbar(TRUE), FALSE, FALSE,
298 /* The status bar in the bottom. */
299 gtk_box_pack_end(GTK_BOX(widgets), GTK_WIDGET(status_bar), FALSE, FALSE, 0);
301 first_window = (options->fullscreen && !has_net_wm())?
302 fs_window : main_window;
304 gtk_container_add(GTK_CONTAINER(first_window), GTK_WIDGET(widgets));
305 g_signal_connect_after(first_window, "map", G_CALLBACK(first_map), NULL);
306 gtk_widget_show_all(GTK_WIDGET(first_window));
310 * Called when going from fullscreen mode to window mode, or when
311 * the displayed image changed in window mode.
313 void goto_window(void)
315 gint new_width, new_height;
317 if (current_image == NULL) {
318 new_width = 1;
319 new_height = 1;
320 } else {
321 new_width = current_image->width;
322 new_height = current_image->height;
325 if (new_width >= rt->scr_width)
326 new_width = 3 * rt->scr_width / 4;
328 if (new_height >= rt->scr_height)
329 new_height = 3 * rt->scr_height / 4;
331 resize_window(new_width, new_height, FALSE);
335 * Return TRUE if we managed to toggle the fullscreen mode using the
336 * NET WM protocol.
338 static gboolean net_wm_toggle_fullscreen(gboolean enable)
340 if (get_current_window() != main_window || has_net_wm() == FALSE)
341 return FALSE;
343 if (enable)
344 gtk_window_fullscreen(main_window);
345 else
346 gtk_window_unfullscreen(main_window);
348 return TRUE;
351 void toggle_fullscreen(gboolean enable)
353 /* We first try using the NET WM protocol, then with the old method. */
354 if (net_wm_toggle_fullscreen(enable) == FALSE) {
355 GtkWindow *new, *old;
357 if (enable) {
358 /* Go to fullscreen mode. */
359 new = fs_window;
360 old = main_window;
361 } else {
362 /* Go to window mode. */
363 new = main_window;
364 old = fs_window;
367 gtk_widget_show(GTK_WIDGET(new));
368 gtk_widget_hide(GTK_WIDGET(old));
370 gtk_widget_reparent(GTK_WIDGET(widgets), GTK_WIDGET(new));
374 if (enable == FALSE)
375 goto_window();
377 options->fullscreen = enable;
378 schedule_hide_cursor();
381 void update_window_title(void)
383 const gchar *title;
385 title = filename_to_utf8(current_image->node->data);
386 gtk_window_set_title(main_window, title);
389 GtkWindow *get_current_window(void)
391 if (GTK_IS_WIDGET(gl_widget) && GTK_WIDGET_VISIBLE(gl_widget))
392 return GTK_WINDOW(gtk_widget_get_toplevel(gl_widget));
394 return NULL;