16 #include "wmgeneral.h"
17 #include "stringlist.h"
19 #include "xpm/back.xpm"
20 #include "xpm/star.xpm"
21 #include "xpm/no_icon.xpm"
26 * Delay between refreshes (in microseconds)
33 /* Database structures */
35 enum th_type
{THEME
, WALL
};
53 /* Themes directories, last one will be replaced */
54 char * themes_dir
[] = {
55 "/usr/share/WindowMaker/Themes",
56 "/usr/X11R6/share/WindowMaker/Themes",
57 "/usr/local/share/WindowMaker/Themes",
58 "$GNUSTEP_USER_ROOT/Library/WindowMaker/Themes"
62 /* Wallpapers directories, last one will be replaced */
63 char * wallpapers_dir
[] = {
64 "/usr/share/WindowMaker/Backgrounds",
65 "/usr/X11R6/share/WindowMaker/Backgrounds",
66 "/usr/local/share/WindowMaker/Backgrounds",
67 "$GNUSTEP_USER_ROOT/Library/WindowMaker/Backgrounds"
71 char hid_cat_db
[] = ".wmThemeCh.cat.db";
72 char cat_db_file
[] = "wmThemeCh.cat.db";
73 char reg_cat
[] = "categories";
75 int current_category
= 0;
76 unsigned long int auto_switch_delay
= 0;
77 unsigned long int auto_switch_next
= 0;
81 XpmAttributes Attributes
;
89 int size
= (ICONSIZE
* ICONSIZE
- 1) / 8 + 1;
91 mask_bits
= malloc (size
);
93 /* must have iconsize % 8 = 0 */
95 for (i
= 0; i
< 4 * ICONSIZE
/ 8; i
++) {
98 for (i
= 0; i
< ICONSIZE
- 8; i
++) {
99 mask_bits
[off
++] = 0xf0;
100 for (j
= 0; j
< (ICONSIZE
/ 8 - 2); j
++) {
101 mask_bits
[off
++] = 0xff;
103 mask_bits
[off
++] = 0x0f;
105 for (i
= 0; i
< 4 * ICONSIZE
/ 8; i
++) {
106 mask_bits
[off
++] = 0;
113 #define ADD_CATEGORY(string) \
115 struct category * newcat; \
117 newcat = malloc (sizeof (struct category) ); \
118 newcat->name = strdup (string); \
119 newcat->themes = create_list (); \
120 add_item (cat_db, (unsigned int) newcat); \
123 #define PROCESS_CATEGORY_FILE \
124 if ( (catfile = fopen (catname,"r") ) ) \
126 while (fscanf (catfile, "%255s", ImageName) == 1) { \
127 ADD_CATEGORY(ImageName); \
133 /* Register categories recognized by system + user */
138 char * home
= getenv ("HOME");
144 catname
= malloc (strlen (home
) + strlen (PACKAGE_NAME
)
145 + strlen (reg_cat
) + 4);
147 sprintf (catname
, "%s/.%s/%s", home
, PACKAGE_NAME
, reg_cat
);
149 PROCESS_CATEGORY_FILE
151 catname
= malloc (strlen (PACKAGE
) + strlen (reg_cat
) + 13);
153 sprintf (catname
, "/usr/share/%s/%s", PACKAGE
, reg_cat
);
155 PROCESS_CATEGORY_FILE
157 catname
= malloc (strlen (PACKAGE
) + strlen (reg_cat
) + 19);
159 sprintf (catname
, "/usr/local/share/%s/%s", PACKAGE
, reg_cat
);
161 PROCESS_CATEGORY_FILE
167 enum de_type
{ ERROR
= -1, IGNORED
, STYLE
, DE_THEME
, SUBDIR
, IMAGE
};
171 * 0 : Ignored entries : ., .., category
172 * 1 : regular file (.style)
173 * 2 : theme directory (.themed)
178 entry_type (char * dir
, char * entry
)
180 char * name
= malloc (strlen (dir
) + strlen (entry
) + 2);
183 sprintf (name
, "%s/%s", dir
, entry
);
185 if (stat (name
, &buf
) ) {
193 if (! S_ISDIR (buf
.st_mode
) ) {
194 if (! strcmp (entry
,cat_db_file
) ) return IGNORED
;
195 if (! strcmp (entry
,hid_cat_db
) ) return IGNORED
;
196 /* TODO : Use file (1) */
197 if (strstr (entry
, ".xpm" ) ) return IMAGE
;
198 if (strstr (entry
, ".png" ) ) return IMAGE
;
199 if (strstr (entry
, ".jpg" ) ) return IMAGE
;
200 if (strstr (entry
, ".jpeg") ) return IMAGE
;
201 if (strstr (entry
, ".tif" ) ) return IMAGE
;
202 if (strstr (entry
, ".ppm" ) ) return IMAGE
;
207 if (strstr (entry
, ".themed") ) return DE_THEME
;
208 if (strcmp (entry
,"." ) && strcmp (entry
,"..") ) return SUBDIR
;
215 insert_into_thm (char * path
, enum th_type type
)
217 struct theme
* new_theme
= malloc (sizeof (struct theme
) );
219 new_theme
->type
= type
;
220 new_theme
->path
= strdup (path
);
221 add_item (thm_db
, (int) new_theme
);
227 insert_into_cat (struct theme
* theme
, LIST
* cat_list
)
232 add_item ( ( (struct category
*) get_item (cat_db
, 0) ) -> themes
,
235 /* for each category theme is in */
236 for (j
= 0; (lcat
= get_item (cat_list
, j
) ) != -1; j
++) {
238 lcat_nam
= (char *) lcat
;
239 /* for each user category */
240 for (i
=1; (ucat
= get_item (cat_db
, i
) ) != -1; i
++) {
241 struct category
* cat
= (struct category
*) ucat
;
242 /* check if they match */
243 if (! strcmp (lcat_nam
, cat
->name
) ) {
244 add_item (cat
->themes
, (int) theme
);
254 theme_specific_cat (char * path
, LIST
* cat_list
)
257 char * th_cat_nam
= malloc (strlen (path
) + strlen (hid_cat_db
) + 2);
258 int i
, ret
, version
, subversion
;
262 sprintf (th_cat_nam
, "%s/%s", path
, cat_db_file
);
263 th_cat
= fopen (th_cat_nam
, "r");
266 sprintf (th_cat_nam
, "%s/%s", path
, hid_cat_db
);
267 th_cat
= fopen (th_cat_nam
, "r");
275 ret
= fscanf (th_cat
, "# wmThemeCh categories database file version %i.%i",
276 &version
, &subversion
);
279 printf("%s : invalid signature\n", th_cat_nam
);
286 printf("%s : incompatible version\n", th_cat_nam
);
292 new_list
= create_list ();
293 add_list (new_list
, cat_list
);
295 while ( (ret
= fscanf (th_cat
, "%s", cat_nam
) ) == 1) {
296 for (i
=0; get_item (cat_db
,i
) != -1; i
++) {
297 struct category
* cat
=
298 (struct category
*) get_item (cat_db
,i
);
299 if (! strcmp (cat_nam
, cat
->name
) ) {
300 /* printf("%s : '%s'\n", th_cat_nam, cat_nam); */
301 add_item (new_list
, (int) strdup (cat
->name
) );
313 /* Read "categories" file in path.
314 * Themes in path and its subdirs are belonging to categories listed
315 * in that file if these categories are defined by user profile.
316 * Updates cat_list accordingly.
319 add_dir_cat (const char * path
, LIST
* cat_list
)
322 char * th_cat_nam
= malloc (strlen (path
) + strlen (hid_cat_db
) + 2);
323 int ret
, version
, subversion
;
326 sprintf (th_cat_nam
, "%s/%s", path
, hid_cat_db
);
327 th_cat
= fopen (th_cat_nam
, "r");
334 ret
= fscanf (th_cat
, "# wmThemeCh categories database file version %i.%i",
335 &version
, &subversion
);
338 printf("%s : invalid signature\n", th_cat_nam
);
345 while ( (ret
= fscanf (th_cat
, "%s", cat_nam
) ) == 1) {
348 for (i
=0; get_item (cat_db
, i
) != -1; i
++) {
349 struct category
* cat
=
350 (struct category
*) get_item (cat_db
, i
);
351 if (! strcmp (cat_nam
, cat
->name
) ) {
352 /* printf("%s : '%s'\n", th_cat_nam, cat_nam); */
353 add_item (cat_list
, (int) strdup (cat
->name
) );
367 get_themes (char * path
, LIST
* par_cat_list
)
369 struct dirent
** namelist
;
370 LIST
* cat_list
= create_list();
371 int themes_count
= 0;
373 int count
= scandir (path
, &namelist
, NULL
, alphasort
);
380 if (par_cat_list
) add_list (cat_list
, par_cat_list
);
382 add_dir_cat (path
, cat_list
);
386 struct theme
* new_theme
;
389 sprintf (fullname
, "%s/%s", path
, namelist
[count
]->d_name
);
391 switch (entry_type (path
, namelist
[count
]->d_name
) ) {
393 case IGNORED
: break;
395 new_theme
= insert_into_thm (fullname
, THEME
);
396 insert_into_cat (new_theme
, cat_list
);
399 new_theme
= insert_into_thm (fullname
, THEME
);
400 th_spec_cat
= theme_specific_cat (fullname
, cat_list
);
401 insert_into_cat (new_theme
, th_spec_cat
);
402 if (th_spec_cat
!= cat_list
) {
403 delete_list (th_spec_cat
);
407 get_themes (fullname
, cat_list
);
418 get_wallpapers (char * path
, LIST
* par_cat_list
)
420 struct dirent
** namelist
;
421 LIST
* cat_list
= create_list();
422 int themes_count
= 0;
424 int count
= scandir (path
, &namelist
, NULL
, NULL
);
431 if (par_cat_list
) add_list (cat_list
, par_cat_list
);
433 add_dir_cat (path
, cat_list
);
437 struct theme
* new_theme
;
439 sprintf (fullname
, "%s/%s", path
, namelist
[count
]->d_name
);
441 switch (entry_type (path
, namelist
[count
]->d_name
) ) {
445 case DE_THEME
: break;
447 get_wallpapers (fullname
, cat_list
);
450 new_theme
= insert_into_thm (fullname
, WALL
);
451 insert_into_cat (new_theme
, cat_list
);
463 char * user_theme_dir
= "/Library/WindowMaker/Themes";
464 char * user_wallpaper_dir
= "/Library/WindowMaker/Backgrounds";
465 char * gnustep_user_root
= getenv("GNUSTEP_USER_ROOT");
469 thm_db
= create_list();
470 cat_db
= create_list();
472 if (!gnustep_user_root
) {
473 char * home
= getenv ("HOME");
474 gnustep_user_root
= malloc (strlen (home
) + 9);
475 sprintf (gnustep_user_root
, "%s/GNUstep", home
);
478 themes_dir
[3] = malloc (strlen (gnustep_user_root
)
479 + strlen (user_theme_dir
) + 1);
480 sprintf (themes_dir
[3], "%s%s", gnustep_user_root
, user_theme_dir
);
482 wallpapers_dir
[3] = malloc (strlen (gnustep_user_root
)
483 + strlen (user_wallpaper_dir
) + 1);
484 sprintf (wallpapers_dir
[3], "%s%s", gnustep_user_root
, user_wallpaper_dir
);
488 for (dir_idx
=0; dir_idx
< 4; dir_idx
++) {
489 get_themes ( themes_dir
[dir_idx
], NULL
);
490 get_wallpapers (wallpapers_dir
[dir_idx
], NULL
);
501 get_pixmap_path (const char * icon_name
)
504 char * home
= getenv ("HOME");
505 struct stat stat_buf
;
507 path
= malloc ( strlen (home
) + strlen (PACKAGE_NAME
)
508 + strlen (icon_name
) + 8);
510 sprintf (path
, "%s/.%s/%s.xpm", home
, PACKAGE_NAME
, icon_name
);
512 if (! stat (path
, &stat_buf
) ) {
517 path
= malloc (strlen (PACKAGE
) + strlen (icon_name
) + 23);
519 sprintf (path
, "/usr/local/share/%s/%s.xpm", PACKAGE
, icon_name
);
521 if (! stat (path
, &stat_buf
) ) {
526 path
= malloc (strlen (PACKAGE
) + strlen (icon_name
) + 17);
528 sprintf (path
, "/usr/share/%s/%s.xpm", PACKAGE
, icon_name
);
530 if (! stat (path
, &stat_buf
) ) {
540 DrawPixmap (char * XpmFileName
)
542 static Pixmap NewPixmap
, NewShapeMask
= 0;
543 static int ret
, havePixmap
= 0;
545 /* copyXPMArea(5, 69, 54, 54, 5, 5); * Clear window */
546 copyXPMArea(4, 4, 56, 56, 4, 4); /* Clear window */
550 * free up the colors, if we alloc'd some before
552 if (Attributes
.nalloc_pixels
> 0)
553 XFreeColors(display
, cmap
, Attributes
.alloc_pixels
,
554 Attributes
.nalloc_pixels
, 0);
556 * Free last pixmap -- we dont need it anymore...
557 * A ShapeMask is returned if the Pixmap
558 * had the color None used.
559 * We could probably change Transparent to None
560 * to make use of this, but for now,
561 * lets just ignore it...
563 if (NewShapeMask
!= 0) XFreePixmap (display
, NewShapeMask
);
565 XFreePixmap(display
, NewPixmap
);
567 XpmFreeAttributes (&Attributes
);
573 * Grab new pixmap. Accept a reasonable color match.
575 Attributes
.valuemask
= XpmExactColors
| XpmCloseness
576 | XpmReturnAllocPixels
;
577 Attributes
.exactColors
= 0;
578 Attributes
.closeness
= 40000;
580 /* TODO : We might cache icons */
583 if (strcmp (XpmFileName
,"*") ) {
584 ret
= XpmReadFileToPixmap (display
, Root
, XpmFileName
,
585 &NewPixmap
, &NewShapeMask
, &Attributes
);
587 ret
= XpmCreatePixmapFromData (display
, Root
, star_xpm
,
588 &NewPixmap
, &NewShapeMask
, &Attributes
);
591 ret
= XpmCreatePixmapFromData (display
, Root
, no_icon_xpm
,
592 &NewPixmap
, &NewShapeMask
, &Attributes
);
597 int Height
= Attributes
.height
;
598 XCopyArea (display
, NewPixmap
, wmgen
.pixmap
, NormalGC
,
599 0, 0, Attributes
.width
, Height
, 4, 4);
604 * Make changes visible
618 char * XpmFileName
= NULL
;
621 if (get_item (cat_db
, current_category
) == -1) current_category
= 0;
622 if (current_category
) {
623 XpmFileName
= get_pixmap_path (
624 ( (struct category
*) get_item
625 (cat_db
, current_category
) ) -> name
);
627 XpmFileName
= strdup("*");
630 DrawPixmap (XpmFileName
);
632 if (XpmFileName
) free (XpmFileName
);
644 static unsigned int oldidx
= -1;
646 struct category
* cur_cat
= (struct category
*)
647 get_item (cat_db
, current_category
);
649 for (i
= 0; get_item (cur_cat
->themes
, i
) != -1; i
++);
653 case 1 : val
= 0; break;
655 fd
= open ("/dev/random", O_RDONLY
);
657 /* We're disallowing "changing" to the same */
658 read (fd
, &val
, sizeof (int) );
660 if (val
>= oldidx
) val
++;
666 switch ( ( (struct theme
*) get_item (cur_cat
->themes
, val
) ) -> type
) {
668 sprintf (Command
, "setstyle \"%s\"", ( (struct theme
*)
669 get_item (cur_cat
->themes
, val
) ) -> path
);
672 sprintf (Command
, "wmsetbg -u \"%s\"", ( (struct theme
*)
673 get_item (cur_cat
->themes
, val
) ) -> path
);
678 auto_switch_next
= time(NULL
) + (auto_switch_delay
* 60);
684 pressEvent (XButtonEvent
*xev
)
686 /* Mouse's left button clicked */
687 if (xev
->button
== Button1
) ChangeTheme ();
689 /* Mouse's right button clicked */
690 if (xev
->button
== Button3
) ChangeCategory ();
697 while (XPending (display
) )
701 XNextEvent (display
, &event
);
703 switch (event
.type
) {
704 case Expose
: RedrawWindow (); break;
705 case ButtonPress
: pressEvent (&event
.xbutton
); break;
706 case ButtonRelease
: break;
720 printf ("%s\n", PACKAGE_STRING
);
721 printf ("Report problems to <%s>\n", PACKAGE_BUGREPORT
);
722 printf ("\nusage: %s [options]...\n\n", PACKAGE_NAME
);
723 printf ("\t-display <Display>\tUse alternate X display.\n");
724 printf ("\t-h\t\t\tDisplay help screen.\n\n");
729 ParseCMDLine (int argc
, char *argv
[])
733 for (i
= 1; i
< argc
; i
++) {
734 if (strcmp(argv
[i
], "-a") == 0) {
736 x
= sscanf(argv
[i
+1], "%u", &auto_switch_delay
);
738 auto_switch_delay
= 0;
739 printf("Found auto-option but could not parse parameter\n");
745 printf("Found auto-option but number is missing!\n");
750 if (!strcmp (argv
[i
], "-display") ) {
762 Init (int argc
, char * argv
[])
764 char * basename
= current_category
765 ? ( (struct category
*)
766 get_item (cat_db
, current_category
)
772 ParseCMDLine (argc
, argv
);
775 if (current_category
) {
776 path
= get_pixmap_path (basename
);
782 openXwindow (argc
, argv
, back_xpm
, mask_bits
,
785 cmap
= DefaultColormap(display
, DefaultScreen(display
));
787 Attributes
.nalloc_pixels
= 0;
791 if (path
) free (path
);
798 main (int argc
, char *argv
[])
800 unsigned int delay_timer
= 0;
803 if (auto_switch_delay
> 0) {
804 auto_switch_next
= time(NULL
) + (auto_switch_delay
* 60);
807 /* TODO : use sigsuspend */
811 delay_timer
+= DELAY
;
812 if ( delay_timer
> 10000000L ) { /* check every 10 seconds */
814 if (auto_switch_delay
> 0) {
815 if (auto_switch_next
< time(NULL
)) {