1 /* $Id$ */
2 /* Copyright (c) 2007-2015 Pierre Pronchery <khorben@defora.org> */
3 /* This file is part of DeforaOS Desktop Browser */
4 /* Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the authors nor the names of the contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* TODO:
30 * - let the user define the desktop folder (possibly default to FDO's)
31 * - track multiple selection on delete/properties
32 * - avoid code duplication with DeforaOS Panel ("main" applet) */
33
34
35
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <dirent.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <locale.h>
46 #include <libintl.h>
47 #include <X11/Xlib.h>
48 #include <gtk/gtk.h>
49 #include <gdk/gdkx.h>
50 #include <X11/Xatom.h>
51 #include <X11/extensions/Xrandr.h>
52 #include <System.h>
53 #include "../include/Browser/desktop.h"
54 #include "../include/Browser/vfs.h"
55 #include "desktop.h"
56 #include "../config.h"
57 #define _(string) gettext(string)
58 #define N_(string) string
59
60 #define COMMON_SYMLINK
61 #include "common.c"
62
63
64 /* constants */
65 #ifndef PROGNAME
66 # define PROGNAME "desktop"
67 #endif
68 #ifndef PREFIX
69 # define PREFIX "/usr/local"
70 #endif
71 #ifndef DATADIR
72 # define DATADIR PREFIX "/share"
73 #endif
74 #ifndef LOCALEDIR
75 # define LOCALEDIR DATADIR "/locale"
76 #endif
77
78
79 /* Desktop */
80 /* private */
81 /* types */
82 typedef struct _DesktopCategory DesktopCategory;
83
84 struct _Desktop
85 {
86 DesktopPrefs prefs;
87 PangoFontDescription * font;
88 #if GTK_CHECK_VERSION(3, 0, 0)
89 GdkRGBA background;
90 GdkRGBA foreground;
91 #else
92 GdkColor background;
93 GdkColor foreground;
94 #endif
95
96 /* workarea */
97 GdkRectangle window;
98 GdkRectangle workarea;
99
100 /* icons */
101 DesktopIcon ** icon;
102 size_t icon_cnt;
103
104 /* common */
105 char * path;
106 size_t path_cnt;
107 DIR * refresh_dir;
108 time_t refresh_mti;
109 guint refresh_source;
110 /* files */
111 Mime * mime;
112 char const * home;
113 GdkPixbuf * file;
114 GdkPixbuf * folder;
115 gboolean show_hidden;
116 /* applications */
117 DesktopCategory * category;
118 /* categories */
119 GSList * apps;
120
121 /* preferences */
122 GtkWidget * pr_window;
123 GtkWidget * pr_color;
124 GtkWidget * pr_background;
125 GtkWidget * pr_background_how;
126 GtkWidget * pr_background_extend;
127 GtkWidget * pr_ilayout;
128 GtkWidget * pr_imonitor;
129 GtkWidget * pr_ibcolor;
130 GtkWidget * pr_ifcolor;
131 GtkWidget * pr_ifont;
132 GtkWidget * pr_monitors;
133 GtkWidget * pr_monitors_res;
134 GtkWidget * pr_monitors_size;
135
136 /* internal */
137 GdkScreen * screen;
138 GdkDisplay * display;
139 GdkWindow * root;
140 GtkWidget * desktop;
141 GdkWindow * back;
142 GtkIconTheme * theme;
143 GtkWidget * menu;
144 #if GTK_CHECK_VERSION(3, 0, 0)
145 cairo_t * cairo;
146 #else
147 GdkPixmap * pixmap;
148 #endif
149 };
150
151 struct _DesktopCategory
152 {
153 gboolean show;
154 char const * category;
155 char const * name;
156 char const * icon;
157 };
158
159 typedef enum _DesktopHows
160 {
161 DESKTOP_HOW_NONE = 0,
162 DESKTOP_HOW_CENTERED,
163 DESKTOP_HOW_SCALED,
164 DESKTOP_HOW_SCALED_RATIO,
165 DESKTOP_HOW_TILED
166 } DesktopHows;
167 #define DESKTOP_HOW_LAST DESKTOP_HOW_TILED
168 #define DESKTOP_HOW_COUNT (DESKTOP_HOW_LAST + 1)
169
170
171 /* constants */
172 #define DESKTOP ".desktop"
173 #define DESKTOPRC ".desktoprc"
174
175 static DesktopCategory _desktop_categories[] =
176 {
177 { FALSE, "Audio", "Audio", "gnome-mime-audio", },
178 { FALSE, "Development", "Development", "applications-development"},
179 { FALSE, "Education", "Education", "applications-science" },
180 { FALSE, "Game", "Games", "applications-games" },
181 { FALSE, "Graphics", "Graphics", "applications-graphics" },
182 { FALSE, "AudioVideo", "Multimedia", "applications-multimedia"},
183 { FALSE, "Network", "Network", "applications-internet" },
184 { FALSE, "Office", "Office", "applications-office" },
185 { FALSE, "Settings", "Settings", "gnome-settings" },
186 { FALSE, "System", "System", "applications-system" },
187 { FALSE, "Utility", "Utilities", "applications-utilities"},
188 { FALSE, "Video", "Video", "video" }
189 };
190 static const size_t _desktop_categories_cnt = sizeof(_desktop_categories)
191 / sizeof(*_desktop_categories);
192
193 static const char * _desktop_hows[DESKTOP_HOW_COUNT] =
194 {
195 "none",
196 "centered",
197 "scaled",
198 "scaled_ratio",
199 "tiled"
200 };
201
202 static const char * _desktop_icons_config[DESKTOP_ICONS_COUNT] =
203 {
204 "none", "applications", "categories", "files", "homescreen"
205 };
206
207 static const char * _desktop_icons[DESKTOP_ICONS_COUNT] =
208 {
209 N_("Do not draw icons"),
210 N_("Applications"),
211 N_("Categories"),
212 N_("Desktop contents"),
213 N_("Home screen")
214 };
215
216
217 /* prototypes */
218 static int _desktop_error(Desktop * desktop, char const * message,
219 char const * error, int ret);
220 static int _desktop_serror(Desktop * desktop, char const * message, int ret);
221
222 /* accessors */
223 static Config * _desktop_get_config(Desktop * desktop);
224 static int _desktop_get_workarea(Desktop * desktop);
225
226 /* useful */
227 #if GTK_CHECK_VERSION(3, 0, 0)
228 static void _desktop_draw_background(Desktop * desktop, GdkRGBA * color,
229 char const * filename, DesktopHows how, gboolean extend);
230 #else
231 static void _desktop_draw_background(Desktop * desktop, GdkColor * color,
232 char const * filename, DesktopHows how, gboolean extend);
233 #endif
234
235 static int _desktop_icon_add(Desktop * desktop, DesktopIcon * icon);
236 static int _desktop_icon_remove(Desktop * desktop, DesktopIcon * icon);
237
238 static void _desktop_show_preferences(Desktop * desktop);
239
240 /* callbacks */
241 static gboolean _desktop_on_refresh(gpointer data);
242
243
244 /* public */
245 /* functions */
246 /* desktop_new */
247 /* callbacks */
248 static void _new_events(Desktop * desktop, GdkWindow * window,
249 GdkEventMask mask);
250 static void _new_icons(Desktop * desktop);
251 static int _on_message(void * data, uint32_t value1, uint32_t value2,
252 uint32_t value3);
253 static void _on_popup(gpointer data);
254 static void _on_popup_event(gpointer data, XButtonEvent * xbev);
255 static void _on_realize(gpointer data);
256 static GdkFilterReturn _on_root_event(GdkXEvent * xevent, GdkEvent * event,
257 gpointer data);
258
desktop_new(DesktopPrefs * prefs)259 Desktop * desktop_new(DesktopPrefs * prefs)
260 {
261 Desktop * desktop;
262 #if !GTK_CHECK_VERSION(2, 24, 0)
263 gint depth;
264 #endif
265 GdkEventMask mask = GDK_PROPERTY_CHANGE_MASK;
266
267 if((desktop = object_new(sizeof(*desktop))) == NULL)
268 return NULL;
269 memset(desktop, 0, sizeof(*desktop));
270 /* set default foreground to white */
271 memset(&desktop->foreground, 0xff, sizeof(desktop->foreground));
272 desktop->prefs.alignment = DESKTOP_ALIGNMENT_VERTICAL;
273 desktop->prefs.icons = DESKTOP_ICONS_FILES;
274 desktop->prefs.monitor = -1;
275 if(prefs != NULL)
276 desktop->prefs = *prefs;
277 desktop->font = NULL;
278 /* workarea */
279 desktop->screen = gdk_screen_get_default();
280 desktop->display = gdk_screen_get_display(desktop->screen);
281 desktop->root = gdk_screen_get_root_window(desktop->screen);
282 desktop->theme = gtk_icon_theme_get_default();
283 desktop->menu = NULL;
284 if((desktop->home = getenv("HOME")) == NULL
285 && (desktop->home = g_get_home_dir()) == NULL)
286 desktop->home = "/";
287 desktop_message_register(NULL, DESKTOP_CLIENT_MESSAGE, _on_message,
288 desktop);
289 /* query the root window */
290 #if GTK_CHECK_VERSION(2, 24, 0)
291 gdk_window_get_position(desktop->root, &desktop->window.x,
292 &desktop->window.y);
293 desktop->window.width = gdk_window_get_width(desktop->root);
294 desktop->window.height = gdk_window_get_height(desktop->root);
295 #else
296 gdk_window_get_geometry(desktop->root, &desktop->window.x,
297 &desktop->window.y, &desktop->window.width,
298 &desktop->window.height, &depth);
299 #endif
300 if(desktop->prefs.window)
301 {
302 /* create the desktop window */
303 desktop->desktop = gtk_window_new(GTK_WINDOW_TOPLEVEL);
304 gtk_window_set_default_size(GTK_WINDOW(desktop->desktop),
305 desktop->window.width, desktop->window.height);
306 gtk_window_set_type_hint(GTK_WINDOW(desktop->desktop),
307 GDK_WINDOW_TYPE_HINT_DESKTOP);
308 /* support pop-up menus on the desktop window if enabled */
309 if(desktop->prefs.popup)
310 g_signal_connect_swapped(desktop->desktop, "popup-menu",
311 G_CALLBACK(_on_popup), desktop);
312 /* draw the icons and background when realized */
313 g_signal_connect_swapped(desktop->desktop, "realize",
314 G_CALLBACK(_on_realize), desktop);
315 gtk_window_move(GTK_WINDOW(desktop->desktop), desktop->window.x,
316 desktop->window.y);
317 gtk_widget_show(desktop->desktop);
318 }
319 else
320 {
321 desktop->desktop = NULL;
322 desktop->back = desktop->root;
323 /* draw the icons and background when idle */
324 desktop_reset(desktop);
325 /* support pop-up menus on the root window if enabled */
326 if(desktop->prefs.popup)
327 mask |= GDK_BUTTON_PRESS_MASK;
328 }
329 /* manage events on the root window */
330 _new_events(desktop, desktop->root, mask);
331 /* load the default icons */
332 _new_icons(desktop);
333 return desktop;
334 }
335
_new_events(Desktop * desktop,GdkWindow * window,GdkEventMask mask)336 static void _new_events(Desktop * desktop, GdkWindow * window,
337 GdkEventMask mask)
338 {
339 mask = gdk_window_get_events(window) | mask;
340 gdk_window_set_events(window, mask);
341 gdk_window_add_filter(window, _on_root_event, desktop);
342 }
343
_new_icons(Desktop * desktop)344 static void _new_icons(Desktop * desktop)
345 {
346 const char * file[] = { "gnome-fs-regular",
347 #if GTK_CHECK_VERSION(2, 6, 0)
348 GTK_STOCK_FILE,
349 #endif
350 GTK_STOCK_MISSING_IMAGE, NULL };
351 const char * folder[] = { "gnome-fs-directory",
352 #if GTK_CHECK_VERSION(2, 6, 0)
353 GTK_STOCK_DIRECTORY,
354 #endif
355 GTK_STOCK_MISSING_IMAGE, NULL };
356 char const ** p;
357
358 for(p = file; *p != NULL && desktop->file == NULL; p++)
359 desktop->file = gtk_icon_theme_load_icon(desktop->theme,
360 *p, DESKTOPICON_ICON_SIZE, 0, NULL);
361 for(p = folder; *p != NULL && desktop->folder == NULL; p++)
362 desktop->folder = gtk_icon_theme_load_icon(desktop->theme, *p,
363 DESKTOPICON_ICON_SIZE, 0, NULL);
364 }
365
_on_message(void * data,uint32_t value1,uint32_t value2,uint32_t value3)366 static int _on_message(void * data, uint32_t value1, uint32_t value2,
367 uint32_t value3)
368 {
369 Desktop * desktop = data;
370 DesktopMessage message;
371 DesktopAlignment alignment;
372 DesktopIcons icons;
373 DesktopLayout layout;
374
375 switch((message = value1))
376 {
377 case DESKTOP_MESSAGE_SET_ALIGNMENT:
378 alignment = value2;
379 desktop_set_alignment(desktop, alignment);
380 break;
381 case DESKTOP_MESSAGE_SET_ICONS:
382 icons = value2;
383 desktop_set_icons(desktop, icons);
384 break;
385 case DESKTOP_MESSAGE_SET_LAYOUT:
386 layout = value2;
387 desktop_set_layout(desktop, layout);
388 break;
389 case DESKTOP_MESSAGE_SHOW:
390 if(value2 == DESKTOP_SHOW_SETTINGS)
391 _desktop_show_preferences(desktop);
392 break;
393 }
394 return GDK_FILTER_CONTINUE;
395 }
396
397 static void _on_popup_new_folder(gpointer data);
398 static void _on_popup_new_text_file(gpointer data);
399 static void _on_popup_paste(gpointer data);
400 static void _on_popup_preferences(gpointer data);
401 static void _on_popup_symlink(gpointer data);
402
_on_popup(gpointer data)403 static void _on_popup(gpointer data)
404 {
405 Desktop * desktop = data;
406
407 _on_popup_event(desktop, NULL);
408 }
409
_on_popup_event(gpointer data,XButtonEvent * xbev)410 static void _on_popup_event(gpointer data, XButtonEvent * xbev)
411 {
412 Desktop * desktop = data;
413 GtkWidget * menuitem;
414 GtkWidget * submenu;
415 GtkWidget * image;
416
417 desktop->menu = gtk_menu_new();
418 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
419 submenu = gtk_menu_new();
420 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
421 gtk_menu_shell_append(GTK_MENU_SHELL(desktop->menu), menuitem);
422 /* submenu for new documents */
423 menuitem = gtk_image_menu_item_new_with_label(_("Folder"));
424 image = gtk_image_new_from_icon_name("folder-new", GTK_ICON_SIZE_MENU);
425 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
426 g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(
427 _on_popup_new_folder), desktop);
428 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
429 menuitem = gtk_separator_menu_item_new();
430 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
431 menuitem = gtk_image_menu_item_new_with_label(_("Symbolic link..."));
432 g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(
433 _on_popup_symlink), desktop);
434 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
435 menuitem = gtk_image_menu_item_new_with_label(_("Text file"));
436 image = gtk_image_new_from_icon_name("stock_new-text",
437 GTK_ICON_SIZE_MENU);
438 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
439 g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(
440 _on_popup_new_text_file), desktop);
441 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
442 /* edition */
443 menuitem = gtk_separator_menu_item_new();
444 gtk_menu_shell_append(GTK_MENU_SHELL(desktop->menu), menuitem);
445 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_PASTE, NULL);
446 g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(
447 _on_popup_paste), desktop);
448 gtk_menu_shell_append(GTK_MENU_SHELL(desktop->menu), menuitem);
449 /* preferences */
450 menuitem = gtk_separator_menu_item_new();
451 gtk_menu_shell_append(GTK_MENU_SHELL(desktop->menu), menuitem);
452 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES,
453 NULL);
454 g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(
455 _on_popup_preferences), desktop);
456 gtk_menu_shell_append(GTK_MENU_SHELL(desktop->menu), menuitem);
457 gtk_widget_show_all(desktop->menu);
458 gtk_menu_popup(GTK_MENU(desktop->menu), NULL, NULL, NULL, NULL, 3,
459 (xbev != NULL)
460 ? xbev->time : gtk_get_current_event_time());
461 }
462
_on_popup_new_folder(gpointer data)463 static void _on_popup_new_folder(gpointer data)
464 {
465 static char const newfolder[] = N_("New folder");
466 Desktop * desktop = data;
467 String * path;
468
469 gtk_widget_destroy(desktop->menu);
470 desktop->menu = NULL;
471 if((path = string_new_append(desktop->path, "/", newfolder, NULL))
472 == NULL)
473 {
474 _desktop_serror(desktop, newfolder, 0);
475 return;
476 }
477 if(mkdir(path, 0777) != 0)
478 desktop_error(desktop, path, 0);
479 string_delete(path);
480 }
481
_on_popup_new_text_file(gpointer data)482 static void _on_popup_new_text_file(gpointer data)
483 {
484 static char const newtext[] = N_("New text file.txt");
485 Desktop * desktop = data;
486 String * path;
487 int fd;
488
489 gtk_widget_destroy(desktop->menu);
490 desktop->menu = NULL;
491 if((path = string_new_append(desktop->path, "/", _(newtext), NULL))
492 == NULL)
493 {
494 _desktop_serror(desktop, _(newtext), 0);
495 return;
496 }
497 if((fd = creat(path, 0666)) < 0)
498 desktop_error(desktop, path, 0);
499 else
500 close(fd);
501 string_delete(path);
502 }
503
_on_popup_paste(gpointer data)504 static void _on_popup_paste(gpointer data)
505 {
506 Desktop * desktop = data;
507
508 /* FIXME implement */
509 gtk_widget_destroy(desktop->menu);
510 desktop->menu = NULL;
511 }
512
_on_popup_preferences(gpointer data)513 static void _on_popup_preferences(gpointer data)
514 {
515 Desktop * desktop = data;
516
517 _desktop_show_preferences(desktop);
518 }
519
_on_popup_symlink(gpointer data)520 static void _on_popup_symlink(gpointer data)
521 {
522 Desktop * desktop = data;
523
524 if(_common_symlink(NULL, desktop->path) != 0)
525 desktop_error(desktop, "symlink", 0);
526 }
527
_on_realize(gpointer data)528 static void _on_realize(gpointer data)
529 {
530 Desktop * desktop = data;
531 GdkEventMask mask = desktop->prefs.popup ? GDK_BUTTON_PRESS_MASK : 0;
532
533 #if GTK_CHECK_VERSION(2, 14, 0)
534 desktop->back = gtk_widget_get_window(desktop->desktop);
535 #else
536 desktop->back = desktop->desktop->window;
537 #endif
538 /* support pop-up menus on the desktop window if enabled */
539 if(mask != 0)
540 _new_events(desktop, desktop->back, mask);
541 desktop_reset(desktop);
542 }
543
544 static GdkFilterReturn _event_button_press(XButtonEvent * xbev,
545 Desktop * desktop);
546 static GdkFilterReturn _event_configure(XConfigureEvent * xevent,
547 Desktop * desktop);
548 static GdkFilterReturn _event_property(XPropertyEvent * xevent,
549 Desktop * desktop);
550
_on_root_event(GdkXEvent * xevent,GdkEvent * event,gpointer data)551 static GdkFilterReturn _on_root_event(GdkXEvent * xevent, GdkEvent * event,
552 gpointer data)
553 {
554 Desktop * desktop = data;
555 XEvent * xev = xevent;
556
557 if(xev->type == ButtonPress)
558 return _event_button_press(xevent, desktop);
559 else if(xev->type == ConfigureNotify)
560 return _event_configure(xevent, desktop);
561 else if(xev->type == PropertyNotify)
562 return _event_property(xevent, desktop);
563 #ifdef DEBUG
564 fprintf(stderr, "DEBUG: %s() %d\n", __func__, xev->type);
565 #endif
566 return GDK_FILTER_CONTINUE;
567 }
568
_event_button_press(XButtonEvent * xbev,Desktop * desktop)569 static GdkFilterReturn _event_button_press(XButtonEvent * xbev,
570 Desktop * desktop)
571 {
572 if(xbev->button != 3 || desktop->menu != NULL)
573 {
574 if(desktop->menu != NULL)
575 {
576 gtk_widget_destroy(desktop->menu);
577 desktop->menu = NULL;
578 }
579 return GDK_FILTER_CONTINUE;
580 }
581 /* ignore if not managing files */
582 if(desktop->prefs.icons != DESKTOP_ICONS_FILES)
583 return GDK_FILTER_CONTINUE;
584 _on_popup_event(desktop, xbev);
585 return GDK_FILTER_CONTINUE;
586 }
587
_event_configure(XConfigureEvent * xevent,Desktop * desktop)588 static GdkFilterReturn _event_configure(XConfigureEvent * xevent,
589 Desktop * desktop)
590 {
591 desktop->window.x = xevent->x;
592 desktop->window.y = xevent->y;
593 desktop->window.width = xevent->width;
594 desktop->window.height = xevent->height;
595 #ifdef DEBUG
596 fprintf(stderr, "DEBUG: %s() (%dx%d) @ (%d,%d))\n", __func__,
597 desktop->window.width, desktop->window.height,
598 desktop->window.x, desktop->window.y);
599 #endif
600 /* FIXME run it directly? */
601 desktop_reset(desktop);
602 return GDK_FILTER_CONTINUE;
603 }
604
_event_property(XPropertyEvent * xevent,Desktop * desktop)605 static GdkFilterReturn _event_property(XPropertyEvent * xevent,
606 Desktop * desktop)
607 {
608 Atom atom;
609
610 atom = gdk_x11_get_xatom_by_name("_NET_WORKAREA");
611 if(xevent->atom != atom)
612 return GDK_FILTER_CONTINUE;
613 _desktop_get_workarea(desktop);
614 return GDK_FILTER_CONTINUE;
615 }
616
617
618 /* desktop_delete */
desktop_delete(Desktop * desktop)619 void desktop_delete(Desktop * desktop)
620 {
621 size_t i;
622
623 if(desktop->desktop != NULL)
624 gtk_widget_destroy(desktop->desktop);
625 if(desktop->refresh_source != 0)
626 g_source_remove(desktop->refresh_source);
627 for(i = 0; i < desktop->icon_cnt; i++)
628 desktopicon_delete(desktop->icon[i]);
629 free(desktop->icon);
630 if(desktop->mime != NULL)
631 mime_delete(desktop->mime);
632 g_slist_foreach(desktop->apps, (GFunc)config_delete, NULL);
633 g_slist_free(desktop->apps);
634 free(desktop->path);
635 if(desktop->font != NULL)
636 pango_font_description_free(desktop->font);
637 object_delete(desktop);
638 }
639
640
641 /* accessors */
642 /* desktop_get_drag_data */
desktop_get_drag_data(Desktop * desktop,GtkSelectionData * seldata)643 int desktop_get_drag_data(Desktop * desktop, GtkSelectionData * seldata)
644 {
645 #if !GTK_CHECK_VERSION(3, 0, 0)
646 int ret = 0;
647 size_t i;
648 size_t len;
649 char const * path;
650 unsigned char * p;
651
652 seldata->format = 0;
653 seldata->data = NULL;
654 seldata->length = 0;
655 for(i = 0; i < desktop->icon_cnt; i++)
656 {
657 if(desktopicon_get_selected(desktop->icon[i]) != TRUE)
658 continue;
659 if((path = desktopicon_get_path(desktop->icon[i])) == NULL)
660 continue;
661 len = strlen(path + 1);
662 if((p = realloc(seldata->data, seldata->length + len)) == NULL)
663 {
664 ret = -error_set_code(1, "%s", strerror(errno));
665 continue;
666 }
667 seldata->data = p;
668 memcpy(&p[seldata->length], path, len);
669 seldata->length += len;
670 }
671 return ret;
672 #else
673 return -1;
674 #endif
675 }
676
677
678 /* desktop_get_file */
desktop_get_file(Desktop * desktop)679 GdkPixbuf * desktop_get_file(Desktop * desktop)
680 {
681 g_object_ref(desktop->file);
682 return desktop->file;
683 }
684
685
686 /* desktop_get_folder */
desktop_get_folder(Desktop * desktop)687 GdkPixbuf * desktop_get_folder(Desktop * desktop)
688 {
689 g_object_ref(desktop->folder);
690 return desktop->folder;
691 }
692
693
694 /* desktop_get_mime */
desktop_get_mime(Desktop * desktop)695 Mime * desktop_get_mime(Desktop * desktop)
696 {
697 return desktop->mime;
698 }
699
700
701 /* desktop_get_theme */
desktop_get_theme(Desktop * desktop)702 GtkIconTheme * desktop_get_theme(Desktop * desktop)
703 {
704 return desktop->theme;
705 }
706
707
708 /* desktop_set_alignment */
709 static void _alignment_horizontal(Desktop * desktop);
710 static void _alignment_vertical(Desktop * desktop);
711
desktop_set_alignment(Desktop * desktop,DesktopAlignment alignment)712 void desktop_set_alignment(Desktop * desktop, DesktopAlignment alignment)
713 {
714 switch(alignment)
715 {
716 case DESKTOP_ALIGNMENT_VERTICAL:
717 _alignment_vertical(desktop);
718 break;
719 case DESKTOP_ALIGNMENT_HORIZONTAL:
720 _alignment_horizontal(desktop);
721 break;
722 }
723 }
724
_alignment_horizontal(Desktop * desktop)725 static void _alignment_horizontal(Desktop * desktop)
726 {
727 size_t i;
728 int x = desktop->workarea.x;
729 int y = desktop->workarea.y;
730 int width = x + desktop->workarea.width;
731
732 for(i = 0; i < desktop->icon_cnt; i++)
733 {
734 if(x + DESKTOPICON_MAX_WIDTH > width)
735 {
736 y += DESKTOPICON_MAX_HEIGHT;
737 x = desktop->workarea.x;
738 }
739 desktopicon_move(desktop->icon[i], x, y);
740 x += DESKTOPICON_MAX_WIDTH;
741 }
742 }
743
_alignment_vertical(Desktop * desktop)744 static void _alignment_vertical(Desktop * desktop)
745 {
746 size_t i;
747 int x = desktop->workarea.x;
748 int y = desktop->workarea.y;
749 int height = desktop->workarea.y + desktop->workarea.height;
750
751 for(i = 0; i < desktop->icon_cnt; i++)
752 {
753 if(y + DESKTOPICON_MAX_HEIGHT > height)
754 {
755 x += DESKTOPICON_MAX_WIDTH;
756 y = desktop->workarea.y;
757 }
758 desktopicon_move(desktop->icon[i], x, y);
759 y += DESKTOPICON_MAX_HEIGHT;
760 }
761 }
762
763
764 /* desktop_set_icons */
765 static int _icons_applications(Desktop * desktop);
766 static int _icons_categories(Desktop * desktop);
767 static int _icons_files(Desktop * desktop);
768 static int _icons_files_add_home(Desktop * desktop);
769 static int _icons_homescreen(Desktop * desktop);
770 static void _icons_reset(Desktop * desktop);
771 static void _icons_set_categories(Desktop * desktop, gpointer data);
772 static void _icons_set_homescreen(Desktop * desktop, gpointer data);
773
desktop_set_icons(Desktop * desktop,DesktopIcons icons)774 void desktop_set_icons(Desktop * desktop, DesktopIcons icons)
775 {
776 _icons_reset(desktop);
777 desktop->prefs.icons = icons;
778 switch(icons)
779 {
780 case DESKTOP_ICONS_APPLICATIONS:
781 _icons_applications(desktop);
782 break;
783 case DESKTOP_ICONS_CATEGORIES:
784 _icons_categories(desktop);
785 break;
786 case DESKTOP_ICONS_FILES:
787 _icons_files(desktop);
788 break;
789 case DESKTOP_ICONS_HOMESCREEN:
790 _icons_homescreen(desktop);
791 break;
792 case DESKTOP_ICONS_NONE:
793 /* nothing to do */
794 break;
795 }
796 desktop_refresh(desktop);
797 }
798
_icons_applications(Desktop * desktop)799 static int _icons_applications(Desktop * desktop)
800 {
801 DesktopIcon * desktopicon;
802 GdkPixbuf * icon;
803
804 if(desktop->category == NULL)
805 return 0;
806 if((desktopicon = desktopicon_new(desktop, _("Back"), NULL)) == NULL)
807 return -_desktop_serror(desktop, "Back", 1);
808 desktopicon_set_callback(desktopicon, _icons_set_categories, NULL);
809 desktopicon_set_first(desktopicon, TRUE);
810 desktopicon_set_immutable(desktopicon, TRUE);
811 icon = gtk_icon_theme_load_icon(desktop->theme, "back",
812 DESKTOPICON_ICON_SIZE, 0, NULL);
813 if(icon != NULL)
814 desktopicon_set_icon(desktopicon, icon);
815 if(_desktop_icon_add(desktop, desktopicon) != 0)
816 {
817 desktopicon_delete(desktopicon);
818 return -1;
819 }
820 return 0;
821 }
822
_icons_categories(Desktop * desktop)823 static int _icons_categories(Desktop * desktop)
824 {
825 DesktopIcon * desktopicon;
826 GdkPixbuf * icon;
827
828 desktop->category = NULL;
829 if((desktopicon = desktopicon_new(desktop, _("Back"), NULL)) == NULL)
830 return -_desktop_serror(desktop, "Back", 1);
831 desktopicon_set_callback(desktopicon, _icons_set_homescreen, NULL);
832 desktopicon_set_first(desktopicon, TRUE);
833 desktopicon_set_immutable(desktopicon, TRUE);
834 icon = gtk_icon_theme_load_icon(desktop->theme, "back",
835 DESKTOPICON_ICON_SIZE, 0, NULL);
836 if(icon != NULL)
837 desktopicon_set_icon(desktopicon, icon);
838 if(_desktop_icon_add(desktop, desktopicon) != 0)
839 {
840 desktopicon_delete(desktopicon);
841 return -1;
842 }
843 return 0;
844 }
845
_icons_files(Desktop * desktop)846 static int _icons_files(Desktop * desktop)
847 {
848 const char path[] = "/" DESKTOP;
849 struct stat st;
850
851 if(desktop->mime == NULL)
852 desktop->mime = mime_new(NULL);
853 _icons_files_add_home(desktop);
854 desktop->path_cnt = strlen(desktop->home) + 1 + sizeof(path);
855 if((desktop->path = malloc(desktop->path_cnt)) == NULL)
856 return -desktop_error(NULL, "malloc", 1);
857 snprintf(desktop->path, desktop->path_cnt, "%s/%s", desktop->home,
858 path);
859 if(stat(desktop->path, &st) == 0)
860 {
861 if(!S_ISDIR(st.st_mode))
862 return _desktop_error(NULL, desktop->path,
863 strerror(ENOTDIR), 1);
864 }
865 else if(errno != ENOENT || mkdir(desktop->path, 0777) != 0)
866 return desktop_error(NULL, desktop->path, 1);
867 return 0;
868 }
869
_icons_files_add_home(Desktop * desktop)870 static int _icons_files_add_home(Desktop * desktop)
871 {
872 DesktopIcon * desktopicon;
873 GdkPixbuf * icon;
874
875 if((desktopicon = desktopicon_new(desktop, _("Home"), desktop->home))
876 == NULL)
877 return -_desktop_serror(desktop, "Home", 1);
878 desktopicon_set_first(desktopicon, TRUE);
879 desktopicon_set_immutable(desktopicon, TRUE);
880 icon = gtk_icon_theme_load_icon(desktop->theme, "gnome-home",
881 DESKTOPICON_ICON_SIZE, 0, NULL);
882 if(icon == NULL)
883 icon = gtk_icon_theme_load_icon(desktop->theme, "gnome-fs-home",
884 DESKTOPICON_ICON_SIZE, 0, NULL);
885 if(icon != NULL)
886 desktopicon_set_icon(desktopicon, icon);
887 if(_desktop_icon_add(desktop, desktopicon) != 0)
888 {
889 desktopicon_delete(desktopicon);
890 return -1;
891 }
892 return 0;
893 }
894
_icons_homescreen(Desktop * desktop)895 static int _icons_homescreen(Desktop * desktop)
896 {
897 DesktopIcon * desktopicon;
898 GdkPixbuf * icon;
899 #ifdef EMBEDDED
900 char const * paths[] =
901 {
902 DATADIR "/applications/deforaos-phone-contacts.desktop",
903 DATADIR "/applications/deforaos-phone-dialer.desktop",
904 DATADIR "/applications/deforaos-phone-messages.desktop",
905 NULL
906 };
907 char const ** p;
908 #endif
909
910 if((desktopicon = desktopicon_new(desktop, _("Applications"), NULL))
911 == NULL)
912 return _desktop_serror(desktop, "Applications", 1);
913 desktopicon_set_callback(desktopicon, _icons_set_categories, NULL);
914 desktopicon_set_immutable(desktopicon, TRUE);
915 icon = gtk_icon_theme_load_icon(desktop->theme, "gnome-applications",
916 DESKTOPICON_ICON_SIZE, 0, NULL);
917 if(icon != NULL)
918 desktopicon_set_icon(desktopicon, icon);
919 _desktop_icon_add(desktop, desktopicon);
920 #ifdef EMBEDDED
921 for(p = paths; *p != NULL; p++)
922 if(access(*p, R_OK) == 0
923 && (desktopicon = desktopicon_new_application(
924 desktop, *p, DATADIR)) != NULL)
925 _desktop_icon_add(desktop, desktopicon);
926 #endif
927 return 0;
928 }
929
_icons_reset(Desktop * desktop)930 static void _icons_reset(Desktop * desktop)
931 {
932 size_t i;
933
934 if(desktop->path != NULL)
935 free(desktop->path);
936 desktop->path = NULL;
937 desktop->path_cnt = 0;
938 for(i = 0; i < desktop->icon_cnt; i++)
939 {
940 desktopicon_set_immutable(desktop->icon[i], FALSE);
941 desktopicon_set_updated(desktop->icon[i], FALSE);
942 }
943 for(i = 0; i < _desktop_categories_cnt; i++)
944 _desktop_categories[i].show = FALSE;
945 }
946
_icons_set_categories(Desktop * desktop,gpointer data)947 static void _icons_set_categories(Desktop * desktop, gpointer data)
948 {
949 #ifdef DEBUG
950 fprintf(stderr, "DEBUG: %s()\n", __func__);
951 #endif
952 desktop_set_icons(desktop, DESKTOP_ICONS_CATEGORIES);
953 }
954
_icons_set_homescreen(Desktop * desktop,gpointer data)955 static void _icons_set_homescreen(Desktop * desktop, gpointer data)
956 {
957 #ifdef DEBUG
958 fprintf(stderr, "DEBUG: %s()\n", __func__);
959 #endif
960 desktop_set_icons(desktop, DESKTOP_ICONS_HOMESCREEN);
961 }
962
963
964 /* desktop_set_layout */
desktop_set_layout(Desktop * desktop,DesktopLayout layout)965 int desktop_set_layout(Desktop * desktop, DesktopLayout layout)
966 {
967 XRRScreenConfiguration * sc;
968 Rotation r;
969 SizeID size;
970
971 sc = XRRGetScreenInfo(GDK_DISPLAY_XDISPLAY(desktop->display),
972 GDK_WINDOW_XID(desktop->root));
973 size = XRRConfigCurrentConfiguration(sc, &r);
974 switch(layout)
975 {
976 case DESKTOP_LAYOUT_NORMAL:
977 case DESKTOP_LAYOUT_LANDSCAPE:
978 r = RR_Rotate_0;
979 break;
980 case DESKTOP_LAYOUT_PORTRAIT:
981 r = RR_Rotate_90;
982 break;
983 case DESKTOP_LAYOUT_ROTATE:
984 r <<= 1;
985 r = (r > 16) ? 1 : r;
986 break;
987 case DESKTOP_LAYOUT_TOGGLE:
988 r = (r != RR_Rotate_0) ? RR_Rotate_0 : RR_Rotate_90;
989 break;
990 }
991 gdk_error_trap_push();
992 XRRSetScreenConfig(GDK_DISPLAY_XDISPLAY(desktop->display), sc,
993 GDK_WINDOW_XID(desktop->root), size, r, CurrentTime);
994 return gdk_error_trap_pop();
995 }
996
997
998 /* useful */
999 /* desktop_error */
desktop_error(Desktop * desktop,char const * message,int ret)1000 int desktop_error(Desktop * desktop, char const * message, int ret)
1001 {
1002 /* FIXME no longer assume errno is properly set */
1003 return _desktop_error(desktop, message, strerror(errno), ret);
1004 }
1005
1006
1007 /* desktop_refresh */
1008 static void _refresh_categories(Desktop * desktop);
1009 static void _refresh_files(Desktop * desktop);
1010 static void _refresh_homescreen(Desktop * desktop);
1011
desktop_refresh(Desktop * desktop)1012 void desktop_refresh(Desktop * desktop)
1013 {
1014 #ifdef DEBUG
1015 fprintf(stderr, "DEBUG: %s()\n", __func__);
1016 #endif
1017 if(desktop->refresh_source != 0)
1018 g_source_remove(desktop->refresh_source);
1019 switch(desktop->prefs.icons)
1020 {
1021 case DESKTOP_ICONS_APPLICATIONS:
1022 case DESKTOP_ICONS_CATEGORIES:
1023 _refresh_categories(desktop);
1024 break;
1025 case DESKTOP_ICONS_FILES:
1026 _refresh_files(desktop);
1027 break;
1028 case DESKTOP_ICONS_HOMESCREEN:
1029 case DESKTOP_ICONS_NONE:
1030 _refresh_homescreen(desktop);
1031 break;
1032 }
1033 }
1034
_refresh_categories(Desktop * desktop)1035 static void _refresh_categories(Desktop * desktop)
1036 {
1037 g_slist_foreach(desktop->apps, (GFunc)config_delete, NULL);
1038 g_slist_free(desktop->apps);
1039 desktop->apps = NULL;
1040 desktop->refresh_source = g_idle_add(_desktop_on_refresh, desktop);
1041 }
1042
_refresh_files(Desktop * desktop)1043 static void _refresh_files(Desktop * desktop)
1044 {
1045 struct stat st;
1046
1047 if(desktop->path == NULL)
1048 return;
1049 if((desktop->refresh_dir = browser_vfs_opendir(desktop->path, &st))
1050 == NULL)
1051 {
1052 desktop_error(NULL, desktop->path, 1);
1053 desktop->refresh_source = 0;
1054 return;
1055 }
1056 desktop->refresh_mti = st.st_mtime;
1057 desktop->refresh_source = g_idle_add(_desktop_on_refresh, desktop);
1058 }
1059
_refresh_homescreen(Desktop * desktop)1060 static void _refresh_homescreen(Desktop * desktop)
1061 {
1062 /* for cleanup */
1063 desktop->refresh_source = g_idle_add(_desktop_on_refresh, desktop);
1064 }
1065
1066
1067 /* desktop_reset */
1068 static void _reset_background(Desktop * desktop, Config * config);
1069 static void _reset_icons(Desktop * desktop, Config * config);
1070 static void _reset_icons_colors(Desktop * desktop, Config * config);
1071 static void _reset_icons_font(Desktop * desktop, Config * config);
1072 static void _reset_icons_monitor(Desktop * desktop, Config * config);
1073 /* callbacks */
1074 static gboolean _reset_on_idle(gpointer data);
1075
desktop_reset(Desktop * desktop)1076 void desktop_reset(Desktop * desktop)
1077 {
1078 if(desktop->refresh_source != 0)
1079 g_source_remove(desktop->refresh_source);
1080 desktop->refresh_source = g_idle_add(_reset_on_idle, desktop);
1081 }
1082
_reset_background(Desktop * desktop,Config * config)1083 static void _reset_background(Desktop * desktop, Config * config)
1084 {
1085 #if GTK_CHECK_VERSION(3, 0, 0)
1086 GdkRGBA color = { 0.0, 0.0, 0.0, 0.0 };
1087 #else
1088 GdkColor color = { 0, 0, 0, 0 };
1089 #endif
1090 char const * filename;
1091 DesktopHows how = DESKTOP_HOW_SCALED;
1092 gboolean extend = FALSE;
1093 size_t i;
1094 char const * p;
1095
1096 if((p = config_get(config, "background", "color")) != NULL)
1097 #if GTK_CHECK_VERSION(3, 0, 0)
1098 gdk_rgba_parse(&color, p);
1099 #else
1100 gdk_color_parse(p, &color);
1101 #endif
1102 filename = config_get(config, "background", "wallpaper");
1103 if((p = config_get(config, "background", "how")) != NULL)
1104 for(i = 0; i < DESKTOP_HOW_COUNT; i++)
1105 if(strcmp(_desktop_hows[i], p) == 0)
1106 how = i;
1107 if((p = config_get(config, "background", "extend")) != NULL)
1108 extend = strtol(p, NULL, 10) ? TRUE : FALSE;
1109 _desktop_draw_background(desktop, &color, filename, how, extend);
1110 }
1111
_reset_icons(Desktop * desktop,Config * config)1112 static void _reset_icons(Desktop * desktop, Config * config)
1113 {
1114 String const * p;
1115 String * q;
1116 size_t i;
1117 int j;
1118
1119 _reset_icons_colors(desktop, config);
1120 _reset_icons_font(desktop, config);
1121 for(i = 0; i < desktop->icon_cnt; i++)
1122 {
1123 desktopicon_set_background(desktop->icon[i],
1124 &desktop->background);
1125 desktopicon_set_font(desktop->icon[i], desktop->font);
1126 desktopicon_set_foreground(desktop->icon[i],
1127 &desktop->foreground);
1128 }
1129 _reset_icons_monitor(desktop, config);
1130 /* icons layout */
1131 if(desktop->prefs.icons < 0
1132 && (p = config_get(config, "icons", "layout")) != NULL)
1133 {
1134 for(i = 0; i < DESKTOP_ICONS_COUNT; i++)
1135 if(strcmp(_desktop_icons_config[i], p) == 0)
1136 {
1137 desktop->prefs.icons = i;
1138 break;
1139 }
1140 }
1141 if(desktop->prefs.icons < 0
1142 || desktop->prefs.icons >= DESKTOP_ICONS_COUNT)
1143 desktop->prefs.icons = DESKTOP_ICONS_FILES;
1144 /* icons alignment */
1145 if(desktop->prefs.alignment < 0)
1146 desktop->prefs.alignment = (desktop->prefs.icons
1147 == DESKTOP_ICONS_FILES)
1148 ? DESKTOP_ALIGNMENT_VERTICAL
1149 : DESKTOP_ALIGNMENT_HORIZONTAL;
1150 /* show hidden */
1151 if((p = config_get(config, "icons", "show_hidden")) != NULL)
1152 {
1153 j = strtol(p, &q, 10);
1154 if(p[0] == '\0' || *q != '\0' || j < 0)
1155 j = 0;
1156 desktop->show_hidden = j ? 1 : 0;
1157 }
1158 }
1159
_reset_icons_colors(Desktop * desktop,Config * config)1160 static void _reset_icons_colors(Desktop * desktop, Config * config)
1161 {
1162 String const * p;
1163 #if GTK_CHECK_VERSION(3, 0, 0)
1164 GdkRGBA color;
1165 #else
1166 GdkColor color;
1167 #endif
1168
1169 if((p = config_get(config, "icons", "background")) != NULL)
1170 {
1171 #if GTK_CHECK_VERSION(3, 0, 0)
1172 gdk_rgba_parse(&color, p);
1173 #else
1174 gdk_color_parse(p, &color);
1175 #endif
1176 desktop->background = color;
1177 }
1178 if((p = config_get(config, "icons", "foreground")) != NULL)
1179 {
1180 #if GTK_CHECK_VERSION(3, 0, 0)
1181 gdk_rgba_parse(&color, p);
1182 #else
1183 gdk_color_parse(p, &color);
1184 #endif
1185 desktop->foreground = color;
1186 }
1187 }
1188
_reset_icons_font(Desktop * desktop,Config * config)1189 static void _reset_icons_font(Desktop * desktop, Config * config)
1190 {
1191 String const * p;
1192
1193 if(desktop->font != NULL)
1194 pango_font_description_free(desktop->font);
1195 if((p = config_get(config, "icons", "font")) != NULL)
1196 desktop->font = pango_font_description_from_string(p);
1197 else
1198 {
1199 desktop->font = pango_font_description_new();
1200 pango_font_description_set_weight(desktop->font,
1201 PANGO_WEIGHT_BOLD);
1202 }
1203 }
1204
_reset_icons_monitor(Desktop * desktop,Config * config)1205 static void _reset_icons_monitor(Desktop * desktop, Config * config)
1206 {
1207 String const * p;
1208 char * q;
1209
1210 /* icons monitor */
1211 if(desktop->prefs.monitor < 0
1212 && (p = config_get(config, "icons", "monitor")) != NULL)
1213 {
1214 desktop->prefs.monitor = strtol(p, &q, 10);
1215 if(p[0] == '\0' || *q != '\0')
1216 desktop->prefs.monitor = -1;
1217 }
1218 }
1219
1220 /* callbacks */
_reset_on_idle(gpointer data)1221 static gboolean _reset_on_idle(gpointer data)
1222 {
1223 Desktop * desktop = data;
1224 Config * config;
1225
1226 #ifdef DEBUG
1227 fprintf(stderr, "DEBUG: %s()\n", __func__);
1228 #endif
1229 desktop->refresh_source = 0;
1230 if((config = _desktop_get_config(desktop)) == NULL)
1231 return FALSE;
1232 _reset_background(desktop, config);
1233 _reset_icons(desktop, config);
1234 config_delete(config);
1235 _desktop_get_workarea(desktop);
1236 desktop_set_icons(desktop, desktop->prefs.icons);
1237 return FALSE;
1238 }
1239
1240
1241 /* desktop_icon_add */
desktop_icon_add(Desktop * desktop,DesktopIcon * icon)1242 void desktop_icon_add(Desktop * desktop, DesktopIcon * icon)
1243 {
1244 if(_desktop_icon_add(desktop, icon) == 0)
1245 desktop_icons_align(desktop);
1246 }
1247
1248
1249 /* desktop_icon_remove */
desktop_icon_remove(Desktop * desktop,DesktopIcon * icon)1250 void desktop_icon_remove(Desktop * desktop, DesktopIcon * icon)
1251 {
1252 if(_desktop_icon_remove(desktop, icon) == 0)
1253 desktop_icons_align(desktop);
1254 }
1255
1256
1257 /* desktop_icons_align */
1258 static int _align_compare(const void * a, const void * b);
1259
desktop_icons_align(Desktop * desktop)1260 void desktop_icons_align(Desktop * desktop)
1261 {
1262 qsort(desktop->icon, desktop->icon_cnt, sizeof(void *), _align_compare);
1263 desktop_set_alignment(desktop, desktop->prefs.alignment);
1264 }
1265
_align_compare(const void * a,const void * b)1266 static int _align_compare(const void * a, const void * b)
1267 {
1268 DesktopIcon * icona = *(DesktopIcon**)a;
1269 DesktopIcon * iconb = *(DesktopIcon**)b;
1270 gboolean firsta = desktopicon_get_first(icona);
1271 gboolean firstb = desktopicon_get_first(iconb);
1272 gboolean dira;
1273 gboolean dirb;
1274
1275 if(firsta && !firstb)
1276 return -1;
1277 else if(!firsta && firstb)
1278 return 1;
1279 dira = desktopicon_get_isdir(icona);
1280 dirb = desktopicon_get_isdir(iconb);
1281 if(dira && !dirb)
1282 return -1;
1283 else if(!dira && dirb)
1284 return 1;
1285 return strcmp(desktopicon_get_name(icona), desktopicon_get_name(iconb));
1286 }
1287
1288
1289 /* desktop_select_all */
desktop_select_all(Desktop * desktop)1290 void desktop_select_all(Desktop * desktop)
1291 {
1292 size_t i;
1293
1294 for(i = 0; i < desktop->icon_cnt; i++)
1295 desktopicon_set_selected(desktop->icon[i], TRUE);
1296 }
1297
1298
1299 /* desktop_select_above */
desktop_select_above(Desktop * desktop,DesktopIcon * icon)1300 void desktop_select_above(Desktop * desktop, DesktopIcon * icon)
1301 /* FIXME icons may be wrapped */
1302 {
1303 size_t i;
1304
1305 for(i = 1; i < desktop->icon_cnt; i++)
1306 if(desktop->icon[i] == icon)
1307 {
1308 desktopicon_set_selected(desktop->icon[i], TRUE);
1309 return;
1310 }
1311 }
1312
1313
1314 /* desktop_select_under */
desktop_select_under(Desktop * desktop,DesktopIcon * icon)1315 void desktop_select_under(Desktop * desktop, DesktopIcon * icon)
1316 /* FIXME icons may be wrapped */
1317 {
1318 size_t i;
1319
1320 for(i = 0; i < desktop->icon_cnt; i++)
1321 if(desktop->icon[i] == icon && i + 1 < desktop->icon_cnt)
1322 {
1323 desktopicon_set_selected(desktop->icon[i], TRUE);
1324 return;
1325 }
1326 }
1327
1328
1329 /* desktop_unselect_all */
desktop_unselect_all(Desktop * desktop)1330 void desktop_unselect_all(Desktop * desktop)
1331 {
1332 size_t i;
1333
1334 for(i = 0; i < desktop->icon_cnt; i++)
1335 desktopicon_set_selected(desktop->icon[i], FALSE);
1336 }
1337
1338
1339 /* private */
1340 /* functions */
1341 /* desktop_error */
1342 static int _error_text(char const * message, char const * error, int ret);
1343
_desktop_error(Desktop * desktop,char const * message,char const * error,int ret)1344 static int _desktop_error(Desktop * desktop, char const * message,
1345 char const * error, int ret)
1346 {
1347 GtkWidget * dialog;
1348
1349 if(desktop == NULL)
1350 return _error_text(message, error, ret);
1351 dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR,
1352 GTK_BUTTONS_CLOSE, "%s",
1353 #if GTK_CHECK_VERSION(2, 6, 0)
1354 _("Error"));
1355 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1356 "%s: %s", message,
1357 #endif
1358 error);
1359 gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
1360 if(ret < 0)
1361 {
1362 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
1363 gtk_main_quit), NULL);
1364 ret = -ret;
1365 }
1366 else
1367 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
1368 gtk_widget_destroy), NULL);
1369 gtk_widget_show(dialog);
1370 return ret;
1371 }
1372
_error_text(char const * message,char const * error,int ret)1373 static int _error_text(char const * message, char const * error, int ret)
1374 {
1375 fprintf(stderr, "%s: %s%s%s\n", PROGNAME,
1376 (message != NULL) ? message : "",
1377 (message != NULL) ? ": " : "", error);
1378 return ret;
1379 }
1380
1381
1382 /* desktop_serror */
_desktop_serror(Desktop * desktop,char const * message,int ret)1383 static int _desktop_serror(Desktop * desktop, char const * message, int ret)
1384 {
1385 return _desktop_error(desktop, message, error_get(NULL), ret);
1386 }
1387
1388
1389 /* desktop_get_config */
_desktop_get_config(Desktop * desktop)1390 static Config * _desktop_get_config(Desktop * desktop)
1391 {
1392 Config * config;
1393 String * pathname = NULL;
1394
1395 if((config = config_new()) == NULL
1396 || (pathname = string_new_append(desktop->home,
1397 "/" DESKTOPRC, NULL)) == NULL)
1398 {
1399 if(config != NULL)
1400 config_delete(config);
1401 if(pathname != NULL)
1402 object_delete(pathname);
1403 _desktop_serror(NULL, _("Could not load preferences"), FALSE);
1404 return NULL;
1405 }
1406 config_load(config, pathname); /* XXX ignore errors */
1407 return config;
1408 }
1409
1410
1411 /* desktop_get_workarea */
_desktop_get_workarea(Desktop * desktop)1412 static int _desktop_get_workarea(Desktop * desktop)
1413 {
1414 Atom atom;
1415 Atom type;
1416 int format;
1417 unsigned long cnt;
1418 unsigned long bytes;
1419 unsigned char * p = NULL;
1420 unsigned long * u;
1421 int res;
1422
1423 if(desktop->prefs.monitor >= 0 && desktop->prefs.monitor
1424 < gdk_screen_get_n_monitors(desktop->screen))
1425 {
1426 gdk_screen_get_monitor_geometry(desktop->screen,
1427 desktop->prefs.monitor, &desktop->workarea);
1428 #ifdef DEBUG
1429 fprintf(stderr, "DEBUG: %s() (%d, %d) %dx%d\n", __func__,
1430 desktop->workarea.x, desktop->workarea.y,
1431 desktop->workarea.width,
1432 desktop->workarea.height);
1433 #endif
1434 desktop_icons_align(desktop);
1435 return 0;
1436 }
1437 atom = gdk_x11_get_xatom_by_name("_NET_WORKAREA");
1438 gdk_error_trap_push();
1439 res = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(desktop->display),
1440 GDK_WINDOW_XID(desktop->root), atom, 0,
1441 G_MAXLONG, False, XA_CARDINAL, &type, &format,
1442 &cnt, &bytes, &p);
1443 if(gdk_error_trap_pop() || res != Success || cnt < 4)
1444 gdk_screen_get_monitor_geometry(desktop->screen, 0,
1445 &desktop->workarea);
1446 else
1447 {
1448 u = (unsigned long *)p;
1449 desktop->workarea.x = u[0];
1450 desktop->workarea.y = u[1];
1451 if((desktop->workarea.width = u[2]) == 0
1452 || (desktop->workarea.height = u[3]) == 0)
1453 gdk_screen_get_monitor_geometry(desktop->screen, 0,
1454 &desktop->workarea);
1455 }
1456 if(p != NULL)
1457 XFree(p);
1458 #ifdef DEBUG
1459 fprintf(stderr, "DEBUG: %s() (%d, %d) %dx%d\n", __func__,
1460 desktop->workarea.x, desktop->workarea.y,
1461 desktop->workarea.width, desktop->workarea.height);
1462 #endif
1463 desktop_icons_align(desktop);
1464 return 0;
1465 }
1466
1467
1468 /* useful */
1469 /* desktop_background */
1470 static gboolean _background_how_centered(Desktop * desktop,
1471 GdkRectangle * window, char const * filename, GError ** error);
1472 static gboolean _background_how_scaled(Desktop * desktop, GdkRectangle * window,
1473 char const * filename, GError ** error);
1474 static gboolean _background_how_scaled_ratio(Desktop * desktop,
1475 GdkRectangle * window, char const * filename, GError ** error);
1476 static gboolean _background_how_tiled(Desktop * desktop, GdkRectangle * window,
1477 char const * filename, GError ** error);
1478 static void _background_monitor(Desktop * desktop, char const * filename,
1479 DesktopHows how, gboolean extend, GdkRectangle * window,
1480 int monitor);
1481 static void _background_monitors(Desktop * desktop, char const * filename,
1482 DesktopHows how, gboolean extend, GdkRectangle * window);
1483
1484 #if GTK_CHECK_VERSION(3, 0, 0)
_desktop_draw_background(Desktop * desktop,GdkRGBA * color,char const * filename,DesktopHows how,gboolean extend)1485 static void _desktop_draw_background(Desktop * desktop, GdkRGBA * color,
1486 char const * filename, DesktopHows how, gboolean extend)
1487 #else
1488 static void _desktop_draw_background(Desktop * desktop, GdkColor * color,
1489 char const * filename, DesktopHows how, gboolean extend)
1490 #endif
1491 {
1492 #if !GTK_CHECK_VERSION(3, 0, 0)
1493 GdkGC * gc;
1494 GtkStyle * style;
1495 #endif
1496
1497 #ifdef DEBUG
1498 fprintf(stderr, "DEBUG: %s(\"%s\", %u, %s)\n", __func__, filename, how,
1499 extend ? "TRUE" : "FALSE");
1500 #endif
1501 if(how == DESKTOP_HOW_NONE)
1502 return;
1503 #if GTK_CHECK_VERSION(3, 0, 0)
1504 desktop->cairo = gdk_cairo_create(desktop->root);
1505 cairo_set_source_rgba(desktop->cairo, color->red, color->green,
1506 color->blue, 1.0);
1507 gdk_cairo_rectangle(desktop->cairo, &desktop->window);
1508 if(filename != NULL)
1509 /* draw the background */
1510 _background_monitors(desktop, filename, how, extend,
1511 &desktop->window);
1512 cairo_paint(desktop->cairo);
1513 cairo_destroy(desktop->cairo);
1514 desktop->cairo = NULL;
1515 #else
1516 /* draw default color */
1517 desktop->pixmap = gdk_pixmap_new(desktop->back, desktop->window.width,
1518 desktop->window.height, -1);
1519 gc = gdk_gc_new(desktop->pixmap);
1520 gdk_gc_set_rgb_fg_color(gc, color);
1521 gdk_draw_rectangle(desktop->pixmap, gc, TRUE, 0, 0,
1522 desktop->window.width, desktop->window.height);
1523 if(filename != NULL)
1524 /* draw the background */
1525 _background_monitors(desktop, filename, how, extend,
1526 &desktop->window);
1527 if(desktop->desktop != NULL)
1528 {
1529 style = gtk_style_new();
1530 style->bg_pixmap[GTK_STATE_NORMAL] = desktop->pixmap;
1531 gtk_widget_set_style(desktop->desktop, style);
1532 }
1533 else
1534 {
1535 gdk_window_set_back_pixmap(desktop->back, desktop->pixmap,
1536 FALSE);
1537 gdk_window_clear(desktop->back);
1538 gdk_pixmap_unref(desktop->pixmap);
1539 }
1540 desktop->pixmap = NULL;
1541 #endif
1542 }
1543
_background_how_centered(Desktop * desktop,GdkRectangle * window,char const * filename,GError ** error)1544 static gboolean _background_how_centered(Desktop * desktop,
1545 GdkRectangle * window, char const * filename, GError ** error)
1546 {
1547 GdkPixbuf * background;
1548 gint w;
1549 gint h;
1550 gint x;
1551 gint y;
1552
1553 if((background = gdk_pixbuf_new_from_file(filename, error)) == NULL)
1554 return FALSE;
1555 w = gdk_pixbuf_get_width(background);
1556 h = gdk_pixbuf_get_height(background);
1557 x = (window->width - w) / 2 + window->x;
1558 y = (window->height - h) / 2 + window->y;
1559 #if GTK_CHECK_VERSION(3, 0, 0)
1560 gdk_cairo_set_source_pixbuf(desktop->cairo, background, x, y);
1561 #else
1562 gdk_draw_pixbuf(desktop->pixmap, NULL, background, 0, 0, x, y, w, h,
1563 GDK_RGB_DITHER_NONE, 0, 0);
1564 #endif
1565 g_object_unref(background);
1566 return TRUE;
1567 }
1568
_background_how_scaled(Desktop * desktop,GdkRectangle * window,char const * filename,GError ** error)1569 static gboolean _background_how_scaled(Desktop * desktop, GdkRectangle * window,
1570 char const * filename, GError ** error)
1571 {
1572 GdkPixbuf * background;
1573 gint w;
1574 gint h;
1575 gint x;
1576 gint y;
1577
1578 #if GTK_CHECK_VERSION(2, 6, 0)
1579 background = gdk_pixbuf_new_from_file_at_scale(filename, window->width,
1580 window->height, FALSE, error);
1581 #elif GTK_CHECK_VERSION(2, 4, 0)
1582 background = gdk_pixbuf_new_from_file_at_size(filename, window->width,
1583 window->height, error);
1584 #else
1585 background = gdk_pixbuf_new_from_file(filename, error);
1586 #endif
1587 if(background == NULL)
1588 return FALSE;
1589 w = gdk_pixbuf_get_width(background);
1590 h = gdk_pixbuf_get_height(background);
1591 x = (window->width - w) / 2 + window->x;
1592 y = (window->height - h) / 2 + window->y;
1593 #if GTK_CHECK_VERSION(3, 0, 0)
1594 gdk_cairo_set_source_pixbuf(desktop->cairo, background, x, y);
1595 #else
1596 gdk_draw_pixbuf(desktop->pixmap, NULL, background, 0, 0, x, y, w, h,
1597 GDK_RGB_DITHER_NONE, 0, 0);
1598 #endif
1599 g_object_unref(background);
1600 return TRUE;
1601 }
1602
_background_how_scaled_ratio(Desktop * desktop,GdkRectangle * window,char const * filename,GError ** error)1603 static gboolean _background_how_scaled_ratio(Desktop * desktop,
1604 GdkRectangle * window, char const * filename, GError ** error)
1605 {
1606 #if GTK_CHECK_VERSION(2, 4, 0)
1607 GdkPixbuf * background;
1608 gint w;
1609 gint h;
1610 gint x;
1611 gint y;
1612
1613 background = gdk_pixbuf_new_from_file_at_size(filename, window->width,
1614 window->height, error);
1615 if(background == NULL)
1616 return FALSE;
1617 w = gdk_pixbuf_get_width(background);
1618 h = gdk_pixbuf_get_height(background);
1619 x =(window->width - w) / 2 + window->x;
1620 y = (window->height - h) / 2 + window->y;
1621 #if GTK_CHECK_VERSION(3, 0, 0)
1622 gdk_cairo_set_source_pixbuf(desktop->cairo, background, x, y);
1623 #else
1624 gdk_draw_pixbuf(desktop->pixmap, NULL, background, 0, 0, x, y, w, h,
1625 GDK_RGB_DITHER_NONE, 0, 0);
1626 #endif
1627 g_object_unref(background);
1628 return TRUE;
1629 #else
1630 return _background_how_scaled(desktop, window, filename, error);
1631 #endif
1632 }
1633
_background_how_tiled(Desktop * desktop,GdkRectangle * window,char const * filename,GError ** error)1634 static gboolean _background_how_tiled(Desktop * desktop, GdkRectangle * window,
1635 char const * filename, GError ** error)
1636 {
1637 GdkPixbuf * background;
1638 gint w;
1639 gint h;
1640 gint i;
1641 gint j;
1642
1643 if((background = gdk_pixbuf_new_from_file(filename, error)) == NULL)
1644 return FALSE;
1645 w = gdk_pixbuf_get_width(background);
1646 h = gdk_pixbuf_get_height(background);
1647 for(j = 0; j < window->height; j += h)
1648 for(i = 0; i < window->width; i += w)
1649 #if GTK_CHECK_VERSION(3, 0, 0)
1650 gdk_cairo_set_source_pixbuf(desktop->cairo, background,
1651 i + window->x, j + window->y);
1652 #else
1653 gdk_draw_pixbuf(desktop->pixmap, NULL, background, 0, 0,
1654 i + window->x, j + window->y, w, h,
1655 GDK_RGB_DITHER_NONE, 0, 0);
1656 #endif
1657 g_object_unref(background);
1658 return TRUE;
1659 }
1660
_background_monitor(Desktop * desktop,char const * filename,DesktopHows how,gboolean extend,GdkRectangle * window,int monitor)1661 static void _background_monitor(Desktop * desktop, char const * filename,
1662 DesktopHows how, gboolean extend, GdkRectangle * window,
1663 int monitor)
1664 {
1665 GError * error = NULL;
1666
1667 if(extend != TRUE)
1668 gdk_screen_get_monitor_geometry(desktop->screen, monitor,
1669 window);
1670 switch(how)
1671 {
1672 case DESKTOP_HOW_NONE:
1673 break;
1674 case DESKTOP_HOW_CENTERED:
1675 _background_how_centered(desktop, window, filename,
1676 &error);
1677 break;
1678 case DESKTOP_HOW_SCALED_RATIO:
1679 _background_how_scaled_ratio(desktop, window, filename,
1680 &error);
1681 break;
1682 case DESKTOP_HOW_TILED:
1683 _background_how_tiled(desktop, window, filename,
1684 &error);
1685 break;
1686 case DESKTOP_HOW_SCALED:
1687 _background_how_scaled(desktop, window, filename,
1688 &error);
1689 break;
1690 }
1691 if(error != NULL)
1692 {
1693 desktop_error(desktop, error->message, 1);
1694 g_error_free(error);
1695 }
1696 }
1697
_background_monitors(Desktop * desktop,char const * filename,DesktopHows how,gboolean extend,GdkRectangle * window)1698 static void _background_monitors(Desktop * desktop, char const * filename,
1699 DesktopHows how, gboolean extend, GdkRectangle * window)
1700 {
1701 gint n;
1702 gint i;
1703
1704 n = (extend != TRUE) ? gdk_screen_get_n_monitors(desktop->screen) : 1;
1705 for(i = 0; i < n; i++)
1706 _background_monitor(desktop, filename, how, extend, window, i);
1707 }
1708
1709
1710 /* desktop_icon_add */
_desktop_icon_add(Desktop * desktop,DesktopIcon * icon)1711 static int _desktop_icon_add(Desktop * desktop, DesktopIcon * icon)
1712 {
1713 DesktopIcon ** p;
1714
1715 if((p = realloc(desktop->icon, sizeof(*p) * (desktop->icon_cnt + 1)))
1716 == NULL)
1717 return -desktop_error(desktop, desktopicon_get_name(icon), 1);
1718 desktop->icon = p;
1719 desktop->icon[desktop->icon_cnt++] = icon;
1720 desktopicon_set_background(icon, &desktop->background);
1721 desktopicon_set_font(icon, desktop->font);
1722 desktopicon_set_foreground(icon, &desktop->foreground);
1723 desktopicon_show(icon);
1724 return 0;
1725 }
1726
1727
1728 /* desktop_icon_remove */
_desktop_icon_remove(Desktop * desktop,DesktopIcon * icon)1729 static int _desktop_icon_remove(Desktop * desktop, DesktopIcon * icon)
1730 {
1731 size_t i;
1732 DesktopIcon ** p;
1733
1734 for(i = 0; i < desktop->icon_cnt; i++)
1735 {
1736 if(desktop->icon[i] != icon)
1737 continue;
1738 desktopicon_delete(icon);
1739 for(desktop->icon_cnt--; i < desktop->icon_cnt; i++)
1740 desktop->icon[i] = desktop->icon[i + 1];
1741 if((p = realloc(desktop->icon, sizeof(*p)
1742 * (desktop->icon_cnt))) != NULL)
1743 desktop->icon = p; /* we can ignore errors... */
1744 else if(desktop->icon_cnt == 0)
1745 desktop->icon = NULL; /* ...except when it's not one */
1746 return 0;
1747 }
1748 return 1;
1749 }
1750
1751
1752 /* desktop_show_preferences */
1753 static void _preferences_background(Desktop * desktop, GtkWidget * notebook);
1754 static void _preferences_icons(Desktop * desktop, GtkWidget * notebook);
1755 static void _preferences_monitors(Desktop * desktop, GtkWidget * notebook);
1756 static void _preferences_set(Desktop * desktop);
1757 static void _preferences_set_color(Config * config, char const * section,
1758 char const * variable, char const * fallback,
1759 GtkWidget * widget);
1760 static gboolean _on_preferences_closex(gpointer data);
1761 static void _on_preferences_monitors_changed(gpointer data);
1762 static void _on_preferences_monitors_refresh(gpointer data);
1763 static void _on_preferences_response(GtkWidget * widget, gint response,
1764 gpointer data);
1765 static void _on_preferences_response_apply(gpointer data);
1766 static void _on_preferences_response_cancel(gpointer data);
1767 static void _on_preferences_response_ok(gpointer data);
1768 static void _on_preferences_update_preview(gpointer data);
1769
_desktop_show_preferences(Desktop * desktop)1770 static void _desktop_show_preferences(Desktop * desktop)
1771 {
1772 GtkWidget * vbox;
1773 GtkWidget * notebook;
1774
1775 if(desktop->menu != NULL)
1776 gtk_widget_destroy(desktop->menu);
1777 desktop->menu = NULL;
1778 if(desktop->pr_window != NULL)
1779 {
1780 gtk_window_present(GTK_WINDOW(desktop->pr_window));
1781 return;
1782 }
1783 /* window */
1784 desktop->pr_window = gtk_dialog_new_with_buttons(
1785 _("Desktop preferences"), NULL,
1786 GTK_DIALOG_DESTROY_WITH_PARENT,
1787 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1788 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
1789 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1790 gtk_window_set_position(GTK_WINDOW(desktop->pr_window),
1791 GTK_WIN_POS_CENTER);
1792 gtk_window_set_resizable(GTK_WINDOW(desktop->pr_window), FALSE);
1793 g_signal_connect_swapped(G_OBJECT(desktop->pr_window), "delete-event",
1794 G_CALLBACK(_on_preferences_closex), desktop);
1795 g_signal_connect(G_OBJECT(desktop->pr_window), "response", G_CALLBACK(
1796 _on_preferences_response), desktop);
1797 #if GTK_CHECK_VERSION(2, 14, 0)
1798 vbox = gtk_dialog_get_content_area(GTK_DIALOG(desktop->pr_window));
1799 #else
1800 vbox = GTK_DIALOG(desktop->pr_window)->vbox;
1801 #endif
1802 /* notebook */
1803 notebook = gtk_notebook_new();
1804 _preferences_background(desktop, notebook);
1805 _preferences_icons(desktop, notebook);
1806 _preferences_monitors(desktop, notebook);
1807 _on_preferences_monitors_refresh(desktop);
1808 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
1809 /* container */
1810 _preferences_set(desktop);
1811 gtk_widget_show_all(desktop->pr_window);
1812 }
1813
_preferences_background(Desktop * desktop,GtkWidget * notebook)1814 static void _preferences_background(Desktop * desktop, GtkWidget * notebook)
1815 {
1816 GtkSizeGroup * group;
1817 GtkWidget * vbox2;
1818 GtkWidget * hbox;
1819 GtkWidget * label;
1820 GtkFileFilter * filter;
1821
1822 #if GTK_CHECK_VERSION(3, 0, 0)
1823 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1824 #else
1825 vbox2 = gtk_vbox_new(FALSE, 4);
1826 #endif
1827 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
1828 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1829 #if GTK_CHECK_VERSION(3, 0, 0)
1830 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1831 #else
1832 hbox = gtk_hbox_new(FALSE, 0);
1833 #endif
1834 label = gtk_label_new(_("Default color: "));
1835 #if GTK_CHECK_VERSION(3, 0, 0)
1836 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
1837 #else
1838 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1839 #endif
1840 gtk_size_group_add_widget(group, label);
1841 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
1842 desktop->pr_color = gtk_color_button_new();
1843 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_color, TRUE, TRUE, 0);
1844 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
1845 #if GTK_CHECK_VERSION(3, 0, 0)
1846 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1847 #else
1848 hbox = gtk_hbox_new(FALSE, 0);
1849 #endif
1850 label = gtk_label_new(_("Wallpaper: "));
1851 #if GTK_CHECK_VERSION(3, 0, 0)
1852 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
1853 #else
1854 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1855 #endif
1856 gtk_size_group_add_widget(group, label);
1857 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
1858 desktop->pr_background = gtk_file_chooser_button_new(_("Background"),
1859 GTK_FILE_CHOOSER_ACTION_OPEN);
1860 filter = gtk_file_filter_new();
1861 gtk_file_filter_set_name(filter, _("Picture files"));
1862 gtk_file_filter_add_mime_type(filter, "image/bmp");
1863 gtk_file_filter_add_mime_type(filter, "image/gif");
1864 gtk_file_filter_add_mime_type(filter, "image/jpeg");
1865 gtk_file_filter_add_mime_type(filter, "image/pbm");
1866 gtk_file_filter_add_mime_type(filter, "image/png");
1867 gtk_file_filter_add_mime_type(filter, "image/svg+xml");
1868 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(desktop->pr_background),
1869 filter);
1870 filter = gtk_file_filter_new();
1871 gtk_file_filter_set_name(filter, _("All files"));
1872 gtk_file_filter_add_pattern(filter, "*");
1873 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(desktop->pr_background),
1874 filter);
1875 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(
1876 desktop->pr_background), gtk_image_new());
1877 g_signal_connect_swapped(desktop->pr_background, "update-preview",
1878 G_CALLBACK(_on_preferences_update_preview), desktop);
1879 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_background, TRUE, TRUE,
1880 0);
1881 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
1882 #if GTK_CHECK_VERSION(3, 0, 0)
1883 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1884 #else
1885 hbox = gtk_hbox_new(FALSE, 0);
1886 #endif
1887 label = gtk_label_new(_("Position: "));
1888 #if GTK_CHECK_VERSION(3, 0, 0)
1889 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
1890 #else
1891 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1892 #endif
1893 gtk_size_group_add_widget(group, label);
1894 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
1895 #if GTK_CHECK_VERSION(2, 24, 0)
1896 desktop->pr_background_how = gtk_combo_box_text_new();
1897 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(
1898 desktop->pr_background_how), _("Do not draw"));
1899 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(
1900 desktop->pr_background_how), _("Centered"));
1901 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(
1902 desktop->pr_background_how), _("Scaled"));
1903 gtk_combo_box_text_append_text(
1904 GTK_COMBO_BOX_TEXT(desktop->pr_background_how),
1905 _("Scaled (keep ratio)"));
1906 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(
1907 desktop->pr_background_how), _("Tiled"));
1908 #else
1909 desktop->pr_background_how = gtk_combo_box_new_text();
1910 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_background_how),
1911 _("Do not draw"));
1912 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_background_how),
1913 _("Centered"));
1914 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_background_how),
1915 _("Scaled"));
1916 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_background_how),
1917 _("Scaled (keep ratio)"));
1918 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_background_how),
1919 _("Tiled"));
1920 #endif
1921 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_background_how, TRUE,
1922 TRUE, 0);
1923 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
1924 desktop->pr_background_extend = gtk_check_button_new_with_mnemonic(
1925 _("E_xtend background to all monitors"));
1926 gtk_box_pack_start(GTK_BOX(vbox2), desktop->pr_background_extend, FALSE,
1927 TRUE, 0);
1928 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
1929 _("Background")));
1930 }
1931
_preferences_icons(Desktop * desktop,GtkWidget * notebook)1932 static void _preferences_icons(Desktop * desktop, GtkWidget * notebook)
1933 {
1934 GtkSizeGroup * group;
1935 GtkWidget * vbox2;
1936 GtkWidget * hbox;
1937 GtkWidget * label;
1938 size_t i;
1939
1940 #if GTK_CHECK_VERSION(3, 0, 0)
1941 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1942 #else
1943 vbox2 = gtk_vbox_new(FALSE, 4);
1944 #endif
1945 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
1946 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1947 /* icons */
1948 #if GTK_CHECK_VERSION(3, 0, 0)
1949 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1950 #else
1951 hbox = gtk_hbox_new(FALSE, 0);
1952 #endif
1953 label = gtk_label_new(_("Layout: "));
1954 #if GTK_CHECK_VERSION(3, 0, 0)
1955 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
1956 #else
1957 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1958 #endif
1959 gtk_size_group_add_widget(group, label);
1960 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
1961 #if GTK_CHECK_VERSION(2, 24, 0)
1962 desktop->pr_ilayout = gtk_combo_box_text_new();
1963 #else
1964 desktop->pr_ilayout = gtk_combo_box_new_text();
1965 #endif
1966 for(i = 0; i < sizeof(_desktop_icons) / sizeof(*_desktop_icons);
1967 i++)
1968 #if GTK_CHECK_VERSION(2, 24, 0)
1969 gtk_combo_box_text_append_text(
1970 GTK_COMBO_BOX_TEXT(desktop->pr_ilayout),
1971 _(_desktop_icons[i]));
1972 #else
1973 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_ilayout),
1974 _(_desktop_icons[i]));
1975 #endif
1976 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_ilayout, TRUE, TRUE, 0);
1977 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
1978 /* monitor */
1979 #if GTK_CHECK_VERSION(3, 0, 0)
1980 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1981 #else
1982 hbox = gtk_hbox_new(FALSE, 0);
1983 #endif
1984 label = gtk_label_new(_("Monitor: "));
1985 #if GTK_CHECK_VERSION(3, 0, 0)
1986 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
1987 #else
1988 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1989 #endif
1990 gtk_size_group_add_widget(group, label);
1991 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
1992 #if GTK_CHECK_VERSION(2, 24, 0)
1993 desktop->pr_imonitor = gtk_combo_box_text_new();
1994 #else
1995 desktop->pr_imonitor = gtk_combo_box_new_text();
1996 #endif
1997 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_imonitor, TRUE, TRUE, 0);
1998 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
1999 /* background color */
2000 #if GTK_CHECK_VERSION(3, 0, 0)
2001 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2002 #else
2003 hbox = gtk_hbox_new(FALSE, 0);
2004 #endif
2005 label = gtk_label_new(_("Background color: "));
2006 #if GTK_CHECK_VERSION(3, 0, 0)
2007 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2008 #else
2009 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2010 #endif
2011 gtk_size_group_add_widget(group, label);
2012 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2013 desktop->pr_ibcolor = gtk_color_button_new();
2014 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_ibcolor, TRUE, TRUE, 0);
2015 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2016 /* foreground color */
2017 #if GTK_CHECK_VERSION(3, 0, 0)
2018 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2019 #else
2020 hbox = gtk_hbox_new(FALSE, 0);
2021 #endif
2022 label = gtk_label_new(_("Foreground color: "));
2023 #if GTK_CHECK_VERSION(3, 0, 0)
2024 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2025 #else
2026 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2027 #endif
2028 gtk_size_group_add_widget(group, label);
2029 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2030 desktop->pr_ifcolor = gtk_color_button_new();
2031 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_ifcolor, TRUE, TRUE, 0);
2032 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2033 /* font */
2034 #if GTK_CHECK_VERSION(3, 0, 0)
2035 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2036 #else
2037 hbox = gtk_hbox_new(FALSE, 0);
2038 #endif
2039 label = gtk_label_new(_("Font: "));
2040 #if GTK_CHECK_VERSION(3, 0, 0)
2041 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2042 #else
2043 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2044 #endif
2045 gtk_size_group_add_widget(group, label);
2046 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2047 desktop->pr_ifont = gtk_font_button_new();
2048 gtk_font_button_set_use_font(GTK_FONT_BUTTON(desktop->pr_ifont), TRUE);
2049 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_ifont, TRUE, TRUE, 0);
2050 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2051 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
2052 _("Icons")));
2053 }
2054
_preferences_monitors(Desktop * desktop,GtkWidget * notebook)2055 static void _preferences_monitors(Desktop * desktop, GtkWidget * notebook)
2056 {
2057 GtkSizeGroup * group;
2058 GtkWidget * vbox2;
2059 GtkWidget * hbox;
2060 GtkWidget * label;
2061 GtkWidget * widget;
2062
2063 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2064 #if GTK_CHECK_VERSION(3, 0, 0)
2065 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
2066 #else
2067 vbox2 = gtk_vbox_new(FALSE, 4);
2068 #endif
2069 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
2070 /* selector */
2071 #if GTK_CHECK_VERSION(3, 0, 0)
2072 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2073 #else
2074 hbox = gtk_hbox_new(FALSE, 0);
2075 #endif
2076 label = gtk_label_new(_("Monitor: "));
2077 #if GTK_CHECK_VERSION(3, 0, 0)
2078 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2079 #else
2080 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2081 #endif
2082 gtk_size_group_add_widget(group, label);
2083 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2084 #if GTK_CHECK_VERSION(2, 24, 0)
2085 desktop->pr_monitors = gtk_combo_box_text_new();
2086 #else
2087 desktop->pr_monitors = gtk_combo_box_new_text();
2088 #endif
2089 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_monitors, TRUE, TRUE, 0);
2090 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2091 /* geometry */
2092 #if GTK_CHECK_VERSION(3, 0, 0)
2093 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2094 #else
2095 hbox = gtk_hbox_new(FALSE, 0);
2096 #endif
2097 label = gtk_label_new(_("Resolution: "));
2098 #if GTK_CHECK_VERSION(3, 0, 0)
2099 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2100 #else
2101 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2102 #endif
2103 gtk_size_group_add_widget(group, label);
2104 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2105 desktop->pr_monitors_res = gtk_label_new(NULL);
2106 #if GTK_CHECK_VERSION(3, 0, 0)
2107 g_object_set(desktop->pr_monitors_res, "halign", GTK_ALIGN_START, NULL);
2108 #else
2109 gtk_misc_set_alignment(GTK_MISC(desktop->pr_monitors_res), 0.0, 0.5);
2110 #endif
2111 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_monitors_res, TRUE, TRUE,
2112 0);
2113 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2114 /* size */
2115 #if GTK_CHECK_VERSION(3, 0, 0)
2116 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2117 #else
2118 hbox = gtk_hbox_new(FALSE, 0);
2119 #endif
2120 label = gtk_label_new(_("Size: "));
2121 #if GTK_CHECK_VERSION(3, 0, 0)
2122 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2123 #else
2124 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2125 #endif
2126 gtk_size_group_add_widget(group, label);
2127 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2128 desktop->pr_monitors_size = gtk_label_new(NULL);
2129 #if GTK_CHECK_VERSION(3, 0, 0)
2130 g_object_set(desktop->pr_monitors_size, "halign", GTK_ALIGN_START,
2131 NULL);
2132 #else
2133 gtk_misc_set_alignment(GTK_MISC(desktop->pr_monitors_size), 0.0, 0.5);
2134 #endif
2135 gtk_box_pack_start(GTK_BOX(hbox), desktop->pr_monitors_size, TRUE, TRUE,
2136 0);
2137 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2138 /* refresh */
2139 #if GTK_CHECK_VERSION(3, 0, 0)
2140 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2141 #else
2142 hbox = gtk_hbox_new(FALSE, 0);
2143 #endif
2144 label = gtk_label_new(NULL);
2145 gtk_size_group_add_widget(group, label);
2146 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
2147 widget = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
2148 g_signal_connect_swapped(widget, "clicked", G_CALLBACK(
2149 _on_preferences_monitors_refresh), desktop);
2150 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
2151 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2152 /* updates */
2153 g_signal_connect_swapped(desktop->pr_monitors, "changed", G_CALLBACK(
2154 _on_preferences_monitors_changed), desktop);
2155 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
2156 _("Monitors")));
2157 }
2158
_on_preferences_closex(gpointer data)2159 static gboolean _on_preferences_closex(gpointer data)
2160 {
2161 _on_preferences_response_cancel(data);
2162 return TRUE;
2163 }
2164
_on_preferences_monitors_changed(gpointer data)2165 static void _on_preferences_monitors_changed(gpointer data)
2166 {
2167 Desktop * desktop = data;
2168 gint active;
2169 GdkRectangle geometry;
2170 gint width;
2171 gint height;
2172 char buf[64];
2173
2174 active = gtk_combo_box_get_active(GTK_COMBO_BOX(desktop->pr_monitors));
2175 geometry.x = 0;
2176 geometry.y = 0;
2177 geometry.width = gdk_screen_get_width(desktop->screen);
2178 geometry.height = gdk_screen_get_height(desktop->screen);
2179 width = gdk_screen_get_width_mm(desktop->screen);
2180 height = gdk_screen_get_height_mm(desktop->screen);
2181 #if GTK_CHECK_VERSION(2, 14, 0)
2182 if(active-- > 0)
2183 {
2184 gdk_screen_get_monitor_geometry(desktop->screen, active,
2185 &geometry);
2186 width = gdk_screen_get_monitor_width_mm(desktop->screen,
2187 active);
2188 height = gdk_screen_get_monitor_height_mm(desktop->screen,
2189 active);
2190 }
2191 #endif
2192 if(width < 0 || height < 0)
2193 snprintf(buf, sizeof(buf), "%s", _("Unknown size"));
2194 else
2195 snprintf(buf, sizeof(buf), _("%dx%d (at %d,%d)"),
2196 geometry.width, geometry.height,
2197 geometry.x, geometry.y);
2198 gtk_label_set_text(GTK_LABEL(desktop->pr_monitors_res), buf);
2199 if(width < 0 || height < 0)
2200 snprintf(buf, sizeof(buf), "%s", _("Unknown resolution"));
2201 else
2202 snprintf(buf, sizeof(buf), _("%dx%d mm (%.0fx%.0f DPI)"),
2203 width, height, geometry.width * 25.4 / width,
2204 geometry.height * 25.4 / height);
2205 gtk_label_set_text(GTK_LABEL(desktop->pr_monitors_size), buf);
2206 }
2207
_on_preferences_monitors_refresh(gpointer data)2208 static void _on_preferences_monitors_refresh(gpointer data)
2209 {
2210 Desktop * desktop = data;
2211 GtkTreeModel * model1;
2212 GtkTreeModel * model2;
2213 gint active;
2214 #if GTK_CHECK_VERSION(2, 14, 0)
2215 gint n;
2216 gint i;
2217 char * name;
2218 char buf[32];
2219 #endif
2220
2221 active = gtk_combo_box_get_active(GTK_COMBO_BOX(desktop->pr_imonitor));
2222 model1 = gtk_combo_box_get_model(GTK_COMBO_BOX(desktop->pr_imonitor));
2223 model2 = gtk_combo_box_get_model(GTK_COMBO_BOX(desktop->pr_monitors));
2224 gtk_list_store_clear(GTK_LIST_STORE(model1));
2225 gtk_list_store_clear(GTK_LIST_STORE(model2));
2226 #if GTK_CHECK_VERSION(2, 24, 0)
2227 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(desktop->pr_imonitor),
2228 _("Default monitor"));
2229 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(desktop->pr_monitors),
2230 _("Whole screen"));
2231 #else
2232 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_imonitor),
2233 _("Default monitor"));
2234 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_monitors),
2235 _("Whole screen"));
2236 #endif
2237 #if GTK_CHECK_VERSION(2, 14, 0)
2238 n = gdk_screen_get_n_monitors(desktop->screen);
2239 for(i = 0; i < n; i++)
2240 {
2241 snprintf(buf, sizeof(buf), _("Monitor %d"), i);
2242 name = gdk_screen_get_monitor_plug_name(desktop->screen, i);
2243 # if GTK_CHECK_VERSION(2, 24, 0)
2244 gtk_combo_box_text_append_text(
2245 GTK_COMBO_BOX_TEXT(desktop->pr_imonitor),
2246 (name != NULL) ? name : buf);
2247 gtk_combo_box_text_append_text(
2248 GTK_COMBO_BOX_TEXT(desktop->pr_monitors),
2249 (name != NULL) ? name : buf);
2250 # else
2251 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_imonitor),
2252 (name != NULL) ? name : buf);
2253 gtk_combo_box_append_text(GTK_COMBO_BOX(desktop->pr_monitors),
2254 (name != NULL) ? name : buf);
2255 # endif
2256 g_free(name);
2257 }
2258 #endif
2259 gtk_combo_box_set_active(GTK_COMBO_BOX(desktop->pr_imonitor), active);
2260 gtk_combo_box_set_active(GTK_COMBO_BOX(desktop->pr_monitors), 0);
2261 }
2262
_on_preferences_response(GtkWidget * widget,gint response,gpointer data)2263 static void _on_preferences_response(GtkWidget * widget, gint response,
2264 gpointer data)
2265 {
2266 Desktop * desktop = data;
2267
2268 if(response == GTK_RESPONSE_OK)
2269 _on_preferences_response_ok(desktop);
2270 else if(response == GTK_RESPONSE_APPLY)
2271 _on_preferences_response_apply(desktop);
2272 else if(response == GTK_RESPONSE_CANCEL)
2273 _on_preferences_response_cancel(desktop);
2274 }
2275
_on_preferences_response_apply(gpointer data)2276 static void _on_preferences_response_apply(gpointer data)
2277 {
2278 Desktop * desktop = data;
2279 Config * config;
2280 #if GTK_CHECK_VERSION(3, 0, 0)
2281 GdkRGBA color;
2282 #else
2283 GdkColor color;
2284 #endif
2285 char * p;
2286 char const * q;
2287 int i;
2288 char buf[12];
2289
2290 if((config = _desktop_get_config(desktop)) == NULL)
2291 return;
2292 /* XXX not very efficient */
2293 desktop_reset(desktop);
2294 /* background */
2295 p = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(
2296 desktop->pr_background));
2297 config_set(config, "background", "wallpaper", p);
2298 g_free(p);
2299 #if GTK_CHECK_VERSION(3, 4, 0)
2300 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(desktop->pr_color),
2301 &color);
2302 p = gdk_rgba_to_string(&color);
2303 #elif GTK_CHECK_VERSION(3, 0, 0)
2304 gtk_color_button_get_rgba(GTK_COLOR_BUTTON(desktop->pr_color), &color);
2305 p = gdk_rgba_to_string(&color);
2306 #else
2307 gtk_color_button_get_color(GTK_COLOR_BUTTON(desktop->pr_color), &color);
2308 p = gdk_color_to_string(&color);
2309 #endif
2310 config_set(config, "background", "color", p);
2311 g_free(p);
2312 i = gtk_combo_box_get_active(GTK_COMBO_BOX(desktop->pr_background_how));
2313 if(i >= 0 && i < DESKTOP_HOW_COUNT)
2314 config_set(config, "background", "how", _desktop_hows[i]);
2315 p = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
2316 desktop->pr_background_extend)) ? "1" : "0";
2317 config_set(config, "background", "extend", p);
2318 /* icons */
2319 i = gtk_combo_box_get_active(GTK_COMBO_BOX(desktop->pr_ilayout));
2320 if(i >= 0 && i < DESKTOP_ICONS_COUNT)
2321 config_set(config, "icons", "layout", _desktop_icons_config[i]);
2322 desktop->prefs.icons = i; /* applied by _new_idle() */
2323 #if GTK_CHECK_VERSION(3, 4, 0)
2324 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(desktop->pr_ibcolor),
2325 &color);
2326 p = gdk_rgba_to_string(&color);
2327 #elif GTK_CHECK_VERSION(3, 0, 0)
2328 gtk_color_button_get_rgba(GTK_COLOR_BUTTON(desktop->pr_ibcolor),
2329 &color);
2330 p = gdk_rgba_to_string(&color);
2331 #else
2332 gtk_color_button_get_color(GTK_COLOR_BUTTON(desktop->pr_ibcolor),
2333 &color);
2334 p = gdk_color_to_string(&color);
2335 #endif
2336 config_set(config, "icons", "background", p);
2337 g_free(p);
2338 #if GTK_CHECK_VERSION(3, 4, 0)
2339 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(desktop->pr_ifcolor),
2340 &color);
2341 p = gdk_rgba_to_string(&color);
2342 #elif GTK_CHECK_VERSION(3, 0, 0)
2343 gtk_color_button_get_rgba(GTK_COLOR_BUTTON(desktop->pr_ifcolor),
2344 &color);
2345 p = gdk_rgba_to_string(&color);
2346 #else
2347 gtk_color_button_get_color(GTK_COLOR_BUTTON(desktop->pr_ifcolor),
2348 &color);
2349 p = gdk_color_to_string(&color);
2350 #endif
2351 config_set(config, "icons", "foreground", p);
2352 g_free(p);
2353 q = gtk_font_button_get_font_name(GTK_FONT_BUTTON(desktop->pr_ifont));
2354 config_set(config, "icons", "font", q);
2355 i = gtk_combo_box_get_active(GTK_COMBO_BOX(desktop->pr_imonitor));
2356 desktop->prefs.monitor = (i >= 0) ? i - 1 : i;
2357 snprintf(buf, sizeof(buf), "%d", desktop->prefs.monitor);
2358 config_set(config, "icons", "monitor", buf);
2359 config_set(config, "icons", "show_hidden", desktop->show_hidden
2360 ? "1" : "0");
2361 /* XXX code duplication */
2362 if((p = string_new_append(desktop->home, "/" DESKTOPRC, NULL)) != NULL)
2363 {
2364 /* FIXME save configuration in _on_preferences_ok() instead */
2365 if(config_save(config, p) != 0)
2366 error_print(PROGNAME);
2367 string_delete(p);
2368 }
2369 config_delete(config);
2370 }
2371
_on_preferences_response_cancel(gpointer data)2372 static void _on_preferences_response_cancel(gpointer data)
2373 {
2374 Desktop * desktop = data;
2375
2376 gtk_widget_hide(desktop->pr_window);
2377 _preferences_set(desktop);
2378 }
2379
_on_preferences_response_ok(gpointer data)2380 static void _on_preferences_response_ok(gpointer data)
2381 {
2382 Desktop * desktop = data;
2383
2384 gtk_widget_hide(desktop->pr_window);
2385 _on_preferences_response_apply(desktop);
2386 }
2387
_on_preferences_update_preview(gpointer data)2388 static void _on_preferences_update_preview(gpointer data)
2389 {
2390 Desktop * desktop = data;
2391 #if !GTK_CHECK_VERSION(2, 6, 0)
2392 gint ratio = desktop->window.width / desktop->window.height;
2393 #endif
2394 GtkFileChooser * chooser = GTK_FILE_CHOOSER(desktop->pr_background);
2395 GtkWidget * widget;
2396 char * filename;
2397 GdkPixbuf * pixbuf;
2398 gboolean active = FALSE;
2399 GError * error = NULL;
2400
2401 widget = gtk_file_chooser_get_preview_widget(chooser);
2402 if((filename = gtk_file_chooser_get_preview_filename(chooser)) != NULL)
2403 {
2404 #if GTK_CHECK_VERSION(2, 6, 0)
2405 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, 96, -1,
2406 TRUE, &error);
2407 #else
2408 pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 96,
2409 96 / ratio, &error);
2410 #endif
2411 if(error != NULL)
2412 {
2413 _desktop_error(NULL, NULL, error->message, 1);
2414 g_error_free(error);
2415 }
2416 if(pixbuf != NULL)
2417 {
2418 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), pixbuf);
2419 g_object_unref(pixbuf);
2420 active = TRUE;
2421 }
2422 }
2423 g_free(filename);
2424 gtk_file_chooser_set_preview_widget_active(chooser, active);
2425 }
2426
_preferences_set(Desktop * desktop)2427 static void _preferences_set(Desktop * desktop)
2428 {
2429 Config * config;
2430 String const * p;
2431 String * q;
2432 String const * filename = NULL;
2433 const char black[] = "#000000000000";
2434 const char white[] = "#ffffffffffff";
2435 int how;
2436 gboolean extend = FALSE;
2437 size_t i;
2438 int j;
2439
2440 /* FIXME:
2441 * - cache the current configuration within the Desktop class
2442 * - apply the configuration values to the widgets */
2443 if((config = _desktop_get_config(desktop)) != NULL)
2444 {
2445 /* background */
2446 filename = config_get(config, "background", "wallpaper");
2447 _preferences_set_color(config, "background", "color", NULL,
2448 desktop->pr_color);
2449 how = 0;
2450 if((p = config_get(config, "background", "how")) != NULL)
2451 for(i = 0; i < DESKTOP_HOW_COUNT; i++)
2452 if(strcmp(_desktop_hows[i], p) == 0)
2453 {
2454 how = i;
2455 break;
2456 }
2457 gtk_combo_box_set_active(GTK_COMBO_BOX(
2458 desktop->pr_background_how), how);
2459 if((p = config_get(config, "background", "extend")) != NULL)
2460 extend = strtol(p, NULL, 10) ? TRUE : FALSE;
2461 /* icons */
2462 how = DESKTOP_ICONS_FILES;
2463 if((p = config_get(config, "icons", "layout")) != NULL)
2464 for(i = 0; i < DESKTOP_ICONS_COUNT; i++)
2465 if(strcmp(_desktop_icons_config[i], p) == 0)
2466 {
2467 how = i;
2468 break;
2469 }
2470 gtk_combo_box_set_active(GTK_COMBO_BOX(desktop->pr_ilayout),
2471 how);
2472 _preferences_set_color(config, "icons", "background", black,
2473 desktop->pr_ibcolor);
2474 _preferences_set_color(config, "icons", "foreground", white,
2475 desktop->pr_ifcolor);
2476 if((p = config_get(config, "icons", "font")) != NULL)
2477 gtk_font_button_set_font_name(GTK_FONT_BUTTON(
2478 desktop->pr_ifont), p);
2479 else if((q = pango_font_description_to_string(desktop->font))
2480 != NULL)
2481 {
2482 gtk_font_button_set_font_name(GTK_FONT_BUTTON(
2483 desktop->pr_ifont), q);
2484 g_free(q);
2485 }
2486 if((p = config_get(config, "icons", "monitor")) != NULL)
2487 {
2488 j = strtol(p, &q, 10);
2489 if(p[0] == '\0' || *q != '\0' || j < 0)
2490 j = -1;
2491 gtk_combo_box_set_active(GTK_COMBO_BOX(
2492 desktop->pr_imonitor), j + 1);
2493 }
2494 config_delete(config);
2495 }
2496 else
2497 {
2498 gtk_combo_box_set_active(GTK_COMBO_BOX(
2499 desktop->pr_background_how), 0);
2500 gtk_combo_box_set_active(GTK_COMBO_BOX(desktop->pr_ilayout),
2501 DESKTOP_ICONS_FILES);
2502 gtk_combo_box_set_active(GTK_COMBO_BOX(desktop->pr_imonitor),
2503 0);
2504 }
2505 if(filename != NULL)
2506 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(
2507 desktop->pr_background), filename);
2508 else
2509 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(
2510 desktop->pr_background));
2511 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
2512 desktop->pr_background_extend), extend);
2513 }
2514
_preferences_set_color(Config * config,char const * section,char const * variable,char const * fallback,GtkWidget * widget)2515 static void _preferences_set_color(Config * config, char const * section,
2516 char const * variable, char const * fallback,
2517 GtkWidget * widget)
2518 {
2519 char const * p;
2520 #if GTK_CHECK_VERSION(3, 0, 0)
2521 GdkRGBA color = { 0.0, 0.0, 0.0, 0.0 };
2522 #else
2523 GdkColor color = { 0, 0, 0, 0 };
2524 #endif
2525
2526 if((p = config_get(config, section, variable)) == NULL)
2527 p = fallback;
2528 #if GTK_CHECK_VERSION(3, 4, 0)
2529 if(p != NULL && gdk_rgba_parse(&color, p) == TRUE)
2530 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(widget), &color);
2531 #elif GTK_CHECK_VERSION(3, 0, 0)
2532 if(p != NULL && gdk_rgba_parse(&color, p) == TRUE)
2533 gtk_color_button_set_rgba(GTK_COLOR_BUTTON(widget), &color);
2534 #else
2535 if(p != NULL && gdk_color_parse(p, &color) == TRUE)
2536 gtk_color_button_set_color(GTK_COLOR_BUTTON(widget), &color);
2537 #endif
2538 }
2539
2540
2541 /* callbacks */
2542 /* desktop_on_refresh */
2543 static void _refresh_cleanup(Desktop * desktop);
2544 static void _refresh_done_applications(Desktop * desktop);
2545 static void _refresh_done_categories(Desktop * desktop);
2546 static void _refresh_done_categories_open(Desktop * desktop, gpointer data);
2547 static gboolean _refresh_done_timeout(gpointer data);
2548 static int _refresh_loop(Desktop * desktop);
2549 static gint _categories_apps_compare(gconstpointer a, gconstpointer b);
2550 static int _refresh_loop_categories(Desktop * desktop);
2551 static void _refresh_loop_categories_path(Desktop * desktop, char const * path,
2552 char const * apppath);
2553 static void _refresh_loop_categories_xdg(Desktop * desktop,
2554 void (*callback)(Desktop * desktop, char const * path,
2555 char const * apppath));
2556 static void _refresh_loop_categories_xdg_home(Desktop * desktop,
2557 void (*callback)(Desktop * desktop, char const * path,
2558 char const * apppath));
2559 static void _refresh_loop_categories_xdg_path(Desktop * desktop,
2560 void (*callback)(Desktop * desktop, char const * path,
2561 char const * apppath), char const * path);
2562 static int _refresh_loop_files(Desktop * desktop);
2563 static int _refresh_loop_lookup(Desktop * desktop, char const * name);
2564 static gboolean _refresh_done(Desktop * desktop);
2565
_desktop_on_refresh(gpointer data)2566 static gboolean _desktop_on_refresh(gpointer data)
2567 {
2568 Desktop * desktop = data;
2569 unsigned int i;
2570
2571 for(i = 0; i < 16 && _refresh_loop(desktop) == 0; i++);
2572 if(i == 16)
2573 return TRUE;
2574 return _refresh_done(desktop);
2575 }
2576
_refresh_cleanup(Desktop * desktop)2577 static void _refresh_cleanup(Desktop * desktop)
2578 {
2579 size_t i;
2580
2581 for(i = 0; i < desktop->icon_cnt;)
2582 if(desktopicon_get_immutable(desktop->icon[i]) == TRUE)
2583 i++;
2584 else if(desktopicon_get_updated(desktop->icon[i]) != TRUE)
2585 _desktop_icon_remove(desktop, desktop->icon[i]);
2586 else
2587 desktopicon_set_updated(desktop->icon[i++], FALSE);
2588 }
2589
_refresh_done(Desktop * desktop)2590 static gboolean _refresh_done(Desktop * desktop)
2591 {
2592 switch(desktop->prefs.icons)
2593 {
2594 case DESKTOP_ICONS_APPLICATIONS:
2595 _refresh_done_applications(desktop);
2596 break;
2597 case DESKTOP_ICONS_CATEGORIES:
2598 _refresh_done_categories(desktop);
2599 break;
2600 default:
2601 break;
2602 }
2603 _refresh_cleanup(desktop);
2604 if(desktop->refresh_dir != NULL)
2605 browser_vfs_closedir(desktop->refresh_dir);
2606 desktop->refresh_dir = NULL;
2607 desktop_icons_align(desktop);
2608 desktop->refresh_source = g_timeout_add(1000, _refresh_done_timeout,
2609 desktop);
2610 return FALSE;
2611 }
2612
_refresh_done_applications(Desktop * desktop)2613 static void _refresh_done_applications(Desktop * desktop)
2614 {
2615 GSList * p;
2616 Config * config;
2617 const char section[] = "Desktop Entry";
2618 char const * q;
2619 char const * r;
2620 DesktopCategory * dc = desktop->category;
2621 char const * path;
2622 DesktopIcon * icon;
2623
2624 for(p = desktop->apps; p != NULL; p = p->next)
2625 {
2626 config = p->data;
2627 if(dc != NULL)
2628 {
2629 if((q = config_get(config, section, "Categories"))
2630 == NULL)
2631 continue;
2632 if((r = string_find(q, dc->category)) == NULL)
2633 continue;
2634 r += string_length(dc->category);
2635 if(*r != '\0' && *r != ';')
2636 continue;
2637 }
2638 path = config_get(config, NULL, "path");
2639 q = config_get(config, NULL, "datadir");
2640 if((icon = desktopicon_new_application(desktop, path, q))
2641 == NULL)
2642 continue;
2643 _desktop_icon_add(desktop, icon);
2644 }
2645 }
2646
_refresh_done_categories(Desktop * desktop)2647 static void _refresh_done_categories(Desktop * desktop)
2648 {
2649 GSList * p;
2650 Config * config;
2651 const char section[] = "Desktop Entry";
2652 char const * q;
2653 char const * r;
2654 size_t i;
2655 DesktopCategory * dc;
2656 char const * path;
2657 DesktopIcon * icon;
2658
2659 for(p = desktop->apps; p != NULL; p = p->next)
2660 {
2661 config = p->data;
2662 path = config_get(config, NULL, "path");
2663 if((q = config_get(config, section, "Categories")) == NULL)
2664 {
2665 if((icon = desktopicon_new_application(desktop, path,
2666 NULL)) != NULL)
2667 _desktop_icon_add(desktop, icon);
2668 continue;
2669 }
2670 for(i = 0; i < _desktop_categories_cnt; i++)
2671 {
2672 dc = &_desktop_categories[i];
2673 if((r = string_find(q, dc->category)) == NULL)
2674 continue;
2675 r += string_length(dc->category);
2676 if(*r == '\0' || *r == ';')
2677 break;
2678 }
2679 if(i == _desktop_categories_cnt)
2680 {
2681 if((icon = desktopicon_new_application(desktop, path,
2682 NULL)) != NULL)
2683 _desktop_icon_add(desktop, icon);
2684 continue;
2685 }
2686 if(dc->show == TRUE)
2687 continue;
2688 dc->show = TRUE;
2689 if((icon = desktopicon_new_category(desktop, dc->name,
2690 dc->icon)) == NULL)
2691 continue;
2692 desktopicon_set_callback(icon, _refresh_done_categories_open,
2693 dc);
2694 _desktop_icon_add(desktop, icon);
2695 }
2696 }
2697
_refresh_done_categories_open(Desktop * desktop,gpointer data)2698 static void _refresh_done_categories_open(Desktop * desktop, gpointer data)
2699 {
2700 DesktopCategory * dc = data;
2701
2702 #ifdef DEBUG
2703 fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, dc->name);
2704 #endif
2705 desktop->category = dc;
2706 desktop_set_icons(desktop, DESKTOP_ICONS_APPLICATIONS);
2707 }
2708
_refresh_done_timeout(gpointer data)2709 static gboolean _refresh_done_timeout(gpointer data)
2710 {
2711 Desktop * desktop = data;
2712 struct stat st;
2713
2714 desktop->refresh_source = 0;
2715 if(desktop->path == NULL)
2716 return FALSE;
2717 if(stat(desktop->path, &st) != 0)
2718 return desktop_error(NULL, desktop->path, FALSE);
2719 if(st.st_mtime == desktop->refresh_mti)
2720 return TRUE;
2721 desktop_refresh(desktop);
2722 return FALSE;
2723 }
2724
_refresh_loop(Desktop * desktop)2725 static int _refresh_loop(Desktop * desktop)
2726 {
2727 switch(desktop->prefs.icons)
2728 {
2729 case DESKTOP_ICONS_APPLICATIONS:
2730 case DESKTOP_ICONS_CATEGORIES:
2731 return _refresh_loop_categories(desktop);
2732 case DESKTOP_ICONS_FILES:
2733 return _refresh_loop_files(desktop);
2734 case DESKTOP_ICONS_HOMESCREEN:
2735 case DESKTOP_ICONS_NONE:
2736 return 1; /* nothing to do */
2737 }
2738 return -1;
2739 }
2740
_refresh_loop_categories(Desktop * desktop)2741 static int _refresh_loop_categories(Desktop * desktop)
2742 {
2743 _refresh_loop_categories_xdg(desktop, _refresh_loop_categories_path);
2744 return 1;
2745 }
2746
_refresh_loop_categories_path(Desktop * desktop,char const * path,char const * apppath)2747 static void _refresh_loop_categories_path(Desktop * desktop, char const * path,
2748 char const * apppath)
2749 {
2750 DIR * dir;
2751 int fd;
2752 struct stat st;
2753 struct dirent * de;
2754 size_t len;
2755 const char ext[] = ".desktop";
2756 const char section[] = "Desktop Entry";
2757 char * name = NULL;
2758 char * p;
2759 Config * config = NULL;
2760 String const * q;
2761 String const * r;
2762
2763 #if defined(__sun)
2764 if((fd = open(apppath, O_RDONLY)) < 0
2765 || fstat(fd, &st) != 0
2766 || (dir = fdopendir(fd)) == NULL)
2767 #else
2768 if((dir = opendir(apppath)) == NULL
2769 || (fd = dirfd(dir)) < 0
2770 || fstat(fd, &st) != 0)
2771 #endif
2772 {
2773 if(errno != ENOENT)
2774 desktop_error(NULL, apppath, 1);
2775 return;
2776 }
2777 if(st.st_mtime > desktop->refresh_mti)
2778 desktop->refresh_mti = st.st_mtime;
2779 while((de = readdir(dir)) != NULL)
2780 {
2781 if(de->d_name[0] == '.')
2782 if(de->d_name[1] == '\0' || (de->d_name[1] == '.'
2783 && de->d_name[2] == '\0'))
2784 continue;
2785 len = strlen(de->d_name);
2786 if(len < sizeof(ext))
2787 continue;
2788 if(strncmp(&de->d_name[len - sizeof(ext) + 1], ext,
2789 sizeof(ext)) != 0)
2790 continue;
2791 if((p = realloc(name, strlen(apppath) + len + 2)) == NULL)
2792 {
2793 desktop_error(NULL, apppath, 1);
2794 continue;
2795 }
2796 name = p;
2797 snprintf(name, strlen(apppath) + len + 2, "%s/%s", apppath,
2798 de->d_name);
2799 #ifdef DEBUG
2800 fprintf(stderr, "DEBUG: %s() name=\"%s\" path=\"%s\"\n",
2801 __func__, name, path);
2802 #endif
2803 if(config == NULL)
2804 config = config_new();
2805 else
2806 config_reset(config);
2807 if(config == NULL || config_load(config, name) != 0)
2808 {
2809 desktop_error(NULL, NULL, 1); /* XXX */
2810 continue;
2811 }
2812 q = config_get(config, section, "Name");
2813 r = config_get(config, section, "Type");
2814 if(q == NULL || r == NULL)
2815 continue;
2816 /* remember the path */
2817 config_set(config, NULL, "path", name);
2818 config_set(config, NULL, "datadir", path);
2819 desktop->apps = g_slist_insert_sorted(desktop->apps, config,
2820 _categories_apps_compare);
2821 config = NULL;
2822 }
2823 free(name);
2824 closedir(dir);
2825 if(config != NULL)
2826 config_delete(config);
2827 }
2828
_refresh_loop_categories_xdg(Desktop * desktop,void (* callback)(Desktop * desktop,char const * path,char const * apppath))2829 static void _refresh_loop_categories_xdg(Desktop * desktop,
2830 void (*callback)(Desktop * desktop, char const * path,
2831 char const * apppath))
2832 {
2833 char const * path;
2834 char * p;
2835 size_t i;
2836 size_t j;
2837
2838 if((path = getenv("XDG_DATA_DIRS")) == NULL || strlen(path) == 0)
2839 /* FIXME use DATADIR */
2840 path = "/usr/local/share:/usr/share";
2841 if((p = strdup(path)) == NULL)
2842 {
2843 desktop_error(NULL, "strdup", 1);
2844 return;
2845 }
2846 for(i = 0, j = 0;; i++)
2847 if(p[i] == '\0')
2848 {
2849 _refresh_loop_categories_xdg_path(desktop, callback,
2850 &p[j]);
2851 break;
2852 }
2853 else if(p[i] == ':')
2854 {
2855 p[i] = '\0';
2856 _refresh_loop_categories_xdg_path(desktop, callback,
2857 &p[j]);
2858 j = i + 1;
2859 }
2860 free(p);
2861 _refresh_loop_categories_xdg_home(desktop, callback);
2862 }
2863
_refresh_loop_categories_xdg_home(Desktop * desktop,void (* callback)(Desktop * desktop,char const * path,char const * apppath))2864 static void _refresh_loop_categories_xdg_home(Desktop * desktop,
2865 void (*callback)(Desktop * desktop, char const * path,
2866 char const * apppath))
2867 {
2868 char const fallback[] = ".local/share";
2869 char const * path;
2870 char const * homedir;
2871 size_t len;
2872 char * p;
2873
2874 /* use $XDG_DATA_HOME if set and not empty */
2875 if((path = getenv("XDG_DATA_HOME")) != NULL && strlen(path) > 0)
2876 {
2877 _refresh_loop_categories_xdg_path(desktop, callback, path);
2878 return;
2879 }
2880 /* fallback to "$HOME/.local/share" */
2881 if((homedir = getenv("HOME")) == NULL)
2882 homedir = g_get_home_dir();
2883 len = strlen(homedir) + 1 + sizeof(fallback);
2884 if((p = malloc(len)) == NULL)
2885 {
2886 desktop_error(NULL, homedir, 1);
2887 return;
2888 }
2889 snprintf(p, len, "%s/%s", homedir, fallback);
2890 _refresh_loop_categories_xdg_path(desktop, callback, p);
2891 free(p);
2892 }
2893
_refresh_loop_categories_xdg_path(Desktop * desktop,void (* callback)(Desktop * desktop,char const * path,char const * apppath),char const * path)2894 static void _refresh_loop_categories_xdg_path(Desktop * desktop,
2895 void (*callback)(Desktop * desktop, char const * path,
2896 char const * apppath), char const * path)
2897 {
2898 const char applications[] = "/applications";
2899 char * apppath;
2900
2901 if((apppath = string_new_append(path, applications, NULL)) == NULL)
2902 desktop_error(NULL, path, 1);
2903 callback(desktop, path, apppath);
2904 string_delete(apppath);
2905 }
2906
_categories_apps_compare(gconstpointer a,gconstpointer b)2907 static gint _categories_apps_compare(gconstpointer a, gconstpointer b)
2908 {
2909 Config * ca = (Config *)a;
2910 Config * cb = (Config *)b;
2911 char const * cap;
2912 char const * cbp;
2913 const char section[] = "Desktop Entry";
2914 const char variable[] = "Name";
2915
2916 /* these should not fail */
2917 cap = config_get(ca, section, variable);
2918 cbp = config_get(cb, section, variable);
2919 return string_compare(cap, cbp);
2920 }
2921
_refresh_loop_files(Desktop * desktop)2922 static int _refresh_loop_files(Desktop * desktop)
2923 {
2924 struct dirent * de;
2925 String * p;
2926 DesktopIcon * desktopicon;
2927
2928 while((de = browser_vfs_readdir(desktop->refresh_dir)) != NULL)
2929 {
2930 if(de->d_name[0] == '.')
2931 {
2932 if(de->d_name[1] == '\0')
2933 continue;
2934 if(de->d_name[1] == '.' && de->d_name[2] == '\0')
2935 continue;
2936 if(desktop->show_hidden == 0)
2937 continue;
2938 }
2939 if(_refresh_loop_lookup(desktop, de->d_name) == 1)
2940 continue;
2941 break;
2942 }
2943 if(de == NULL)
2944 return -1;
2945 if((p = string_new_append(desktop->path, "/", de->d_name, NULL))
2946 == NULL)
2947 return -_desktop_serror(desktop, de->d_name, 1);
2948 if((desktopicon = desktopicon_new(desktop, de->d_name, p)) != NULL)
2949 desktop_icon_add(desktop, desktopicon);
2950 string_delete(p);
2951 return 0;
2952 }
2953
_refresh_loop_lookup(Desktop * desktop,char const * name)2954 static int _refresh_loop_lookup(Desktop * desktop, char const * name)
2955 {
2956 size_t i;
2957 char const * p;
2958
2959 for(i = 0; i < desktop->icon_cnt; i++)
2960 {
2961 if(desktopicon_get_updated(desktop->icon[i]) == TRUE)
2962 continue;
2963 if((p = desktopicon_get_path(desktop->icon[i])) == NULL
2964 || (p = strrchr(p, '/')) == NULL)
2965 continue;
2966 if(strcmp(name, ++p) != 0)
2967 continue;
2968 desktopicon_set_updated(desktop->icon[i], TRUE);
2969 return 1;
2970 }
2971 return 0;
2972 }
2973
2974
2975 /* error */
_error(char const * message,int ret)2976 static int _error(char const * message, int ret)
2977 {
2978 fputs("desktop: ", stderr);
2979 perror(message);
2980 return ret;
2981 }
2982
2983
2984 /* usage */
_usage(void)2985 static int _usage(void)
2986 {
2987 fprintf(stderr, _("Usage: %s [-H|-V][-a|-c|-f|-h|-n][-m monitor][-N][-w]\n"
2988 " -H Place icons horizontally\n"
2989 " -V Place icons vertically\n"
2990 " -a Display the applications registered\n"
2991 " -c Sort the applications registered by category\n"
2992 " -f Display contents of the desktop folder (default)\n"
2993 " -h Display the homescreen\n"
2994 " -m Monitor where to display the desktop\n"
2995 " -n Do not display icons on the desktop\n"
2996 " -N Do not intercept mouse clicks on the desktop\n"
2997 " -w Draw the desktop as a window\n"), PROGNAME);
2998 return 1;
2999 }
3000
3001
3002 /* main */
main(int argc,char * argv[])3003 int main(int argc, char * argv[])
3004 {
3005 int o;
3006 Desktop * desktop;
3007 DesktopPrefs prefs;
3008 char * p;
3009
3010 if(setlocale(LC_ALL, "") == NULL)
3011 _error("setlocale", 1);
3012 bindtextdomain(PACKAGE, LOCALEDIR);
3013 textdomain(PACKAGE);
3014 prefs.alignment = -1;
3015 prefs.icons = -1;
3016 prefs.monitor = -1;
3017 prefs.popup = 1;
3018 prefs.window = 0;
3019 gtk_init(&argc, &argv);
3020 while((o = getopt(argc, argv, "HVacfhm:nNw")) != -1)
3021 switch(o)
3022 {
3023 case 'H':
3024 prefs.alignment = DESKTOP_ALIGNMENT_HORIZONTAL;
3025 break;
3026 case 'V':
3027 prefs.alignment = DESKTOP_ALIGNMENT_VERTICAL;
3028 break;
3029 case 'a':
3030 prefs.icons = DESKTOP_ICONS_APPLICATIONS;
3031 break;
3032 case 'c':
3033 prefs.icons = DESKTOP_ICONS_CATEGORIES;
3034 break;
3035 case 'f':
3036 prefs.icons = DESKTOP_ICONS_FILES;
3037 break;
3038 case 'h':
3039 prefs.icons = DESKTOP_ICONS_HOMESCREEN;
3040 break;
3041 case 'm':
3042 prefs.monitor = strtol(optarg, &p, 0);
3043 if(optarg[0] == '\0' || *p != '\0')
3044 return _usage();
3045 break;
3046 case 'n':
3047 prefs.icons = DESKTOP_ICONS_NONE;
3048 break;
3049 case 'N':
3050 prefs.popup = 0;
3051 break;
3052 case 'w':
3053 prefs.window = 1;
3054 break;
3055 default:
3056 return _usage();
3057 }
3058 if(optind < argc)
3059 return _usage();
3060 if((desktop = desktop_new(&prefs)) == NULL)
3061 {
3062 gtk_main();
3063 return 2;
3064 }
3065 gtk_main();
3066 desktop_delete(desktop);
3067 return 0;
3068 }
3069