quran: use mmap() instead of read()
[cnoor.git] / txtwin.c
blob0d45a69998be21a855bd5f00362431e6d8a9aa7c
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <gtk/gtk.h>
6 #include <gdk/gdkkeysyms.h>
7 #include "txtwin.h"
8 #include "util.h"
10 struct txtwin {
11 /* a GtkTextView */
12 GtkWidget *main;
13 GtkAdjustment *adjst;
14 /* a GtkEntry */
15 GtkWidget *bar;
16 /* command arg */
17 int arg;
20 static void on_window_destroy(GtkWidget *widget, gpointer data)
22 gtk_main_quit();
25 enum location {
26 LOC_PAGE,
27 LOC_STEP,
28 LOC_LINE,
29 LOC_PERCENT,
30 LOC_BEG,
31 LOC_END
34 static void update_bar(struct txtwin *tw)
36 int val = gtk_adjustment_get_value(tw->adjst) +
37 gtk_adjustment_get_page_size(tw->adjst);
38 int max = gtk_adjustment_get_upper(tw->adjst);
39 char msg[128];
40 sprintf(msg, "%d%%", val * 100 / max);
41 gtk_entry_set_text(GTK_ENTRY(tw->bar), msg);
44 static int get_arg(struct txtwin *tw, int def)
46 return tw->arg == 0 ? def : tw->arg;
49 static void scroll(struct txtwin *tw, enum location loc, int n)
51 int val = gtk_adjustment_get_value(tw->adjst);
52 int page = gtk_adjustment_get_page_size(tw->adjst);
53 int end = gtk_adjustment_get_upper(tw->adjst);
54 int max = end - page;
55 n *= get_arg(tw, 1);
56 switch(loc) {
57 case LOC_PAGE:
58 val += n * gtk_adjustment_get_page_increment(tw->adjst);
59 break;
60 case LOC_STEP:
61 val += n * gtk_adjustment_get_step_increment(tw->adjst);
62 break;
63 case LOC_LINE:
64 val = get_arg(tw, 0) ? 0 : max;
65 break;
66 case LOC_PERCENT:
67 val = get_arg(tw, 0) * end / 100 - page;
68 break;
69 case LOC_BEG:
70 val = 0;
71 break;
72 case LOC_END:
73 val = max;
74 break;
76 if (val > max)
77 val = max;
78 if (val < 0)
79 val = 0;
80 tw->arg = 0;
81 gtk_adjustment_set_value(tw->adjst, val);
82 update_bar(tw);
85 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event,
86 gpointer data)
88 struct txtwin *tw = data;
89 int mod = event->state & gtk_accelerator_get_default_mod_mask();
90 if (mod == GDK_CONTROL_MASK) {
91 switch(event->keyval) {
92 case GDK_f:
93 scroll(tw, LOC_PAGE, 1);
94 break;
95 case GDK_b:
96 scroll(tw, LOC_PAGE, -1);
97 break;
98 case GDK_l:
99 gtk_widget_queue_draw(tw->main);
100 break;
101 case GDK_n:
102 scroll(tw, LOC_STEP, 1);
103 break;
104 case GDK_p:
105 scroll(tw, LOC_STEP, -1);
106 break;
107 default:
108 break;
110 return 1;
112 switch(event->keyval) {
113 case GDK_Down:
114 case GDK_j:
115 scroll(tw, LOC_STEP, 1);
116 break;
117 case GDK_Up:
118 case GDK_k:
119 scroll(tw, LOC_STEP, -1);
120 break;
121 case GDK_G:
122 scroll(tw, LOC_LINE, 1);
123 break;
124 case GDK_End:
125 scroll(tw, LOC_END, 1);
126 break;
127 case GDK_Home:
128 scroll(tw, LOC_BEG, 1);
129 break;
130 case GDK_Next:
131 case GDK_space:
132 scroll(tw, LOC_PAGE, 1);
133 break;
134 case GDK_Prior:
135 case GDK_BackSpace:
136 scroll(tw, LOC_PAGE, -1);
137 break;
138 case GDK_q:
139 gtk_main_quit();
140 break;
141 case GDK_percent:
142 scroll(tw, LOC_PERCENT, 1);
143 break;
144 case GDK_Escape:
145 tw->arg = 0;
146 break;
147 default:
148 if (isdigit(event->keyval))
149 tw->arg = tw->arg * 10 + event->keyval - '0';
150 break;
152 return 1;
155 static void on_size_allocate(GtkWidget *w, GtkAllocation *a, gpointer tw)
157 update_bar(tw);
160 struct txtwin *txtwin_alloc()
162 GtkWidget *window;
163 GtkWidget *vbox;
164 struct txtwin *tw = xmalloc(sizeof(struct txtwin));
165 memset(tw, 0, sizeof(*tw));
166 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
167 gtk_window_set_title(GTK_WINDOW(window), "CNOOR");
168 g_signal_connect(G_OBJECT(window), "destroy",
169 G_CALLBACK(on_window_destroy), NULL);
171 vbox = gtk_vbox_new(FALSE, 2);
172 gtk_container_add(GTK_CONTAINER(window), vbox);
174 /* create the textview */
175 tw->main = gtk_text_view_new();
176 gtk_box_pack_start(GTK_BOX(vbox), tw->main, 1, 1, 0);
177 gtk_signal_connect(GTK_OBJECT(tw->main), "key_press_event",
178 GTK_SIGNAL_FUNC(on_key_press), tw);
179 gtk_signal_connect(GTK_OBJECT(window), "size_allocate",
180 GTK_SIGNAL_FUNC(on_size_allocate), tw);
181 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tw->main),
182 GTK_WRAP_WORD);
183 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tw->main), FALSE);
185 /* add the adjustment */
186 tw->adjst = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 100, 1, 9, 10));
187 gtk_widget_set_scroll_adjustments(tw->main, NULL, tw->adjst);
189 /* create the minibuffer */
190 tw->bar = gtk_entry_new();
191 gtk_box_pack_start(GTK_BOX(vbox), tw->bar, 0, 0, 0);
192 gtk_signal_connect(GTK_OBJECT(tw->bar), "key_press_event",
193 GTK_SIGNAL_FUNC(on_key_press), tw);
194 update_bar(tw);
196 gtk_widget_set_size_request(window, 800, 600);
197 gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
198 gtk_widget_show_all(window);
199 return tw;
202 void txtwin_free(struct txtwin *tw)
204 free(tw);
207 void txtwin_loop(struct txtwin *tw)
209 gtk_main();
212 void txtwin_gtk_init(int argc, char **argv)
214 gtk_init(&argc, &argv);
217 static GtkTextBuffer *txtwin_buffer(struct txtwin *tw)
219 return gtk_text_view_get_buffer(GTK_TEXT_VIEW(tw->main));
222 void txtwin_append(struct txtwin *tw, char *s, char *tag)
224 GtkTextIter iter;
225 GtkTextBuffer *buf = txtwin_buffer(tw);
226 gtk_text_buffer_get_end_iter(buf, &iter);
227 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, s, strlen(s),
228 tag, NULL);
231 void txtwin_tag(struct txtwin *tw, char *name, char *fg, char *bg, char *font)
233 GtkTextBuffer *buf = txtwin_buffer(tw);
234 gtk_text_buffer_create_tag(buf, name,
235 "foreground", fg,
236 "background", bg,
237 "font", font,
238 NULL);