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 /* Listen to X client messages in order to be able to pickup
235 the "delete window" message that is generated for example
236 when someone clicks the top-right X button within the window
237 manager decoration (or when user hits ALT-F4). */
238 xcb_set_wm_protocols (f->xcb.c, f->xcb.draw, 1, &deleteWindowAtom);
240 bool finished = false;
243 if ((e = xcb_poll_for_event (f->xcb.c)))
245 switch (e->response_type & 0x7f)
248 xcb_copy_area(f->xcb.c, f->xcb.pixmap, f->xcb.draw, gc,
249 0, 0, 0, 0, BG_W, BG_H);
250 xcb_flush (f->xcb.c);
252 case XCB_CLIENT_MESSAGE:
253 if (((xcb_client_message_event_t *)e)->data.data32[0] == deleteWindowAtom)
258 case XCB_BUTTON_PRESS:
264 flame_draw_flame (f);
265 xcb_flush (f->xcb.c);
273 static void title_set (flame *f, const char *title)
275 xcb_intern_atom_reply_t *rep;
280 atom_name = "UTF8_STRING";
281 rep = xcb_intern_atom_reply (f->xcb.c,
282 xcb_intern_atom (f->xcb.c,
287 encoding = rep->atom;
291 /* SetWMName (f->xcb.c, f->xcb.draw.window, encoding, strlen (title), title); */
294 atom_name = "_NET_WM_NAME";
295 rep = xcb_intern_atom_reply (f->xcb.c,
296 xcb_intern_atom (f->xcb.c,
301 xcb_change_property(f->xcb.c, XCB_PROP_MODE_REPLACE,
303 rep->atom, encoding, 8, strlen (title), title);
308 flame_draw_flame (flame *f)
322 image = xcb_image_get (f->xcb.c, f->xcb.draw,
324 XCB_ALL_PLANES, XCB_IMAGE_FORMAT_Z_PIXMAP);
325 /* If the top-level window is minimized (iconic) then the xcb_image_get()
326 will return NULL. In this case, we'll skip both updating and drawing
327 the flame, and we will also do a small sleep so that the program doesn't
328 hog as much CPU while minimized.
330 Another (non-polling == cleaner) way to not hog the CPU while minimized
331 would be to pass the XCB_EVENT_MASK_STRUCTURE_NOTIFY flag to
332 xcb_create_window(). This will give you XCB_UNMAP_NOTIFY and
333 XCB_MAP_NOTIFY events whenever the window is "minimized" (made iconic)
334 and "unminimized" (made normal again). This information would then be
335 used to make the main loop use the xcb_wait_for_event() instead of
336 xcb_poll_for_event() while the window is minimized (iconic). */
342 f->im = (unsigned int *)image->data;
344 /* modify the base of the flame */
345 flame_modify_flame_base (f);
346 /* process the flame array, propagating the flames up the array */
347 flame_process_flame (f);
349 for (y = 0 ; y < ((BG_H >> 1) - 1) ; y++)
351 for (x = 0 ; x < ((BG_W >> 1) - 1) ; x++)
356 ptr = f->flame2 + (y << f->ws) + x;
357 cl1 = cl = (int)*ptr;
358 ptr = f->flame2 + (y << f->ws) + x + 1;
360 ptr = f->flame2 + ((y + 1) << f->ws) + x + 1;
362 ptr = f->flame2 + ((y + 1) << f->ws) + x;
366 xcb_image_put_pixel (image,
369 xcb_image_put_pixel (image,
371 f->pal[((cl1+cl2) >> 1)]);
372 xcb_image_put_pixel (image,
374 f->pal[((cl1 + cl3) >> 1)]);
375 xcb_image_put_pixel (image,
377 f->pal[((cl1 + cl4) >> 1)]);
380 xcb_image_put (f->xcb.c, f->xcb.draw, f->xcb.gc, image,
382 xcb_image_destroy (image);
385 /* set the flame palette */
387 flame_set_palette (flame *f)
389 xcb_alloc_color_cookie_t cookies[IMAX];
390 xcb_alloc_color_reply_t *rep;
396 for (i = 0 ; i < IMAX ; i++)
403 if (r > 255) r = 255;
405 if (g > 255) g = 255;
407 if (b > 255) b = 255;
409 cookies[i] = xcb_alloc_color (f->xcb.c, f->xcb.cmap,
410 r << 8, g << 8, b << 8);
413 for (i = 0 ; i < IMAX ; i++)
415 rep = xcb_alloc_color_reply (f->xcb.c, cookies[i], NULL);
416 f->pal[i] = rep->pixel;
421 /* set the flame array to zero */
423 flame_set_flame_zero (flame *f)
429 for (y = 0 ; y < (BG_H >> 1) ; y++)
431 for (x = 0 ; x < (BG_W >> 1) ; x++)
433 ptr = f->flame + (y << f->ws) + x;
440 flame_set_random_flame_base (flame *f)
446 /* initialize a random number seed from the time, so we get random */
447 /* numbers each time */
450 for (x = 0 ; x < (BG_W >> 1) ; x++)
452 ptr = f->flame + (y << f->ws) + x;
457 /* modify the base of the flame with random values */
459 flame_modify_flame_base (flame *f)
467 for (x = 0 ; x < (BG_W >> 1) ; x++)
469 ptr = f->flame + (y << f->ws) + x;
470 *ptr += ((rand ()%VARIANCE) - VARTREND);
472 if (val > IMAX) *ptr = 0;
473 if (val < 0) *ptr = 0;
477 /* process entire flame array */
479 flame_process_flame (flame *f)
488 for (y = ((BG_H >> 1) - 1) ; y >= 2 ; y--)
490 for (x = 1 ; x < ((BG_W >> 1) - 1) ; x++)
492 ptr = f->flame + (y << f->ws) + x;
493 val = (unsigned int)*ptr;
495 *ptr = (unsigned int)IMAX;
496 val = (unsigned int)*ptr;
499 tmp = (val * VSPREAD) >> 8;
500 p = ptr - (2 << f->ws);
501 *p = *p + (tmp >> 1);
502 p = ptr - (1 << f->ws);
504 tmp = (val * HSPREAD) >> 8;
505 p = ptr - (1 << f->ws) - 1;
507 p = ptr - (1 << f->ws) + 1;
510 *p = *p + (tmp >>1 );
512 *p = *p + (tmp >> 1);
513 p = f->flame2 + (y << f->ws) + x;
515 if (y < ((BG_H >> 1) - 1))
516 *ptr = (val * RESIDUAL) >> 8;
523 ilog2 (unsigned int n)