wmshutdown: Destroy dialog window before shutting down. This is especially useful...
[dockapps.git] / wmwebcam / wmwebcam.c
blobce9718663a5b3037d91c698c673f065e6fa3f6e0
1 /* wmwebcam - modified vidcat - read the README file for more info */
3 /*
4 * vidcat.c
6 * Copyright (C) 1998 - 2000 Rasca, Berlin
7 * EMail: thron@gmx.de
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <getopt.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <linux/types.h>
35 #include <linux/videodev.h>
37 #include <jpeglib.h>
39 #include <X11/Xlib.h>
40 #include <X11/xpm.h>
41 #include <X11/extensions/shape.h>
43 #include "wmwebcam-mask.xbm"
44 #include "minirgb.h"
47 //////////////////////// CHANGE THESE IF NECESSARY ///////////////////////////
49 #define DEF_WIDTH 352 // changing these requires adjustements
50 #define DEF_HEIGHT 288 // to the source, use default if possible
52 #define SENDINGDELAY 60 // default delay between saving jpeg
53 // images and scriptrunning (in seconds)
55 #define OUTPUTFILE "/tmp/wmwebcam.jpg" // default output file
56 #define CUSTOMSCRIPT "wmwebcam.pl" // default custom script
57 #define QUAL_DEFAULT 100 // default jpeg outputquality
59 //////////////////////////////////////////////////////////////////////////////
61 char *basename (const char *s);
63 Display *display;
64 Window win;
65 Window iconwin;
66 GC gc;
67 MiniRGB ui; /* 64x64 main window buffer */
68 MiniRGB draw; /* buffer with images etc */
70 void new_window(char *name, char *mask_data)
72 Pixel fg, bg;
73 XGCValues gcval;
74 XSizeHints sizehints;
75 XClassHint classhint;
76 XWMHints wmhints;
77 int screen;
78 Window root;
79 Pixmap mask;
80 screen = DefaultScreen(display);
81 root = DefaultRootWindow(display);
83 sizehints.flags = USSize;
84 sizehints.width = 64;
85 sizehints.height = 64;
87 fg = BlackPixel(display, screen);
88 bg = WhitePixel(display, screen);
90 win = XCreateSimpleWindow(display, root,
91 0, 0, sizehints.width,
92 sizehints.height, 1, fg, bg);
93 iconwin =
94 XCreateSimpleWindow(display, win, 0, 0,
95 sizehints.width, sizehints.height, 1, fg, bg);
97 XSetWMNormalHints(display, win, &sizehints);
98 classhint.res_name = name;
99 classhint.res_class = name;
100 XSetClassHint(display, win, &classhint);
102 XSelectInput(display, win,
103 ExposureMask | ButtonPressMask | ButtonReleaseMask |
104 StructureNotifyMask);
105 XSelectInput(display, iconwin,
106 ExposureMask | ButtonPressMask | ButtonReleaseMask |
107 StructureNotifyMask);
109 XStoreName(display, win, name);
110 XSetIconName(display, win, name);
112 gcval.foreground = fg;
113 gcval.background = bg;
114 gcval.graphics_exposures = False;
115 gc =
116 XCreateGC(display, win,
117 GCForeground | GCBackground | GCGraphicsExposures,
118 &gcval);
120 mask = XCreateBitmapFromData(display, win, mask_data, 128, 64);
122 XShapeCombineMask(display, win, ShapeBounding, 0, 0,
123 mask, ShapeSet);
124 XShapeCombineMask(display, iconwin, ShapeBounding, 0,
125 0, mask, ShapeSet);
127 wmhints.initial_state = WithdrawnState;
128 wmhints.flags = StateHint;
129 wmhints.icon_window = iconwin;
130 wmhints.icon_x = sizehints.x;
131 wmhints.icon_y = sizehints.y;
132 wmhints.window_group = win;
133 wmhints.flags =
134 StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
135 XSetWMHints(display, win, &wmhints);
137 XMapWindow(display, win);
140 void redraw_window(void)
142 minirgb_draw(win, gc, 0, 0, 64, 64, &ui);
143 minirgb_draw(iconwin, gc, 0, 0, 64, 64, &ui);
146 #define copyXPMArea(x, y, w, h, dx, dy) minirgb_copy(&draw, &ui, x, y, w, h, dx, dy)
149 char *
150 get_image (int dev, int width, int height,int *size)
152 struct video_capability vid_caps;
153 struct video_mbuf vid_buf;
154 struct video_mmap vid_mmap;
155 char *map;
156 int len;
158 if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) {
159 perror ("ioctl (VIDIOCGCAP)");
160 return (NULL);
163 if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) {
164 struct video_window vid_win;
166 if (ioctl (dev, VIDIOCGWIN, &vid_win) != -1) {
167 vid_win.width = width;
168 vid_win.height = height;
169 if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1)
170 return (NULL);
173 map = malloc (width * height * 3);
174 len = read (dev, map, width * height * 3);
175 if (len <= 0) { free (map); return (NULL); }
176 *size = 0;
177 return (map);
180 map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED,dev,0);
181 if ((unsigned char *)-1 == (unsigned char *)map) {
182 perror ("mmap()");
183 return (NULL);
186 vid_mmap.format = VIDEO_PALETTE_RGB24;
187 vid_mmap.frame = 0;
188 vid_mmap.width = width;
189 vid_mmap.height = height;
190 if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) {
191 perror ("VIDIOCMCAPTURE");
192 munmap (map, vid_buf.size);
193 return (NULL);
195 if (ioctl (dev, VIDIOCSYNC, &vid_mmap) == -1) {
196 perror ("VIDIOCSYNC");
197 munmap (map, vid_buf.size);
198 return (NULL);
200 *size = vid_buf.size;
201 return (map);
204 void
205 put_image_jpeg (char *image, int width, int height, int quality)
208 FILE *output;
209 int y, x, line_width;
210 JSAMPROW row_ptr[1];
211 struct jpeg_compress_struct cjpeg;
212 struct jpeg_error_mgr jerr;
213 char *line;
215 output = fopen("/tmp/wmwebcam.jpg","w");
217 if(!output) return;
219 line = malloc (width * 3);
220 if (!line)
221 return;
222 cjpeg.err = jpeg_std_error(&jerr);
223 jpeg_create_compress (&cjpeg);
224 cjpeg.image_width = width;
225 cjpeg.image_height= height;
226 cjpeg.input_components = 3;
227 cjpeg.in_color_space = JCS_RGB;
228 jpeg_set_defaults (&cjpeg);
230 jpeg_set_quality (&cjpeg, quality, TRUE);
231 cjpeg.dct_method = JDCT_FASTEST;
232 jpeg_stdio_dest (&cjpeg, output);
234 jpeg_start_compress (&cjpeg, TRUE);
236 row_ptr[0] = line;
237 line_width = width * 3;
238 for ( y = 0; y < height; y++) {
239 for (x = 0; x < line_width; x+=3) {
240 line[x] = image[x+2];
241 line[x+1] = image[x+1];
242 line[x+2] = image[x];
244 jpeg_write_scanlines (&cjpeg, row_ptr, 1);
245 image += line_width;
247 jpeg_finish_compress (&cjpeg);
248 jpeg_destroy_compress (&cjpeg);
249 free (line);
250 fclose (output);
253 void
254 put_image (char *image, int width, int height)
257 int x, y, r,g,b, c;
258 unsigned char *p = (unsigned char *)image;
259 unsigned char *buf = (unsigned char *)image;
261 for (y = 0; y < 288; y++ ) {
262 c=0;
263 for (x = 0; x < 348; x++ ) {
264 r = buf[0]; g = buf[1]; b = buf[2]; buf += 3;
265 c++;
266 if (c == 6) {
267 c = 0;
268 *p++ = b; *p++ = g; *p++ = r;
273 memcpy(draw.mem, image, 352*288*3);
277 main (int argc, char *argv[])
279 XEvent Event;
280 char *image, *device = VIDEO_DEV;
282 int delay = SENDINGDELAY;
283 int width = DEF_WIDTH, height = DEF_HEIGHT, size, dev = -1;
284 int max_try = 5;
285 int quality = QUAL_DEFAULT;
287 display = XOpenDisplay(NULL);
288 if (!display) {
289 fprintf(stderr, "Unable to open default display\n");
290 exit(1);
293 if (minirgb_init(display)) {
294 fprintf(stderr, "minirgb init failed!\n");
295 exit(1);
298 new_window("wmwebcam", wmwebcam_mask_bits);
299 minirgb_new(&ui, 64, 64);
300 minirgb_new(&draw, 352, 288);
301 copyXPMArea(0, 0, 64, 64, 0, 0);
303 while (1) {
304 while (max_try) {
305 dev = open (device, O_RDWR);
306 if (dev == -1) {
307 if (!--max_try) {
308 fprintf (stderr, "Can't open device %s\n", VIDEO_DEV);
309 exit (0);
311 sleep (1);
312 } else {
313 break;
316 image = get_image (dev, width, height, &size);
317 if (!size) close (dev);
319 if (image) {
321 if (delay == SENDINGDELAY) { put_image_jpeg(image, width, height, quality); }
323 put_image(image, width, height);
325 copyXPMArea(1, 1, 54, 47, 5, 5);
327 while (XPending(display)) {
328 XNextEvent(display, &Event);
329 switch (Event.type) {
330 case Expose:
331 redraw_window();
332 break;
333 case DestroyNotify:
334 XCloseDisplay(display);
335 exit(0);
336 break;
339 redraw_window();
341 if (size) {
342 munmap (image, size);
343 close (dev);
344 } else if (image) {
345 free (image);
348 // close device first before starting to send the image
350 if (delay == SENDINGDELAY) { system (CUSTOMSCRIPT); delay = 0; }
352 delay++;
353 sleep (1);
355 } else {
356 fprintf (stderr, "Error: Can't get image\n"); exit(0);
359 return (0);