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 #include <stdio.h>
22 #include <string.h>
23 #include <gtk/gtk.h>
24 #include <stdlib.h>
25 #include <X11/Intrinsic.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include "xsnow.h"
29 #include "utils.h"
30 #include "windows.h"
31 #include "meteo.h"
32 #include "debug.h"
33 #include "version.h"
34 #include "flags.h"
35 
36 
37 #ifdef TRACEBACK_AVAILALBLE
traceback()38 void traceback()
39 {
40    // see man backtrace
41 #define BT_BUF_SIZE 100
42    void *buffer[BT_BUF_SIZE];
43    int nptrs = backtrace(buffer, BT_BUF_SIZE);
44    backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO);
45 }
46 #endif
47 
IsReadableFile(char * path)48 int IsReadableFile(char *path)
49 {
50    if (!path || access(path,R_OK) != 0)
51       return 0;
52    struct stat path_stat;
53    stat(path,&path_stat);
54    return S_ISREG(path_stat.st_mode);
55 }
56 
HomeOpen(const char * file,const char * mode,char ** path)57 FILE *HomeOpen(const char *file,const char *mode, char **path)
58 {
59    char *h = getenv("HOME");
60    if (h == NULL)
61       return NULL;
62    char *home = strdup(h);
63    (*path) = (char *) malloc(strlen(home)+strlen(file)+2);
64    strcpy(*path,home);
65    strcat(*path,"/");
66    strcat(*path,file);
67    FILE *f = fopen(*path,mode);
68    free(home);
69    return f;
70 }
71 
ClearScreen()72 void ClearScreen()
73 {
74    // remove all our snow-related drawings
75    XClearArea(global.display, global.SnowWin, 0,0,0,0,True);
76    // Yes this is hairy: also remove meteorite.
77    // It could be that a meteor region is still hanging around
78    meteo_erase();
79    XFlush(global.display);
80 
81 }
82 
mywrite(int fd,const void * buf,size_t count)83 ssize_t mywrite(int fd, const void *buf, size_t count)
84 {
85    const size_t m = 4096; // max per write
86    size_t w       = 0;    // # written chars
87    char *b        = (char *)buf;
88 
89    while (w < count)
90    {
91       size_t l = count - w;
92       if (l > m)
93 	 l = m;
94       ssize_t x = write(fd, b+w, l);
95       if (x < 0)
96 	 return -1;
97       w += x;
98    }
99    return 0;
100 }
101 
myXClearArea(Display * dsp,Window win,int x,int y,int w,int h,int exposures)102 void myXClearArea(Display*dsp, Window win, int x, int y, int w, int h, int exposures)
103 {
104    if (w == 0 || h == 0 || w<0 || h<0 || w>20000 || h>20000)
105    {
106       P("myXClearArea: %d %d %d %d %d\n",x,y,w,h,exposures);
107 #ifdef TRACEBACK_AVAILALBLE
108       traceback();
109 #endif
110       return;
111    }
112    XClearArea(dsp, win, x,y,w,h,exposures);
113 }
114 
sq3(float x,float y,float z)115 float sq3(float x, float y, float z)
116 {
117    return x*x + y*y + z*z;
118 }
119 
sq2(float x,float y)120 float sq2(float x, float y)
121 {
122    return x*x + y*y;
123 }
124 
fsignf(float x)125 float fsignf(float x)
126 {
127    if (x>0)
128       return 1.0f;
129    if (x<0)
130       return -1.0f;
131    return 0.0f;
132 }
133 
ValidColor(const char * colorName)134 int ValidColor(const char *colorName)
135 {
136    XColor scrncolor;
137    XColor exactcolor;
138    int scrn = DefaultScreen(global.display);
139    return (XAllocNamedColor(global.display, DefaultColormap(global.display, scrn),
140 	    colorName, &scrncolor, &exactcolor));
141 }
142 
AllocNamedColor(const char * colorName,Pixel dfltPix)143 Pixel AllocNamedColor(const char *colorName, Pixel dfltPix)
144 {
145    XColor scrncolor;
146    XColor exactcolor;
147    int scrn = DefaultScreen(global.display);
148    if (XAllocNamedColor(global.display, DefaultColormap(global.display, scrn),
149 	    colorName, &scrncolor, &exactcolor))
150       return scrncolor.pixel;
151    else
152       return dfltPix;
153 }
154 
IAllocNamedColor(const char * colorName,Pixel dfltPix)155 Pixel IAllocNamedColor(const char *colorName, Pixel dfltPix)
156 {
157    return AllocNamedColor(colorName, dfltPix) | 0xff000000;
158 }
159 
randint(int m)160 int randint(int m)
161 {
162    if (m <=0 )
163       return 0;
164    return drand48()*m;
165 }
166 // https://www.alanzucconi.com/2015/09/16/how-to-sample-from-a-gaussian-distribution/
167 // Interesting but not used now in xsnow
gaussian(double mean,double std,double min,double max)168 double gaussian (double mean, double std, double min, double max)
169 {
170    double x;
171    do {
172       double v1, v2, s;
173       do {
174 	 v1 = 2.0 * drand48() - 1.0;
175 	 v2 = 2.0 * drand48() - 1.0;
176 	 s = v1 * v1 + v2 * v2;
177       } while (s >= 1.0 || s == 0);
178       x = mean + v1 * sqrt((-2.0 * log(s)) / s) * std;
179    } while (x < min || x > max);
180    return x;
181 }
182 
add_to_mainloop(gint prio,float time,GSourceFunc func)183 guint add_to_mainloop(gint prio,float time,GSourceFunc func)
184 {
185    return g_timeout_add_full(prio,(int)1000*(time),func,NULL,NULL);
186 }
187 
add_to_mainloop1(gint prio,float time,GSourceFunc func,gpointer datap)188 guint add_to_mainloop1(gint prio,float time,GSourceFunc func,gpointer datap)
189 {
190    return g_timeout_add_full(prio,(int)1000*(time),func,datap,NULL);
191 }
192 
remove_from_mainloop(guint * tag)193 void remove_from_mainloop(guint *tag)
194 {
195    if (*tag)
196       g_source_remove(*tag);
197    *tag = 0;
198 }
199 
is_little_endian(void)200 int is_little_endian(void)
201 {
202    volatile int endiantest = 1;
203    return (*(char *)&endiantest) == 1;
204 }
205 
my_cairo_paint_with_alpha(cairo_t * cr,double alpha)206 void my_cairo_paint_with_alpha(cairo_t *cr, double alpha)
207 {
208    if (alpha > 0.9)
209       cairo_paint(cr);
210    else
211       cairo_paint_with_alpha(cr,alpha);
212    P("%d alpha %f\n",global.counter++,alpha);
213 }
214 
PrintVersion()215 void PrintVersion()
216 {
217    printf("%s\n%s\n",
218 	 PACKAGE_STRING, VERSIONBY);
219 }
220 
rgba2color(GdkRGBA * c,char ** s)221 void rgba2color(GdkRGBA *c, char **s)
222 {
223    *s = (char *)malloc(8);
224    sprintf(*s,"#%02lx%02lx%02lx",lrint(c->red*255),lrint(c->green*255),lrint(c->blue*255));
225 }
226 
Thanks(void)227 void Thanks(void)
228 {
229    if (global.HaltedByInterrupt)
230       printf("\nXsnow: Caught signal %d\n",global.HaltedByInterrupt);
231    if (strlen(global.Message))
232       printf("\n%s\n",global.Message);
233    printf("\nThank you for using xsnow\n");
234 }
235 
ScaleChanged(int * prevscale)236 int ScaleChanged(int *prevscale)
237 {
238    int newscale;
239    if (*prevscale != (newscale=(int)(Flags.Scale*global.WindowScale)))
240    {
241       *prevscale = newscale;
242       return TRUE;
243    }
244    return FALSE;
245 }
246