]>
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 char *icon_theme_name
;
38 XSettingsClient
*xsettings_client
;
40 #define ICON_FALLBACK "exec"
42 char *icon_path(Launcher
*launcher
, const char *icon_name
, int size
);
43 void launcher_load_themes(Launcher
*launcher
);
44 void free_desktop_entry(DesktopEntry
*entry
);
45 int launcher_read_desktop_file(const char *path
, DesktopEntry
*entry
);
46 Imlib_Image
scale_icon(Imlib_Image original
, int icon_size
);
47 void free_icon(Imlib_Image icon
);
48 void free_icon_theme(IconTheme
*theme
);
51 void default_launcher()
54 launcher_max_icon_size
= 0;
56 xsettings_client
= NULL
;
62 if (launcher_enabled
) {
63 // if XSETTINGS manager running, tint2 read the icon_theme_name.
64 xsettings_client
= xsettings_client_new(server
.dsp
, server
.screen
, xsettings_notify_cb
, NULL
, NULL
);
69 void init_launcher_panel(void *p
)
71 Panel
*panel
=(Panel
*)p
;
72 Launcher
*launcher
= &panel
->launcher
;
74 launcher
->area
.parent
= p
;
75 launcher
->area
.panel
= p
;
76 launcher
->area
._draw_foreground
= draw_launcher
;
77 launcher
->area
.size_mode
= SIZE_BY_CONTENT
;
78 launcher
->area
._resize
= resize_launcher
;
79 launcher
->area
.resize
= 1;
80 launcher
->area
.redraw
= 1;
83 if (launcher
->list_apps
== NULL
)
86 launcher
->area
.on_screen
= 1;
89 launcher_load_themes(launcher
);
90 launcher_load_icons(launcher
);
94 void cleanup_launcher()
99 xsettings_client_destroy(xsettings_client
);
100 for (i
= 0 ; i
< nb_panel
; i
++) {
101 Panel
*panel
= &panel1
[i
];
102 Launcher
*launcher
= &panel
->launcher
;
103 cleanup_launcher_theme(launcher
);
106 for (l
= launcher
->list_apps
; l
; l
= l
->next
) {
109 g_slist_free(launcher
->list_apps
);
110 launcher
->list_apps
= NULL
;
112 g_free(icon_theme_name
);
113 launcher_enabled
= 0;
117 void cleanup_launcher_theme(Launcher
*launcher
)
119 free_area(&launcher
->area
);
121 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
122 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
124 free_icon(launcherIcon
->icon_scaled
);
125 free_icon(launcherIcon
->icon_original
);
126 free(launcherIcon
->icon_name
);
127 free(launcherIcon
->icon_path
);
128 free(launcherIcon
->cmd
);
132 g_slist_free(launcher
->list_icons
);
134 for (l
= launcher
->list_themes
; l
; l
= l
->next
) {
135 IconTheme
*theme
= (IconTheme
*) l
->data
;
136 free_icon_theme(theme
);
139 g_slist_free(launcher
->list_themes
);
140 launcher
->list_icons
= launcher
->list_themes
= NULL
;
144 int resize_launcher(void *obj
)
146 Launcher
*launcher
= obj
;
148 int count
, icon_size
;
149 int icons_per_column
=1, icons_per_row
=1, marging
=0;
151 if (panel_horizontal
)
152 icon_size
= launcher
->area
.height
;
154 icon_size
= launcher
->area
.width
;
155 icon_size
= icon_size
- (2 * launcher
->area
.bg
->border
.width
) - (2 * launcher
->area
.paddingy
);
156 if (launcher_max_icon_size
> 0 && icon_size
> launcher_max_icon_size
)
157 icon_size
= launcher_max_icon_size
;
159 // Resize icons if necessary
160 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
161 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
162 if (launcherIcon
->icon_size
!= icon_size
|| !launcherIcon
->icon_original
) {
163 launcherIcon
->icon_size
= icon_size
;
165 // Get the path for an icon file with the new size
166 char *new_icon_path
= icon_path(launcher
, launcherIcon
->icon_name
, launcherIcon
->icon_size
);
167 if (!new_icon_path
) {
169 free_icon(launcherIcon
->icon_original
);
170 launcherIcon
->icon_original
= NULL
;
171 free_icon(launcherIcon
->icon_scaled
);
172 launcherIcon
->icon_scaled
= NULL
;
173 new_icon_path
= icon_path(launcher
, ICON_FALLBACK
, launcherIcon
->icon_size
);
175 launcherIcon
->icon_original
= imlib_load_image(new_icon_path
);
176 fprintf(stderr
, "launcher.c %d: Using icon %s\n", __LINE__
, new_icon_path
);
179 launcherIcon
->icon_scaled
= scale_icon(launcherIcon
->icon_original
, icon_size
);
182 if (launcherIcon
->icon_path
&& strcmp(new_icon_path
, launcherIcon
->icon_path
) == 0) {
183 // If it's the same file just rescale
184 free_icon(launcherIcon
->icon_scaled
);
185 launcherIcon
->icon_scaled
= scale_icon(launcherIcon
->icon_original
, icon_size
);
187 fprintf(stderr
, "launcher.c %d: Using icon %s\n", __LINE__
, launcherIcon
->icon_path
);
189 // Free the old files
190 free_icon(launcherIcon
->icon_original
);
191 free_icon(launcherIcon
->icon_scaled
);
192 // Load the new file and scale
193 launcherIcon
->icon_original
= imlib_load_image(new_icon_path
);
194 launcherIcon
->icon_scaled
= scale_icon(launcherIcon
->icon_original
, launcherIcon
->icon_size
);
195 free(launcherIcon
->icon_path
);
196 launcherIcon
->icon_path
= new_icon_path
;
197 fprintf(stderr
, "launcher.c %d: Using icon %s\n", __LINE__
, launcherIcon
->icon_path
);
202 count
= g_slist_length(launcher
->list_icons
);
204 if (panel_horizontal
) {
205 if (!count
) launcher
->area
.width
= 0;
207 int height
= launcher
->area
.height
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
208 // here icons_per_column always higher than 0
209 icons_per_column
= (height
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
210 marging
= height
- (icons_per_column
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
211 icons_per_row
= count
/ icons_per_column
+ (count%icons_per_column
!= 0);
212 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
);
216 if (!count
) launcher
->area
.height
= 0;
218 int width
= launcher
->area
.width
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
219 // here icons_per_row always higher than 0
220 icons_per_row
= (width
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
221 marging
= width
- (icons_per_row
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
222 icons_per_column
= count
/ icons_per_row
+ (count%icons_per_row
!= 0);
223 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
);
228 int start
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingy
+ marging
/2;
229 if (panel_horizontal
) {
231 posx
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
235 posy
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
238 for (i
=1, l
= launcher
->list_icons
; l
; i
++, l
= l
->next
) {
239 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
241 launcherIcon
->y
= posy
;
242 launcherIcon
->x
= posx
;
243 //printf("launcher %d : %d,%d\n", i, posx, posy);
244 if (panel_horizontal
) {
245 if (i
% icons_per_column
)
246 posy
+= icon_size
+ launcher
->area
.paddingx
;
249 posx
+= (icon_size
+ launcher
->area
.paddingx
);
253 if (i
% icons_per_row
)
254 posx
+= icon_size
+ launcher
->area
.paddingx
;
257 posy
+= (icon_size
+ launcher
->area
.paddingx
);
265 void draw_launcher(void *obj
, cairo_t
*c
)
267 Launcher
*launcher
= obj
;
269 if (launcher
->list_icons
== 0) return;
271 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
272 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
273 int pos_x
= launcherIcon
->x
;
274 int pos_y
= launcherIcon
->y
;
275 Imlib_Image icon_scaled
= launcherIcon
->icon_scaled
;
277 imlib_context_set_image (icon_scaled
);
278 if (server
.real_transparency
) {
279 render_image(launcher
->area
.pix
, pos_x
, pos_y
, imlib_image_get_width(), imlib_image_get_height() );
282 imlib_context_set_drawable(launcher
->area
.pix
);
283 imlib_render_image_on_drawable (pos_x
, pos_y
);
288 Imlib_Image
scale_icon(Imlib_Image original
, int icon_size
)
290 Imlib_Image icon_scaled
;
292 imlib_context_set_image (original
);
293 icon_scaled
= imlib_create_cropped_scaled_image(0, 0, imlib_image_get_width(), imlib_image_get_height(), icon_size
, icon_size
);
295 icon_scaled
= imlib_create_image(icon_size
, icon_size
);
296 imlib_context_set_image (icon_scaled
);
297 imlib_context_set_color(255, 255, 255, 255);
298 imlib_image_fill_rectangle(0, 0, icon_size
, icon_size
);
303 void free_icon(Imlib_Image icon
)
306 imlib_context_set_image(icon
);
311 void launcher_action(LauncherIcon
*icon
)
313 char *cmd
= malloc(strlen(icon
->cmd
) + 10);
314 sprintf(cmd
, "(%s&)", icon
->cmd
);
319 /***************** Freedesktop app.desktop and icon theme handling *********************/
320 /* http://standards.freedesktop.org/desktop-entry-spec/ */
321 /* http://standards.freedesktop.org/icon-theme-spec/ */
323 // Splits line at first '=' and returns 1 if successful, and parts are not empty
324 // key and value point to the parts
325 int parse_dektop_line(char *line
, char **key
, char **value
)
330 for (p
= line
; *p
; p
++) {
340 if (found
&& (strlen(*key
) == 0 || strlen(*value
) == 0))
345 int parse_theme_line(char *line
, char **key
, char **value
)
347 return parse_dektop_line(line
, key
, value
);
350 void expand_exec(DesktopEntry
*entry
, const char *path
)
357 char *exec2
= malloc(strlen(entry
->exec
) + (entry
->name
? strlen(entry
->name
) : 1) + (entry
->icon
? strlen(entry
->icon
) : 1) + 100);
359 // p will never point to an escaped char
360 for (p
= entry
->exec
, q
= exec2
; *p
; p
++, q
++) {
364 // Copy the escaped char
365 if (*p
== '%') // For % we delete the backslash, i.e. write % over it
374 if (*p
== 'i' && entry
->icon
!= NULL
) {
375 sprintf(q
, "--icon '%s'", entry
->icon
);
376 q
+= strlen("--icon ''");
377 q
+= strlen(entry
->icon
);
378 q
--; // To balance the q++ in the for
379 } else if (*p
== 'c' && entry
->name
!= NULL
) {
380 sprintf(q
, "'%s'", entry
->name
);
382 q
+= strlen(entry
->name
);
383 q
--; // To balance the q++ in the for
384 } else if (*p
== 'c') {
385 sprintf(q
, "'%s'", path
);
388 q
--; // To balance the q++ in the for
390 // We don't care about other expansions
391 q
--; // Delete the last % from q
402 //TODO Use UTF8 when parsing the file
403 int launcher_read_desktop_file(const char *path
, DesktopEntry
*entry
)
409 entry
->name
= entry
->icon
= entry
->exec
= NULL
;
411 if ((fp
= fopen(path
, "rt")) == NULL
) {
412 fprintf(stderr
, "Could not open file %s\n", path
);
416 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
417 int len
= strlen(line
);
420 line
[len
- 1] = '\0';
421 if (parse_dektop_line(line
, &key
, &value
)) {
422 if (strcmp(key
, "Name") == 0) {
423 entry
->name
= strdup(value
);
424 } else if (strcmp(key
, "Exec") == 0) {
425 entry
->exec
= strdup(value
);
426 } else if (strcmp(key
, "Icon") == 0) {
427 entry
->icon
= strdup(value
);
433 // entry->name, entry->icon, entry->exec will never be empty strings (can be NULL though)
435 expand_exec(entry
, path
);
440 void free_desktop_entry(DesktopEntry
*entry
)
447 void test_launcher_read_desktop_file()
449 fprintf(stdout
, "\033[1;33m");
451 launcher_read_desktop_file("/usr/share/applications/firefox.desktop", &entry
);
452 printf("Name:%s Icon:%s Exec:%s\n", entry
.name
, entry
.icon
, entry
.exec
);
453 fprintf(stdout
, "\033[0m");
456 //TODO Use UTF8 when parsing the file
457 IconTheme
*load_theme(char *name
)
459 // Look for name/index.theme in $HOME/.icons, /usr/share/icons, /usr/share/pixmaps (stop at the first found)
460 // Parse index.theme -> list of IconThemeDir with attributes
471 file_name
= g_build_filename(g_get_home_dir(), ".icons", name
, "index.theme", NULL
);
472 if (!g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
474 file_name
= g_build_filename("/usr/share/icons", name
, "index.theme", NULL
);
475 if (!g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
477 file_name
= g_build_filename("/usr/share/pixmaps", name
, "index.theme", NULL
);
478 if (!g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
489 if ((f
= fopen(file_name
, "rt")) == NULL
) {
490 fprintf(stderr
, "Could not open theme '%s'\n", file_name
);
496 theme
= calloc(1, sizeof(IconTheme
));
497 theme
->name
= strdup(name
);
498 theme
->list_inherits
= NULL
;
499 theme
->list_directories
= NULL
;
501 IconThemeDir
*current_dir
= NULL
;
502 int inside_header
= 1;
503 while (fgets(line
, sizeof(line
), f
) != NULL
) {
506 int line_len
= strlen(line
);
508 if (line
[line_len
- 1] == '\n') {
509 line
[line_len
- 1] = '\0';
518 if (parse_theme_line(line
, &key
, &value
)) {
519 if (strcmp(key
, "Inherits") == 0) {
520 // value is like oxygen,wood,default
522 token
= strtok(value
, ",\n");
523 while (token
!= NULL
)
525 theme
->list_inherits
= g_slist_append(theme
->list_inherits
, strdup(token
));
526 token
= strtok(NULL
, ",\n");
528 } else if (strcmp(key
, "Directories") == 0) {
529 // value is like 48x48/apps,48x48/mimetypes,32x32/apps,scalable/apps,scalable/mimetypes
531 token
= strtok(value
, ",\n");
532 while (token
!= NULL
)
534 IconThemeDir
*dir
= calloc(1, sizeof(IconThemeDir
));
535 dir
->name
= strdup(token
);
536 dir
->max_size
= dir
->min_size
= dir
->size
= -1;
537 dir
->type
= ICON_DIR_TYPE_THRESHOLD
;
539 theme
->list_directories
= g_slist_append(theme
->list_directories
, dir
);
540 token
= strtok(NULL
, ",\n");
544 } else if (current_dir
!= NULL
) {
545 if (parse_theme_line(line
, &key
, &value
)) {
546 if (strcmp(key
, "Size") == 0) {
548 sscanf(value
, "%d", ¤t_dir
->size
);
549 if (current_dir
->max_size
== -1)
550 current_dir
->max_size
= current_dir
->size
;
551 if (current_dir
->min_size
== -1)
552 current_dir
->min_size
= current_dir
->size
;
553 } else if (strcmp(key
, "MaxSize") == 0) {
555 sscanf(value
, "%d", ¤t_dir
->max_size
);
556 } else if (strcmp(key
, "MinSize") == 0) {
558 sscanf(value
, "%d", ¤t_dir
->min_size
);
559 } else if (strcmp(key
, "Threshold") == 0) {
561 sscanf(value
, "%d", ¤t_dir
->threshold
);
562 } else if (strcmp(key
, "Type") == 0) {
563 // value is Fixed, Scalable or Threshold : default to scalable for unknown Type.
564 if (strcmp(value
, "Fixed") == 0) {
565 current_dir
->type
= ICON_DIR_TYPE_FIXED
;
566 } else if (strcmp(value
, "Threshold") == 0) {
567 current_dir
->type
= ICON_DIR_TYPE_THRESHOLD
;
569 current_dir
->type
= ICON_DIR_TYPE_SCALABLE
;
571 } else if (strcmp(key
, "Context") == 0) {
572 // usual values: Actions, Applications, Devices, FileSystems, MimeTypes
573 current_dir
->context
= strdup(value
);
578 if (line
[0] == '[' && line
[line_len
- 1] == ']' && strcmp(line
, "[Icon Theme]") != 0) {
581 line
[line_len
- 1] = '\0';
582 char *dir_name
= line
+ 1;
583 GSList
* dir_item
= theme
->list_directories
;
584 while (dir_item
!= NULL
)
586 IconThemeDir
*dir
= dir_item
->data
;
587 if (strcmp(dir
->name
, dir_name
) == 0) {
591 dir_item
= g_slist_next(dir_item
);
600 void free_icon_theme(IconTheme
*theme
)
604 for (l_inherits
= theme
->list_inherits
; l_inherits
; l_inherits
= l_inherits
->next
) {
605 free(l_inherits
->data
);
608 for (l_dir
= theme
->list_directories
; l_dir
; l_dir
= l_dir
->next
) {
609 IconThemeDir
*dir
= (IconThemeDir
*)l_dir
->data
;
616 void test_launcher_read_theme_file()
618 fprintf(stdout
, "\033[1;33m");
619 IconTheme
*theme
= load_theme("oxygen");
621 printf("Could not load theme\n");
624 printf("Loaded theme: %s\n", theme
->name
);
625 GSList
* item
= theme
->list_inherits
;
628 printf("Inherits:%s\n", (char*)item
->data
);
629 item
= g_slist_next(item
);
631 item
= theme
->list_directories
;
634 IconThemeDir
*dir
= item
->data
;
635 printf("Dir:%s Size=%d MinSize=%d MaxSize=%d Threshold=%d Type=%s Context=%s\n",
636 dir
->name
, dir
->size
, dir
->min_size
, dir
->max_size
, dir
->threshold
,
637 dir
->type
== ICON_DIR_TYPE_FIXED
? "Fixed" :
638 dir
->type
== ICON_DIR_TYPE_SCALABLE
? "Scalable" :
639 dir
->type
== ICON_DIR_TYPE_THRESHOLD
? "Threshold" : "?????",
641 item
= g_slist_next(item
);
643 fprintf(stdout
, "\033[0m");
647 // Populates the list_icons list
648 void launcher_load_icons(Launcher
*launcher
)
650 // Load apps (.desktop style launcher items)
651 GSList
* app
= launcher
->list_apps
;
652 while (app
!= NULL
) {
654 launcher_read_desktop_file(app
->data
, &entry
);
656 LauncherIcon
*launcherIcon
= calloc(1, sizeof(LauncherIcon
));
657 launcherIcon
->is_app_desktop
= 1;
658 launcherIcon
->cmd
= strdup(entry
.exec
);
659 launcherIcon
->icon_name
= entry
.icon
? strdup(entry
.icon
) : strdup(ICON_FALLBACK
);
660 launcherIcon
->icon_size
= 1;
661 free_desktop_entry(&entry
);
662 launcher
->list_icons
= g_slist_append(launcher
->list_icons
, launcherIcon
);
664 app
= g_slist_next(app
);
669 // Populates the list_themes list
670 void launcher_load_themes(Launcher
*launcher
)
672 // load the user theme, all the inherited themes recursively (DFS), and the hicolor theme
673 // avoid inheritance loops
674 if (!icon_theme_name
) {
675 fprintf(stderr
, "Missing launcher theme, default to 'hicolor'.\n");
676 icon_theme_name
= "hicolor";
679 fprintf(stderr
, "Loading %s. Icon theme :", icon_theme_name
);
681 GSList
*queue
= g_slist_append(NULL
, strdup(icon_theme_name
));
682 GSList
*queued
= g_slist_append(NULL
, strdup(icon_theme_name
));
684 int hicolor_loaded
= 0;
685 while (queue
|| !hicolor_loaded
) {
687 GSList
* queued_item
= queued
;
688 while (queued_item
!= NULL
) {
689 if (strcmp(queued_item
->data
, "hicolor") == 0) {
693 queued_item
= g_slist_next(queued_item
);
697 queue
= g_slist_append(queue
, strdup("hicolor"));
698 queued
= g_slist_append(queued
, strdup("hicolor"));
701 char *name
= queue
->data
;
702 queue
= g_slist_remove(queue
, name
);
704 fprintf(stderr
, " '%s',", name
);
705 IconTheme
*theme
= load_theme(name
);
707 launcher
->list_themes
= g_slist_append(launcher
->list_themes
, theme
);
709 GSList
* item
= theme
->list_inherits
;
713 char *parent
= item
->data
;
715 GSList
* queued_item
= queued
;
716 while (queued_item
!= NULL
) {
717 if (strcmp(queued_item
->data
, parent
) == 0) {
721 queued_item
= g_slist_next(queued_item
);
724 queue
= g_slist_insert(queue
, strdup(parent
), pos
);
726 queued
= g_slist_append(queued
, strdup(parent
));
728 item
= g_slist_next(item
);
732 fprintf(stderr
, "\n");
736 for (l
= queue
; l
; l
= l
->next
)
739 for (l
= queued
; l
; l
= l
->next
)
741 g_slist_free(queued
);
744 int directory_matches_size(IconThemeDir
*dir
, int size
)
746 if (dir
->type
== ICON_DIR_TYPE_FIXED
) {
747 return dir
->size
== size
;
748 } else if (dir
->type
== ICON_DIR_TYPE_SCALABLE
) {
749 return dir
->min_size
<= size
&& size
<= dir
->max_size
;
750 } else /*if (dir->type == ICON_DIR_TYPE_THRESHOLD)*/ {
751 return dir
->size
- dir
->threshold
<= size
&& size
<= dir
->size
+ dir
->threshold
;
755 int directory_size_distance(IconThemeDir
*dir
, int size
)
757 if (dir
->type
== ICON_DIR_TYPE_FIXED
) {
758 return abs(dir
->size
- size
);
759 } else if (dir
->type
== ICON_DIR_TYPE_SCALABLE
) {
760 if (size
< dir
->min_size
) {
761 return dir
->min_size
- size
;
762 } else if (size
> dir
->max_size
) {
763 return size
- dir
->max_size
;
767 } else /*if (dir->type == ICON_DIR_TYPE_THRESHOLD)*/ {
768 if (size
< dir
->size
- dir
->threshold
) {
769 return dir
->min_size
- size
;
770 } else if (size
> dir
->size
+ dir
->threshold
) {
771 return size
- dir
->max_size
;
778 // Returns the full path to an icon file (or NULL) given the icon name
779 char *icon_path(Launcher
*launcher
, const char *icon_name
, int size
)
781 if (icon_name
== NULL
)
784 // If the icon_name is already a path and the file exists, return it
785 if (strstr(icon_name
, "/") == icon_name
) {
786 if (g_file_test(icon_name
, G_FILE_TEST_EXISTS
))
787 return strdup(icon_name
);
792 GSList
*basenames
= NULL
;
793 char *home_icons
= g_build_filename(g_get_home_dir(), ".icons", NULL
);
794 basenames
= g_slist_append(basenames
, home_icons
);
795 basenames
= g_slist_append(basenames
, "/usr/share/icons");
796 basenames
= g_slist_append(basenames
, "/usr/share/pixmaps");
798 GSList
*extensions
= NULL
;
799 extensions
= g_slist_append(extensions
, ".png");
800 extensions
= g_slist_append(extensions
, ".xpm");
801 // if the icon name already contains one of the extensions (e.g. vlc.png instead of vlc) add a special entry
803 for (ext
= extensions
; ext
; ext
= g_slist_next(ext
)) {
804 char *extension
= (char*) ext
->data
;
805 if (strlen(icon_name
) > strlen(extension
) &&
806 strcmp(extension
, icon_name
+ strlen(icon_name
) - strlen(extension
)) == 0) {
807 extensions
= g_slist_append(extensions
, "");
813 // Stage 1: exact size match
814 // the theme must have a higher priority than having an exact size match, so we will just use
815 // the code that searches for the best size match (it will find the exact size match if one exists)
817 for (theme = launcher->list_themes; theme; theme = g_slist_next(theme)) {
819 for (dir = ((IconTheme*)theme->data)->list_directories; dir; dir = g_slist_next(dir)) {
820 if (directory_matches_size((IconThemeDir*)dir->data, size)) {
822 for (base = basenames; base; base = g_slist_next(base)) {
824 for (ext = extensions; ext; ext = g_slist_next(ext)) {
825 char *base_name = (char*) base->data;
826 char *theme_name = ((IconTheme*)theme->data)->name;
827 char *dir_name = ((IconThemeDir*)dir->data)->name;
828 char *extension = (char*) ext->data;
829 char *file_name = malloc(strlen(base_name) + strlen(theme_name) +
830 strlen(dir_name) + strlen(icon_name) + strlen(extension) + 100);
831 // filename = directory/$(themename)/subdirectory/iconname.extension
832 sprintf(file_name, "%s/%s/%s/%s%s", base_name, theme_name, dir_name, icon_name, extension);
833 //printf("found exact: %s\n", file_name);
834 //printf("checking %s\n", file_name);
835 if (g_file_test(file_name, G_FILE_TEST_EXISTS)) {
836 g_slist_free(basenames);
837 g_slist_free(extensions);
852 // Stage 2: best size match
853 // Contrary to the freedesktop spec, we are not choosing the closest icon in size, but the next larger icon
854 // otherwise the quality is usually crap (for size 22, if you can choose 16 or 32, you're better with 32)
855 // We do fallback to the closest size if we cannot find a larger or equal icon
857 // These 3 variables are used for keeping the closest size match
858 int minimal_size
= INT_MAX
;
859 char *best_file_name
= NULL
;
860 GSList
*best_file_theme
= NULL
;
862 // These 3 variables are used for keeping the next larger match
863 int next_larger_size
= -1;
864 char *next_larger
= NULL
;
865 GSList
*next_larger_theme
= NULL
;
867 for (theme
= launcher
->list_themes
; theme
; theme
= g_slist_next(theme
)) {
869 for (dir
= ((IconTheme
*)theme
->data
)->list_directories
; dir
; dir
= g_slist_next(dir
)) {
871 for (base
= basenames
; base
; base
= g_slist_next(base
)) {
873 for (ext
= extensions
; ext
; ext
= g_slist_next(ext
)) {
874 char *base_name
= (char*) base
->data
;
875 char *theme_name
= ((IconTheme
*)theme
->data
)->name
;
876 char *dir_name
= ((IconThemeDir
*)dir
->data
)->name
;
877 char *extension
= (char*) ext
->data
;
878 char *file_name
= malloc(strlen(base_name
) + strlen(theme_name
) +
879 strlen(dir_name
) + strlen(icon_name
) + strlen(extension
) + 100);
880 // filename = directory/$(themename)/subdirectory/iconname.extension
881 sprintf(file_name
, "%s/%s/%s/%s%s", base_name
, theme_name
, dir_name
, icon_name
, extension
);
882 if (g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
883 //printf("found: %s\n", file_name);
885 if (directory_size_distance((IconThemeDir
*)dir
->data
, size
) < minimal_size
&& (!best_file_theme
? 1 : theme
== best_file_theme
)) {
886 if (best_file_name
) {
887 free(best_file_name
);
888 best_file_name
= NULL
;
890 best_file_name
= strdup(file_name
);
891 minimal_size
= directory_size_distance((IconThemeDir
*)dir
->data
, size
);
892 best_file_theme
= theme
;
893 //printf("best_file_name = %s; minimal_size = %d\n", best_file_name, minimal_size);
896 if (((IconThemeDir
*)dir
->data
)->size
>= size
&&
897 (next_larger_size
== -1 || ((IconThemeDir
*)dir
->data
)->size
< next_larger_size
) &&
898 (!next_larger_theme
? 1 : theme
== next_larger_theme
)) {
903 next_larger
= strdup(file_name
);
904 next_larger_size
= ((IconThemeDir
*)dir
->data
)->size
;
905 next_larger_theme
= theme
;
906 //printf("next_larger = %s; next_larger_size = %d\n", next_larger, next_larger_size);
915 g_slist_free(basenames
);
916 g_slist_free(extensions
);
917 free(best_file_name
);
921 if (best_file_name
) {
922 g_slist_free(basenames
);
923 g_slist_free(extensions
);
925 return best_file_name
;
928 // Stage 3: look in unthemed icons
931 for (base
= basenames
; base
; base
= g_slist_next(base
)) {
933 for (ext
= extensions
; ext
; ext
= g_slist_next(ext
)) {
934 char *base_name
= (char*) base
->data
;
935 char *extension
= (char*) ext
->data
;
936 char *file_name
= malloc(strlen(base_name
) + strlen(icon_name
) +
937 strlen(extension
) + 100);
938 // filename = directory/iconname.extension
939 sprintf(file_name
, "%s/%s%s", base_name
, icon_name
, extension
);
940 //printf("checking %s\n", file_name);
941 if (g_file_test(file_name
, G_FILE_TEST_EXISTS
)) {
942 g_slist_free(basenames
);
943 g_slist_free(extensions
);
954 fprintf(stderr
, "Could not find icon %s\n", icon_name
);
956 g_slist_free(basenames
);
957 g_slist_free(extensions
);
This page took 0.076815 seconds and 4 git commands to generate.