Hi, some days ago I took a look in the WMLive CD structure. I found a lot of icons (more than 1000), used to show the icon for an application. IMO this is an error, because is not possible to have all the icons in the WindowMaker folders. Some of the icons was multiple times, with different names, new applications don't have icon (yes, default.xpm), we need maintain the config files only for the icons,...
Then, I spent some time and found one solution. I was reading http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html and this is a patch to support .desktop files. These files are usually in /usr/share/applications/appname.desktop and a reference to the Icon is included in the file. Now, we don't need modify the config file to setup the icon. We don't need a lot of icons in the WindowMaker folders (less disk usage, less package size). Please, send comments to the list about this patch before apply it in the git. Testers are welcome. You need select an application without icon configured. If the icon is selected in a config file, this patch is not used. Best Regards, kix >From 80b048ee3aeb57c023c9435e647bcd060cf5dcd6 Mon Sep 17 00:00:00 2001 From: Rodolfo García Peñas (kix) <[email protected]> Date: Fri, 3 Feb 2012 13:01:35 +0100 Subject: [PATCH] WindowMaker: Support for icons from .desktop files Most applications includes a .desktop file with information about them. This files are like this: $ cat /usr/share/applications/ddd.desktop [Desktop Entry] [snip] Icon=ddd These files include an icon name for the application, and normaly the icon is installed with the application package. This patch permits to read icons from the .desktop files. With this patch a lot of icons of the WindowMaker package are not needed (save disk space and package size), and the configuration files don't need to maintain information about icon files. The WindowMaker flow is the same as usual. Only when an icon is not found, before select the default icon, a search for the .desktop info is done. If the search found an icon, is selected. If the search fail, then the default icon is set. --- src/Makefile.am | 2 + src/desktop_entry.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/desktop_entry.h | 25 +++++ src/wdefaults.c | 13 ++- 4 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 src/desktop_entry.c create mode 100644 src/desktop_entry.h diff --git a/src/Makefile.am b/src/Makefile.am index 0521d11..5d00bf5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,8 @@ wmaker_SOURCES = \ def_pixmaps.h \ defaults.c \ defaults.h \ + desktop_entry.c \ + desktop_entry.h \ dialog.c \ dialog.h \ dock.c \ diff --git a/src/desktop_entry.c b/src/desktop_entry.c new file mode 100644 index 0000000..4f9e9fc --- /dev/null +++ b/src/desktop_entry.c @@ -0,0 +1,257 @@ +/* desktop_entry.c - Some stuff from free desktop + * + * Window Maker window manager + * + * Copyright (c) 2012 Rodolfo "kix" García Peñas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <WINGs/WUtil.h> +#include "wconfig.h" +#include "desktop_entry.h" + +/* Returns the icon file patch from a .desktop file */ +WMPropList *get_iconpath_from_desktop_file(char *classe) +{ + char *dtf, *icn, *fcn; + WMPropList *ret; + + /* First, search the .desktop file */ + dtf = get_desktop_file(classe); + + /* Now, get the iconfile named in the .desktop file */ + icn = get_iconname_from_desktopfile(dtf); + wfree(dtf); + + /* Test if the file exists */ + fcn = get_correct_path(icn); + wfree(icn); + + if (!fcn) + return NULL; + + ret = WMCreatePLString(fcn); + wfree(fcn); + + return ret; +} + +/* This function returns the .desktop filename for a application class */ +char *get_desktop_file(char *classe) +{ + char *oclass, *desktopfile; + int i; + + if (!classe) + return NULL; + + oclass = wmalloc(strlen(classe) + 1); + sprintf(oclass, "%s", classe); + + /* create a new string, with class in lowercase */ + for (i = 0; i < strlen(oclass); i++) + oclass[i] = (char) tolower(oclass[i]); + + /* strlen("/usr/share/applications/") + strlen(".desktop") = 32 */ + desktopfile = wmalloc(strlen(oclass) + 33); + sprintf(desktopfile, "/usr/share/applications/%s.desktop", oclass); + wfree(oclass); + + /* Now, return the desktop file name */ + return(desktopfile); +} + +/* This function returns the Icon defined in a .desktop file */ +char *get_iconname_from_desktopfile(char *desktopfile) +{ + FILE *dt = NULL; + char *iconline = NULL; + char *iconname = NULL; + char linebuf[MAXLINE]; + int i, j, hasdot, hasslash; + + /* If .desktop file name is null, return */ + if (!desktopfile) + return NULL; + + /* Open the .desktop file */ + dt = fopen(desktopfile, "rb"); + if (!dt) { + werror(_("%s:could not open desktop file"), desktopfile); + return NULL; + } + + /* Search the "Icon" line in the file an save it */ + iconline = wmalloc(MAXLINE); + while (!feof(dt)) { + if (!fgets(linebuf, MAXLINE - 1, dt)) + break; + + /* Found, save it */ + if (!strncmp(linebuf, "Icon", 4)) { + snprintf(iconline, MAXLINE - 1, "%s", linebuf); + break; + } + } + /* Close the file */ + fclose(dt); + + /* If no iconline found */ + if (!strlen(iconline)) { + wfree(iconline); + return NULL; + } + + /* Parse the line searching for "=" */ + for (i = 0; iconline[i] != '\0'; i++) { + if (iconline[i] == '=') + break; + } + + /* Not found ? */ + if (iconline[i] == '\0') { + wfree(iconline); + return NULL; + } + + /* Here i contains the position of "=" + * Remove the spaces */ + for (i = i + 1; iconline[i] != '\0'; i++) { + if (!isspace(iconline[i])) + break; + } + + /* Not found ? */ + if (iconline[i] == '\0') { + wfree(iconline); + return NULL; + } + + /* Save the data */ + iconname = wmalloc(strlen(iconline) - i + 1); + + /* While save the data, check if has dot (extension?) + * and check if has slash (full path?) */ + hasdot = hasslash = 0; + for (j = 0; iconline[j+i] != '\0'; j++) { + /* Like chomp() */ + if ((iconline[j+i] == '\n') || (iconline[j+i] == '\r')) { + iconname[j] = '\0'; + break; + } + iconname[j] = iconline[j+i]; + } + wfree(iconline); + + return(iconname); +} + + +/* This function returns the full patch of the icon + * The value in the .desktop file can have these problems: + * 1. No fullpath: "ddd.xpm" + * 2. No extension "ddd" or "/path/ddd" + * For 1, the possible paths (in order) are: + * - $HOME/.icons + * - $XDG_DATA_DIR/icons + * - /usr/share/pixmaps + * For 2, possible extensions are (in order): + * - .png (required, in lowercase!) + * - .xpm (required, in lowercase!) + * - .svg (optional, not supported by wmaker) */ +char *get_correct_path(char *fp) +{ + struct stat dummy; + int y, z; + char *tmp, *homedir, *xdgdir, *pixdir; + char *paths[3]; + char *extensions[2] = { "png", "xpm" }; + char *toret = NULL; + int i = 0; + + if (!fp) + return NULL; + + /* Don't spend time; Full path? Test it! */ + if (stat(fp, &dummy) > 0) { + toret = wstrdup(fp); + return toret; + } + + /* Read the $HOME, don't use wgethomedir() */ + tmp = getenv("HOME"); + if (tmp) { + homedir = wmalloc(strlen(tmp) + 8); + sprintf(homedir, "%s/.icons", tmp); + if (stat(homedir, &dummy) >= 0) { + paths[i] = homedir; + i++; + } + } + + /* Read $XDG_DATA_DIR */ + tmp = getenv("XDG_DATA_DIR"); + if (tmp) { + xdgdir = wmalloc(strlen(tmp) + 1); + sprintf(xdgdir, "%s", tmp); + if (stat(xdgdir, &dummy) >= 0) { + paths[i] = xdgdir; + i++; + } + } + + /* /usr/share/pixmaps/ (strlen = 19) */ + pixdir = wmalloc(19); + sprintf(pixdir, "/usr/share/pixmaps"); + if (stat(pixdir, &dummy) >= 0) { + paths[i] = pixdir; + i++; + } + + /* Now we have two arrays, one with extensions + * and other with tested paths */ + for (y = 0; y < i; y++) { + for (z = 0; z < 2; z++) { + /* Create the full path and test it */ + tmp = wmalloc(strlen(paths[y]) + strlen(fp) + + strlen(extensions[z]) + 3); + sprintf(tmp, "%s/%s.%s", paths[y], fp, extensions[z]); + if (stat(tmp, &dummy) >= 0) { + /* Found, save and exit */ + toret = wstrdup(tmp); + wfree(tmp); + break; + } + wfree(tmp); + } + } + + /* Clean up */ + for (y = 0; y < i; y++) { + wfree(paths[y]); + } + + /* Return */ + return(toret); +} diff --git a/src/desktop_entry.h b/src/desktop_entry.h new file mode 100644 index 0000000..a8a835c --- /dev/null +++ b/src/desktop_entry.h @@ -0,0 +1,25 @@ +/* desktop_entry.h - .desktop support + * + * Window Maker window manager + * + * Copyright (c) 2012 Rodolfo "kix" García Peñas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +WMPropList *get_iconpath_from_desktop_file(char *classe); +char *get_desktop_file(char *classe); +char *get_iconname_from_desktopfile(char *desktopfile); +char *get_correct_path(char *fp); diff --git a/src/wdefaults.c b/src/wdefaults.c index 8df9dc8..6c30cfc 100644 --- a/src/wdefaults.c +++ b/src/wdefaults.c @@ -41,6 +41,7 @@ #include "workspace.h" #include "defaults.h" #include "icon.h" +#include "desktop_entry.h" /* Global stuff */ extern WPreferences wPreferences; @@ -365,10 +366,16 @@ static WMPropList *get_generic_value(WScreen *scr, char *instance, char *class, } if (!value && !noDefault) { - dict = WMGetFromPLDictionary(WDWindowAttributes->dictionary, AnyWindow); - if (dict) { - value = WMGetFromPLDictionary(dict, option); + /* Search an icon in desktop file */ + value = get_iconpath_from_desktop_file(class); + + if (!value) { + dict = WMGetFromPLDictionary(WDWindowAttributes->dictionary, AnyWindow); + + if (dict) { + value = WMGetFromPLDictionary(dict, option); + } } } -- 1.7.2.3
>From 80b048ee3aeb57c023c9435e647bcd060cf5dcd6 Mon Sep 17 00:00:00 2001 From: Rodolfo GarcÃa Peñas (kix) <[email protected]> Date: Fri, 3 Feb 2012 13:01:35 +0100 Subject: [PATCH] WindowMaker: Support for icons from .desktop files Most applications includes a .desktop file with information about them. This files are like this: $ cat /usr/share/applications/ddd.desktop [Desktop Entry] [snip] Icon=ddd These files include an icon name for the application, and normaly the icon is installed with the application package. This patch permits to read icons from the .desktop files. With this patch a lot of icons of the WindowMaker package are not needed (save disk space and package size), and the configuration files don't need to maintain information about icon files. The WindowMaker flow is the same as usual. Only when an icon is not found, before select the default icon, a search for the .desktop info is done. If the search found an icon, is selected. If the search fail, then the default icon is set. --- src/Makefile.am | 2 + src/desktop_entry.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/desktop_entry.h | 25 +++++ src/wdefaults.c | 13 ++- 4 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 src/desktop_entry.c create mode 100644 src/desktop_entry.h diff --git a/src/Makefile.am b/src/Makefile.am index 0521d11..5d00bf5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,8 @@ wmaker_SOURCES = \ def_pixmaps.h \ defaults.c \ defaults.h \ + desktop_entry.c \ + desktop_entry.h \ dialog.c \ dialog.h \ dock.c \ diff --git a/src/desktop_entry.c b/src/desktop_entry.c new file mode 100644 index 0000000..4f9e9fc --- /dev/null +++ b/src/desktop_entry.c @@ -0,0 +1,257 @@ +/* desktop_entry.c - Some stuff from free desktop + * + * Window Maker window manager + * + * Copyright (c) 2012 Rodolfo "kix" GarcÃa Peñas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <WINGs/WUtil.h> +#include "wconfig.h" +#include "desktop_entry.h" + +/* Returns the icon file patch from a .desktop file */ +WMPropList *get_iconpath_from_desktop_file(char *classe) +{ + char *dtf, *icn, *fcn; + WMPropList *ret; + + /* First, search the .desktop file */ + dtf = get_desktop_file(classe); + + /* Now, get the iconfile named in the .desktop file */ + icn = get_iconname_from_desktopfile(dtf); + wfree(dtf); + + /* Test if the file exists */ + fcn = get_correct_path(icn); + wfree(icn); + + if (!fcn) + return NULL; + + ret = WMCreatePLString(fcn); + wfree(fcn); + + return ret; +} + +/* This function returns the .desktop filename for a application class */ +char *get_desktop_file(char *classe) +{ + char *oclass, *desktopfile; + int i; + + if (!classe) + return NULL; + + oclass = wmalloc(strlen(classe) + 1); + sprintf(oclass, "%s", classe); + + /* create a new string, with class in lowercase */ + for (i = 0; i < strlen(oclass); i++) + oclass[i] = (char) tolower(oclass[i]); + + /* strlen("/usr/share/applications/") + strlen(".desktop") = 32 */ + desktopfile = wmalloc(strlen(oclass) + 33); + sprintf(desktopfile, "/usr/share/applications/%s.desktop", oclass); + wfree(oclass); + + /* Now, return the desktop file name */ + return(desktopfile); +} + +/* This function returns the Icon defined in a .desktop file */ +char *get_iconname_from_desktopfile(char *desktopfile) +{ + FILE *dt = NULL; + char *iconline = NULL; + char *iconname = NULL; + char linebuf[MAXLINE]; + int i, j, hasdot, hasslash; + + /* If .desktop file name is null, return */ + if (!desktopfile) + return NULL; + + /* Open the .desktop file */ + dt = fopen(desktopfile, "rb"); + if (!dt) { + werror(_("%s:could not open desktop file"), desktopfile); + return NULL; + } + + /* Search the "Icon" line in the file an save it */ + iconline = wmalloc(MAXLINE); + while (!feof(dt)) { + if (!fgets(linebuf, MAXLINE - 1, dt)) + break; + + /* Found, save it */ + if (!strncmp(linebuf, "Icon", 4)) { + snprintf(iconline, MAXLINE - 1, "%s", linebuf); + break; + } + } + /* Close the file */ + fclose(dt); + + /* If no iconline found */ + if (!strlen(iconline)) { + wfree(iconline); + return NULL; + } + + /* Parse the line searching for "=" */ + for (i = 0; iconline[i] != '\0'; i++) { + if (iconline[i] == '=') + break; + } + + /* Not found ? */ + if (iconline[i] == '\0') { + wfree(iconline); + return NULL; + } + + /* Here i contains the position of "=" + * Remove the spaces */ + for (i = i + 1; iconline[i] != '\0'; i++) { + if (!isspace(iconline[i])) + break; + } + + /* Not found ? */ + if (iconline[i] == '\0') { + wfree(iconline); + return NULL; + } + + /* Save the data */ + iconname = wmalloc(strlen(iconline) - i + 1); + + /* While save the data, check if has dot (extension?) + * and check if has slash (full path?) */ + hasdot = hasslash = 0; + for (j = 0; iconline[j+i] != '\0'; j++) { + /* Like chomp() */ + if ((iconline[j+i] == '\n') || (iconline[j+i] == '\r')) { + iconname[j] = '\0'; + break; + } + iconname[j] = iconline[j+i]; + } + wfree(iconline); + + return(iconname); +} + + +/* This function returns the full patch of the icon + * The value in the .desktop file can have these problems: + * 1. No fullpath: "ddd.xpm" + * 2. No extension "ddd" or "/path/ddd" + * For 1, the possible paths (in order) are: + * - $HOME/.icons + * - $XDG_DATA_DIR/icons + * - /usr/share/pixmaps + * For 2, possible extensions are (in order): + * - .png (required, in lowercase!) + * - .xpm (required, in lowercase!) + * - .svg (optional, not supported by wmaker) */ +char *get_correct_path(char *fp) +{ + struct stat dummy; + int y, z; + char *tmp, *homedir, *xdgdir, *pixdir; + char *paths[3]; + char *extensions[2] = { "png", "xpm" }; + char *toret = NULL; + int i = 0; + + if (!fp) + return NULL; + + /* Don't spend time; Full path? Test it! */ + if (stat(fp, &dummy) > 0) { + toret = wstrdup(fp); + return toret; + } + + /* Read the $HOME, don't use wgethomedir() */ + tmp = getenv("HOME"); + if (tmp) { + homedir = wmalloc(strlen(tmp) + 8); + sprintf(homedir, "%s/.icons", tmp); + if (stat(homedir, &dummy) >= 0) { + paths[i] = homedir; + i++; + } + } + + /* Read $XDG_DATA_DIR */ + tmp = getenv("XDG_DATA_DIR"); + if (tmp) { + xdgdir = wmalloc(strlen(tmp) + 1); + sprintf(xdgdir, "%s", tmp); + if (stat(xdgdir, &dummy) >= 0) { + paths[i] = xdgdir; + i++; + } + } + + /* /usr/share/pixmaps/ (strlen = 19) */ + pixdir = wmalloc(19); + sprintf(pixdir, "/usr/share/pixmaps"); + if (stat(pixdir, &dummy) >= 0) { + paths[i] = pixdir; + i++; + } + + /* Now we have two arrays, one with extensions + * and other with tested paths */ + for (y = 0; y < i; y++) { + for (z = 0; z < 2; z++) { + /* Create the full path and test it */ + tmp = wmalloc(strlen(paths[y]) + strlen(fp) + + strlen(extensions[z]) + 3); + sprintf(tmp, "%s/%s.%s", paths[y], fp, extensions[z]); + if (stat(tmp, &dummy) >= 0) { + /* Found, save and exit */ + toret = wstrdup(tmp); + wfree(tmp); + break; + } + wfree(tmp); + } + } + + /* Clean up */ + for (y = 0; y < i; y++) { + wfree(paths[y]); + } + + /* Return */ + return(toret); +} diff --git a/src/desktop_entry.h b/src/desktop_entry.h new file mode 100644 index 0000000..a8a835c --- /dev/null +++ b/src/desktop_entry.h @@ -0,0 +1,25 @@ +/* desktop_entry.h - .desktop support + * + * Window Maker window manager + * + * Copyright (c) 2012 Rodolfo "kix" GarcÃa Peñas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +WMPropList *get_iconpath_from_desktop_file(char *classe); +char *get_desktop_file(char *classe); +char *get_iconname_from_desktopfile(char *desktopfile); +char *get_correct_path(char *fp); diff --git a/src/wdefaults.c b/src/wdefaults.c index 8df9dc8..6c30cfc 100644 --- a/src/wdefaults.c +++ b/src/wdefaults.c @@ -41,6 +41,7 @@ #include "workspace.h" #include "defaults.h" #include "icon.h" +#include "desktop_entry.h" /* Global stuff */ extern WPreferences wPreferences; @@ -365,10 +366,16 @@ static WMPropList *get_generic_value(WScreen *scr, char *instance, char *class, } if (!value && !noDefault) { - dict = WMGetFromPLDictionary(WDWindowAttributes->dictionary, AnyWindow); - if (dict) { - value = WMGetFromPLDictionary(dict, option); + /* Search an icon in desktop file */ + value = get_iconpath_from_desktop_file(class); + + if (!value) { + dict = WMGetFromPLDictionary(WDWindowAttributes->dictionary, AnyWindow); + + if (dict) { + value = WMGetFromPLDictionary(dict, option); + } } } -- 1.7.2.3
