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>
34 #include <xcb/xcb_atom.h>
36 /* Needed for xcb_set_wm_protocols() */
37 #include <xcb/xcb_icccm.h>
39 #define XCB_ALL_PLANES ~0
40 #include <xcb/xcb_icccm.h>
42 /* some defines for the flame */
49 /* default width and height of the window */
61 xcb_drawable_t pixmap;
68 unsigned int pal[IMAX];
72 /* the flame arrays */
79 static xcb_atom_t get_atom (xcb_connection_t *connection, const char *atomName);
80 static void title_set (flame *f, const char *title);
81 static int ilog2 (unsigned int n);
82 static void flame_set_palette (flame *f);
83 static void flame_set_flame_zero (flame *f);
84 static void flame_set_random_flame_base (flame *f);
85 static void flame_modify_flame_base (flame *f);
86 static void flame_process_flame (flame *f);
87 static void flame_draw_flame (flame *f);
94 xcb_gcontext_t gc = { 0 };
101 xcb_rectangle_t rect_coord = { 0, 0, BG_W, BG_H};
103 f = (flame *)malloc (sizeof (flame));
107 f->xcb.c = xcb_connect (NULL, &screen_nbr);
113 screen = xcb_aux_get_screen (f->xcb.c, screen_nbr);
115 f->xcb.draw = screen->root;
116 f->xcb.gc = xcb_generate_id (f->xcb.c);
117 mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
118 values[0] = screen->black_pixel;
119 values[1] = 0; /* no graphics exposures */
120 xcb_create_gc (f->xcb.c, f->xcb.gc, f->xcb.draw, mask, values);
122 gc = xcb_generate_id (f->xcb.c);
123 mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
124 values[0] = screen->white_pixel;
125 values[1] = 0; /* no graphics exposures */
126 xcb_create_gc (f->xcb.c, gc, f->xcb.draw, mask, values);
128 f->xcb.depth = xcb_aux_get_depth (f->xcb.c, screen);
129 mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
130 values[0] = screen->white_pixel;
131 values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;
132 f->xcb.draw = xcb_generate_id (f->xcb.c);
133 xcb_create_window (f->xcb.c, f->xcb.depth,
138 XCB_WINDOW_CLASS_INPUT_OUTPUT,
141 title_set (f, "XCB Flames");
143 f->xcb.pixmap = xcb_generate_id (f->xcb.c);
144 xcb_create_pixmap (f->xcb.c, f->xcb.depth,
145 f->xcb.pixmap, f->xcb.draw,
147 xcb_poly_fill_rectangle(f->xcb.c, f->xcb.pixmap, gc, 1, &rect_coord);
149 xcb_map_window (f->xcb.c, f->xcb.draw);
150 xcb_flush (f->xcb.c);
152 f->xcb.cmap = xcb_generate_id (f->xcb.c);
153 xcb_create_colormap (f->xcb.c,
154 XCB_COLORMAP_ALLOC_NONE,
157 screen->root_visual);
159 /* Allocation of the flame arrays */
160 flame_width = BG_W >> 1;
161 flame_height = BG_H >> 1;
162 f->ws = ilog2 (flame_width);
163 size = (1 << f->ws) * flame_height * sizeof (unsigned int);
164 f->flame = (unsigned int *)malloc (size);
167 xcb_disconnect (f->xcb.c);
171 f->flame2 = (unsigned int *)malloc (size);
175 xcb_disconnect (f->xcb.c);
180 /* allocation of the image */
181 f->ims = ilog2 (BG_W);
183 /* initialization of the palette */
184 flame_set_palette (f);
190 flame_shutdown (flame *f)
197 xcb_disconnect (f->xcb.c);
205 xcb_generic_event_t *e;
206 xcb_gcontext_t gc = { 0 };
211 printf ("Can't initialize global data\nExiting...\n");
215 flame_set_flame_zero (f);
216 flame_set_random_flame_base (f);
218 xcb_atom_t deleteWindowAtom = xcb_atom_get(f->xcb.c, "WM_DELETE_WINDOW");
219 xcb_atom_t wmprotocolsAtom = xcb_atom_get(f->xcb.c, "WM_PROTOCOLS");
220 /* Listen to X client messages in order to be able to pickup
221 the "delete window" message that is generated for example
222 when someone clicks the top-right X button within the window
223 manager decoration (or when user hits ALT-F4). */
224 xcb_set_wm_protocols (f->xcb.c, wmprotocolsAtom, f->xcb.draw, 1, &deleteWindowAtom);
226 bool finished = false;
229 if ((e = xcb_poll_for_event (f->xcb.c)))
231 switch (XCB_EVENT_RESPONSE_TYPE(e))
234 xcb_copy_area(f->xcb.c, f->xcb.pixmap, f->xcb.draw, gc,
235 0, 0, 0, 0, BG_W, BG_H);
236 xcb_flush (f->xcb.c);
238 case XCB_CLIENT_MESSAGE:
239 if (((xcb_client_message_event_t *)e)->data.data32[0] == deleteWindowAtom)
244 case XCB_BUTTON_PRESS:
250 flame_draw_flame (f);
251 xcb_flush (f->xcb.c);
259 static void title_set (flame *f, const char *title)
261 xcb_intern_atom_reply_t *rep;
266 atom_name = "UTF8_STRING";
267 rep = xcb_intern_atom_reply (f->xcb.c,
268 xcb_intern_atom (f->xcb.c,
273 encoding = rep->atom;
277 /* SetWMName (f->xcb.c, f->xcb.draw.window, encoding, strlen (title), title); */
280 atom_name = "_NET_WM_NAME";
281 rep = xcb_intern_atom_reply (f->xcb.c,
282 xcb_intern_atom (f->xcb.c,
287 xcb_change_property(f->xcb.c, XCB_PROP_MODE_REPLACE,
289 rep->atom, encoding, 8, strlen (title), title);
294 flame_draw_flame (flame *f)
308 image = xcb_image_get (f->xcb.c, f->xcb.draw,
310 XCB_ALL_PLANES, XCB_IMAGE_FORMAT_Z_PIXMAP);
311 /* If the top-level window is minimized (iconic) then the xcb_image_get()
312 will return NULL. In this case, we'll skip both updating and drawing
313 the flame, and we will also do a small sleep so that the program doesn't
314 hog as much CPU while minimized.
316 Another (non-polling == cleaner) way to not hog the CPU while minimized
317 would be to pass the XCB_EVENT_MASK_STRUCTURE_NOTIFY flag to
318 xcb_create_window(). This will give you XCB_UNMAP_NOTIFY and
319 XCB_MAP_NOTIFY events whenever the window is "minimized" (made iconic)
320 and "unminimized" (made normal again). This information would then be
321 used to make the main loop use the xcb_wait_for_event() instead of
322 xcb_poll_for_event() while the window is minimized (iconic). */
328 f->im = (unsigned int *)image->data;
330 /* modify the base of the flame */
331 flame_modify_flame_base (f);
332 /* process the flame array, propagating the flames up the array */
333 flame_process_flame (f);
335 for (y = 0 ; y < ((BG_H >> 1) - 1) ; y++)
337 for (x = 0 ; x < ((BG_W >> 1) - 1) ; x++)
342 ptr = f->flame2 + (y << f->ws) + x;
343 cl1 = cl = (int)*ptr;
344 ptr = f->flame2 + (y << f->ws) + x + 1;
346 ptr = f->flame2 + ((y + 1) << f->ws) + x + 1;
348 ptr = f->flame2 + ((y + 1) << f->ws) + x;
352 xcb_image_put_pixel (image,
355 xcb_image_put_pixel (image,
357 f->pal[((cl1+cl2) >> 1)]);
358 xcb_image_put_pixel (image,
360 f->pal[((cl1 + cl3) >> 1)]);
361 xcb_image_put_pixel (image,
363 f->pal[((cl1 + cl4) >> 1)]);
366 xcb_image_put (f->xcb.c, f->xcb.draw, f->xcb.gc, image,
368 xcb_image_destroy (image);
371 /* set the flame palette */
373 flame_set_palette (flame *f)
375 xcb_alloc_color_cookie_t cookies[IMAX];
376 xcb_alloc_color_reply_t *rep;
382 for (i = 0 ; i < IMAX ; i++)
389 if (r > 255) r = 255;
391 if (g > 255) g = 255;
393 if (b > 255) b = 255;
395 cookies[i] = xcb_alloc_color (f->xcb.c, f->xcb.cmap,
396 r << 8, g << 8, b << 8);
399 for (i = 0 ; i < IMAX ; i++)
401 rep = xcb_alloc_color_reply (f->xcb.c, cookies[i], NULL);
402 f->pal[i] = rep->pixel;
407 /* set the flame array to zero */
409 flame_set_flame_zero (flame *f)
415 for (y = 0 ; y < (BG_H >> 1) ; y++)
417 for (x = 0 ; x < (BG_W >> 1) ; x++)
419 ptr = f->flame + (y << f->ws) + x;
426 flame_set_random_flame_base (flame *f)
432 /* initialize a random number seed from the time, so we get random */
433 /* numbers each time */
436 for (x = 0 ; x < (BG_W >> 1) ; x++)
438 ptr = f->flame + (y << f->ws) + x;
443 /* modify the base of the flame with random values */
445 flame_modify_flame_base (flame *f)
453 for (x = 0 ; x < (BG_W >> 1) ; x++)
455 ptr = f->flame + (y << f->ws) + x;
456 *ptr += ((rand ()%VARIANCE) - VARTREND);
458 if (val > IMAX) *ptr = 0;
459 if (val < 0) *ptr = 0;
463 /* process entire flame array */
465 flame_process_flame (flame *f)
474 for (y = ((BG_H >> 1) - 1) ; y >= 2 ; y--)
476 for (x = 1 ; x < ((BG_W >> 1) - 1) ; x++)
478 ptr = f->flame + (y << f->ws) + x;
479 val = (unsigned int)*ptr;
481 *ptr = (unsigned int)IMAX;
482 val = (unsigned int)*ptr;
485 tmp = (val * VSPREAD) >> 8;
486 p = ptr - (2 << f->ws);
487 *p = *p + (tmp >> 1);
488 p = ptr - (1 << f->ws);
490 tmp = (val * HSPREAD) >> 8;
491 p = ptr - (1 << f->ws) - 1;
493 p = ptr - (1 << f->ws) + 1;
496 *p = *p + (tmp >>1 );
498 *p = *p + (tmp >> 1);
499 p = f->flame2 + (y << f->ws) + x;
501 if (y < ((BG_H >> 1) - 1))
502 *ptr = (val * RESIDUAL) >> 8;
509 ilog2 (unsigned int n)