gnome-control-center/control-center/control-center-categories.c
Jody Goldberg f8403674b3 Ensure that the selected entry is visible.
2004-05-18  Jody Goldberg <jody@gnome.org>

	* control-center.c (select_entry) : Ensure that the selected
	  entry is visible.

2004-05-17  Jody Goldberg <jody@gnome.org>

	* control-center-categories.c : merge the icon theme handling from the
	  existing control center into the ximian shell.
2004-05-18 14:58:20 +00:00

494 lines
14 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* capplet-dir.c
* Copyright (C) 2000, 2001 Ximian, Inc.
* Copyright (C) 1998 Red Hat Software, Inc.
*
* Written by Bradford Hovinen <hovinen@ximian.com>,
* Jonathan Blandford <jrb@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "control-center-categories.h"
#include <gnome.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <string.h>
#include <glib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <libgnomevfs/gnome-vfs.h>
/********************************************************************
*
* Stolen from nautilus to keep control center and nautilus in sync
*/
static gboolean
eel_str_has_suffix (const char *haystack, const char *needle)
{
const char *h, *n;
if (needle == NULL) {
return TRUE;
}
if (haystack == NULL) {
return needle[0] == '\0';
}
/* Eat one character at a time. */
h = haystack + strlen(haystack);
n = needle + strlen(needle);
do {
if (n == needle) {
return TRUE;
}
if (h == haystack) {
return FALSE;
}
} while (*--h == *--n);
return FALSE;
}
static char *
eel_str_strip_trailing_str (const char *source, const char *remove_this)
{
const char *end;
if (source == NULL) {
return NULL;
}
if (remove_this == NULL) {
return g_strdup (source);
}
end = source + strlen (source);
if (strcmp (end - strlen (remove_this), remove_this) != 0) {
return g_strdup (source);
}
else {
return g_strndup (source, strlen (source) - strlen(remove_this));
}
}
static char *
nautilus_remove_icon_file_name_suffix (const char *icon_name)
{
guint i;
const char *suffix;
static const char *icon_file_name_suffixes[] = { ".svg", ".svgz", ".png", ".jpg", ".xpm" };
for (i = 0; i < G_N_ELEMENTS (icon_file_name_suffixes); i++) {
suffix = icon_file_name_suffixes[i];
if (eel_str_has_suffix (icon_name, suffix)) {
return eel_str_strip_trailing_str (icon_name, suffix);
}
}
return g_strdup (icon_name);
}
/********************************************************************/
static GdkPixbuf *
find_icon (GnomeDesktopItem *dentry)
{
GdkPixbuf *res;
char const *icon;
GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
icon = gnome_desktop_item_get_string (dentry, GNOME_DESKTOP_ITEM_ICON);
if (icon == NULL || icon[0] == 0)
icon = "gnome-settings";
else if (g_path_is_absolute (icon))
res = gdk_pixbuf_new_from_file (icon, NULL);
else {
char *no_suffix = nautilus_remove_icon_file_name_suffix (icon);
res = gtk_icon_theme_load_icon (icon_theme, no_suffix, 48, 0, NULL);
g_free (no_suffix);
if (res == NULL) {
char *path = g_build_filename (GNOMECC_ICONS_DIR, icon, NULL);
res = gdk_pixbuf_new_from_file (path, NULL);
g_free (path);
}
}
if (res == NULL)
res = gtk_icon_theme_load_icon (icon_theme, "gnome-unknown", 48, 0, NULL);
if (res == NULL)
res = gtk_icon_theme_load_icon (icon_theme, "gtk-missing-image", 48, 0, NULL);
return res;
}
GnomeDesktopItem *
get_directory_entry (GnomeVFSURI *uri)
{
GnomeVFSURI *desktop_uri;
char *desktop_uri_string;
GnomeDesktopItem *entry;
desktop_uri = gnome_vfs_uri_append_file_name (uri, ".directory");
desktop_uri_string = gnome_vfs_uri_to_string (desktop_uri, GNOME_VFS_URI_HIDE_NONE);
entry = gnome_desktop_item_new_from_uri (desktop_uri_string,
GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS,
NULL);
gnome_vfs_uri_unref (desktop_uri);
g_free (desktop_uri_string);
return entry;
}
typedef void (*DirectoryCallback) (GnomeVFSURI *uri, const char *name, GnomeDesktopItem *entry, gpointer user_data);
typedef void (*EntryCallback) (GnomeVFSURI *uri, const char *name, GnomeDesktopItem *entry, gpointer user_data);
static void
read_entries (GnomeVFSURI *uri, gint auto_recurse_level, DirectoryCallback dcb, EntryCallback ecb, gpointer user_data)
{
gchar *test;
GnomeVFSDirectoryHandle *parent_dir;
GnomeVFSResult result;
GnomeVFSFileInfo *child = gnome_vfs_file_info_new ();
result = gnome_vfs_directory_open_from_uri (&parent_dir, uri,
GNOME_VFS_FILE_INFO_DEFAULT);
if (result != GNOME_VFS_OK)
return;
while (gnome_vfs_directory_read_next (parent_dir, child) == GNOME_VFS_OK) {
GnomeVFSURI *fulluri;
char *fullpath;
if (child->name[0] == '.')
continue;
fulluri = gnome_vfs_uri_append_path (uri, child->name);
fullpath = gnome_vfs_uri_to_string (fulluri, GNOME_VFS_URI_HIDE_NONE);
if (child->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
if (auto_recurse_level != 0) {
gint recurse;
if (auto_recurse_level < 0)
recurse = auto_recurse_level;
else
recurse = auto_recurse_level - 1;
read_entries (fulluri, recurse, dcb, ecb, user_data);
} else {
GnomeDesktopItem *entry;
entry = get_directory_entry (fulluri);
dcb (fulluri, child->name, entry, user_data);
if (entry)
gnome_desktop_item_unref (entry);
}
} else {
test = rindex(child->name, '.');
/* if it's a .desktop file, it's interesting for sure! */
if (test && !strcmp (".desktop", test)) {
GnomeDesktopItem *entry;
entry = gnome_desktop_item_new_from_uri (fullpath,
GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS,
NULL);
if (entry) {
ecb (fulluri, child->name, entry, user_data);
gnome_desktop_item_unref (entry);
}
}
}
gnome_vfs_uri_unref (fulluri);
g_free (fullpath);
}
gnome_vfs_directory_close (parent_dir);
}
typedef struct {
GSList *entries;
GSList *names;
GnomeDesktopItem *directory_entry;
char *name;
} CategoryLoadInformation;
typedef struct {
CategoryLoadInformation *other;
GSList *categories;
} FullLoadInformation;
static void
do_sort (GnomeDesktopItem *item, void **base, size_t nmemb,
int (*compar)(const void *, const void *),
const char *(*get_name)(const void *))
{
char **sort_orders = NULL;
qsort (base, nmemb, sizeof (void *), compar);
if (item)
sort_orders = gnome_desktop_item_get_strings (item, GNOME_DESKTOP_ITEM_SORT_ORDER);
if (sort_orders) {
int i;
int j = 0;
for (i = 0; sort_orders[i]; i++) {
int k;
for (k = j; k < nmemb; k++) {
const char *name = get_name (base[k]);
if (name && !strcmp (name, sort_orders[i])) {
void *temp = base[k];
memmove (base + j + 1, base + j, (k - j) * sizeof (void *));
base[j] = temp;
j++;
/* if (j >= nmemb), then k >= j >= nmemb
and thus we don't need a break
here. */
}
}
if (j >= nmemb)
break;
}
g_strfreev (sort_orders);
}
}
static int
compare_entries (const void *ap, const void *bp)
{
ControlCenterEntry *a = *(ControlCenterEntry **)ap;
ControlCenterEntry *b = *(ControlCenterEntry **)bp;
if (a->title == NULL && b->title == NULL)
return 0;
if (a->title == NULL)
return 1;
if (b->title == NULL)
return -1;
return strcmp (a->title,
b->title);
}
static const char *
get_entry_name (const void *ap)
{
ControlCenterEntry *a = (ControlCenterEntry *)ap;
return a->name;
}
static void
free_entry (ControlCenterEntry *entry)
{
g_object_unref (entry->icon_pixbuf);
entry->icon_pixbuf = NULL;
g_free (entry->name);
if (entry->desktop_entry)
gnome_desktop_item_unref (entry->desktop_entry);
}
static void
free_category (ControlCenterCategory *category)
{
int i;
for (i = 0; i < category->count; i++) {
free_entry (category->entries[i]);
}
g_free (category->entries);
if (category->directory_entry)
gnome_desktop_item_unref (category->directory_entry);
}
static ControlCenterCategory *
load_information_to_category (CategoryLoadInformation *info, gboolean real_category)
{
ControlCenterCategory *category = g_new (ControlCenterCategory, 1);
int i;
GSList *iterator, *name_iterator;
category->count = g_slist_length (info->entries);
category->entries = g_new (ControlCenterEntry *, category->count);
category->directory_entry = info->directory_entry;
category->title = NULL;
category->name = info->name;
category->user_data = NULL;
category->real_category = real_category;
if (category->directory_entry)
category->title = gnome_desktop_item_get_localestring (category->directory_entry,
GNOME_DESKTOP_ITEM_NAME);
if (!category->title || !category->title[0])
category->title = category->name;
if (!category->title || !category->title[0])
category->title = _("Others");
for (i = 0, iterator = info->entries, name_iterator = info->names;
i < category->count;
i++, iterator = iterator->next, name_iterator = name_iterator->next) {
category->entries[i] = g_new (ControlCenterEntry, 1);
category->entries[i]->desktop_entry = iterator->data;
category->entries[i]->icon_pixbuf = find_icon (category->entries[i]->desktop_entry);
category->entries[i]->user_data = NULL;
category->entries[i]->name = name_iterator->data;
category->entries[i]->category = category;
if (category->entries[i]->desktop_entry) {
category->entries[i]->title =
gnome_desktop_item_get_localestring (category->entries[i]->desktop_entry,
GNOME_DESKTOP_ITEM_NAME);
category->entries[i]->comment =
gnome_desktop_item_get_localestring (category->entries[i]->desktop_entry,
GNOME_DESKTOP_ITEM_COMMENT);
} else {
category->entries[i]->title = NULL;
category->entries[i]->comment = NULL;
}
}
do_sort (category->directory_entry, (void **) category->entries, category->count, compare_entries, get_entry_name);
g_slist_free (info->entries);
g_slist_free (info->names);
return category;
}
static int
compare_categories (const void *ap, const void *bp)
{
ControlCenterCategory *a = *(ControlCenterCategory **)ap;
ControlCenterCategory *b = *(ControlCenterCategory **)bp;
if (a->title == NULL && b->title == NULL)
return 0;
if (a->title == NULL)
return 1;
if (b->title == NULL)
return -1;
return strcmp (a->title,
b->title);
}
static const char *
get_category_name (const void *ap)
{
ControlCenterCategory *a = (ControlCenterCategory *)ap;
return a->name;
}
static ControlCenterInformation *
load_information_to_information (GnomeVFSURI *base_uri, FullLoadInformation *info)
{
ControlCenterInformation *information = g_new (ControlCenterInformation, 1);
int i;
GSList *iterator;
information->count = g_slist_length (info->categories);
information->categories = g_new (ControlCenterCategory *, information->count);
i = 0;
for (iterator = info->categories; iterator != NULL; iterator = iterator->next) {
ControlCenterCategory *category = iterator->data;
if (category->count)
information->categories[i++] = category;
else {
free_category (category);
}
}
if (information->count != i) {
information->count = i;
information->categories = g_renew (ControlCenterCategory *, information->categories, information->count);
}
g_slist_free (info->categories);
information->directory_entry = get_directory_entry (base_uri);
information->title = NULL;
if (information->directory_entry) {
do_sort (information->directory_entry, (void **) information->categories, information->count, compare_categories, get_category_name);
information->title = gnome_desktop_item_get_localestring (information->directory_entry,
GNOME_DESKTOP_ITEM_NAME);
}
if (!information->title || !information->title[0])
information->title = _("Gnome Control Center");
return information;
}
static void
add_to_category (GnomeVFSURI *uri, const char *name, GnomeDesktopItem *entry, gpointer user_data)
{
CategoryLoadInformation *catinfo = user_data;
catinfo->entries = g_slist_prepend (catinfo->entries, entry);
catinfo->names = g_slist_prepend (catinfo->names, g_strdup (name));
gnome_desktop_item_ref (entry);
}
static void
add_to_other (GnomeVFSURI *uri, const char *name, GnomeDesktopItem *entry, gpointer user_data)
{
FullLoadInformation *info = user_data;
if (info->other == NULL) {
info->other = g_new (CategoryLoadInformation, 1);
info->other->entries = NULL;
info->other->names = NULL;
info->other->directory_entry = NULL;
info->other->name = NULL;
}
add_to_category (uri, name, entry, info->other);
}
static void
create_category (GnomeVFSURI *uri, const char *name, GnomeDesktopItem *entry, gpointer user_data)
{
FullLoadInformation *info = user_data;
CategoryLoadInformation catinfo;
catinfo.entries = NULL;
catinfo.names = NULL;
catinfo.directory_entry = entry;
catinfo.name = g_strdup (name);
if (entry)
gnome_desktop_item_ref (entry);
read_entries (uri, -1, NULL, add_to_category, &catinfo);
info->categories = g_slist_prepend (info->categories,
load_information_to_category (&catinfo, TRUE));
}
ControlCenterInformation *
control_center_get_categories (const gchar *prefsuri)
{
FullLoadInformation info;
GnomeVFSURI *uri;
ControlCenterInformation *information;
info.categories = NULL;
info.other = NULL;
uri = gnome_vfs_uri_new (prefsuri);
read_entries (uri, 0, create_category, add_to_other, &info);
if (info.other)
info.categories = g_slist_prepend (info.categories, load_information_to_category (info.other, FALSE));
g_free (info.other);
information = load_information_to_information (uri, &info);
gnome_vfs_uri_unref (uri);
return information;
}