]>
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
._resize
= resize_launcher
;
60 launcher
->area
.resize
= 1;
61 launcher
->area
.redraw
= 1;
62 launcher
->area
.on_screen
= 1;
64 if (panel_horizontal
) {
65 // panel horizonal => fixed height and posy
66 launcher
->area
.posy
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingy
;
67 launcher
->area
.height
= panel
->area
.height
- (2 * launcher
->area
.posy
);
70 // panel vertical => fixed width, height, posy and posx
71 launcher
->area
.posx
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingxlr
;
72 launcher
->area
.width
= panel
->area
.width
- (2 * panel
->area
.bg
->border
.width
) - (2 * panel
->area
.paddingy
);
77 GSList
* path
= launcher
->list_icon_paths
;
78 GSList
* cmd
= launcher
->list_cmds
;
79 while (path
!= NULL
&& cmd
!= NULL
)
81 LauncherIcon
*launcherIcon
= malloc(sizeof(LauncherIcon
));
82 launcherIcon
->icon
= imlib_load_image(path
->data
);
83 launcherIcon
->cmd
= strdup(cmd
->data
);
84 launcher
->list_icons
= g_slist_append(launcher
->list_icons
, launcherIcon
);
85 path
= g_slist_next(path
);
86 cmd
= g_slist_next(cmd
);
92 void cleanup_launcher()
96 for (i
= 0 ; i
< nb_panel
; i
++) {
97 Panel
*panel
= &panel1
[i
];
98 Launcher
*launcher
= &panel
->launcher
;
99 free_area(&launcher
->area
);
101 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
102 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
103 if (launcherIcon
&& launcherIcon
->icon
) {
104 imlib_context_set_image (launcherIcon
->icon
);
107 free(launcherIcon
->cmd
);
110 g_slist_free(launcher
->list_icons
);
111 for (l
= launcher
->list_icon_paths
; l
; l
= l
->next
) {
114 g_slist_free(launcher
->list_icon_paths
);
115 for (l
= launcher
->list_cmds
; l
; l
= l
->next
) {
118 g_slist_free(launcher
->list_cmds
);
120 launcher_enabled
= 0;
123 void resize_launcher(void *obj
)
125 Launcher
*launcher
= obj
;
126 Panel
*panel
= launcher
->area
.panel
;
128 int count
, icon_size
;
129 int icons_per_column
=1, icons_per_row
=1, marging
=0;
131 if (panel_horizontal
)
132 icon_size
= launcher
->area
.height
;
134 icon_size
= launcher
->area
.width
;
135 icon_size
= icon_size
- (2 * launcher
->area
.bg
->border
.width
) - (2 * launcher
->area
.paddingy
);
136 if (launcher_max_icon_size
> 0 && icon_size
> launcher_max_icon_size
)
137 icon_size
= launcher_max_icon_size
;
140 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
144 if (panel_horizontal
) {
145 if (!count
) launcher
->area
.width
= 0;
147 int height
= launcher
->area
.height
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
148 // here icons_per_column always higher than 0
149 icons_per_column
= (height
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
150 marging
= height
- (icons_per_column
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
151 icons_per_row
= count
/ icons_per_column
+ (count%icons_per_column
!= 0);
152 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
);
155 launcher
->area
.posx
= panel
->area
.bg
->border
.width
+ panel
->area
.paddingxlr
;
156 launcher
->area
.posy
= panel
->area
.bg
->border
.width
;
159 if (!count
) launcher
->area
.height
= 0;
161 int width
= launcher
->area
.width
- 2*launcher
->area
.bg
->border
.width
- 2*launcher
->area
.paddingy
;
162 // here icons_per_row always higher than 0
163 icons_per_row
= (width
+launcher
->area
.paddingx
) / (icon_size
+launcher
->area
.paddingx
);
164 marging
= width
- (icons_per_row
-1)*(icon_size
+launcher
->area
.paddingx
) - icon_size
;
165 icons_per_column
= count
/ icons_per_row
+ (count%icons_per_row
!= 0);
166 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
);
169 launcher
->area
.posx
= panel
->area
.bg
->border
.width
;
170 launcher
->area
.posy
= panel
->area
.height
- panel
->area
.bg
->border
.width
- panel
->area
.paddingxlr
- launcher
->area
.height
;
174 int start
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingy
;// +marging/2;
175 if (panel_horizontal
) {
177 posx
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
181 posy
= launcher
->area
.bg
->border
.width
+ launcher
->area
.paddingxlr
;
184 for (i
=1, l
= launcher
->list_icons
; l
; i
++, l
= l
->next
) {
185 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
187 launcherIcon
->y
= posy
;
188 launcherIcon
->x
= posx
;
189 launcherIcon
->width
= icon_size
;
190 launcherIcon
->height
= icon_size
;
191 if (panel_horizontal
) {
192 if (i
% icons_per_column
)
193 posy
+= icon_size
+ launcher
->area
.paddingx
;
196 posx
+= (icon_size
+ launcher
->area
.paddingx
);
200 if (i
% icons_per_row
)
201 posx
+= icon_size
+ launcher
->area
.paddingx
;
204 posy
+= (icon_size
+ launcher
->area
.paddingx
);
209 // resize force the redraw
210 launcher
->area
.redraw
= 1;
214 void draw_launcher(void *obj
, cairo_t
*c
)
216 Launcher
*launcher
= obj
;
218 if (launcher
->list_icons
== 0) return;
220 for (l
= launcher
->list_icons
; l
; l
= l
->next
) {
221 LauncherIcon
*launcherIcon
= (LauncherIcon
*)l
->data
;
222 int pos_x
= launcherIcon
->x
;
223 int pos_y
= launcherIcon
->y
;
224 int width
= launcherIcon
->width
;
225 int height
= launcherIcon
->height
;
226 Imlib_Image icon_scaled
;
227 if (launcherIcon
->icon
) {
228 imlib_context_set_image (launcherIcon
->icon
);
229 icon_scaled
= imlib_create_cropped_scaled_image(0, 0, imlib_image_get_width(), imlib_image_get_height(), width
, height
);
231 icon_scaled
= imlib_create_image(width
, height
);
232 imlib_context_set_image (icon_scaled
);
233 imlib_context_set_color(255, 255, 255, 255);
234 imlib_image_fill_rectangle(0, 0, width
, height
);
238 imlib_context_set_image (icon_scaled
);
239 if (server
.real_transparency
) {
240 render_image(launcher
->area
.pix
, pos_x
, pos_y
, imlib_image_get_width(), imlib_image_get_height() );
243 imlib_context_set_drawable(launcher
->area
.pix
);
244 imlib_render_image_on_drawable (pos_x
, pos_y
);
250 void launcher_action(LauncherIcon
*icon
)
252 char *cmd
= malloc(strlen(icon
->cmd
) + 10);
253 sprintf(cmd
, "(%s&)", icon
->cmd
);
258 /***************** Freedesktop app.desktop and icon theme handling *********************/
259 /* http://standards.freedesktop.org/desktop-entry-spec/ */
260 /* http://standards.freedesktop.org/icon-theme-spec/ */
262 int parse_dektop_line(char *line
, char **key
, char **value
)
267 for (p
= line
; *p
; p
++) {
277 if (found
&& (strlen(*key
) == 0 || strlen(*value
) == 0))
282 void expand_exec(DesktopEntry
*entry
, const char *path
)
289 char *exec2
= malloc(strlen(entry
->exec
) + strlen(entry
->name
) + strlen(entry
->icon
) + 100);
291 // p will never point to an escaped char
292 for (p
= entry
->exec
, q
= exec2
; *p
; p
++, q
++) {
296 // Copy the escaped char
297 if (*p
== '%') // For % we delete the backslash, i.e. write % over it
306 if (*p
== 'i' && entry
->icon
!= NULL
) {
307 sprintf(q
, "--icon '%s'", entry
->icon
);
308 q
+= strlen("--icon ''");
309 q
+= strlen(entry
->icon
);
310 q
--; // To balance the q++ in the for
311 } else if (*p
== 'c' && entry
->name
!= NULL
) {
312 sprintf(q
, "'%s'", entry
->name
);
314 q
+= strlen(entry
->name
);
315 q
--; // To balance the q++ in the for
316 } else if (*p
== 'c') {
317 sprintf(q
, "'%s'", path
);
320 q
--; // To balance the q++ in the for
322 // We don't care about other expansions
323 q
--; // Delete the last % from q
334 int launcher_read_desktop_file(const char *path
, DesktopEntry
*entry
)
341 entry
->name
= entry
->icon
= entry
->exec
= NULL
;
343 if ((fp
= fopen(path
, "r")) == NULL
) {
344 fprintf(stderr
, "Could not open file %s\n", path
);
349 while (fgets(buffer
, sizeof(line
) - (buffer
- line
), fp
) != NULL
) {
350 //TODO use UTF8 capable strlen
351 int len
= strlen(buffer
);
352 int total_len
= strlen(line
);
353 if (!g_utf8_validate(buffer
, total_len
, NULL
)) {
354 // Not a real newline, read more
356 if (sizeof(line
) - (buffer
- line
) < 2) {
357 fprintf(stderr
, "%s %d: line too long (%s)\n", __FILE__
, __LINE__
, path
);
363 // We have a valid line
364 buffer
[len
-1] = '\0';
366 if (parse_dektop_line(line
, &key
, &value
)) {
367 if (strcmp(key
, "Name") == 0) {
368 //TODO use UTF-8 capable strdup
369 entry
->name
= strdup(value
);
370 } else if (strcmp(key
, "Exec") == 0) {
371 entry
->exec
= strdup(value
);
372 } else if (strcmp(key
, "Icon") == 0) {
373 //TODO use UTF-8 capable strdup
374 entry
->icon
= strdup(value
);
380 // entry->name, entry->icon, entry->exec will never be empty strings (can be NULL though)
382 expand_exec(entry
, path
);
387 void test_launcher_read_desktop_file()
390 launcher_read_desktop_file("/usr/share/applications/firefox.desktop", &entry
);
391 printf("Name:%s Icon:%s Exec:%s\n", entry
.name
, entry
.icon
, entry
.exec
);
394 IconTheme
*load_theme(char *name
)
397 // Look for name/index.theme in $HOME/.icons, /usr/share/icons, /usr/share/pixmaps (stop at the first found)
398 // Parse index.theme -> list of IconThemeDir with attributes
399 // Return IconTheme struct
403 // Populates the icon_themes list
404 void launcher_load_themes()
406 //TODO load the user theme, all the inherited themes recursively (DFS), and the hicolor theme
407 // avoid inheritance loops
410 // Returns the full path to an icon file (or NULL) given the icon name
411 char *icon_path(const char *name
)
416 // Stage 1: exact size match
417 LookupIcon (iconname, size):
418 for each subdir in $(theme subdir list) { // <---- each subdir in each theme
419 for each directory in $(basename list) {
420 for extension in ("png", "svg", "xpm") {
421 if DirectoryMatchesSize(subdir, size) {
422 filename = directory/$(themename)/subdirectory/iconname.extension
430 // Stage 2: best size match
431 minimal_size = MAXINT
432 for each subdir in $(theme subdir list) { // <---- each subdir in each theme
433 for each directory in $(basename list) {
434 for extension in ("png", "svg", "xpm") {
435 filename = directory/$(themename)/subdirectory/iconname.extension
436 if exist filename and DirectorySizeDistance(subdir, size) < minimal_size
437 closest_filename = filename
438 minimal_size = DirectorySizeDistance(subdir, size)
442 if closest_filename set
443 return closest_filename
445 // Stage 3: look in unthemed icons
446 for each directory in $(basename list) { // <---- $HOME/.icons, /usr/share/icons, /usr/share/pixmaps
447 for extension in ("png", "svg", "xpm") {
448 if exists directory/iconname.extension
449 return directory/iconname.extension
453 return failed icon lookup
455 // With the following helper functions:
457 DirectoryMatchesSize(subdir, iconsize):
458 read Type and size data from subdir
460 return Size == iconsize
462 return MinSize <= iconsize <= MaxSize
464 return Size - Threshold <= iconsize <= Size + Threshold
466 DirectorySizeDistance(subdir, size):
467 read Type and size data from subdir
469 return abs(Size - iconsize)
471 if iconsize < MinSize
472 return MinSize - iconsize
473 if iconsize > MaxSize
474 return iconsize - MaxSize
477 if iconsize < Size - Threshold
478 return MinSize - iconsize
479 if iconsize > Size + Threshold
480 return iconsize - MaxSize
This page took 0.056821 seconds and 5 git commands to generate.