1 /* -copyright-
2 #-#
3 #-# xsnow: let it snow on your desktop
4 #-# Copyright (C) 1984,1988,1990,1993-1995,2000-2001 Rick Jansen
5 #-# 2019,2020,2021 Willem Vermin
6 #-#
7 #-# This program is free software: you can redistribute it and/or modify
8 #-# it under the terms of the GNU General Public License as published by
9 #-# the Free Software Foundation, either version 3 of the License, or
10 #-# (at your option) any later version.
11 #-#
12 #-# This program is distributed in the hope that it will be useful,
13 #-# but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 #-# GNU General Public License for more details.
16 #-#
17 #-# You should have received a copy of the GNU General Public License
18 #-# along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #-#
20 *
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <stdio.h>
26 #include <gtk/gtk.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <X11/Xlib.h>
30 #include <X11/Intrinsic.h>
31 #include "fallensnow.h"
32 #include "utils.h"
33 #include "windows.h"
34 #include "flags.h"
35 #include "snow.h"
36 #include "Santa.h"
37 #include "blowoff.h"
38 #include "wind.h"
39 #include "debug.h"
40
41 #define NOTACTIVE \
42 (Flags.BirdsOnly || !WorkspaceActive() || Flags.NoSnowFlakes)
43
44
45 static void drawquartcircle(int n, short int *y); // nb: dimension of y > n+1
46 static void CreateSurfaceFromFallen(FallenSnow *f);
47 static void EraseFallenPixel(FallenSnow *fsnow,int x);
48 static void CreateDeshBottom(short int *desh, int w, int h);
49 static int do_change_bottom(void *dummy);
50 static int do_adjust_bottom(void *dummy);
51 static float gaussf(float x, float mu, float sigma);
52
fallensnow_init()53 void fallensnow_init()
54 {
55 InitFallenSnow();
56 add_to_mainloop(PRIORITY_DEFAULT, time_change_bottom, do_change_bottom);
57 add_to_mainloop(PRIORITY_DEFAULT, time_adjust_bottom, do_adjust_bottom);
58 P(" \n");
59 }
60
UpdateFallenSnowAtBottom()61 void UpdateFallenSnowAtBottom()
62 {
63 FallenSnow *fsnow = FindFallen(global.FsnowFirst, 0);
64 if (fsnow)
65 fsnow->y = global.SnowWinHeight;
66 }
67
fallensnow_draw(cairo_t * cr)68 void fallensnow_draw(cairo_t *cr)
69 {
70 if (NOTACTIVE)
71 return;
72 FallenSnow *fsnow = global.FsnowFirst;
73 while(fsnow)
74 {
75 if (HandleFallenSnow(fsnow))
76 {
77 P("fallensnow_draw %d %d\n",counter++,
78 cairo_image_surface_get_width(fsnow->surface));
79 P("fallensnow_draw: x:%d y:%d\n",fsnow->x,fsnow->y);
80 cairo_set_source_surface (cr, fsnow->surface, fsnow->x, fsnow->y-fsnow->h+1);
81 my_cairo_paint_with_alpha(cr,ALPHA);
82 fsnow->prevx = fsnow->x;
83 fsnow->prevy = fsnow->y-fsnow->h+1;
84 fsnow->prevw = cairo_image_surface_get_width(fsnow->surface);
85 fsnow->prevh = fsnow->h;
86 }
87 fsnow = fsnow->next;
88 }
89 }
90
fallensnow_erase()91 void fallensnow_erase()
92 {
93 if (NOTACTIVE)
94 return;
95 FallenSnow *fsnow = global.FsnowFirst;
96 while(fsnow)
97 {
98 if (HandleFallenSnow(fsnow))
99 {
100 P("fallensnow_erase %d %d %d %d %d\n",counter++,
101 fsnow->prevx, fsnow->prevy, fsnow->prevw, fsnow->prevh);
102
103 myXClearArea(global.display,global.SnowWin,
104 fsnow->prevx, fsnow->prevy, fsnow->prevw, fsnow->prevh, global.xxposures);
105 }
106 fsnow = fsnow->next;
107 }
108
109 }
110
fallensnow_ui()111 void fallensnow_ui()
112 {
113 UIDO(MaxWinSnowDepth , InitFallenSnow(); ClearScreen(); );
114 UIDO(MaxScrSnowDepth ,
115 SetMaxScreenSnowDepth();
116 InitFallenSnow();
117 ClearScreen();
118 );
119 UIDO(NoKeepSBot , InitFallenSnow(); ClearScreen(); );
120 UIDO(NoKeepSWin , InitFallenSnow(); ClearScreen(); );
121 UIDO(IgnoreTop , );
122 UIDO(IgnoreBottom , );
123 }
124
do_fallen(void * d)125 int do_fallen(void *d)
126 {
127
128 if (Flags.Done)
129 return FALSE;
130 if (NOTACTIVE)
131 return TRUE;
132
133 FallenSnow *fsnow = global.FsnowFirst;
134 while(fsnow)
135 {
136 if (HandleFallenSnow(fsnow))
137 DrawFallen(fsnow);
138 fsnow = fsnow->next;
139 }
140 XFlush(global.display);
141 return TRUE;
142 (void)d;
143 }
144
drawquartcircle(int n,short int * y)145 void drawquartcircle(int n, short int *y) // nb: dimension of y > n+1
146 {
147 int i;
148 float n2 = n*n;
149 for(i=0; i<=n; i++)
150 y[i] = lrintf(sqrtf(n2 - i*i));
151 }
152
153 // inspired by Mr. Gauss, and adapted for xsnow
gaussf(float x,float mu,float sigma)154 float gaussf(float x, float mu, float sigma)
155 {
156 float y = (x-mu)/sigma;
157 float y2 = y*y;
158 return expf(-y2);
159 }
160
CreateDeshBottom(short int * desh,int w,int h)161 void CreateDeshBottom(short int *desh, int w, int h)
162 {
163 #if 0
164 const float twopi = 2*355.0/113.0;
165 int i;
166 {
167 float p = drand48()*4+1;
168 int start = drand48()*w;
169 float a = twopi/w;
170 for(i=0; i<w; i++)
171 {
172 desh[i] = h*(0.45f*cosf(p*(i+start)*a)+0.55f);
173 }
174 P("desh: %f %d\n",p,start);
175 }
176 #endif
177
178 float *y = (float*)malloc(sizeof(float)*w);
179 int i,j;
180
181 float base = 0.1;
182 for (i=0; i<w; i++)
183 y[i] = 0;
184 for (j=0; j<3; j++)
185 {
186 float sigma = (0.02+drand48()*0.2)*w;
187 float mu = drand48()*w;
188 float z = 1.0+drand48();
189 for (i=0; i<w; i++)
190 y[i] += z*gaussf(i,mu,sigma);
191 P("desh: %d %d %d %f\n",j,(int)sigma,(int)mu,z);
192 }
193
194 float maxy = -1;
195 for (i=0; i<w; i++)
196 if(y[i]>maxy)
197 maxy=y[i];
198
199 for(i=0; i<w; i++)
200 {
201 y[i] = y[i]/maxy;
202 if (y[i] < base)
203 y[i] = base;
204 }
205
206 for (i=0; i<w; i++)
207 desh[i] = h*y[i];
208
209 #if 0
210 FILE *ff = fopen("/tmp/desh","w");
211 for (i=0; i<w; i++)
212 fprintf(ff,"%d %d\n",i,desh[i]);
213 fclose(ff);
214 #endif
215
216 free(y);
217 }
218 // insert a node at the start of the list
PushFallenSnow(FallenSnow ** first,WinInfo * win,int x,int y,int w,int h)219 void PushFallenSnow(FallenSnow **first, WinInfo *win, int x, int y, int w, int h)
220 {
221 FallenSnow *p = (FallenSnow *)malloc(sizeof(FallenSnow));
222 p->win = *win;
223 p->x = x;
224 p->y = y;
225 p->w = w;
226 p->h = h;
227 p->prevx = 0;
228 p->prevy = 0;
229 p->prevw = 10;
230 p->prevh = 10;
231 p->w8 = ((w-1)/8+1)*8;
232 p->acth = (short int *)malloc(sizeof(*(p->acth))*w);
233 p->desh = (short int *)malloc(sizeof(*(p->desh))*w);
234 p->r = (short int *)malloc(sizeof(*(p->r))*w);
235 p->pacth = (short int *)malloc(sizeof(*(p->pacth))*w);
236 p->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,w,h);
237
238 cairo_t *cr = cairo_create(p->surface);
239 cairo_set_source_rgba(cr,1,0,0,0.0);
240 cairo_rectangle(cr,0,0,w,h);
241 cairo_fill(cr);
242 cairo_destroy(cr);
243
244 int l = 0,i;
245 for (i=0; i<w; i++)
246 {
247 p->acth[i] = 0; // specify l to get sawtooth effect
248 p->pacth[i] = 0;
249 p->desh[i] = h;
250 l++;
251 if (l > h)
252 l = 0;
253 p->r[i] = 0; // no spikes
254 //p->r[i] = drand48()*2; //0,1
255 //p->r[i] = drand48()*5-2; // -2, -1, 0, 1, 2
256 }
257
258 if (win->id == 0)
259 CreateDeshBottom(p->desh,w,h);
260
261 if (w > h && win->id != 0)
262 {
263 drawquartcircle(h,&(p->desh[w-h-1]));
264 for(i=0; i<=h; i++)
265 p->desh[i] = p->desh[w-1-i];
266 }
267
268 p->next = *first;
269 *first = p;
270 }
271
272 // change bottom snow desired height
do_change_bottom(void * dummy)273 int do_change_bottom(void *dummy)
274 {
275 (void)dummy;
276 FallenSnow *fsnow = FindFallen(global.FsnowFirst, 0);
277 if (fsnow)
278 CreateDeshBottom(fsnow->desh, fsnow->w, fsnow->h);
279 return TRUE;
280 }
281
do_adjust_bottom(void * dummy)282 int do_adjust_bottom(void *dummy)
283 {
284 (void)dummy;
285 FallenSnow *fsnow = FindFallen(global.FsnowFirst, 0);
286 if (fsnow)
287 {
288 int i;
289 int adjustments = 0;
290 for(i=0; i<fsnow->w; i++)
291 {
292 int d = fsnow->acth[i] - fsnow->desh[i];
293 if (d > 0)
294 {
295 int c = 1;
296 if (d > 10)
297 c=2;
298 adjustments++;
299 fsnow->acth[i] -= c;
300 }
301 }
302 P("adjustments: %d\n",adjustments);
303 }
304 return TRUE;
305 }
306
307 // pop from list
PopFallenSnow(FallenSnow ** list)308 int PopFallenSnow(FallenSnow **list)
309 {
310 FallenSnow *next_node = NULL;
311
312 if (*list == NULL)
313 return 0;
314
315 next_node = (*list)->next;
316 FreeFallenSnow(*list);
317 *list = next_node;
318 return 1;
319 }
320
321 // remove by id
RemoveFallenSnow(FallenSnow ** list,Window id)322 int RemoveFallenSnow(FallenSnow **list, Window id)
323 {
324 P("RemoveFallenSnow\n");
325 if (*list == NULL)
326 return 0;
327
328 FallenSnow *fallen = *list;
329 if (fallen->win.id == id)
330 {
331 fallen = fallen->next;
332 FreeFallenSnow(*list);
333 *list = fallen;
334 return 1;
335 }
336
337 FallenSnow *scratch = NULL;
338
339 while (1)
340 {
341 if (fallen->next == NULL)
342 return 0;
343 scratch = fallen->next;
344 if (scratch->win.id == id)
345 break;
346 fallen = fallen->next;
347 }
348
349 fallen->next = scratch->next;
350 FreeFallenSnow(scratch);
351
352 return 1;
353 }
354
FreeFallenSnow(FallenSnow * fallen)355 void FreeFallenSnow(FallenSnow *fallen)
356 {
357 free(fallen->acth);
358 free(fallen->desh);
359 free(fallen->r);
360 free(fallen->pacth);
361 cairo_surface_destroy(fallen->surface);
362 free(fallen);
363 }
364
FindFallen(FallenSnow * first,Window id)365 FallenSnow *FindFallen(FallenSnow *first, Window id)
366 {
367 FallenSnow *fsnow = first;
368 while(fsnow)
369 {
370 if(fsnow->win.id == id)
371 return fsnow;
372 fsnow = fsnow->next;
373 }
374 return NULL;
375 }
376 // print list
PrintFallenSnow(FallenSnow * list)377 void PrintFallenSnow(FallenSnow *list)
378 {
379 FallenSnow *fallen = list;
380
381 while (fallen != NULL) {
382 int sumact = 0;
383 int i;
384 for(i=0; i<fallen->w; i++)
385 sumact += fallen->acth[i];
386 printf("id:%#10lx ws:%4d x:%6d y:%6d w:%6d sty:%2d hid:%2d sum:%8d\n", fallen->win.id, fallen->win.ws,
387 fallen->x, fallen->y, fallen->w, fallen->win.sticky, fallen->win.hidden, sumact);
388 fallen = fallen->next;
389 }
390 }
391
CleanFallenArea(FallenSnow * fsnow,int xstart,int w)392 void CleanFallenArea(FallenSnow *fsnow,int xstart,int w)
393 {
394 if(global.IsDouble)
395 return;
396 P("CleanFallenArea %d %d\n",counter++,global.IsDouble);
397 int x = fsnow->prevx;
398 int y = fsnow->prevy;
399 myXClearArea(global.display, global.SnowWin, x+xstart, y, w, fsnow->h+global.MaxSnowFlakeHeight, global.xxposures);
400 }
401
402 // clean area for fallensnow with id
CleanFallen(Window id)403 void CleanFallen(Window id)
404 {
405 P("CleanFallen %#lx\n",id);
406 FallenSnow *fsnow = global.FsnowFirst;
407 // search the id
408 while(fsnow)
409 {
410 if(fsnow->win.id == id)
411 {
412 CleanFallenArea(fsnow,0,fsnow->w);
413 //myXClearArea(global.display,global.SnowWin,
414 // fsnow->prevx, fsnow->prevy, fsnow->prevw, fsnow->prevh, global.xxposures);
415 break;
416 }
417 fsnow = fsnow->next;
418 }
419 }
420
CreateSurfaceFromFallen(FallenSnow * f)421 void CreateSurfaceFromFallen(FallenSnow *f)
422 {
423 P("createsurface %#10lx %d %d %d %d %d %d\n",f->id,f->x,f->y,f->w,f->h,
424 cairo_image_surface_get_width(f->surface),
425 cairo_image_surface_get_height(f->surface));
426 int i;
427 GdkRGBA color;
428
429 cairo_t *cr = cairo_create(f->surface);
430 int h = f->h;
431 int w = f->w;
432 short int *acth = f->acth;
433 short int *pacth = f->pacth;
434 short int *r = f->r;
435
436 cairo_set_antialias(cr,CAIRO_ANTIALIAS_NONE);
437 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
438
439 cairo_set_source_rgba(cr,0,0,0,0);
440 cairo_set_line_width(cr,1);
441 for (i=0; i<w; i++) // remove
442 {
443 if (acth[i] < pacth[i])
444 {
445 cairo_move_to(cr,i,h-acth[i]+r[i]);
446 cairo_line_to(cr,i,0);
447 pacth[i] = acth[i];
448 }
449 }
450 cairo_stroke(cr);
451
452 gdk_rgba_parse(&color,Flags.SnowColor);
453 cairo_set_source_rgb(cr,color.red, color.green, color.blue);
454 cairo_set_line_width(cr,1);
455 for (i=0; i<w; i++) // add
456 {
457 if (acth[i] > pacth[i])
458 {
459 cairo_move_to(cr,i,h+2); // +2 because line_to to the same xy as move_to doesnt paint anything
460 cairo_line_to(cr,i,h-acth[i]+r[i]);
461 pacth[i] = acth[i];
462 }
463 }
464 cairo_stroke(cr);
465
466 cairo_destroy(cr);
467 }
468
DrawFallen(FallenSnow * fsnow)469 void DrawFallen(FallenSnow *fsnow)
470 {
471 if(fsnow->win.id == 0 || (!fsnow->win.hidden &&
472 (fsnow->win.ws == global.CWorkSpace || fsnow->win.sticky)))
473 {
474 // do not interfere with Santa
475 if(!Flags.NoSanta)
476 {
477 int in = XRectInRegion(global.SantaPlowRegion, fsnow->x, fsnow->y - fsnow->h,
478 fsnow->w, fsnow->h);
479 if (in == RectangleIn || in == RectanglePart)
480 {
481 // determine front of Santa in fsnow
482 int xfront = global.SantaX+global.SantaWidth - fsnow->x;
483 // determine back of Santa in fsnow, Santa can move backwards in strong wind
484 int xback = xfront - global.SantaWidth;
485 const int clearing = 3;
486 float vy = -1.5*global.ActualSantaSpeed;
487 if(vy > 0) vy = -vy;
488 if (vy < -100.0)
489 vy = -100;
490 if (global.ActualSantaSpeed > 0)
491 GenerateFlakesFromFallen(fsnow,xfront,clearing,vy);
492 CleanFallenArea(fsnow,xback-clearing,global.SantaWidth+2*clearing);
493 int i;
494 for (i=0; i<fsnow->w; i++)
495 if (i < xfront+clearing && i>=xback-clearing)
496 fsnow->acth[i] = 0;
497 XFlush(global.display);
498 }
499 }
500 CreateSurfaceFromFallen(fsnow);
501 // drawing is handled in fallensnow_draw
502 }
503 }
504
GenerateFlakesFromFallen(FallenSnow * fsnow,int x,int w,float vy)505 void GenerateFlakesFromFallen(FallenSnow *fsnow, int x, int w, float vy)
506 {
507 P("GenerateFlakes %d %d %d %f\n",counter++,x,w,vy);
508 if (!Flags.BlowSnow || Flags.NoSnowFlakes)
509 return;
510 // animation of fallen fallen snow
511 // x-values x..x+w are transformed in flakes, vertical speed vy
512 int i;
513 int ifirst = x; if (ifirst < 0) ifirst = 0;
514 if (ifirst > fsnow->w) ifirst = fsnow->w;
515 int ilast = x+w; if(ilast < 0) ilast = 0;
516 if (ilast > fsnow->w) ilast = fsnow->w;
517 P("ifirst ilast: %d %d %d %d\n",ifirst,ilast,w,w<global.MaxSnowFlakeWidth?w:global.MaxSnowFlakeWidth);
518 P("maxheight: %d maxw: %d\n",global.MaxSnowFlakeHeight,global.MaxSnowFlakeWidth);
519 //for (i=ifirst; i<ilast; i+=w<global.MaxSnowFlakeHeight?w:global.MaxSnowFlakeWidth)
520 for (i=ifirst; i<ilast; i+=1)
521 {
522 int j;
523 for(j=0; j<fsnow->acth[i]; j++)
524 {
525 int k, kmax = BlowOff();
526 for(k=0; k<kmax; k++)
527 {
528 float p = 0;
529 p = drand48();
530 // In X11, (global.Trans!=1) we want not too much
531 // generated flakes
532 // Otherwize, we go for more dramatic effects
533 // But, it appeared that, if global.Trans==1, too much snow
534 // is generated, choking the x server.
535 if (p < 0.15)
536 {
537 Snow *flake = MakeFlake(-1);
538 flake->rx = fsnow->x + i + 16*(drand48()-0.5);
539 flake->ry = fsnow->y - j - 8;
540 if (Flags.NoWind)
541 flake->vx = 0;
542 else
543 flake->vx = global.NewWind/8;
544 flake->vy = vy;
545 flake->cyclic = 0;
546 }
547 }
548 }
549 }
550 }
551
EraseFallenPixel(FallenSnow * fsnow,int x)552 void EraseFallenPixel(FallenSnow *fsnow, int x)
553 {
554 if(fsnow->acth[x] > 0)
555 {
556 if(!global.IsDouble)
557 {
558 int x1 = fsnow->x + x;
559 int y1 = fsnow->y - fsnow->acth[x];
560 myXClearArea(global.display, global.SnowWin, x1 , y1, 1, 1, global.xxposures);
561 }
562 fsnow->acth[x]--;
563 }
564 }
565
InitFallenSnow()566 void InitFallenSnow()
567 {
568 while (global.FsnowFirst)
569 PopFallenSnow(&global.FsnowFirst);
570 // create fallensnow on bottom of screen:
571 WinInfo *NullWindow = (WinInfo *)malloc(sizeof(WinInfo));
572 memset(NullWindow,0,sizeof(WinInfo));
573
574 PushFallenSnow(&global.FsnowFirst, NullWindow, 0, global.SnowWinHeight, global.SnowWinWidth, global.MaxScrSnowDepth);
575 free(NullWindow);
576 }
577
578 // removes some fallen snow from fsnow, w pixels. If fallensnowheight < h: no removal
579 // also add snowflakes
UpdateFallenSnowWithWind(FallenSnow * fsnow,int w,int h)580 void UpdateFallenSnowWithWind(FallenSnow *fsnow, int w, int h)
581 {
582 int i;
583 int x = randint(fsnow->w - w);
584 for(i=x; i<x+w; i++)
585 if(fsnow->acth[i] > h)
586 {
587 // animation of blown off snow
588 if (!Flags.NoWind && global.Wind != 0 && drand48() > 0.5)
589 {
590 int j, jmax = BlowOff();
591 for (j=0; j< jmax; j++)
592 {
593 Snow *flake = MakeFlake(0);
594 flake->rx = fsnow->x + i;
595 flake->ry = fsnow->y - fsnow->acth[i] - drand48()*8;
596 flake->vx = fsignf(global.NewWind)*global.WindMax;
597 flake->vy = -5;
598 flake->cyclic = (fsnow->win.id == 0); // not cyclic for Windows, cyclic for bottom
599 P("%d:\n",counter++);
600 }
601 EraseFallenPixel(fsnow,i);
602 }
603 }
604 }
605
SetMaxScreenSnowDepth()606 void SetMaxScreenSnowDepth()
607 {
608 global.MaxScrSnowDepth = Flags.MaxScrSnowDepth;
609 if (global.MaxScrSnowDepth> (global.SnowWinHeight-SNOWFREE)) {
610 printf("** Maximum snow depth set to %d\n", global.SnowWinHeight-SNOWFREE);
611 global.MaxScrSnowDepth = global.SnowWinHeight-SNOWFREE;
612 }
613 }
614
615
UpdateFallenSnowPartial(FallenSnow * fsnow,int x,int w)616 void UpdateFallenSnowPartial(FallenSnow *fsnow, int x, int w)
617 {
618 if (NOTACTIVE)
619 return;
620 P("update ...\n");
621 if(!HandleFallenSnow(fsnow)) return;
622 int imin = x;
623 if(imin < 0) imin = 0;
624 int imax = x + w;
625 if (imax > fsnow->w) imax = fsnow->w;
626 int i, k;
627 k = 0;
628 short int *old;
629 // old will contain the acth values, corresponding with x-1..x+w (including)
630 old = (short int *)malloc(sizeof(*old)*(w+2));
631 for (i=imin-1; i<=imax; i++)
632 {
633 if (i < 0)
634 old[k++] = fsnow->acth[0];
635 else if (i>=fsnow->w)
636 old[k++] = fsnow->acth[fsnow->w-1];
637 else
638 old[k++] = fsnow->acth[i];
639 }
640
641 int add;
642 if (fsnow->acth[imin] < fsnow->desh[imin]/4)
643 add = 4;
644 else if(fsnow->acth[imin] < fsnow->desh[imin]/2)
645 add = 2;
646 else
647 add = 1;
648 k = 1; // old[1] corresponds with acth[0]
649 for (i=imin; i<imax; i++)
650 {
651 if ((fsnow->desh[i] > old[k]) &&
652 (old[k-1] >= old[k] || old[k+1] >= old[k]))
653 fsnow->acth[i] = add + (old[k-1] + old[k+1])/2;
654 k++;
655 }
656 // old will contain the new acth values, corresponding with x-1..x+w (including)
657 k = 0;
658 for (i=imin-1; i<=imax; i++)
659 {
660 if (i < 0)
661 old[k++] = fsnow->acth[0];
662 else if (i>=fsnow->w)
663 old[k++] = fsnow->acth[fsnow->w-1];
664 else
665 old[k++] = fsnow->acth[i];
666 }
667 // and now some smoothing
668 k = 1;
669 for (i=imin; i<imax; i++)
670 {
671 int j;
672 int sum=0;
673 for (j=k-1; j<=k+1; j++)
674 sum += old[j];
675 fsnow->acth[i] = sum/3;
676 k++;
677 }
678 free(old);
679 }
680
HandleFallenSnow(FallenSnow * fsnow)681 int HandleFallenSnow(FallenSnow *fsnow)
682 {
683 if (fsnow->win.id == 0)
684 return !Flags.NoKeepSBot;
685 if (fsnow->win.hidden)
686 return 0;
687 if (!fsnow->win.sticky)
688 {
689 if (fsnow->win.ws != global.CWorkSpace)
690 return 0;
691 }
692 return !Flags.NoKeepSWin;
693 }
694
695
696