/* * global.c - auxiliary routines, mainly gp screen management and config * * Copyright (C) 1997-2004 John Coppens (john@jcoppens.com) * * 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 the Free Software Foundation; either version 2 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 Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "support.h" #include "interface.h" #include "global.h" #include "conf.h" #include "main.h" GList *pagelist = NULL; int page_nr = 0, timer_id = 0, tmpf_fd = 0; char tmpf[50] = "/tmp/cbrXXXXXX"; GnomeCanvas *book_canvas = NULL; GnomeCanvasItem *left_page = NULL, *right_page = NULL; double total_w = 0.0, total_h = 0.0; char *extens[] = { ".jpg", ".jpeg", ".png", ".gif", ".JPG", ".JPEG", ".PNG", ".GIF" }, all_extensions[] = "\\.jpg\\|\\.jpeg\\|\\.png\\|\\.gif\\|" "\\.JPG\\|\\.JPEG\\|\\.PNG\\|\\.GIF"; int nr_extensions = 8, ext_nr = 0; void strtolower(char *s) { int c; for (c = 0; c < strlen(s); c++) if (isalpha(s[c])) s[c] = tolower(s[c]); } gint compare_pages(gconstpointer s1, gconstpointer s2) { return strcmp(s1, s2); } int ok_dialog(char *ttl, char *msg) { GtkWidget *dlg, *lbl; dlg = gnome_dialog_new(ttl, _("Ok"), NULL); gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); lbl = gtk_label_new(msg); gtk_widget_show(lbl); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dlg)->vbox), lbl, TRUE, TRUE, 0); return gnome_dialog_run_and_close(GNOME_DIALOG(dlg)); } void initial_setup(void) { book_canvas = GNOME_CANVAS(lookup_widget(MainWindow, "main_canvas")); if ((tmpf_fd = mkstemp(tmpf)) == -1) { printf(_("Cannot generate temporary file %s\n"), tmpf); return; } } void clear_pagelist(void) { int c; for (c = 0; c < g_list_length(pagelist); c++) g_free(g_list_nth_data(pagelist, c)); g_list_free(pagelist); pagelist = NULL; } int file_type_of(char *fname) { FILE *f; char magic[5] = "1234"; f = fopen(fname, "rb"); if (!f) return -1; if (fread(magic, 1, 4, f) != 4) return -1; if (strstr(magic, "PK\003\004") == magic) return ZIP_FILE; if (strstr(magic, "Rar!") == magic) return RAR_FILE; return -1; } void start_show(void) { GtkWidget *w; char *bff, *p, **names; gboolean first = TRUE; int s, t, bffbeg; if (debug) printf("%s\n", pref.lastbook); switch (pref.booktype = file_type_of(pref.lastbook)) { case ZIP_FILE: bff = g_strdup_printf("unzip -l \"%s\" | grep \"%s\" > %s", pref.lastbook, all_extensions, tmpf); if (debug) printf("ZIP command: %s\n", bff); break; case RAR_FILE: bff = g_strdup_printf("unrar v \"%s\" | grep \"%s\" > %s", pref.lastbook, all_extensions, tmpf); if (debug) printf("RAR command: %s\n", bff); break; default: // Patch from Ilja Pyykkonen 2005/09/04 p = g_strdup_printf(_("Cannot open file '%s': unknown file type"), pref.lastbook); ok_dialog(_("File error"), p); g_free(p); return; } system(bff); if (!g_file_test(tmpf, G_FILE_TEST_EXISTS)) { printf(_("Cannot open temporary file %s\n"), tmpfile); g_free(bff); return; } if (pagelist) clear_pagelist(); switch (pref.booktype) { case RAR_FILE: bffbeg = 1; break; case ZIP_FILE: bffbeg = 28; break; } g_free(bff); g_file_get_contents(tmpf, &bff, NULL, NULL); names = g_strsplit(bff, "\n", 0); for (s = 0; names[s] != NULL; s++) { if (strlen(names[s]) == 0) continue; for (t = 0; t < nr_extensions; t++) if ((p = strstr(names[s]+bffbeg, extens[t])) != NULL) break; if (t == nr_extensions) { // then we don't know how to handle printf(_("Cannot find a suitable extension.\n")); exit(1); } if (p == NULL) continue; // is any valid extension present? p = strdup(names[s]+bffbeg); pagelist = g_list_append(pagelist, p); } g_strfreev(names); pagelist = g_list_sort(pagelist, compare_pages); show_page(0); page_nr = 0; // Thanks James Reeves jreeves[at]monkeyengines.co.uk } void scroll_to(double where) { GtkWidget *wdg; GtkAdjustment *adj; if (debug) printf("[scroll] to %.2f\n"); wdg = lookup_widget(MainWindow, "main_scroller"); adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(wdg)); if (debug) printf("[vscroll] val: %.2f max: %.2f min: %.2f\n", adj->value, adj->upper, adj->lower); gtk_adjustment_set_value(GTK_ADJUSTMENT(adj), where*(adj->upper - adj->page_size)); gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(wdg), adj); } void request_page(int nr, GdkPixbuf **pxm, double *w, double *h) { char *p, *bff, *esc; int len, i, idx = 0; p = (char *)g_list_nth_data(pagelist, nr); len = strlen(p); esc = g_malloc(2*len + 1); for (i = 0; i < len; i++) { switch (p[i]) { case '[': case ']': case '{': case '}': case '"': esc[idx++] = '\\'; }; esc[idx++] = p[i]; } esc[idx] = '\0'; printf(_("Requesting page %d/%d (%s)\n"), nr+1, g_list_length(pagelist), esc); switch (pref.booktype) { case RAR_FILE: bff = g_strdup_printf("unrar p -ierr -clr -- \"%s\" \"%s\" > %s", pref.lastbook, p, tmpf); break; case ZIP_FILE: bff = g_strdup_printf("unzip -p -C \"%s\" \"%s\" > %s", pref.lastbook, p, tmpf); break; } system(bff); g_free(bff); g_free(esc); *pxm = gdk_pixbuf_new_from_file(tmpf, NULL); if (*pxm) { *w = gdk_pixbuf_get_width(*pxm); *h = gdk_pixbuf_get_height(*pxm); } else { printf(_("Can't load the page (%s)\n"), tmpf); } } void show_page(int nr) { GnomeCanvasGroup *grp = gnome_canvas_root(book_canvas); GdkPixbuf *pxm, *pxm1; char *bff, *p; double w, h, w1 = 0, h1 = 0; if (g_list_length(pagelist) == 0) { printf(_("No pages loaded\n")); return; } bff = g_strdup_printf(_("CBR Pager - %s"), (char *)g_list_nth_data(pagelist, nr)); gtk_window_set_title(GTK_WINDOW(MainWindow), bff); g_free(bff); request_page(nr, &pxm, &w, &h); if (pref.nrpages == 2) { request_page(nr+1, &pxm1, &w1, &h1); } if (left_page) gtk_object_destroy(GTK_OBJECT(left_page)); left_page = gnome_canvas_item_new(grp, gnome_canvas_pixbuf_get_type(), "pixbuf", pxm, "x", 0.0, "y", 0.0, "width", w, "height", h, NULL); gdk_pixbuf_unref(pxm); if (pref.nrpages == 2) { if (right_page) gtk_object_destroy(GTK_OBJECT(right_page)); right_page = gnome_canvas_item_new(grp, gnome_canvas_pixbuf_get_type(), "pixbuf", pxm1, "x", w, "y", 0.0, "width", w1, "height", h1, NULL); gdk_pixbuf_unref(pxm1); } total_w = w + w1; total_h = h > h1 ? h : h1; gnome_canvas_set_scroll_region(book_canvas, 0.0, 0.0, total_w, total_h); } void fit_page(int w, int h) { double w_ratio = w / total_w, h_ratio = h / total_h; set_zoom_factor(w_ratio < h_ratio ? w_ratio : h_ratio); } void fit_width(int w) { double w_ratio = w / total_w; set_zoom_factor(w_ratio); } void next_page(int adv) { int by = adv, nr_pages = g_list_length(pagelist); if (by == 0) by = pref.nrpages; if (page_nr == (nr_pages - by)) return; page_nr += by; show_page(page_nr); switch (pref.nextpage) { case 0: scroll_to(0.0); break; case 1: scroll_to(1.0); break; } } void previous_page(int prv) { int by = prv; if (by == 0) by = pref.nrpages; page_nr -= by; if (page_nr < 0) { page_nr = 0; } show_page(page_nr); switch (pref.prevpage) { case 0: scroll_to(0.0); break; case 1: scroll_to(1.0); break; } } void goto_begin(void) { page_nr = 0; show_page(page_nr); } void goto_end(void) { page_nr = g_list_length(pagelist) - pref.nrpages; show_page(page_nr); } void update_nav_position(void) { int x, y, w, h, nh, nw; gtk_window_get_position(GTK_WINDOW(MainWindow), &x, &y); gtk_window_set_policy(GTK_WINDOW(nav_window), FALSE, FALSE, TRUE); gtk_toolbar_set_orientation( GTK_TOOLBAR(lookup_widget(nav_window, "nav_toolbar")), pref.nav_hor ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); gtk_window_get_size(GTK_WINDOW(MainWindow), &w, &h); gtk_window_get_size(GTK_WINDOW(nav_window), &nw, &nh); switch (pref.nav_pos) { case NAV_NW: gtk_window_move(GTK_WINDOW(nav_window), x+5, y+30); break; case NAV_NE: gtk_window_move(GTK_WINDOW(nav_window), x+w-nw-3, y+30); break; case NAV_SE: if (pref.nav_hor) gtk_window_move(GTK_WINDOW(nav_window), x+w-nw-3, y+h-12); else gtk_window_move(GTK_WINDOW(nav_window), x+w-nw-3, y+h-nh); break; case NAV_SW: if (pref.nav_hor) gtk_window_move(GTK_WINDOW(nav_window), x+5, y+h-12); // -nh+10); else gtk_window_move(GTK_WINDOW(nav_window), x+5, y+h-nh); break; } } gboolean follow_timer(gpointer data) { update_nav_position(); return TRUE; } void install_timer(void) { timer_id = gtk_timeout_add(FOLLOW_TIMER, follow_timer, NULL); } void set_zoom_factor(double factor) { gnome_canvas_set_pixels_per_unit(book_canvas, factor); zoom_factor = factor; } void set_zoom_fit(void) { int w, h; gtk_window_get_size(GTK_WINDOW(MainWindow), &w, &h); fit_page(w, h); } void set_zoom_width(void) { int w, h; gtk_window_get_size(GTK_WINDOW(MainWindow), &w, &h); fit_width(w - 20); } void clean_up(void) { close(tmpf_fd); unlink(tmpf); } void main_canvas_keypressed(GdkEventKey *event) { GtkWidget *w; char *wdg; switch (event->keyval) { case GDK_space: case GDK_Right: if (event->state & GDK_SHIFT_MASK) wdg = "last_btn"; else wdg = "next_btn"; break; case GDK_BackSpace: case GDK_Left: if (event->state & GDK_SHIFT_MASK) wdg = "begin_btn"; else wdg = "back_btn"; break; case GDK_o: // Patch from Ilja Pyykkönen 2005/09/04 wdg = "open_btn"; break; case GDK_z: wdg = "zoom_out_btn"; break; case GDK_x: wdg = "zoom_in_btn"; break; case GDK_c: wdg = "zoom_fit_btn"; break; case GDK_v: wdg = "zoom_orig_btn"; break; case GDK_q: wdg = "quit_btn"; break; // End patch from Ilja Pyykkönen 2005/09/04 default: return; } w = lookup_widget(nav_window, wdg); g_signal_emit_by_name(w, "clicked", NULL); } void main_canvas_buttonpressed(GdkEventButton *event) { GtkWidget *w; if (event->type != GDK_BUTTON_PRESS) return; switch (event->button) { case 1: // Left button break; case 3: w = create_help_popup(); gtk_menu_popup(GTK_MENU(w), NULL, NULL, NULL, NULL, event->button, event->time); break; } }