1 /*
2 * Copyright (c) 1999 Sasha Vasko <sasha at aftercode.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20 /*#define DO_CLOCKING */
21
22 #define TRUE 1
23 #define FALSE 0
24
25 #include "../configure.h"
26
27 #include <signal.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #ifdef HAVE_SYS_WAIT_H
31 #include <sys/wait.h>
32 #endif
33
34 #define DO_CLOCKING
35 #ifdef DO_CLOCKING
36 #if TIME_WITH_SYS_TIME
37 # include <sys/time.h>
38 # include <time.h>
39 #else
40 # if HAVE_SYS_TIME_H
41 # include <sys/time.h>
42 # else
43 # include <time.h>
44 # endif
45 #endif
46 #endif
47
48 #include <X11/Intrinsic.h>
49
50 #include "asapp.h"
51 #include "afterstep.h"
52 #include "screen.h"
53 #include "mystyle.h"
54 #include "background.h"
55
56
57 #ifdef DEBUG_BACKGROUNDS
58 #define LOG1(a) fprintf( stderr, a );
59 #define LOG2(a,b) fprintf( stderr, a, b );
60 #define LOG3(a,b,c) fprintf( stderr, a, b, c );
61 #define LOG4(a,b,c,d) fprintf( stderr, a, b, c, d );
62 #else
63 #define LOG1(a)
64 #define LOG2(a,b)
65 #define LOG3(a,b,c)
66 #define LOG4(a,b,c,d)
67 #endif
68
69 /***************************************************/
70 /* this all should go into asimagelib/background.c */
71 static Atom RootPixmapProperty = None;
72
73 ASDeskBack *
FindDeskBack(ASDeskBackArray * backs,long desk)74 FindDeskBack (ASDeskBackArray * backs, long desk)
75 {
76 unsigned long i;
77
78 for (i = 0; i < backs->desks_num; i++)
79 if (backs->desks[i].desk == desk)
80 return &(backs->desks[i]);
81
82 return NULL;
83 }
84
85 int
IsPurePixmap(ASDeskBack * back)86 IsPurePixmap (ASDeskBack * back)
87 {
88 return (back->data_type == XA_PIXMAP && back->data.pixmap != None && back->MyStyle == None);
89 }
90
91 void
BackgroundSetPixmap(Pixmap pix)92 BackgroundSetPixmap (Pixmap pix)
93 {
94 Pixmap current_root = GetRootPixmap (RootPixmapProperty);
95
96 if (current_root == pix)
97 {
98 XClearWindow (dpy, ASDefaultRoot);
99 return;
100 }
101
102 XSetWindowBackgroundPixmap (dpy, ASDefaultRoot, pix);
103 XClearWindow (dpy, ASDefaultRoot);
104
105 /* we shell be setting root pixmap ID in X property with specifyed ID */
106 if (RootPixmapProperty != None)
107 {
108 XChangeProperty (dpy, ASDefaultRoot, RootPixmapProperty, XA_PIXMAP, 32, PropModeReplace, (char *)&pix, 1);
109 XFlush (dpy); /* so that everyone has time to process this change
110 * before we go ahead and delete old background
111 */
112 }
113 }
114
115 Pixmap
BackgroundSetMyStyle(char * style_name)116 BackgroundSetMyStyle (char *style_name)
117 {
118 MyStyle *style;
119 Pixmap pix = None;
120
121 /* get MySyle pointer */
122 if ((style = mystyle_find (style_name)) != NULL)
123 {
124 LOG2 ("\nBackgroundSetMyStyle( %s ) ", style_name)
125 if ((style->set_flags & F_BACKPIXMAP) && style->texture_type != 129)
126 {
127 /* we don't want to free this pixmap ourselves */
128 BackgroundSetPixmap (style->back_icon.pix);
129 return None;
130 } else if (style->set_flags & F_BACKGRADIENT)
131 pix = mystyle_make_pixmap (style, ASDefaultScrWidth, ASDefaultScrHeight, None);
132 if (pix == None)
133 {
134 GC backGC, foreGC;
135
136 pix = XCreatePixmap (dpy, ASDefaultRoot, 1, 1, Scr.d_depth);
137 /* mystyle_get_global_gcs (style, &foreGC, &backGC, NULL, NULL);
138 XDrawPoint (dpy, pix, (backGC != None) ? backGC : foreGC, 1, 1);
139 */ }
140 BackgroundSetPixmap (pix);
141 }
142 /* we will need this pixmap ID later to destroy it gracefully */
143 return pix;
144 }
145
146 /******************************************************************/
147 /* stuff for running external app to set root background */
148 /******************************************************************/
149 #ifdef HAVE_SYS_WAIT_H
150 #define WAIT_CHILDREN(pstatus) waitpid(-1, pstatus, WNOHANG)
151 #elif defined (HAVE_WAIT3)
152 #define WAIT_CHILDREN(pstatus) wait3(pstatus, WNOHANG, NULL)
153 #else
154 #define WAIT_CHILDREN(pstatus) (-1)
155 #endif
156
157 int DrawChildPID = 0;
158 void
sigchild_handler(int signum)159 sigchild_handler (int signum)
160 {
161 int pid;
162 int status;
163
164 signal (SIGCHLD, sigchild_handler);
165 LOG3 ("\n%s:Entering SigChild_handler(%lu)", MyName, time (NULL)) while (1)
166 {
167 pid = WAIT_CHILDREN (&status);
168 if (pid < 0 || pid == DrawChildPID)
169 DrawChildPID = 0;
170 if (pid == 0 || pid < 0)
171 break;
172 }
173 LOG3 ("\n%s:Exiting SigChild_handler(%lu)", MyName, time (NULL))}
174
175 /*
176 This should return 0 if process of running external app to draw background completed or killed.
177 otherwise it returns > 0
178 */
179 int
CheckForDrawChild(int kill_it_to_death)180 CheckForDrawChild (int kill_it_to_death)
181 {
182 int i;
183 int status;
184
185 LOG3 ("\n%s:CheckingForDrawChild(%lu)....", MyName, time (NULL));
186 if (DrawChildPID > 0)
187 {
188 LOG2 ("\n Child has been started with PID (%d).", DrawChildPID);
189 if (kill_it_to_death > 0)
190 {
191 kill (DrawChildPID, SIGTERM);
192 for (i = 0; i < 10; i++) /* give it 10 sec to terminate */
193 {
194 sleep (1);
195 if (WAIT_CHILDREN (&status) <= 0)
196 break;
197 }
198 if (i >= 10)
199 kill (DrawChildPID, SIGKILL); /* no more mercy */
200 DrawChildPID = 0;
201 }
202 } else if (DrawChildPID < 0)
203 DrawChildPID = 0;
204
205 LOG3 ("Done(%lu). Child PID on exit = %d.", time (NULL), DrawChildPID);
206 return DrawChildPID;
207 }
208
209 void
BackgroundSetCommand(char * cmd)210 BackgroundSetCommand (char *cmd)
211 {
212 signal (SIGCHLD, sigchild_handler);
213 if (!(DrawChildPID = fork ())) /* child process */
214 {
215 execl ("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
216
217 /* if all is fine then the thread will exit here */
218 /* so displaying error if not */
219 fprintf (stderr, "\n%s: bad luck running command [%s] to set root pixmap.\n", MyName, cmd);
220 exit (0); /*thread completed */
221 }
222 }
223
224 void
KillOldDrawing()225 KillOldDrawing ()
226 {
227 CheckForDrawChild (1);
228 }
229
230 /* frees all the resources that we currently don't need :
231 - pixmaps used for MyStyle's
232 */
233 void
BackgroundCleanup(ASDeskBackArray * backs,long desk)234 BackgroundCleanup (ASDeskBackArray * backs, long desk)
235 {
236 unsigned long i;
237
238 for (i = 0; i < backs->desks_num; i++)
239 if (backs->desks[i].desk != desk && backs->desks[i].data.pixmap != None)
240 {
241 if (backs->desks[i].data_type != XA_PIXMAP && backs->desks[i].MyStyle != None)
242 {
243 XFreePixmap (dpy, backs->desks[i].data.pixmap);
244 backs->desks[i].data.pixmap = None;
245 }
246 }
247 }
248
249
250 /******************************************************************/
251 /* application interface */
252 /******************************************************************/
253
254 #ifdef DEBUG_BACKGROUNDS
255 void
PrintDeskBackArray(ASDeskBackArray * backs)256 PrintDeskBackArray (ASDeskBackArray * backs)
257 {
258 int i = 0;
259
260 fprintf (stderr, "\n Number of backgrounds = %d", backs->desks_num);
261 for (i = 0; i < backs->desks_num; i++)
262 fprintf (stderr, "\n %d. Desk #%ld type %ld data %ld, MyStyle %ld",
263 i, backs->desks[i].desk, backs->desks[i].data_type,
264 backs->desks[i].data.atom, backs->desks[i].MyStyle);
265
266 }
267 #endif
268
269 void
SetRootPixmapPropertyID(Atom id)270 SetRootPixmapPropertyID (Atom id)
271 {
272 RootPixmapProperty = id;
273 }
274
275 void
BackgroundSetForDesk(ASDeskBackArray * backs,long desk)276 BackgroundSetForDesk (ASDeskBackArray * backs, long desk)
277 {
278 ASDeskBack *back;
279
280 if (desk != 10000 && backs)
281 {
282 LOG2 ("\ntrying to find data for desk %d", desk) if ((back = FindDeskBack (backs, desk)) != NULL)
283 {
284 LOG3 ("\ndesk %d found with pixmap %ld", desk, back->data.pixmap) KillOldDrawing ();
285 if ((back->data_type == XA_PIXMAP) || (back->MyStyle != None && back->data.pixmap != None))
286 BackgroundSetPixmap (back->data.pixmap);
287 else
288 {
289 char *text = XGetAtomName (dpy, ((back->MyStyle != None) ? back->MyStyle : back->data.atom));
290
291 LOG3 ("\ndesk %d has data [%s]", desk, text) if (text != NULL)
292 {
293 if (back->MyStyle != None)
294 back->data.pixmap = BackgroundSetMyStyle (text);
295 else
296 BackgroundSetCommand (text);
297
298 XFree (text);
299 }
300 }
301 }
302 BackgroundCleanup (backs, desk);
303 }
304 }
305
306 void
FreeDeskBackArray(ASDeskBackArray * backs,int free_pixmaps)307 FreeDeskBackArray (ASDeskBackArray * backs, int free_pixmaps)
308 {
309 if (backs->desks)
310 {
311 int i, k;
312
313 for (i = 0; i < backs->desks_num && free_pixmaps; i++)
314 {
315
316 if (backs->desks[i].data_type == XA_PIXMAP || backs->desks[i].MyStyle)
317 if (backs->desks[i].data.pixmap != None)
318 {
319 if (backs->desks[i].desk == Scr.CurrentDesk && RootPixmapProperty != None)
320 {
321 Pixmap pix = None;
322
323 XChangeProperty (dpy, ASDefaultRoot, RootPixmapProperty, XA_PIXMAP, 32, PropModeReplace,
324 (char *)&pix, 1);
325 XFlush (dpy);
326 /* so that everyone has time to process this change
327 * before we go ahead and delet old background
328 */
329 }
330 /* checking if we have already freed this pixmap */
331 for (k = 0; k < i; k++)
332 if (backs->desks[k].data_type == XA_PIXMAP || backs->desks[k].MyStyle)
333 if (backs->desks[k].data.pixmap == backs->desks[i].data.pixmap)
334 break;
335
336 if (k >= i)
337 XFreePixmap(dpy,backs->desks[i].data.pixmap);
338 }
339 }
340 free (backs->desks);
341 backs->desks = NULL;
342 }
343 backs->desks_num = 0;
344 }
345
346 ASDeskBackArray *
UpdateDeskBackArray(ASDeskBackArray * old_info,ASDeskBackArray * new_info)347 UpdateDeskBackArray (ASDeskBackArray * old_info, ASDeskBackArray * new_info)
348 {
349 ASDeskBackArray *updated;
350 int i, k;
351
352 updated = (ASDeskBackArray *) safemalloc (sizeof (ASDeskBackArray));
353 updated->desks_num = new_info->desks_num;
354 for (k = 0; k < old_info->desks_num; k++)
355 if (FindDeskBack (new_info, old_info->desks[k].desk) == NULL)
356 updated->desks_num++;
357
358 updated->desks = (ASDeskBack *) safemalloc (sizeof (ASDeskBack) * updated->desks_num);
359 for (i = 0; i < new_info->desks_num; i++)
360 updated->desks[i] = new_info->desks[i];
361
362 for (k = 0; k < old_info->desks_num; k++)
363 if (FindDeskBack (new_info, old_info->desks[k].desk) == NULL)
364 {
365 updated->desks[i] = old_info->desks[k];
366 i++;
367 }
368
369 return updated;
370 }
371
372 /******************************************************************/
373 /* Backgrounds info X property manipulation */
374 /******************************************************************/
375
376 void
SetBackgroundsProperty(ASDeskBackArray * backs,Atom property)377 SetBackgroundsProperty (ASDeskBackArray * backs, Atom property)
378 {
379 if (backs == NULL || property == None)
380 return;
381 if (backs->desks == NULL || backs->desks_num <= 0)
382 return;
383 set_as_property (ASDefaultRoot, property, (unsigned long *)(backs->desks), backs->desks_num * sizeof (ASDeskBack),
384 (1 << 8) + 0);
385 }
386
387 void
GetBackgroundsProperty(ASDeskBackArray * backs,Atom property)388 GetBackgroundsProperty (ASDeskBackArray * backs, Atom property)
389 {
390 unsigned long version;
391 unsigned long *data;
392
393 if (backs == NULL || property == None)
394 return;
395 if (backs->desks != NULL || backs->desks_num > 0)
396 FreeDeskBackArray (backs, FALSE);
397 data = get_as_property (ASDefaultRoot, property, (size_t *) & (backs->desks_num), &version);
398 if (data && backs->desks_num > 0 && version == (1 << 8) + 0)
399 {
400 backs->desks = (ASDeskBack *) safemalloc (backs->desks_num);
401 memcpy (backs->desks, data, backs->desks_num);
402 XFree (data);
403 backs->desks_num = backs->desks_num / sizeof (ASDeskBack);
404 }
405 }
406