cpdf: add new arguments to usage message
[cpdf.git] / cpdf.c
blobd708111efb40ad2fcd6f247de8e75c7a0bec7b7b
1 /*
2 * ctxt - A small and simple pdf viewer using gtk+ and poppler
4 * Copyright (C) 2009 Ali Gholami Rudi
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License, as published by the
8 * Free Software Foundation.
11 #include <ctype.h>
12 #include <gdk/gdk.h>
13 #include <gdk/gdkkeysyms.h>
14 #include <glib/poppler.h>
15 #include <gtk/gtk.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
20 static GtkWidget *bar;
21 static GtkWidget *img;
22 static GtkAdjustment *vadjst;
23 static GtkAdjustment *hadjst;
24 static PopplerDocument *doc;
25 static PopplerPage *page;
26 static GdkPixbuf *pixbuf;
27 static char filename[PATH_MAX];
28 static int num;
29 static int zoom = 15;
30 static int arg;
32 enum location {
33 LOC_PAGE,
34 LOC_STEP,
35 LOC_BEG,
36 LOC_CENTER,
37 LOC_END
40 static void on_destroy(GtkWidget *w, gpointer data)
42 gtk_main_quit();
45 static void drawbar()
47 int val = gtk_adjustment_get_value(vadjst) +
48 gtk_adjustment_get_page_size(vadjst);
49 int max = gtk_adjustment_get_upper(vadjst);
50 int pages = poppler_document_get_n_pages(doc);
51 char msg[128];
52 sprintf(msg, "%s\t%d%%\t\t\t%d/%d",
53 filename, val * 100 / max, num + 1, pages);
54 gtk_entry_set_text(GTK_ENTRY(bar), msg);
57 static void redraw()
59 double w = 0, h = 0;
60 double z = (float) zoom / (float) 10;
61 if (!page)
62 return;
63 poppler_page_get_size(page, &w, &h);
64 w *= z;
65 h *= z;
66 if (pixbuf)
67 g_object_unref(G_OBJECT(pixbuf));
68 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, w, h);
69 poppler_page_render_to_pixbuf(page, 0, 0, w, h, z, 0, pixbuf);
70 gtk_image_set_from_pixbuf(GTK_IMAGE(img), pixbuf);
71 drawbar();
74 static void cleanup()
76 if (pixbuf)
77 g_object_unref(G_OBJECT(pixbuf));
78 if (page)
79 g_object_unref(G_OBJECT(page));
80 if (doc)
81 g_object_unref(G_OBJECT(doc));
84 static int get_arg(int def)
86 return !arg ? def : arg;
89 static void scroll(enum location loc, int n)
91 int val = gtk_adjustment_get_value(vadjst);
92 int page = gtk_adjustment_get_page_size(vadjst);
93 int end = gtk_adjustment_get_upper(vadjst);
94 int max = end - page;
95 n *= get_arg(1);
96 switch (loc) {
97 case LOC_PAGE:
98 val += n * gtk_adjustment_get_page_increment(vadjst);
99 break;
100 case LOC_STEP:
101 val += n * gtk_adjustment_get_step_increment(vadjst);
102 break;
103 case LOC_BEG:
104 val = 0;
105 break;
106 case LOC_CENTER:
107 val = (end - page) / 2;
108 break;
109 case LOC_END:
110 val = max;
111 break;
113 arg = 0;
114 gtk_adjustment_set_value(vadjst, MAX(0, MIN(max, val)));
115 drawbar();
118 static void hscroll(int n)
120 int val = gtk_adjustment_get_value(hadjst);
121 int page = gtk_adjustment_get_page_size(hadjst);
122 int end = gtk_adjustment_get_upper(hadjst);
123 int max = end - page;
124 arg = 0;
125 val += n * get_arg(1) * gtk_adjustment_get_step_increment(hadjst);
126 gtk_adjustment_set_value(hadjst, MAX(0, MIN(max, val)));
129 static void showpage(int p)
131 if (p < 0 || p >= poppler_document_get_n_pages(doc))
132 return;
133 num = p;
134 if (page)
135 g_object_unref(G_OBJECT(page));
136 page = poppler_document_get_page(doc, p);
137 redraw();
138 gtk_adjustment_set_value(vadjst, 0);
141 static void nextpage(int n)
143 showpage(num + n * get_arg(1));
144 arg = 0;
147 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event,
148 gpointer data)
150 int mod = event->state & gtk_accelerator_get_default_mod_mask();
151 if (mod == GDK_CONTROL_MASK) {
152 switch (event->keyval) {
153 case GDK_f:
154 nextpage(1);
155 break;
156 case GDK_b:
157 nextpage(-1);
158 break;
159 case GDK_l:
160 gtk_widget_queue_draw(img);
161 break;
162 default:
163 break;
165 return 1;
167 switch (event->keyval) {
168 case GDK_Down:
169 case GDK_j:
170 scroll(LOC_STEP, 1);
171 break;
172 case GDK_Up:
173 case GDK_k:
174 scroll(LOC_STEP, -1);
175 break;
176 case GDK_Left:
177 case GDK_h:
178 hscroll(-1);
179 break;
180 case GDK_Right:
181 case GDK_l:
182 hscroll(1);
183 break;
184 case GDK_G:
185 showpage(get_arg(poppler_document_get_n_pages(doc)) - 1);
186 arg = 0;
187 break;
188 case GDK_End:
189 case GDK_L:
190 scroll(LOC_END, 1);
191 break;
192 case GDK_Home:
193 case GDK_H:
194 scroll(LOC_BEG, 1);
195 break;
196 case GDK_M:
197 scroll(LOC_CENTER, 1);
198 break;
199 case GDK_Next:
200 case GDK_space:
201 scroll(LOC_PAGE, 1);
202 break;
203 case GDK_Prior:
204 case GDK_BackSpace:
205 scroll(LOC_PAGE, -1);
206 break;
207 case GDK_q:
208 gtk_main_quit();
209 break;
210 case GDK_z:
211 if (get_arg(0) > 5 && get_arg(0) < 50)
212 zoom = get_arg(0);
213 arg = 0;
214 redraw();
215 break;
216 case GDK_Escape:
217 arg = 0;
218 break;
219 default:
220 if (isdigit(event->keyval))
221 arg = arg * 10 + event->keyval - '0';
222 break;
224 return 1;
227 static void on_size_allocate(GtkWidget *w, GtkAllocation *a,
228 gpointer data)
230 drawbar();
233 static int load_document(void)
235 char abspath[PATH_MAX];
236 char uri[PATH_MAX + 16];
237 realpath(filename, abspath);
238 snprintf(uri, sizeof(uri), "file://%s", abspath);
239 doc = poppler_document_new_from_file(uri, NULL, NULL);
240 return !doc;
243 static void create_window(void)
245 GtkWidget *win;
246 GtkWidget *wrap;
247 GtkWidget *vbox;
249 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
250 gtk_window_set_title(GTK_WINDOW(win), "mypdf");
251 g_signal_connect(G_OBJECT(win), "destroy",
252 G_CALLBACK(on_destroy), NULL);
254 vbox = gtk_vbox_new(FALSE, 2);
255 gtk_container_add(GTK_CONTAINER(win), vbox);
257 /* create the image */
258 wrap = gtk_scrolled_window_new(NULL, NULL);
259 gtk_box_pack_start(GTK_BOX(vbox), wrap, 1, 1, 0);
260 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wrap),
261 GTK_POLICY_NEVER,
262 GTK_POLICY_NEVER);
263 vadjst = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(wrap));
264 hadjst = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(wrap));
265 img = gtk_image_new();
266 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(wrap), img);
268 /* create the minibuffer */
269 bar = gtk_entry_new();
270 gtk_box_pack_start(GTK_BOX(vbox), bar, 0, 0, 0);
271 gtk_signal_connect(GTK_OBJECT(bar), "key_press_event",
272 GTK_SIGNAL_FUNC(on_key_press), NULL);
273 gtk_signal_connect(GTK_OBJECT(win), "key_press_event",
274 GTK_SIGNAL_FUNC(on_key_press), NULL);
275 gtk_signal_connect(GTK_OBJECT(win), "size_allocate",
276 GTK_SIGNAL_FUNC(on_size_allocate), NULL);
278 gtk_widget_set_size_request(win, 800, 600);
279 gtk_window_set_default_size(GTK_WINDOW(win), 1024, 768);
280 gtk_widget_show_all(win);
283 static int read_args(int argc, char *argv[])
285 int i = 0;
286 while (++i < argc) {
287 if (!strcmp("-z", argv[i]))
288 zoom = atoi(argv[++i]);
289 else if (!strcmp("-p", argv[i]))
290 num = atoi(argv[++i]) - 1;
291 else
292 strcpy(filename, argv[i]);
294 return !*filename;
297 int main(int argc, char *argv[])
299 gtk_init(&argc, &argv);
300 if (read_args(argc, argv) || load_document()) {
301 puts("Usage: cpdf [-p page] [-z zoom] path\n");
302 return 1;
304 create_window();
305 showpage(num);
306 gtk_main();
307 cleanup();
308 return 0;