]>
Dogcows Code - chaz/tint2/blob - src/launcher/launcher.c
1 /**************************************************************************
4 * Copyright (C) 2010 (mrovi@interfete-web-club.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 **************************************************************************/
22 #include <cairo-xlib.h>
23 #include <pango/pangocairo.h>
36 int launcher_max_icon_size
;
37 GSList
*icon_themes
= 0;
39 #define ICON_FALLBACK "exec"
41 char *icon_path(Launcher
*launcher
, const char *icon_name
, int size
);
42 void launcher_load_themes(Launcher
*launcher
);
43 void free_desktop_entry(DesktopEntry
*entry
);
44 int launcher_read_desktop_file(const char *path
, DesktopEntry
*entry
);
45 Imlib_Image
scale_icon(Imlib_Image original
, int icon_size
);
46 void free_icon(Imlib_Image icon
);
47 void free_icon_theme(IconTheme
*theme
);
49 void default_launcher()
52 launcher_max_icon_size
= 0;
61 void init_launcher_panel(void *p
)
63 Panel
*panel
=(Panel
*)p
;
64 Launcher
*launcher
= &panel
->launcher
;
66 launcher
->area
.parent
= p
;
67 launcher
->area
.panel
= p
;
68 launcher
->area
._draw_foreground
= draw_launcher
;
69 launcher
->area
.size_mode
= SIZE_BY_CONTENT
;
70 launcher
->area
._resize
= resize_launcher
;
71 launcher
->area
.resize
= 1;
72 launcher
->area
.redraw
= 1;
73 launcher
->area
.on_screen
= 1;
75 if (panel_horizontal
) {
76 // panel horizonal => fixed height and posy
77 launcher
->area
.posy
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingy
;
78 launcher
->area
.height
= panel
->area
.height
- (2 * launcher
->area
.posy
);
81 // panel vertical => fixed width, height, posy and posx
82 launcher
->area
.posx
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingxlr
;
83 launcher
->area
.width
= panel
->area
.width
- (2 * panel
->area
.bg
->border
.width
) - (2 * panel
->area
.paddingy
);
86 fprintf(stderr
, "Loading themes...\n");
87 launcher_load_themes(launcher
);
88 fprintf(stderr
, "Done\n");
90 // Load apps (.desktop style launcher items)
91 GSList
* app
= launcher
->list_apps
;
94 launcher_read_desktop_file(app
->data
, &entry
);
96 LauncherIcon
*launcherIcon
= calloc(1, sizeof(LauncherIcon
));
97 launcherIcon
->is_app_desktop
= 1;
98 launcherIcon
->cmd
= strdup(entry
.exec
);
99 launcherIcon
->icon_name
= entry
.icon
? strdup(entry
.icon
) : strdup(ICON_FALLBACK
);
100 launcherIcon
->icon_size
= 1;
101 free_desktop_entry(&entry
);
102 launcher
->list_icons
= g_slist_append(launcher
->list_icons
, launcherIcon
);
104 app
= g_slist_next(app
);
109 void cleanup_launcher()
113 for (i
= 0 ; i
< nb_panel
; i
++) {
114 Panel
*panel
= &panel1
[i
];
115 Launcher
*launcher
= &panel
->launcher
;
116 free_area(&launcher
->area
);
118 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
119 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
121 free_icon(launcherIcon
->icon_scaled
);
122 free_icon(launcherIcon
->icon_original
);
123 free(launcherIcon
->icon_name
);
124 free(launcherIcon
->icon_path
);
125 free(launcherIcon
->cmd
);
129 g_slist_free(launcher
->list_icons
);
131 for (l
= launcher
->list_apps
; l
; l
= l
->next
) {
134 g_slist_free(launcher
->list_apps
);
136 for (l
= launcher
->icon_themes
; l
; l
= l
->next
) {
137 IconTheme
*theme
= (IconTheme
*) l
->data
;
138 free_icon_theme(theme
);
141 g_slist_free(launcher
->icon_themes
);
143 for (l
= launcher
->icon_theme_names
; l
; l
= l
->next
) {
146 g_slist_free(launcher
->icon_theme_names
);
147 launcher
->list_apps
= launcher
->list_icons
= launcher
->icon_theme_names
= launcher
->icon_themes
= NULL
;
149 launcher_enabled
= 0;
152 void resize_launcher(void *obj
)
154 Launcher
*launcher
= obj
;
155 Panel
*panel
= launcher
->area
.panel
;
157 int count
, icon_size
;
158 int icons_per_column
=1, icons_per_row
=1, marging
=0;
160 if (panel_horizontal
)
161 icon_size
= launcher
->area
.height
;
163 icon_size
= launcher
->area
.width
;
164 icon_size
= icon_size
- (2 * launcher
->area
.bg
->border
.width
) - (2 * launcher
->area
.paddingy
);
165 if (launcher_max_icon_size
> 0 && icon_size
> launcher_max_icon_size
)
166 icon_size
= launcher_max_icon_size
;
168 // Resize icons if necessary
169 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
170 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
171 if (launcherIcon
->icon_size
!= icon_size
|| !launcherIcon
->icon_original
) {
172 launcherIcon
->icon_size
= icon_size
;
173 // Get the path for an icon file with the new size
174 char *new_icon_path
= icon_path(launcher
, launcherIcon
->icon_name
, launcherIcon
->icon_size
);
175 if (!new_icon_path
) {
177 free_icon(launcherIcon
->icon_original
);
178 launcherIcon
->icon_original
= NULL
;
179 free_icon(launcherIcon
->icon_scaled
);
180 launcherIcon
->icon_scaled
= NULL
;
181 new_icon_path
= icon_path(launcher
, ICON_FALLBACK
, launcherIcon
->icon_size
);
183 launcherIcon
->icon_original
= imlib_load_image(new_icon_path
);
184 fprintf(stderr
, "%s %d: Using icon %s\n", __FILE__
, __LINE__
, new_icon_path
);
187 launcherIcon
->icon_scaled
= scale_icon(launcherIcon
->icon_original
, icon_size
);
190 if (launcherIcon
->icon_path
&& strcmp(new_icon_path
, launcherIcon
->icon_path
) == 0) {
191 // If it's the same file just rescale
192 free_icon(launcherIcon
->icon_scaled
);
193 launcherIcon
->icon_scaled
= scale_icon(launcherIcon
->icon_original
, icon_size
);
195 fprintf(stderr
, "%s %d: Using icon %s\n", __FILE__
, __LINE__
, launcherIcon
->icon_path
);
197 // Free the old files
198 free_icon(launcherIcon
->icon_original
);
199 free_icon(launcherIcon
->icon_scaled
);
200 // Load the new file and scale
201 launcherIcon
->icon_original
= imlib_load_image(new_icon_path
);
202 launcherIcon
->icon_scaled
= scale_icon(launcherIcon
->icon_original
, launcherIcon
->icon_size
);
203 free(launcherIcon
->icon_path
);
204 launcherIcon
->icon_path
= new_icon_path
;
205 fprintf(stderr
, "%s %d: Using icon %s\n", __FILE__
, __LINE__
, launcherIcon
->icon_path
);
211 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
215 if (panel_horizontal
) {
216 if (!count
) launcher
->area
.width
= 0;
218 int height
= launcher
->area
.height
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
219 // here icons_per_column always higher than 0
220 icons_per_column
= (height
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
221 marging
= height
- (icons_per_column
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
222 icons_per_row
= count
/ icons_per_column
+ (count%icons_per_column
!= 0);
223 launcher
->area
.width
= (2 * launcher
->area
.bg
->border
.width
) + (2 * launcher
->area
.paddingxlr
) + (icon_size
* icons_per_row
) + ((icons_per_row
-1) * launcher
->area
.paddingx
);
226 launcher
->area
.posx
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingxlr
;
227 launcher
->area
.posy
= panel
->area
.bg
->border
.width
;
230 if (!count
) launcher
->area
.height
= 0;
232 int width
= launcher
->area
.width
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
233 // here icons_per_row always higher than 0
234 icons_per_row
= (width
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
235 marging
= width
- (icons_per_row
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
236 icons_per_column
= count
/ icons_per_row
+ (count%icons_per_row
!= 0);
237 launcher
->area
.height
= (2 * launcher
->area
.bg
->border
.width
) + (2 * launcher
->area
.paddingxlr
) + (icon_size
* icons_per_column
) + ((icons_per_column
-1) * launcher
->area
.paddingx
);
240 launcher
->area
.posx
= panel
->area
.bg
->border
.width
;
241 launcher
->area
.posy
= panel
->area
.height
- panel
->area
.bg
->border
.width
- panel
->area
.paddingxlr
- launcher
->area
.height
;
245 int start
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingy
;// +marging/2;
246 if (panel_horizontal
) {
248 posx
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
252 posy
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
255 for (i
=1, l
= launcher
->list_icons
; l
; i
++, l
= l
->next
) {
256 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
258 launcherIcon
->y
= posy
;
259 launcherIcon
->x
= posx
;
260 if (panel_horizontal
) {
261 if (i
% icons_per_column
)
262 posy
+= icon_size
+ launcher
->area
.paddingx
;
265 posx
+= (icon_size
+ launcher
->area
.paddingx
);
269 if (i
% icons_per_row
)
270 posx
+= icon_size
+ launcher
->area
.paddingx
;
273 posy
+= (icon_size
+ launcher
->area
.paddingx
);
278 // resize force the redraw
279 launcher
->area
.redraw
= 1;
283 void draw_launcher(void *obj
, cairo_t
*c
)
285 Launcher
*launcher
= obj
;
287 if (launcher
->list_icons
== 0) return;
289 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
290 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
291 int pos_x
= launcherIcon
->x
;
292 int pos_y
= launcherIcon
->y
;
293 Imlib_Image icon_scaled
= launcherIcon
->icon_scaled
;
295 imlib_context_set_image (icon_scaled
);
296 if (server
.real_transparency
) {
297 render_image(launcher
->area
.pix
, pos_x
, pos_y
, imlib_image_get_width(), imlib_image_get_height() );
300 imlib_context_set_drawable(launcher
->area
.pix
);
301 imlib_render_image_on_drawable (pos_x
, pos_y
);
306 Imlib_Image
scale_icon(Imlib_Image original
, int icon_size
)
308 Imlib_Image icon_scaled
;
310 imlib_context_set_image (original
);
311 icon_scaled
= imlib_create_cropped_scaled_image(0, 0, imlib_image_get_width(), imlib_image_get_height(), icon_size
, icon_size
);
313 icon_scaled
= imlib_create_image(icon_size
, icon_size
);
314 imlib_context_set_image (icon_scaled
);
315 imlib_context_set_color(255, 255, 255, 255);
316 imlib_image_fill_rectangle(0, 0, icon_size
, icon_size
);
321 void free_icon(Imlib_Image icon
)
324 imlib_context_set_image(icon
);
329 void launcher_action(LauncherIcon
*icon
)
331 char *cmd
= malloc(strlen(icon
->cmd
) + 10);
332 sprintf(cmd
, "(%s&)", icon
->cmd
);
337 /***************** Freedesktop app.desktop and icon theme handling *********************/
338 /* http://standards.freedesktop.org/desktop-entry-spec/ */
339 /* http://standards.freedesktop.org/icon-theme-spec/ */
341 // Splits line at first '=' and returns 1 if successful, and parts are not empty
342 // key and value point to the parts
343 int parse_dektop_line(char *line
, char **key
, char **value
)
348 for (p
= line
; *p
; p
++) {
358 if (found
&& (strlen(*key
) == 0 || strlen(*value
) == 0))
363 int parse_theme_line(char *line
, char **key
, char **value
)
365 return parse_dektop_line(line
, key
, value
);
368 void expand_exec(DesktopEntry
*entry
, const char *path
)
375 char *exec2
= malloc(strlen(entry
->exec
) + (entry
->name
? strlen(entry
->name
) : 1) + (entry
->icon
? strlen(entry
->icon
) : 1) + 100);
377 // p will never point to an escaped char
378 for (p
= entry
->exec
, q
= exec2
; *p
; p
++, q
++) {
382 // Copy the escaped char
383 if (*p
== '%') // For % we delete the backslash, i.e. write % over it
392 if (*p
== 'i' && entry
->icon
!= NULL
) {
393 sprintf(q
, "--icon '%s'", entry
->icon
);
394 q
+= strlen("--icon ''");
395 q
+= strlen(entry
->icon
);
396 q
--; // To balance the q++ in the for
397 } else if (*p
== 'c' && entry
->name
!= NULL
) {
398 sprintf(q
, "'%s'", entry
->name
);
400 q
+= strlen(entry
->name
);
401 q
--; // To balance the q++ in the for
402 } else if (*p
== 'c') {
403 sprintf(q
, "'%s'", path
);
406 q
--; // To balance the q++ in the for
408 // We don't care about other expansions
409 q
--; // Delete the last % from q
420 //TODO Use UTF8 when parsing the file
421 int launcher_read_desktop_file(const char *path
, DesktopEntry
*entry
)
427 entry
->name
= entry
->icon
= entry
->exec
= NULL
;
429 if ((fp
= fopen(path
, "rt")) == NULL
) {
430 fprintf(stderr
, "Could not open file %s\n", path
);
434 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
435 int len
= strlen(line
);
438 line
[len
- 1] = '\0';
439 if (parse_dektop_line(line
, &key
, &value
)) {
440 if (strcmp(key
, "Name") == 0) {
441 entry
->name
= strdup(value
);
442 } else if (strcmp(key
, "Exec") == 0) {
443 entry
->exec
= strdup(value
);
444 } else if (strcmp(key
, "Icon") == 0) {
445 entry
->icon
= strdup(value
);
451 // entry->name, entry->icon, entry->exec will never be empty strings (can be NULL though)
453 expand_exec(entry
, path
);
458 void free_desktop_entry(DesktopEntry
*entry
)
465 void test_launcher_read_desktop_file()
467 fprintf(stdout
, "\033[1;33m");
469 launcher_read_desktop_file("/usr/share/applications/firefox.desktop", &entry
);
470 printf("Name:%s Icon:%s Exec:%s\n", entry
.name
, entry
.icon
, entry
.exec
);
471 fprintf(stdout
, "\033[0m");
474 //TODO Use UTF8 when parsing the file
475 IconTheme
*load_theme(char *name
)
477 // Look for name/index.theme in $HOME/.icons, /usr/share/icons, /usr/share/pixmaps (stop at the first found)
478 // Parse index.theme -> list of IconThemeDir with attributes
489 fprintf(stderr
, "Loading icon theme %s\n", name
);
491 file_name
= malloc(100 + strlen(name
));
492 sprintf(file_name
, "~/.icons/%s/index.theme", name
);
493 if (!g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
494 sprintf(file_name
, "/usr/share/icons/%s/index.theme", name
);
495 if (!g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
496 sprintf(file_name
, "/usr/share/pixmaps/%s/index.theme", name
);
497 if (!g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
504 fprintf(stderr
, "Could not load theme %s\n", name
);
508 if ((f
= fopen(file_name
, "rt")) == NULL
)
513 theme
= calloc(1, sizeof(IconTheme
));
514 theme
->name
= strdup(name
);
515 theme
->list_inherits
= NULL
;
516 theme
->list_directories
= NULL
;
518 IconThemeDir
*current_dir
= NULL
;
519 int inside_header
= 1;
520 while (fgets(line
, sizeof(line
), f
) != NULL
) {
523 int line_len
= strlen(line
);
525 if (line
[line_len
- 1] == '\n') {
526 line
[line_len
- 1] = '\0';
535 if (parse_theme_line(line
, &key
, &value
)) {
536 if (strcmp(key
, "Inherits") == 0) {
537 // value is like oxygen,wood,default
539 token
= strtok(value
, ",\n");
540 while (token
!= NULL
)
542 theme
->list_inherits
= g_slist_append(theme
->list_inherits
, strdup(token
));
543 token
= strtok(NULL
, ",\n");
545 } else if (strcmp(key
, "Directories") == 0) {
546 // value is like 48x48/apps,48x48/mimetypes,32x32/apps,scalable/apps,scalable/mimetypes
548 token
= strtok(value
, ",\n");
549 while (token
!= NULL
)
551 IconThemeDir
*dir
= calloc(1, sizeof(IconThemeDir
));
552 dir
->name
= strdup(token
);
553 dir
->max_size
= dir
->min_size
= dir
->size
= -1;
554 dir
->type
= ICON_DIR_TYPE_THRESHOLD
;
556 theme
->list_directories
= g_slist_append(theme
->list_directories
, dir
);
557 token
= strtok(NULL
, ",\n");
561 } else if (current_dir
!= NULL
) {
562 if (parse_theme_line(line
, &key
, &value
)) {
563 if (strcmp(key
, "Size") == 0) {
565 sscanf(value
, "%d", ¤t_dir
->size
);
566 if (current_dir
->max_size
== -1)
567 current_dir
->max_size
= current_dir
->size
;
568 if (current_dir
->min_size
== -1)
569 current_dir
->min_size
= current_dir
->size
;
570 } else if (strcmp(key
, "MaxSize") == 0) {
572 sscanf(value
, "%d", ¤t_dir
->max_size
);
573 } else if (strcmp(key
, "MinSize") == 0) {
575 sscanf(value
, "%d", ¤t_dir
->min_size
);
576 } else if (strcmp(key
, "Threshold") == 0) {
578 sscanf(value
, "%d", ¤t_dir
->threshold
);
579 } else if (strcmp(key
, "Type") == 0) {
580 // value is Fixed, Scalable or Threshold
581 if (strcmp(value
, "Fixed") == 0) {
582 current_dir
->type
= ICON_DIR_TYPE_FIXED
;
583 } else if (strcmp(value
, "Scalable") == 0) {
584 current_dir
->type
= ICON_DIR_TYPE_SCALABLE
;
585 } else if (strcmp(value
, "Threshold") == 0) {
586 current_dir
->type
= ICON_DIR_TYPE_THRESHOLD
;
588 } else if (strcmp(key
, "Context") == 0) {
589 // usual values: Actions, Applications, Devices, FileSystems, MimeTypes
590 current_dir
->context
= strdup(value
);
595 if (line
[0] == '[' && line
[line_len
- 1] == ']' && strcmp(line
, "[Icon Theme]") != 0) {
598 line
[line_len
- 1] = '\0';
599 char *dir_name
= line
+ 1;
600 GSList
* dir_item
= theme
->list_directories
;
601 while (dir_item
!= NULL
)
603 IconThemeDir
*dir
= dir_item
->data
;
604 if (strcmp(dir
->name
, dir_name
) == 0) {
608 dir_item
= g_slist_next(dir_item
);
617 void free_icon_theme(IconTheme
*theme
)
621 for (l_inherits
= theme
->list_inherits
; l_inherits
; l_inherits
= l_inherits
->next
) {
622 free(l_inherits
->data
);
625 for (l_dir
= theme
->list_directories
; l_dir
; l_dir
= l_dir
->next
) {
626 IconThemeDir
*dir
= (IconThemeDir
*)l_dir
->data
;
633 void test_launcher_read_theme_file()
635 fprintf(stdout
, "\033[1;33m");
636 IconTheme
*theme
= load_theme("oxygen");
638 printf("Could not load theme\n");
641 printf("Loaded theme: %s\n", theme
->name
);
642 GSList
* item
= theme
->list_inherits
;
645 printf("Inherits:%s\n", (char*)item
->data
);
646 item
= g_slist_next(item
);
648 item
= theme
->list_directories
;
651 IconThemeDir
*dir
= item
->data
;
652 printf("Dir:%s Size=%d MinSize=%d MaxSize=%d Threshold=%d Type=%s Context=%s\n",
653 dir
->name
, dir
->size
, dir
->min_size
, dir
->max_size
, dir
->threshold
,
654 dir
->type
== ICON_DIR_TYPE_FIXED
? "Fixed" :
655 dir
->type
== ICON_DIR_TYPE_SCALABLE
? "Scalable" :
656 dir
->type
== ICON_DIR_TYPE_THRESHOLD
? "Threshold" : "?????",
658 item
= g_slist_next(item
);
660 fprintf(stdout
, "\033[0m");
663 // Populates the icon_themes list
664 void launcher_load_themes(Launcher
*launcher
)
666 // load the user theme, all the inherited themes recursively (DFS), and the hicolor theme
667 // avoid inheritance loops
669 GSList
*queue
= NULL
;
670 GSList
*queued
= NULL
;
672 GSList
* icon_theme_name_item
;
673 for (icon_theme_name_item
= launcher
->icon_theme_names
; icon_theme_name_item
; icon_theme_name_item
= g_slist_next(icon_theme_name_item
)) {
675 GSList
* queued_item
= queued
;
676 while (queued_item
!= NULL
) {
677 if (strcmp(queued_item
->data
, icon_theme_name_item
->data
) == 0) {
681 queued_item
= g_slist_next(queued_item
);
684 queue
= g_slist_append(queue
, strdup(icon_theme_name_item
->data
));
685 queued
= g_slist_append(queued
, strdup(icon_theme_name_item
->data
));
689 int hicolor_loaded
= 0;
690 while (queue
|| !hicolor_loaded
) {
692 GSList
* queued_item
= queued
;
693 while (queued_item
!= NULL
) {
694 if (strcmp(queued_item
->data
, "hicolor") == 0) {
698 queued_item
= g_slist_next(queued_item
);
702 queue
= g_slist_append(queue
, strdup("hicolor"));
703 queued
= g_slist_append(queued
, strdup("hicolor"));
706 char *name
= queue
->data
;
707 queue
= g_slist_remove(queue
, name
);
709 IconTheme
*theme
= load_theme(name
);
711 launcher
->icon_themes
= g_slist_append(launcher
->icon_themes
, theme
);
713 GSList
* item
= theme
->list_inherits
;
717 char *parent
= item
->data
;
719 GSList
* queued_item
= queued
;
720 while (queued_item
!= NULL
) {
721 if (strcmp(queued_item
->data
, parent
) == 0) {
725 queued_item
= g_slist_next(queued_item
);
728 queue
= g_slist_insert(queue
, strdup(parent
), pos
);
730 queued
= g_slist_append(queued
, strdup(parent
));
732 item
= g_slist_next(item
);
739 for (l
= queue
; l
; l
= l
->next
)
742 for (l
= queued
; l
; l
= l
->next
)
744 g_slist_free(queued
);
747 int directory_matches_size(IconThemeDir
*dir
, int size
)
749 if (dir
->type
== ICON_DIR_TYPE_FIXED
) {
750 return dir
->size
== size
;
751 } else if (dir
->type
== ICON_DIR_TYPE_SCALABLE
) {
752 return dir
->min_size
<= size
&& size
<= dir
->max_size
;
753 } else /*if (dir->type == ICON_DIR_TYPE_THRESHOLD)*/ {
754 return dir
->size
- dir
->threshold
<= size
&& size
<= dir
->size
+ dir
->threshold
;
758 int directory_size_distance(IconThemeDir
*dir
, int size
)
760 if (dir
->type
== ICON_DIR_TYPE_FIXED
) {
761 return abs(dir
->size
- size
);
762 } else if (dir
->type
== ICON_DIR_TYPE_SCALABLE
) {
763 if (size
< dir
->min_size
) {
764 return dir
->min_size
- size
;
765 } else if (size
> dir
->max_size
) {
766 return size
- dir
->max_size
;
770 } else /*if (dir->type == ICON_DIR_TYPE_THRESHOLD)*/ {
771 if (size
< dir
->size
- dir
->threshold
) {
772 return dir
->min_size
- size
;
773 } else if (size
> dir
->size
+ dir
->threshold
) {
774 return size
- dir
->max_size
;
781 // Returns the full path to an icon file (or NULL) given the icon name
782 char *icon_path(Launcher
*launcher
, const char *icon_name
, int size
)
784 if (icon_name
== NULL
)
787 // If the icon_name is already a path and the file exists, return it
788 if (strstr(icon_name
, "/") == icon_name
) {
789 if (g_file_test(icon_name
, G_FILE_TEST_EXISTS
))
790 return strdup(icon_name
);
795 GSList
*basenames
= NULL
;
796 basenames
= g_slist_append(basenames
, "~/.icons");
797 basenames
= g_slist_append(basenames
, "/usr/share/icons");
798 basenames
= g_slist_append(basenames
, "/usr/share/pixmaps");
800 GSList
*extensions
= NULL
;
801 extensions
= g_slist_append(extensions
, "png");
802 extensions
= g_slist_append(extensions
, "xpm");
804 // Stage 1: exact size match
806 for (theme
= launcher
->icon_themes
; theme
; theme
= g_slist_next(theme
)) {
808 for (dir
= ((IconTheme
*)theme
->data
)->list_directories
; dir
; dir
= g_slist_next(dir
)) {
809 if (directory_matches_size((IconThemeDir
*)dir
->data
, size
)) {
811 for (base
= basenames
; base
; base
= g_slist_next(base
)) {
813 for (ext
= extensions
; ext
; ext
= g_slist_next(ext
)) {
814 char *base_name
= (char*) base
->data
;
815 char *theme_name
= ((IconTheme
*)theme
->data
)->name
;
816 char *dir_name
= ((IconThemeDir
*)dir
->data
)->name
;
817 char *extension
= (char*) ext
->data
;
818 char *file_name
= malloc(strlen(base_name
) + strlen(theme_name
) +
819 strlen(dir_name
) + strlen(icon_name
) + strlen(extension
) + 100);
820 // filename = directory/$(themename)/subdirectory/iconname.extension
821 sprintf(file_name
, "%s/%s/%s/%s.%s", base_name
, theme_name
, dir_name
, icon_name
, extension
);
822 //printf("checking %s\n", file_name);
823 if (g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
824 g_slist_free(basenames
);
825 g_slist_free(extensions
);
837 // Stage 2: best size match
838 // Contrary to the freedesktop spec, we are not choosing the closest icon in size, but the next larger icon
839 // otherwise the quality is usually crap (for size 22, if you can choose 16 or 32, you're better with 32)
840 // We do fallback to the closest size if we cannot find a larger or equal icon
841 int minimal_size
= INT_MAX
;
842 char *best_file_name
= NULL
;
843 int next_larger_size
= -1;
844 char *next_larger
= NULL
;
845 for (theme
= launcher
->icon_themes
; theme
; theme
= g_slist_next(theme
)) {
847 for (dir
= ((IconTheme
*)theme
->data
)->list_directories
; dir
; dir
= g_slist_next(dir
)) {
849 for (base
= basenames
; base
; base
= g_slist_next(base
)) {
851 for (ext
= extensions
; ext
; ext
= g_slist_next(ext
)) {
852 char *base_name
= (char*) base
->data
;
853 char *theme_name
= ((IconTheme
*)theme
->data
)->name
;
854 char *dir_name
= ((IconThemeDir
*)dir
->data
)->name
;
855 char *extension
= (char*) ext
->data
;
856 char *file_name
= malloc(strlen(base_name
) + strlen(theme_name
) +
857 strlen(dir_name
) + strlen(icon_name
) + strlen(extension
) + 100);
858 // filename = directory/$(themename)/subdirectory/iconname.extension
859 sprintf(file_name
, "%s/%s/%s/%s.%s", base_name
, theme_name
, dir_name
, icon_name
, extension
);
860 if (g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
861 if (directory_size_distance((IconThemeDir
*)dir
->data
, size
) < minimal_size
) {
862 if (best_file_name
) {
863 free(best_file_name
);
864 best_file_name
= NULL
;
866 best_file_name
= strdup(file_name
);
867 minimal_size
= directory_size_distance((IconThemeDir
*)dir
->data
, size
);
869 if (((IconThemeDir
*)dir
->data
)->size
>= size
&& (next_larger_size
== -1 || ((IconThemeDir
*)dir
->data
)->size
< next_larger_size
)) {
874 next_larger
= strdup(file_name
);
875 next_larger_size
= ((IconThemeDir
*)dir
->data
)->size
;
884 g_slist_free(basenames
);
885 g_slist_free(extensions
);
886 free(best_file_name
);
889 if (best_file_name
) {
890 g_slist_free(basenames
);
891 g_slist_free(extensions
);
892 return best_file_name
;
895 // Stage 3: look in unthemed icons
898 for (base
= basenames
; base
; base
= g_slist_next(base
)) {
900 for (ext
= extensions
; ext
; ext
= g_slist_next(ext
)) {
901 char *base_name
= (char*) base
->data
;
902 char *extension
= (char*) ext
->data
;
903 char *file_name
= malloc(strlen(base_name
) + strlen(icon_name
) +
904 strlen(extension
) + 100);
905 // filename = directory/iconname.extension
906 sprintf(file_name
, "%s/%s.%s", base_name
, icon_name
, extension
);
907 //printf("checking %s\n", file_name);
908 if (g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
909 g_slist_free(basenames
);
910 g_slist_free(extensions
);
920 fprintf(stderr
, "Could not find icon %s\n", icon_name
);
This page took 0.075299 seconds and 4 git commands to generate.