Logo Search packages:      
Sourcecode: cbrpager version File versions  Download package

global.c

/*
 *  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 <config.h>                                                           
#endif                                                                          

#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>  /* open */
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>   /* wait */

#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;
gboolean     file_list_expanded = FALSE;


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 = NULL, **names;
  int pfd[2];                 /* pipe Mamoru Tasaka */
  int pid_i, pid_j;           /* two children Mamoru Tasaka */
  gboolean first = TRUE;
  int s, t, bffbeg = 0;

  if (debug) printf("%s\n", pref.lastbook);

  switch (pref.booktype = file_type_of(pref.lastbook)) {
    case ZIP_FILE:
      break;
    case RAR_FILE:
      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;
  }

  /* The following patch was received from Mamoru Tasaka, 2008/05/22
     to solve potential security problems with the system() call */

  if (pipe(pfd) == -1) {
    fprintf(stderr, "Creating pipe failed\n");
    return;
  }

  pid_i = fork(); 
  if (pid_i == -1) {
    fprintf(stderr, "Forking failed\n");
    return;
  }
  else if (pid_i == 0) { /* child 1: do unzip or unrar */
    close(pfd[0]);
    close(1); /* close stdout*/
    if (dup(pfd[1]) != 1 ) {
      fprintf(stderr, "Dup failure\n");
      return;
    }
    close(pfd[1]);
    switch(pref.booktype) {
      case ZIP_FILE:
        if (debug) fprintf(stderr, "ZIP command: unzip -l %s\n", 
            pref.lastbook);
        execlp("unzip", "unzip", "-l", pref.lastbook, (char *)NULL);
        return; /* should not reach here */
      case RAR_FILE:
        if (debug) fprintf(stderr, "RAR command: unrar -v %s\n", 
            pref.lastbook);
        execlp("unrar", "unrar", "v", pref.lastbook, (char *)NULL);
        return; /* should not reach here */
    }
  }
  else {
    pid_j = fork() ; 
    if (pid_j == -1) {
      fprintf(stderr, "Forking failed\n");
      return;
    }
    else if (pid_j == 0) { /* child 2; do grep */
      close(pfd[1]);
      close(0); /* close stdin */
      if (dup(pfd[0]) != 0) {
        fprintf(stderr, "Dup failure\n");
        return;
      }
      close(pfd[0]);
      if ((tmpf_fd = open(tmpf, O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR)) == -1) {
        p = g_strdup_printf(_("Cannot open file '%s'"), tmpf);
        ok_dialog(_("File error"), p);
        g_free(p);
        return;
      }
      close(1); /* close stdout */
      if (dup(tmpf_fd) != 1) {
        fprintf(stderr, "Dup failure\n");
        return;
      }
      close(tmpf_fd);
      execlp("grep", "grep", all_extensions, (char *)NULL);
      return; /* should not reach here */
    }
    else { /* parent */
      close(pfd[0]);
      close(pfd[1]);
      /* wait children */
      waitpid(pid_i, 0, 0);
      waitpid(pid_j, 0, 0);
    }
  }
  bff = NULL;

  /* End of this part of Mamoru Tasaka's patch */

  if (!g_file_test(tmpf, G_FILE_TEST_EXISTS)) {
    printf(_("Cannot open temporary file %s\n"), tmpf);
    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;

  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, *esc;
  int len, i, idx = 0, pid;
  
  p = (char *)g_list_nth_data(pagelist, nr);
  len = strlen(p);
  esc = g_malloc(2*len + 1);

  // Escaping characters which might be misinterpreted by the shell
  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), p);

  /* The following patch was received from Mamoru Tasaka, 2008/05/22
     to solve potential security problems with the system() call */

  pid = fork();
  switch (pid) {
    case -1:
      fprintf(stderr, "Forking failed\n");
      return;
    case 0: /* child */
      if ((tmpf_fd = open(tmpf, O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR)) == -1) {
        p = g_strdup_printf(_("Cannot open file '%s'"), tmpf);
        ok_dialog(_("File error"), p);
        g_free(p);
        return;
      }
      close(1); /* close stdout */
      if (dup(tmpf_fd) != 1) {
        fprintf(stderr, "Dup failure\n");
        return;
      }
      close(tmpf_fd);
      switch(pref.booktype) {
        case RAR_FILE:
          execlp("unrar",
                  "unrar", "p", "-ierr", "-clr", "--",
                  pref.lastbook, p, (char *)NULL);
          return; /* should not reach here */
        case ZIP_FILE:
          /* for zip file, esc must be passed instead of p */
          execlp("unzip",
                  "unzip", "-p", "-C",
                  pref.lastbook, esc, (char *)NULL);
          return; /* should not reach here */
      }
      return; /* should not reach here */
    default: /* parent */
      waitpid(pid, 0, 0);
  }

  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
file_list_expand(gboolean expand)
{
  GtkWidget *nav = lookup_widget(nav_window, "nav_toolbar"),
    *paned;
  GtkTreeView *tview;

  if (expand) {
    tview = GTK_TREE_VIEW(gtk_tree_view_new());
    g_object_ref(G_OBJECT(nav));
    gtk_container_remove(GTK_CONTAINER(nav_window), nav);

    if (!pref.nav_hor) {
      paned = gtk_hpaned_new();
      gtk_widget_show(paned);
      gtk_container_add(GTK_CONTAINER(nav_window), paned);
      switch (pref.nav_pos) {
        case NAV_NW:
        case NAV_SW:
        gtk_paned_pack1(GTK_PANED(paned), nav, TRUE, FALSE);
        gtk_paned_pack2(GTK_PANED(paned), GTK_WIDGET(tview), TRUE, FALSE);
          break;
        case NAV_NE:
        case NAV_SE:
        gtk_paned_pack2(GTK_PANED(paned), nav, TRUE, FALSE);
        gtk_paned_pack1(GTK_PANED(paned), GTK_WIDGET(tview), TRUE, FALSE);
          break;
      }
    } else {
      paned = gtk_vpaned_new();
      switch (pref.nav_pos) {
        case NAV_NW:
        case NAV_NE:
        case NAV_SW:
        case NAV_SE:
        break;
      }
    }
    g_object_unref(G_OBJECT(nav));
    gtk_widget_show(GTK_WIDGET(tview));
  } else {
  }
  file_list_expanded = expand;
  printf("Expand %d\n", expand);
}


void
file_list_tbtn_clicked(void)
{
  file_list_expand(!file_list_expanded);
}


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)
{
}

void
main_canvas_keypressed1(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;
  }
}

Generated by  Doxygen 1.6.0   Back to index