Changelog for Rhondas changes
[darcs-mirror-screen-message.debian.git] / sm.c
1 /*
2 #     vlshow.c
3 #     Copyright (C) 2006 Joachim Breitner
4 #
5 #     This program is free software; you can redistribute it and/or modify
6 #     it under the terms of the GNU General Public License as published by
7 #     the Free Software Foundation; either version 2 of the License, or
8 #     (at your option) any later version.
9 #
10 #     This program is distributed in the hope that it will be useful,
11 #     but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #     GNU General Public License for more details.
14 #
15 #     You should have received a copy of the GNU General Public License
16 #     along with this program; if not, write to the Free Software
17 #     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18 */
19
20 #include <gtk/gtk.h>
21 #include <gdk/gdk.h>
22 #include <pango/pango.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include "config.h"
26
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE                             /* for getopt_long */
29 #endif
30 #include <getopt.h>
31
32 static int min(int x, int y) {
33         return x < y ? x : y;
34 }
35
36
37 static gboolean quality = TRUE;
38 static gboolean need_resize = TRUE;
39
40 static GtkWidget* window;
41 static GtkWidget* draw;
42 static GdkCursor *cursor;
43 static GtkWidget* quit;
44 static GtkWidget* tv;
45 static GtkSettings* settings;
46 static GtkTextBuffer* tb;
47 static PangoFontDescription *font;
48 static PangoLayout* layout;
49 static char *foreground = NULL;
50 static char *background = NULL;
51 static char *fontdesc = NULL;
52
53 static void realize(GtkWindow *window, GdkScreen *screen, gpointer data) {
54         gdk_window_set_cursor(draw->window, cursor);
55 }
56
57 static void clear_text(GtkAccelGroup *accel, GObject *window, guint keyval,  GdkModifierType modifier) {
58         if( gtk_text_buffer_get_char_count(tb) )
59                 gtk_text_buffer_set_text(tb,"",-1);
60         else
61                 gtk_main_quit();
62 }
63
64 static char *get_text() {
65         GtkTextIter start, end;
66         gtk_text_buffer_get_start_iter(tb,&start);
67         gtk_text_buffer_get_end_iter(tb,&end);
68         return gtk_text_buffer_get_text(tb, &start, &end, FALSE);
69 }
70
71
72 static void hq(gboolean q, gboolean force){
73         if (q != quality) 
74                 if (q)
75                         gtk_settings_set_long_property(settings,"gtk-xft-antialias",1,"Hier halt");
76                 else
77                         gtk_settings_set_long_property(settings,"gtk-xft-antialias",0,"Hier halt");
78         else
79                 if (force)
80                         gtk_widget_queue_draw(draw);
81
82         quality = q;
83 }
84
85 static void redraw() {
86         const char *text = pango_layout_get_text(layout);
87         if (strlen(text) > 0) {
88                 GdkGC *gc = gtk_widget_get_style(draw)->fg_gc[GTK_STATE_NORMAL];
89                 int w1, h1;
90                 pango_layout_get_pixel_size(layout, &w1, &h1);
91                 if (w1>0 && h1>0) {
92                         int w2 = draw->allocation.width;
93                         int h2 = draw->allocation.height;
94                         gdk_draw_layout(draw->window, gc, (w2-w1)/2,(h2-h1)/2,layout);
95                         hq(TRUE, FALSE);
96                 }
97         }
98 }
99
100 static gboolean text_clicked(GtkWidget *widget, GdkEventButton *event, gpointer *user_data) {
101         if (event->type == GDK_BUTTON_PRESS && event->button == 2) {
102                 GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
103
104                 gchar *txt = gtk_clipboard_wait_for_text(cb);
105                 if (txt != NULL) {
106                         gtk_text_buffer_set_text(tb,txt,-1);
107                         g_free(txt);
108                 }
109
110         }
111         return FALSE;
112 }
113
114 static void resize() {
115         int w1, h1, w2, h2;
116         pango_layout_get_pixel_size(layout, &w1, &h1);
117         if (w1>0 && h1>0) {
118                 w2 = draw->allocation.width;
119                 h2 = draw->allocation.height;
120                 int s = pango_font_description_get_size(font);
121                 s = min ((s*w2/w1), (s*h2/h1));
122                 pango_font_description_set_size(font,s);
123                 pango_layout_set_font_description(layout, font);
124                 need_resize = FALSE;
125         }
126         else
127                 need_resize = TRUE;
128 }
129
130
131 static void newtext(char *text) {
132         pango_layout_set_text(layout, get_text(), -1);
133         resize();
134         hq(FALSE, TRUE);
135 }
136
137 static struct option const long_options[] =
138 {
139         {"help",       no_argument,       NULL, 'h'},
140         {"version",    no_argument,       NULL, 'V'},
141         {"foreground", required_argument, NULL, 'f'},
142         {"background", required_argument, NULL, 'b'},
143         {"font",       required_argument, NULL, 'n'},
144         {0,0,0,0}
145 };
146
147 static void usage(char *cmd) {
148         printf("Usage: %s [-h|--help] [-V|--version] [-f|--foreground=colordesc] [-b|--background=colordesc] [-n|--font=fontdesc]\n", cmd);
149 }
150
151 static void version() {
152         printf("%s\n", PACKAGE_STRING);
153 }
154
155 int main(int argc, char **argv) {
156         GString *input;
157         int c;
158
159         while ((c = getopt_long (argc, argv, "hVf:b:n:", long_options, (int *) 0)) != EOF) {
160                 switch (c) {
161                         case 'h':
162                                 usage(argv[0]);
163                                 return 0;
164                                 break;
165
166                         case 'V':
167                                 version();
168                                 return 0;
169                                 break;
170
171                         case 'f':
172                                 foreground = optarg;
173                                 break;
174
175                         case 'b':
176                                 background = optarg;
177                                 break;
178
179                         case 'n':
180                                 fontdesc = optarg;
181                                 break;
182
183                         default:
184                                 /* unknown switch received - at least
185                                  * give usage but continue and use the
186                                  * data */
187                                 usage(argv[0]);
188                                 break;
189                 }
190         }
191
192         gtk_init(&argc, &argv);
193
194         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
195         gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
196         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
197         gtk_window_set_icon_name (GTK_WINDOW (window), "sm");
198
199         GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(window));
200         gtk_widget_set_size_request(window, gdk_screen_get_width(screen),
201                                             gdk_screen_get_height(screen));
202         gtk_window_fullscreen(GTK_WINDOW(window));
203         g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
204
205         settings = gtk_settings_get_default();
206         GdkColormap *colormap = gtk_widget_get_colormap(GTK_WIDGET(window));
207         GdkColor white, black;
208         gdk_colormap_alloc_color(colormap, &white, TRUE, TRUE);
209         gdk_colormap_alloc_color(colormap, &black, TRUE, TRUE);
210         if (foreground != NULL) {
211                 gdk_color_parse(foreground, &black);
212         } else {
213                 gdk_color_parse("black", &black);
214         }
215         if (background != NULL) {
216                 gdk_color_parse(background, &white);
217         } else {
218                 gdk_color_parse("white", &white);
219         }
220         gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &white);
221         gtk_widget_modify_fg(window, GTK_STATE_NORMAL, &black);
222
223         draw = gtk_drawing_area_new();
224         gtk_widget_set_events(draw, GDK_BUTTON_PRESS_MASK);
225         gtk_widget_set_size_request(draw,400,400);
226         gtk_widget_modify_bg(draw, GTK_STATE_NORMAL, &white);
227         gtk_widget_modify_fg(draw, GTK_STATE_NORMAL, &black);
228         g_signal_connect(G_OBJECT(draw), "realize", G_CALLBACK(realize), NULL);
229         g_signal_connect(G_OBJECT(draw), "button-press-event", G_CALLBACK(text_clicked), NULL);
230
231         GdkPixmap *pixmap = gdk_pixmap_new(NULL, 1, 1, 1);
232         GdkColor color;
233         cursor = gdk_cursor_new_from_pixmap(pixmap, pixmap, &color, &color, 0, 0);
234
235         tv = gtk_text_view_new();
236         gtk_widget_modify_bg(tv, GTK_STATE_NORMAL, &white);
237         gtk_widget_modify_fg(tv, GTK_STATE_NORMAL, &black);
238         tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv));
239
240         if (argc > optind)
241                 if (!strcmp(argv[optind], "-") ) {
242                         // read from stdin
243                         gchar buf[1024];
244                         int num;
245
246                         input = g_string_new("");
247
248                         while ((num = fread (buf, 1, sizeof(buf), stdin)) > 0) {
249                                 g_string_append_len(input, buf, num);
250                         }
251                 } else {
252                         int i;
253
254                         input = g_string_new("");
255
256                         for (i = optind; i < argc; i++) {
257                                 g_string_append(input, argv[i]);
258
259                                 if (i < argc - 1) {
260                                         g_string_append(input, " ");
261                                 }
262                         }
263                 }
264         else
265                 input = g_string_new(":-)");
266
267         gtk_text_buffer_set_text(tb, input->str, input->len);
268         GtkTextIter start, end;
269         gtk_text_buffer_get_bounds(tb, &start, &end);
270         gtk_text_buffer_select_range(tb, &start, &end);
271
272         quit = gtk_button_new_from_stock(GTK_STOCK_QUIT);
273         g_signal_connect(G_OBJECT(quit), "clicked", G_CALLBACK(gtk_main_quit), NULL);
274         gtk_widget_modify_bg(quit, GTK_STATE_NORMAL, &white);
275         gtk_widget_modify_fg(quit, GTK_STATE_NORMAL, &black);
276
277         GtkWidget *hbox = gtk_hbox_new(FALSE,0);
278         gtk_box_pack_start(GTK_BOX(hbox), tv,   TRUE,  TRUE,  0);
279         gtk_box_pack_start(GTK_BOX(hbox), quit, FALSE, FALSE, 0);
280
281         GtkWidget *vbox = gtk_vbox_new(FALSE,0);
282         gtk_box_pack_start(GTK_BOX(vbox), draw, TRUE,  TRUE,  0);
283         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
284
285         gtk_container_add(GTK_CONTAINER(window), vbox);
286
287         font = pango_font_description_new();
288         if (fontdesc != NULL) {
289                 pango_font_description_set_family(font, fontdesc);
290         } else {
291                 pango_font_description_set_family(font, "sans-serif");
292         }
293         pango_font_description_set_size(font, 20*PANGO_SCALE);
294
295         layout=  gtk_widget_create_pango_layout(draw,get_text());
296         pango_layout_set_font_description(layout, font);
297         pango_layout_set_alignment(layout,PANGO_ALIGN_CENTER);
298
299         GtkAccelGroup *accel = gtk_accel_group_new();
300         guint key;
301         GdkModifierType mod;
302         gtk_accelerator_parse("<Ctrl>Q", &key, &mod);
303         gtk_accel_group_connect(accel, key, mod, 0, g_cclosure_new(G_CALLBACK(gtk_main_quit), NULL, NULL));
304         gtk_accelerator_parse("Escape", &key, &mod);
305         gtk_accel_group_connect(accel, key, mod, 0, g_cclosure_new(G_CALLBACK(clear_text), NULL, NULL));
306         gtk_window_add_accel_group(GTK_WINDOW(window), accel);
307         gtk_widget_show_all(window);
308
309         g_signal_connect(G_OBJECT(draw), "configure-event", G_CALLBACK(resize), NULL);
310         g_signal_connect(G_OBJECT(draw), "expose-event", G_CALLBACK(redraw), NULL);
311         g_signal_connect(G_OBJECT(tb), "changed", G_CALLBACK(newtext), NULL);
312
313         resize();
314
315         gtk_main();
316
317         return 0;
318 }