]> mj.ucw.cz Git - osdd.git/blob - test.c
Experiments: Better outlining
[osdd.git] / test.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <poll.h>
6 #include <getopt.h>
7 #include <X11/Xlib.h>
8 #include <X11/Xatom.h>
9 #include <X11/extensions/shape.h>
10 #include <X11/extensions/render.h>
11 #include <X11/Xft/Xft.h>
12
13 #define DEBUG
14 #include "osd.h"
15
16 struct osd_state {
17   Display *dpy;
18   int screen;
19   Visual *visual;
20   Colormap cmap;
21   int depth;
22   int screen_width;
23   int screen_height;
24   Window win;
25   Pixmap mask_bitmap;
26   Pixmap image_pixmap;
27   GC gc;
28   GC mask_gc;
29
30   // Xft stuff
31   XftFont *font;
32   XftDraw *mask_draw;
33   XftDraw *image_draw;
34 };
35
36 int
37 main(int argc, char **argv)
38 {
39   XInitThreads();
40
41   struct osd_state osd_static;
42   bzero(&osd_static, sizeof(osd_static));
43   struct osd_state *osd = &osd_static;
44
45   osd->dpy = XOpenDisplay(NULL);
46   if (!osd->dpy)
47     die("Cannot open display");
48
49   int event_basep, error_basep;
50   if (!XShapeQueryExtension(osd->dpy, &event_basep, &error_basep))
51     die("XShape extension not supported by X server, giving up");
52
53   osd->screen = XDefaultScreen(osd->dpy);
54   osd->visual = XDefaultVisual(osd->dpy, osd->screen);
55   osd->depth = XDefaultDepth(osd->dpy, osd->screen);
56   osd->cmap = DefaultColormap(osd->dpy, osd->screen);
57
58   // These can change. And what about Xinerama?
59   osd->screen_width = XDisplayWidth(osd->dpy, osd->screen);
60   osd->screen_height = XDisplayHeight(osd->dpy, osd->screen);
61
62   XSetWindowAttributes win_attr = {
63     .override_redirect = 1,
64   };
65   osd->win = XCreateWindow(osd->dpy,
66         XRootWindow(osd->dpy, osd->screen),
67         0, 0,
68         osd->screen_width, osd->screen_height,
69         0,
70         osd->depth,
71         CopyFromParent,
72         osd->visual,
73         CWOverrideRedirect,
74         &win_attr);
75   XStoreName(osd->dpy, osd->win, "OSD");
76
77   // FIXME: Size
78   osd->mask_bitmap = XCreatePixmap(osd->dpy, osd->win, osd->screen_width, osd->screen_height, 1);
79   osd->image_pixmap = XCreatePixmap(osd->dpy, osd->win, osd->screen_width, osd->screen_height, osd->depth);
80   DBG("depth = %d\n", osd->depth);
81
82   XGCValues gcv = {
83     .graphics_exposures = 0,
84   };
85   osd->gc = XCreateGC(osd->dpy, osd->win, GCGraphicsExposures, &gcv);
86   osd->mask_gc = XCreateGC(osd->dpy, osd->mask_bitmap, GCGraphicsExposures, &gcv);
87
88   XSetBackground(osd->dpy, osd->gc, BlackPixel(osd->dpy, osd->screen));
89   XColor shadow_color = { .red = 0xffff, .green = 0xffff, .blue = 0 };
90   XAllocColor(osd->dpy, osd->cmap, &shadow_color);
91   XSetForeground(osd->dpy, osd->gc, shadow_color.pixel);
92
93   XSetBackground(osd->dpy, osd->mask_gc, WhitePixel(osd->dpy, osd->screen));
94   XSetForeground(osd->dpy, osd->mask_gc, BlackPixel(osd->dpy, osd->screen));
95
96   // FIXME: Stay on top
97
98   XFillRectangle(osd->dpy, osd->image_pixmap, osd->gc, 0, 0, osd->screen_width, osd->screen_height);
99
100   XFillRectangle(osd->dpy, osd->mask_bitmap, osd->mask_gc, 0, 0, osd->screen_width, osd->screen_height);
101
102   osd->font = XftFontOpenName(osd->dpy, osd->screen, "times-64");
103   if (!osd->font)
104     die("Cannot open font");
105   DBG("Font: asc=%d desc=%d ht=%d", osd->font->ascent, osd->font->descent, osd->font->height);
106
107   osd->mask_draw = XftDrawCreateBitmap(osd->dpy, osd->mask_bitmap);
108   if (!osd->mask_draw)
109     die("Cannot create XftDraw");
110
111   osd->image_draw = XftDrawCreate(osd->dpy, osd->image_pixmap, osd->visual, osd->cmap);
112   if (!osd->image_draw)
113     die("Cannot create XftDraw");
114
115   XRenderColor xrc = { .red = 0, .green = 0xffff, .blue = 0, .alpha = 0xffff };
116   XftColor xfc;
117   if (!XftColorAllocValue(osd->dpy, osd->visual, osd->cmap, &xrc, &xfc))
118     die("XftColorAllocValue failed");
119   const unsigned char str[] = "Žluťoučká vlkodlačice";
120   XftDrawStringUtf8(osd->image_draw, &xfc, osd->font, 100, 100, str, strlen((char *) str));
121
122   XRenderColor xrcm = { .red = 0xffff, .green = 0xffff, .blue = 0xffff, .alpha = 0xffff };
123   XftColor xfcm;
124   if (!XftColorAllocValue(osd->dpy, osd->visual, osd->cmap, &xrcm, &xfcm))
125     die("XftColorAllocValue failed");
126
127   // This is slow, but unlike the method used by libxosd, the result isn't ugly.
128   int outline = 3;
129   for (int dx = -outline; dx <= outline; dx++)
130     for (int dy = -outline; dy <= outline; dy++)
131       if (dx*dx + dy*dy <= outline*outline)
132         XftDrawStringUtf8(osd->mask_draw, &xfcm, osd->font, 100 + dx, 100 + dy, str, strlen((char *) str));
133
134 #if 0
135   XGlyphInfo gi;
136   XftTextExtentsUtf8(osd->dpy, osd->font, str, strlen((char *) str), &gi);
137   DBG("Glyph info: (%d,%d)+(%d,%d) off (%d,%d)\n", gi.x, gi.y, gi.width, gi.height, gi.xOff, gi.yOff);
138   XftDrawRect(osd->image_draw, &xfc, 100 + gi.x, 100 - gi.y, gi.width, gi.height);
139 #endif
140
141   XShapeCombineMask(osd->dpy, osd->win, ShapeBounding, 0, 0, osd->mask_bitmap, ShapeSet);
142
143   XSelectInput(osd->dpy, osd->win, ExposureMask);
144   XMapRaised(osd->dpy, osd->win);
145   XFlush(osd->dpy);
146
147   struct pollfd pfd = {
148     .fd = ConnectionNumber(osd->dpy),
149     .events = POLLIN,
150   };
151
152   for (;;)
153     {
154       timestamp_t now = get_current_time();
155       timestamp_t wait_until = now - 1;
156
157       DBG("... waiting for %d ms\n", (int)(wait_until - now));
158       poll(&pfd, 1, wait_until - now);
159       if (pfd.revents & POLLIN)
160         {
161           while (XPending(osd->dpy))
162             {
163               XEvent ev;
164               XNextEvent(osd->dpy, &ev);
165               switch (ev.type)
166                 {
167                 case Expose:
168                   {
169                     XExposeEvent *ex = &ev.xexpose;
170                     DBG("Expose cnt=%d (%d,%d)+(%d,%d)\n", ex->count, ex->x, ex->y, ex->width, ex->height);
171                     XCopyArea(osd->dpy, osd->image_pixmap, osd->win, osd->gc, ex->x, ex->y, ex->width, ex->height, ex->x, ex->y);
172                     break;
173                   }
174                 default:
175                   DBG("Event %d\n", ev.type);
176                 }
177             }
178         }
179     }
180
181   // FIXME: Cleanup
182 }