New resource and commandline option 'font' to specify an additional font.
[unicode-screensaver.git] / unicode.c
1 /* unicode (c) 2006,2009
2  * Joachim Breitner <mail@joachim-breitner.de>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  *
12  */
13
14 #include <X11/Xft/Xft.h>
15
16 #include "unicode-names.h"
17 #include "screenhack.h"
18
19 #define NUM_FONTS 3
20
21
22 struct unicode_state {
23         Bool blank;
24
25         XftFont*        fonts[NUM_FONTS];
26         XftFont*        tfont;
27         XftDraw*        draw;
28         XftColor        font_color;
29         XColor          bg_color;
30         unsigned        delay;
31 };
32
33 static void *
34 unicode_init (Display *dpy, Window window)
35 {
36         struct unicode_state *state = malloc(sizeof(struct unicode_state));
37         Colormap cmap;
38         XWindowAttributes xgwa;
39         XColor color;
40         XRenderColor font_color;
41         char *extra;
42
43         XGetWindowAttributes (dpy, window, &xgwa);
44         state->blank = True;
45
46         cmap = xgwa.colormap;
47
48         state->fonts[0] = XftFontOpen(dpy, 0,
49                 XFT_FAMILY,  XftTypeString, "Open Symbol",
50                 XFT_PIXEL_SIZE, XftTypeInteger, xgwa.height-100,
51                 NULL
52                 );
53         state->fonts[1] = XftFontOpen(dpy, 0,
54                 XFT_FAMILY,  XftTypeString, "FreeSans",
55                 XFT_PIXEL_SIZE, XftTypeInteger, xgwa.height-100,
56                 NULL
57                 );
58         extra = get_string_resource(dpy, "font", "Font");
59         state->fonts[2] = extra ?
60                 XftFontOpen(dpy, 0,
61                             XFT_FAMILY,  XftTypeString, extra,
62                             XFT_PIXEL_SIZE, XftTypeInteger, xgwa.height-100,
63                             NULL
64                 ) : NULL;
65
66         state->tfont = XftFontOpen(dpy, 0,
67                 XFT_FAMILY,  XftTypeString, "FreeSans",
68                 XFT_PIXEL_SIZE, XftTypeInteger, 40,
69                 NULL
70                 );
71
72         state->draw = XftDrawCreate(dpy, window, xgwa.visual, cmap); 
73         state->bg_color.pixel = get_pixel_resource(dpy, cmap, "background", "Background");
74         XQueryColor(dpy, cmap, &state->bg_color);
75
76         color.pixel = get_pixel_resource(dpy, cmap, "foreground", "Foreground");
77         XQueryColor(dpy, cmap, &color);
78
79         state->delay = get_seconds_resource(dpy, "delay", "Delay")*1000*1000;
80         font_color.red = color.red;
81         font_color.green = color.green;
82         font_color.blue = color.blue;
83         font_color.alpha = 0xFFFF;
84
85         XftColorAllocValue(dpy, xgwa.visual, cmap, &font_color, &state->font_color);
86         XSetWindowBackground(dpy, window, state->bg_color.pixel);
87         XClearWindow (dpy, window);
88
89         return state;
90 }
91
92 static unsigned long
93 unicode_draw (Display *dpy, Window win, void *void_state) {
94         XGlyphInfo      extents;
95         FcChar32        pick;
96         char            name[100];
97         int             font;
98         int             i;
99         struct unicode_state *state = (struct unicode_state *)void_state;
100         unsigned long unicode_names_length
101                 = (sizeof(unicode_names)/sizeof(unicode_names[0]));
102         const UnicodeName* nameEntry;
103
104         if (state->blank) {
105                 XWindowAttributes xgwa;
106                 XGetWindowAttributes (dpy, win, &xgwa);
107
108                 /* Find a unicode character that is contained in one of the fonts
109                    We try 100 random points before sleeping, to avoid an endless cycle */
110                 for (i = 0; i < 100; i++) {
111                         nameEntry = &unicode_names[random() % unicode_names_length];
112                         pick = nameEntry->index;
113                         /* printf("Trying U+%04X\n", pick); */
114
115                         for (font = 0; font < NUM_FONTS; font++) {
116                                 if (state->fonts[font] &&
117                                     XftCharExists (dpy, state->fonts[font], pick)) break;
118                         }
119                         if (font < NUM_FONTS) break;
120                 }
121                 if (i == 100) return (1000*1000);
122
123                 /* printf("Picked font %d, U+%04X\n", font, pick); */
124                 sprintf(name,"U+%04X: ", pick);
125                 strcat(name, unicode_name_get_name(nameEntry));
126
127                 XftTextExtents32(dpy,state->fonts[font],&pick,1,&extents); 
128                 XftDrawString32(state->draw,&state->font_color,state->fonts[font],
129                         xgwa.width/2  - extents.width/2  + extents.x,
130                         xgwa.height/2 - extents.height/2 + extents.y,
131                         &pick,1); 
132
133                 XftDrawStringUtf8(state->draw,&state->font_color,state->tfont,
134                         5,
135                         xgwa.height - 5,
136                         (unsigned char *)name,strlen(name)); 
137                 XSync (dpy, False);
138
139                 state->blank = False;
140                 return (state->delay);
141         } else {
142                 XClearWindow (dpy, win);
143                 XSync (dpy, False);
144                 state->blank = True;
145                 return (1000*1000);
146         }
147
148 }
149
150 static void
151 unicode_reshape (Display *dpy, Window window, void *state,
152                  unsigned int width, unsigned int height) {
153 }               
154
155 static Bool
156 unicode_event (Display *dpy, Window window, void *state,
157                  XEvent *event) {
158                  return False;
159 }               
160
161 static void
162 unicode_free (Display *dpy, Window window, void *state) {
163 }               
164
165
166 char *progclass = "Unicode";
167
168 static char const *unicode_defaults [] = {
169   ".background: white",
170   ".foreground: black",
171   "*delay:      7",
172   0
173 };
174
175 static XrmOptionDescRec unicode_options [] = {
176   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
177   { "-font",            ".font",                XrmoptionSepArg, 0 },
178   { "-foreground",      ".foreground",          XrmoptionSepArg, 0 },
179   { "-background",      ".background",          XrmoptionSepArg, 0 },
180   { 0, 0, 0, 0 }
181 };
182
183 XSCREENSAVER_MODULE("Unicode",unicode)