]>
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 void default_launcher()
42 launcher_max_icon_size
= 0;
51 void init_launcher_panel(void *p
)
53 Panel
*panel
=(Panel
*)p
;
54 Launcher
*launcher
= &panel
->launcher
;
56 launcher
->area
.parent
= p
;
57 launcher
->area
.panel
= p
;
58 launcher
->area
._draw_foreground
= draw_launcher
;
59 launcher
->area
.size_mode
= SIZE_BY_CONTENT
;
60 launcher
->area
._resize
= resize_launcher
;
61 launcher
->area
.resize
= 1;
62 launcher
->area
.redraw
= 1;
63 launcher
->area
.on_screen
= 1;
65 if (panel_horizontal
) {
66 // panel horizonal => fixed height and posy
67 launcher
->area
.posy
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingy
;
68 launcher
->area
.height
= panel
->area
.height
- (2 * launcher
->area
.posy
);
71 // panel vertical => fixed width, height, posy and posx
72 launcher
->area
.posx
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingxlr
;
73 launcher
->area
.width
= panel
->area
.width
- (2 * panel
->area
.bg
->border
.width
) - (2 * panel
->area
.paddingy
);
78 GSList
* path
= launcher
->list_icon_paths
;
79 GSList
* cmd
= launcher
->list_cmds
;
80 while (path
!= NULL
&& cmd
!= NULL
)
82 LauncherIcon
*launcherIcon
= malloc(sizeof(LauncherIcon
));
83 launcherIcon
->icon
= imlib_load_image(path
->data
);
84 launcherIcon
->cmd
= strdup(cmd
->data
);
85 launcher
->list_icons
= g_slist_append(launcher
->list_icons
, launcherIcon
);
86 path
= g_slist_next(path
);
87 cmd
= g_slist_next(cmd
);
93 void cleanup_launcher()
97 for (i
= 0 ; i
< nb_panel
; i
++) {
98 Panel
*panel
= &panel1
[i
];
99 Launcher
*launcher
= &panel
->launcher
;
100 free_area(&launcher
->area
);
102 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
103 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
104 if (launcherIcon
&& launcherIcon
->icon
) {
105 imlib_context_set_image (launcherIcon
->icon
);
108 free(launcherIcon
->cmd
);
111 g_slist_free(launcher
->list_icons
);
112 for (l
= launcher
->list_icon_paths
; l
; l
= l
->next
) {
115 g_slist_free(launcher
->list_icon_paths
);
116 for (l
= launcher
->list_cmds
; l
; l
= l
->next
) {
119 g_slist_free(launcher
->list_cmds
);
121 launcher_enabled
= 0;
124 void resize_launcher(void *obj
)
126 Launcher
*launcher
= obj
;
127 Panel
*panel
= launcher
->area
.panel
;
129 int count
, icon_size
;
130 int icons_per_column
=1, icons_per_row
=1, marging
=0;
132 if (panel_horizontal
)
133 icon_size
= launcher
->area
.height
;
135 icon_size
= launcher
->area
.width
;
136 icon_size
= icon_size
- (2 * launcher
->area
.bg
->border
.width
) - (2 * launcher
->area
.paddingy
);
137 if (launcher_max_icon_size
> 0 && icon_size
> launcher_max_icon_size
)
138 icon_size
= launcher_max_icon_size
;
141 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
145 if (panel_horizontal
) {
146 if (!count
) launcher
->area
.width
= 0;
148 int height
= launcher
->area
.height
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
149 // here icons_per_column always higher than 0
150 icons_per_column
= (height
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
151 marging
= height
- (icons_per_column
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
152 icons_per_row
= count
/ icons_per_column
+ (count%icons_per_column
!= 0);
153 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
);
156 launcher
->area
.posx
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingxlr
;
157 launcher
->area
.posy
= panel
->area
.bg
->border
.width
;
160 if (!count
) launcher
->area
.height
= 0;
162 int width
= launcher
->area
.width
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
163 // here icons_per_row always higher than 0
164 icons_per_row
= (width
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
165 marging
= width
- (icons_per_row
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
166 icons_per_column
= count
/ icons_per_row
+ (count%icons_per_row
!= 0);
167 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
);
170 launcher
->area
.posx
= panel
->area
.bg
->border
.width
;
171 launcher
->area
.posy
= panel
->area
.height
- panel
->area
.bg
->border
.width
- panel
->area
.paddingxlr
- launcher
->area
.height
;
175 int start
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingy
;// +marging/2;
176 if (panel_horizontal
) {
178 posx
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
182 posy
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
185 for (i
=1, l
= launcher
->list_icons
; l
; i
++, l
= l
->next
) {
186 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
188 launcherIcon
->y
= posy
;
189 launcherIcon
->x
= posx
;
190 launcherIcon
->width
= icon_size
;
191 launcherIcon
->height
= icon_size
;
192 if (panel_horizontal
) {
193 if (i
% icons_per_column
)
194 posy
+= icon_size
+ launcher
->area
.paddingx
;
197 posx
+= (icon_size
+ launcher
->area
.paddingx
);
201 if (i
% icons_per_row
)
202 posx
+= icon_size
+ launcher
->area
.paddingx
;
205 posy
+= (icon_size
+ launcher
->area
.paddingx
);
210 // resize force the redraw
211 launcher
->area
.redraw
= 1;
215 void draw_launcher(void *obj
, cairo_t
*c
)
217 Launcher
*launcher
= obj
;
219 if (launcher
->list_icons
== 0) return;
221 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
222 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
223 int pos_x
= launcherIcon
->x
;
224 int pos_y
= launcherIcon
->y
;
225 int width
= launcherIcon
->width
;
226 int height
= launcherIcon
->height
;
227 Imlib_Image icon_scaled
;
228 if (launcherIcon
->icon
) {
229 imlib_context_set_image (launcherIcon
->icon
);
230 icon_scaled
= imlib_create_cropped_scaled_image(0, 0, imlib_image_get_width(), imlib_image_get_height(), width
, height
);
232 icon_scaled
= imlib_create_image(width
, height
);
233 imlib_context_set_image (icon_scaled
);
234 imlib_context_set_color(255, 255, 255, 255);
235 imlib_image_fill_rectangle(0, 0, width
, height
);
239 imlib_context_set_image (icon_scaled
);
240 if (server
.real_transparency
) {
241 render_image(launcher
->area
.pix
, pos_x
, pos_y
, imlib_image_get_width(), imlib_image_get_height() );
244 imlib_context_set_drawable(launcher
->area
.pix
);
245 imlib_render_image_on_drawable (pos_x
, pos_y
);
251 void launcher_action(LauncherIcon
*icon
)
253 char *cmd
= malloc(strlen(icon
->cmd
) + 10);
254 sprintf(cmd
, "(%s&)", icon
->cmd
);
259 /***************** Freedesktop app.desktop and icon theme handling *********************/
260 /* http://standards.freedesktop.org/desktop-entry-spec/ */
261 /* http://standards.freedesktop.org/icon-theme-spec/ */
263 int parse_dektop_line(char *line
, char **key
, char **value
)
268 for (p
= line
; *p
; p
++) {
278 if (found
&& (strlen(*key
) == 0 || strlen(*value
) == 0))
283 void expand_exec(DesktopEntry
*entry
, const char *path
)
290 char *exec2
= malloc(strlen(entry
->exec
) + strlen(entry
->name
) + strlen(entry
->icon
) + 100);
292 // p will never point to an escaped char
293 for (p
= entry
->exec
, q
= exec2
; *p
; p
++, q
++) {
297 // Copy the escaped char
298 if (*p
== '%') // For % we delete the backslash, i.e. write % over it
307 if (*p
== 'i' && entry
->icon
!= NULL
) {
308 sprintf(q
, "--icon '%s'", entry
->icon
);
309 q
+= strlen("--icon ''");
310 q
+= strlen(entry
->icon
);
311 q
--; // To balance the q++ in the for
312 } else if (*p
== 'c' && entry
->name
!= NULL
) {
313 sprintf(q
, "'%s'", entry
->name
);
315 q
+= strlen(entry
->name
);
316 q
--; // To balance the q++ in the for
317 } else if (*p
== 'c') {
318 sprintf(q
, "'%s'", path
);
321 q
--; // To balance the q++ in the for
323 // We don't care about other expansions
324 q
--; // Delete the last % from q
335 int launcher_read_desktop_file(const char *path
, DesktopEntry
*entry
)
342 entry
->name
= entry
->icon
= entry
->exec
= NULL
;
344 if ((fp
= fopen(path
, "r")) == NULL
) {
345 fprintf(stderr
, "Could not open file %s\n", path
);
350 while (fgets(buffer
, sizeof(line
) - (buffer
- line
), fp
) != NULL
) {
351 //TODO use UTF8 capable strlen
352 int len
= strlen(buffer
);
353 int total_len
= strlen(line
);
354 if (!g_utf8_validate(buffer
, total_len
, NULL
)) {
355 // Not a real newline, read more
357 if (sizeof(line
) - (buffer
- line
) < 2) {
358 fprintf(stderr
, "%s %d: line too long (%s)\n", __FILE__
, __LINE__
, path
);
364 // We have a valid line
365 buffer
[len
-1] = '\0';
367 if (parse_dektop_line(line
, &key
, &value
)) {
368 if (strcmp(key
, "Name") == 0) {
369 //TODO use UTF-8 capable strdup
370 entry
->name
= strdup(value
);
371 } else if (strcmp(key
, "Exec") == 0) {
372 entry
->exec
= strdup(value
);
373 } else if (strcmp(key
, "Icon") == 0) {
374 //TODO use UTF-8 capable strdup
375 entry
->icon
= strdup(value
);
381 // entry->name, entry->icon, entry->exec will never be empty strings (can be NULL though)
383 expand_exec(entry
, path
);
388 void test_launcher_read_desktop_file()
391 launcher_read_desktop_file("/usr/share/applications/firefox.desktop", &entry
);
392 printf("Name:%s Icon:%s Exec:%s\n", entry
.name
, entry
.icon
, entry
.exec
);
395 IconTheme
*load_theme(char *name
)
398 // Look for name/index.theme in $HOME/.icons, /usr/share/icons, /usr/share/pixmaps (stop at the first found)
399 // Parse index.theme -> list of IconThemeDir with attributes
400 // Return IconTheme struct
404 // Populates the icon_themes list
405 void launcher_load_themes()
407 //TODO load the user theme, all the inherited themes recursively (DFS), and the hicolor theme
408 // avoid inheritance loops
411 // Returns the full path to an icon file (or NULL) given the icon name
412 char *icon_path(const char *name
)
417 // Stage 1: exact size match
418 LookupIcon (iconname, size):
419 for each subdir in $(theme subdir list) { // <---- each subdir in each theme
420 for each directory in $(basename list) {
421 for extension in ("png", "svg", "xpm") {
422 if DirectoryMatchesSize(subdir, size) {
423 filename = directory/$(themename)/subdirectory/iconname.extension
431 // Stage 2: best size match
432 minimal_size = MAXINT
433 for each subdir in $(theme subdir list) { // <---- each subdir in each theme
434 for each directory in $(basename list) {
435 for extension in ("png", "svg", "xpm") {
436 filename = directory/$(themename)/subdirectory/iconname.extension
437 if exist filename and DirectorySizeDistance(subdir, size) < minimal_size
438 closest_filename = filename
439 minimal_size = DirectorySizeDistance(subdir, size)
443 if closest_filename set
444 return closest_filename
446 // Stage 3: look in unthemed icons
447 for each directory in $(basename list) { // <---- $HOME/.icons, /usr/share/icons, /usr/share/pixmaps
448 for extension in ("png", "svg", "xpm") {
449 if exists directory/iconname.extension
450 return directory/iconname.extension
454 return failed icon lookup
456 // With the following helper functions:
458 DirectoryMatchesSize(subdir, iconsize):
459 read Type and size data from subdir
461 return Size == iconsize
463 return MinSize <= iconsize <= MaxSize
465 return Size - Threshold <= iconsize <= Size + Threshold
467 DirectorySizeDistance(subdir, size):
468 read Type and size data from subdir
470 return abs(Size - iconsize)
472 if iconsize < MinSize
473 return MinSize - iconsize
474 if iconsize > MaxSize
475 return iconsize - MaxSize
478 if iconsize < Size - Threshold
479 return MinSize - iconsize
480 if iconsize > Size + Threshold
481 return iconsize - MaxSize
This page took 0.056443 seconds and 5 git commands to generate.