1 /*****************************************************************************/
3 /*****************************************************************************/
5 /* The Rasterman (Carsten Haitzler) */
6 /* Copyright (C) 1996 */
7 /*****************************************************************************/
9 /* d'Oursse (Vincent TORRI), 2006 */
10 /*****************************************************************************/
11 /* This code is Freeware. You may copy it, modify it or do with it as you */
12 /* please, but you may not claim copyright on any code wholly or partly */
13 /* based on this code. I accept no responisbility for any consequences of */
14 /* using this code, be they proper or otherwise. */
15 /*****************************************************************************/
16 /* Okay, now all the legal mumbo-jumbo is out of the way, I will just say */
17 /* this: enjoy this program, do with it as you please and watch out for more */
18 /* code releases from The Rasterman running under X... the only way to code. */
19 /*****************************************************************************/
21 /* standard library */
32 #include <xcb/xcb_aux.h>
33 #include <xcb/xcb_image.h>
35 /* Needed for xcb_set_wm_protocols() */
36 #include <xcb/xcb_icccm.h>
38 #define XCB_ALL_PLANES ~0
39 #include <xcb/xcb_icccm.h>
41 /* some defines for the flame */
48 /* default width and height of the window */
60 xcb_drawable_t pixmap;
67 unsigned int pal[IMAX];
71 /* the flame arrays */
78 static xcb_atom_t get_atom (xcb_connection_t *connection, const char *atomName);
79 static void title_set (flame *f, const char *title);
80 static int ilog2 (unsigned int n);
81 static void flame_set_palette (flame *f);
82 static void flame_set_flame_zero (flame *f);
83 static void flame_set_random_flame_base (flame *f);
84 static void flame_modify_flame_base (flame *f);
85 static void flame_process_flame (flame *f);
86 static void flame_draw_flame (flame *f);
89 get_atom (xcb_connection_t *connection, const char *atomName)
93 xcb_atom_t atom = XCB_NONE;
94 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection,
95 xcb_intern_atom(connection, 0, strlen(atomName), atomName), NULL);
108 xcb_screen_t *screen;
109 xcb_gcontext_t gc = { 0 };
116 xcb_rectangle_t rect_coord = { 0, 0, BG_W, BG_H};
118 f = (flame *)malloc (sizeof (flame));
122 f->xcb.c = xcb_connect (NULL, &screen_nbr);
128 screen = xcb_aux_get_screen (f->xcb.c, screen_nbr);
130 f->xcb.draw = screen->root;
131 f->xcb.gc = xcb_generate_id (f->xcb.c);
132 mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
133 values[0] = screen->black_pixel;
134 values[1] = 0; /* no graphics exposures */
135 xcb_create_gc (f->xcb.c, f->xcb.gc, f->xcb.draw, mask, values);
137 gc = xcb_generate_id (f->xcb.c);
138 mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
139 values[0] = screen->white_pixel;
140 values[1] = 0; /* no graphics exposures */
141 xcb_create_gc (f->xcb.c, gc, f->xcb.draw, mask, values);
143 f->xcb.depth = xcb_aux_get_depth (f->xcb.c, screen);
144 mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
145 values[0] = screen->white_pixel;
146 values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;
147 f->xcb.draw = xcb_generate_id (f->xcb.c);
148 xcb_create_window (f->xcb.c, f->xcb.depth,
153 XCB_WINDOW_CLASS_INPUT_OUTPUT,
156 title_set (f, "XCB Flames");
158 f->xcb.pixmap = xcb_generate_id (f->xcb.c);
159 xcb_create_pixmap (f->xcb.c, f->xcb.depth,
160 f->xcb.pixmap, f->xcb.draw,
162 xcb_poly_fill_rectangle(f->xcb.c, f->xcb.pixmap, gc, 1, &rect_coord);
164 xcb_map_window (f->xcb.c, f->xcb.draw);
165 xcb_flush (f->xcb.c);
167 f->xcb.cmap = xcb_generate_id (f->xcb.c);
168 xcb_create_colormap (f->xcb.c,
169 XCB_COLORMAP_ALLOC_NONE,
172 screen->root_visual);
174 /* Allocation of the flame arrays */
175 flame_width = BG_W >> 1;
176 flame_height = BG_H >> 1;
177 f->ws = ilog2 (flame_width);
178 size = (1 << f->ws) * flame_height * sizeof (unsigned int);
179 f->flame = (unsigned int *)malloc (size);
182 xcb_disconnect (f->xcb.c);
186 f->flame2 = (unsigned int *)malloc (size);
190 xcb_disconnect (f->xcb.c);
195 /* allocation of the image */
196 f->ims = ilog2 (BG_W);
198 /* initialization of the palette */
199 flame_set_palette (f);
205 flame_shutdown (flame *f)
212 xcb_disconnect (f->xcb.c);
220 xcb_generic_event_t *e;
221 xcb_gcontext_t gc = { 0 };
226 printf ("Can't initialize global data\nExiting...\n");
230 flame_set_flame_zero (f);
231 flame_set_random_flame_base (f);
233 xcb_atom_t deleteWindowAtom = get_atom(f->xcb.c, "WM_DELETE_WINDOW");
234 xcb_atom_t wmprotocolsAtom = get_atom(f->xcb.c, "WM_PROTOCOLS");
235 /* Listen to X client messages in order to be able to pickup
236 the "delete window" message that is generated for example
237 when someone clicks the top-right X button within the window
238 manager decoration (or when user hits ALT-F4). */
239 xcb_set_wm_protocols (f->xcb.c, wmprotocolsAtom, f->xcb.draw, 1, &deleteWindowAtom);
241 bool finished = false;
244 if ((e = xcb_poll_for_event (f->xcb.c)))
246 switch (e->response_type & 0x7f)
249 xcb_copy_area(f->xcb.c, f->xcb.pixmap, f->xcb.draw, gc,
250 0, 0, 0, 0, BG_W, BG_H);
251 xcb_flush (f->xcb.c);
253 case XCB_CLIENT_MESSAGE:
254 if (((xcb_client_message_event_t *)e)->data.data32[0] == deleteWindowAtom)
259 case XCB_BUTTON_PRESS:
265 flame_draw_flame (f);
266 xcb_flush (f->xcb.c);
274 static void title_set (flame *f, const char *title)
276 xcb_intern_atom_reply_t *rep;
281 atom_name = "UTF8_STRING";
282 rep = xcb_intern_atom_reply (f->xcb.c,
283 xcb_intern_atom (f->xcb.c,
288 encoding = rep->atom;
292 /* SetWMName (f->xcb.c, f->xcb.draw.window, encoding, strlen (title), title); */
295 atom_name = "_NET_WM_NAME";
296 rep = xcb_intern_atom_reply (f->xcb.c,
297 xcb_intern_atom (f->xcb.c,
302 xcb_change_property(f->xcb.c, XCB_PROP_MODE_REPLACE,
304 rep->atom, encoding, 8, strlen (title), title);
309 flame_draw_flame (flame *f)
323 image = xcb_image_get (f->xcb.c, f->xcb.draw,
325 XCB_ALL_PLANES, XCB_IMAGE_FORMAT_Z_PIXMAP);
326 /* If the top-level window is minimized (iconic) then the xcb_image_get()
327 will return NULL. In this case, we'll skip both updating and drawing
328 the flame, and we will also do a small sleep so that the program doesn't
329 hog as much CPU while minimized.
331 Another (non-polling == cleaner) way to not hog the CPU while minimized
332 would be to pass the XCB_EVENT_MASK_STRUCTURE_NOTIFY flag to
333 xcb_create_window(). This will give you XCB_UNMAP_NOTIFY and
334 XCB_MAP_NOTIFY events whenever the window is "minimized" (made iconic)
335 and "unminimized" (made normal again). This information would then be
336 used to make the main loop use the xcb_wait_for_event() instead of
337 xcb_poll_for_event() while the window is minimized (iconic). */
343 f->im = (unsigned int *)image->data;
345 /* modify the base of the flame */
346 flame_modify_flame_base (f);
347 /* process the flame array, propagating the flames up the array */
348 flame_process_flame (f);
350 for (y = 0 ; y < ((BG_H >> 1) - 1) ; y++)
352 for (x = 0 ; x < ((BG_W >> 1) - 1) ; x++)
357 ptr = f->flame2 + (y << f->ws) + x;
358 cl1 = cl = (int)*ptr;
359 ptr = f->flame2 + (y << f->ws) + x + 1;
361 ptr = f->flame2 + ((y + 1) << f->ws) + x + 1;
363 ptr = f->flame2 + ((y + 1) << f->ws) + x;
367 xcb_image_put_pixel (image,
370 xcb_image_put_pixel (image,
372 f->pal[((cl1+cl2) >> 1)]);
373 xcb_image_put_pixel (image,
375 f->pal[((cl1 + cl3) >> 1)]);
376 xcb_image_put_pixel (image,
378 f->pal[((cl1 + cl4) >> 1)]);
381 xcb_image_put (f->xcb.c, f->xcb.draw, f->xcb.gc, image,
383 xcb_image_destroy (image);
386 /* set the flame palette */
388 flame_set_palette (flame *f)
390 xcb_alloc_color_cookie_t cookies[IMAX];
391 xcb_alloc_color_reply_t *rep;
397 for (i = 0 ; i < IMAX ; i++)
404 if (r > 255) r = 255;
406 if (g > 255) g = 255;
408 if (b > 255) b = 255;
410 cookies[i] = xcb_alloc_color (f->xcb.c, f->xcb.cmap,
411 r << 8, g << 8, b << 8);
414 for (i = 0 ; i < IMAX ; i++)
416 rep = xcb_alloc_color_reply (f->xcb.c, cookies[i], NULL);
417 f->pal[i] = rep->pixel;
422 /* set the flame array to zero */
424 flame_set_flame_zero (flame *f)
430 for (y = 0 ; y < (BG_H >> 1) ; y++)
432 for (x = 0 ; x < (BG_W >> 1) ; x++)
434 ptr = f->flame + (y << f->ws) + x;
441 flame_set_random_flame_base (flame *f)
447 /* initialize a random number seed from the time, so we get random */
448 /* numbers each time */
451 for (x = 0 ; x < (BG_W >> 1) ; x++)
453 ptr = f->flame + (y << f->ws) + x;
458 /* modify the base of the flame with random values */
460 flame_modify_flame_base (flame *f)
468 for (x = 0 ; x < (BG_W >> 1) ; x++)
470 ptr = f->flame + (y << f->ws) + x;
471 *ptr += ((rand ()%VARIANCE) - VARTREND);
473 if (val > IMAX) *ptr = 0;
474 if (val < 0) *ptr = 0;
478 /* process entire flame array */
480 flame_process_flame (flame *f)
489 for (y = ((BG_H >> 1) - 1) ; y >= 2 ; y--)
491 for (x = 1 ; x < ((BG_W >> 1) - 1) ; x++)
493 ptr = f->flame + (y << f->ws) + x;
494 val = (unsigned int)*ptr;
496 *ptr = (unsigned int)IMAX;
497 val = (unsigned int)*ptr;
500 tmp = (val * VSPREAD) >> 8;
501 p = ptr - (2 << f->ws);
502 *p = *p + (tmp >> 1);
503 p = ptr - (1 << f->ws);
505 tmp = (val * HSPREAD) >> 8;
506 p = ptr - (1 << f->ws) - 1;
508 p = ptr - (1 << f->ws) + 1;
511 *p = *p + (tmp >>1 );
513 *p = *p + (tmp >> 1);
514 p = f->flame2 + (y << f->ws) + x;
516 if (y < ((BG_H >> 1) - 1))
517 *ptr = (val * RESIDUAL) >> 8;
524 ilog2 (unsigned int n)