JWM Source Documentation
background.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "background.h"
12 #include "misc.h"
13 #include "error.h"
14 #include "command.h"
15 #include "color.h"
16 #include "main.h"
17 #include "icon.h"
18 #include "image.h"
19 #include "gradient.h"
20 #include "hint.h"
21 
23 typedef unsigned char BackgroundType;
24 #define BACKGROUND_SOLID 0
25 #define BACKGROUND_GRADIENT 1
26 #define BACKGROUND_COMMAND 2
27 #define BACKGROUND_STRETCH 3
28 #define BACKGROUND_TILE 4
29 #define BACKGROUND_SCALE 5
32 typedef struct BackgroundNode {
33  int desktop;
35  char *value;
36  Pixmap pixmap;
37  struct BackgroundNode *next;
39 
42 
45 
48 
49 static void LoadGradientBackground(BackgroundNode *bp);
50 static void LoadImageBackground(BackgroundNode *bp);
51 
54 {
55  backgrounds = NULL;
56  defaultBackground = NULL;
57  lastBackground = NULL;
58 }
59 
62 {
63 
64  BackgroundNode *bp;
65 
66  for(bp = backgrounds; bp; bp = bp->next) {
67 
68  /* Load background data. */
69  switch(bp->type) {
70  case BACKGROUND_SOLID:
73  break;
74  case BACKGROUND_COMMAND:
75  /* Nothing to do. */
76  break;
77  case BACKGROUND_STRETCH:
78  case BACKGROUND_TILE:
79  case BACKGROUND_SCALE:
81  break;
82  default:
83  Debug("invalid background type in LoadBackground: %d", bp->type);
84  break;
85  }
86 
87  if(bp->desktop == -1) {
88  defaultBackground = bp;
89  }
90 
91  }
92 
93 }
94 
97 {
98  BackgroundNode *bp;
99  for(bp = backgrounds; bp; bp = bp->next) {
100  if(bp->pixmap != None) {
102  bp->pixmap = None;
103  }
104  }
105 }
106 
109 {
110  BackgroundNode *bp;
111  while(backgrounds) {
112  bp = backgrounds->next;
113  Release(backgrounds->value);
114  Release(backgrounds);
115  backgrounds = bp;
116  }
117 }
118 
120 void SetBackground(int desktop, const char *type, const char *value)
121 {
122  static const StringMappingType mapping[] = {
123  { "command", BACKGROUND_COMMAND },
124  { "gradient", BACKGROUND_GRADIENT },
125  { "image", BACKGROUND_STRETCH },
126  { "scale", BACKGROUND_SCALE },
127  { "solid", BACKGROUND_SOLID },
128  { "tile", BACKGROUND_TILE }
129  };
130 
131  BackgroundType bgType;
132  BackgroundNode *bp;
133  BackgroundNode **bpp;
134 
135  /* Make sure we have a value. */
136  if(JUNLIKELY(!value)) {
137  Warning(_("no value specified for background"));
138  return;
139  }
140 
141  /* Parse the background type. */
142  if(type == NULL) {
143  bgType = BACKGROUND_SOLID;
144  } else {
145  const int x = FindValue(mapping, ARRAY_LENGTH(mapping), type);
146  if(x >= 0) {
147  bgType = x;
148  } else {
149  Warning(_("invalid background type: \"%s\""), type);
150  return;
151  }
152  }
153 
154  /* Remove the existing background if this is a duplicate.
155  * This allows later settings to override older settings.
156  * Note that there can be at most one duplicate.
157  */
158  bpp = &backgrounds;
159  while(*bpp) {
160  bp = *bpp;
161  if(bp->desktop == desktop) {
162  *bpp = bp->next;
163  Release(bp->value);
164  Release(bp);
165  break;
166  }
167  bpp = &bp->next;
168  }
169 
170  /* Create the background node. */
171  bp = Allocate(sizeof(BackgroundNode));
172  bp->desktop = desktop;
173  bp->type = bgType;
174  bp->value = CopyString(value);
175  bp->pixmap = None;
176 
177  /* Insert the node into the list. */
178  bp->next = backgrounds;
179  backgrounds = bp;
180 
181 }
182 
185 {
186 
187  XSetWindowAttributes attr;
188  unsigned long attrValues;
189  BackgroundNode *bp;
190 
191  /* Determine the background to load. */
192  for(bp = backgrounds; bp; bp = bp->next) {
193  if(bp->desktop == desktop) {
194  break;
195  }
196  }
197  if(!bp) {
198  bp = defaultBackground;
199  }
200 
201  /* If there is no background specified for this desktop, just return. */
202  if(!bp || !bp->value) {
203  return;
204  }
205 
206  /* If the background isn't changing, don't do anything. */
207  if( lastBackground
208  && bp->type == lastBackground->type
209  && !strcmp(bp->value, lastBackground->value)) {
210  return;
211  }
212  lastBackground = bp;
213 
214  /* Load the background based on type. */
215  if(bp->type == BACKGROUND_COMMAND) {
216  RunCommand(bp->value);
217  return;
218  }
219 
220  attrValues = CWBackPixmap;
221  attr.background_pixmap = bp->pixmap;
222  JXChangeWindowAttributes(display, rootWindow, attrValues, &attr);
225 
226 }
227 
230 {
231 
232  XColor color1;
233  XColor color2;
234  char *temp;
235  char *sep;
236  int len;
237 
238  sep = strchr(bp->value, ':');
239  if(sep) {
240 
241  /* Gradient background. */
242 
243  /* Get the first color. */
244  len = (int)(sep - bp->value);
245  temp = AllocateStack(len + 1);
246  memcpy(temp, bp->value, len);
247  temp[len] = 0;
248  ParseColor(temp, &color1);
249  ReleaseStack(temp);
250 
251  /* Get the second color. */
252  len = strlen(sep + 1);
253  temp = AllocateStack(len + 1);
254  memcpy(temp, sep + 1, len);
255  temp[len] = 0;
256  ParseColor(temp, &color2);
257  ReleaseStack(temp);
258 
259  } else {
260 
261  /* Solid background. */
262  ParseColor(bp->value, &color1);
263  color2.pixel = color1.pixel;
264 
265  }
266 
267  /* Create the background pixmap. */
268  if(color1.pixel == color2.pixel) {
270  rootDepth);
271  JXSetForeground(display, rootGC, color1.pixel);
272  JXDrawPoint(display, bp->pixmap, rootGC, 0, 0);
273  } else {
275  rootDepth);
276  DrawHorizontalGradient(bp->pixmap, rootGC, color1.pixel,
277  color2.pixel, 0, 0, 1, rootHeight);
278  }
279 
280 }
281 
284 {
285 
286  IconNode *ip;
287  int width, height;
288 
289  /* Load the icon. */
290  ExpandPath(&bp->value);
291  ip = LoadNamedIcon(bp->value, 0, bp->type == BACKGROUND_SCALE);
292  if(JUNLIKELY(!ip || ip->width == 0)) {
293  bp->pixmap = None;
294  Warning(_("background image not found: \"%s\""), bp->value);
295  return;
296  }
297 
298  /* Determine the size of the background pixmap. */
299  if(bp->type == BACKGROUND_TILE) {
300  width = ip->width;
301  height = ip->height;
302  } else {
303  width = rootWidth;
304  height = rootHeight;
305  }
306 
307  /* Create the pixmap. */
308  bp->pixmap = JXCreatePixmap(display, rootWindow, width, height, rootDepth);
309 
310  /* Clear the pixmap in case it is too small. */
312  JXFillRectangle(display, bp->pixmap, rootGC, 0, 0, width, height);
313 
314  /* Draw the icon on the background pixmap. */
315  PutIcon(ip, bp->pixmap, 0, 0, 0, width, height);
316 
317  /* We don't need the icon anymore. */
318  DestroyIcon(ip);
319 
320 }

joewing.net / Projects / JWM