diff options
author | Andy Hertzfeld <andy@src.gnome.org> | 2000-03-06 00:22:44 +0000 |
---|---|---|
committer | Andy Hertzfeld <andy@src.gnome.org> | 2000-03-06 00:22:44 +0000 |
commit | abb888bc679b6a81e9ebfd33d3c8febfa43d28a9 (patch) | |
tree | 979ab2468bf69af03c6f3ee8382c3c53a94adbfa | |
parent | 57ee999c6d9730becd2d460eedb5aa757808a255 (diff) | |
download | nautilus-abb888bc679b6a81e9ebfd33d3c8febfa43d28a9.tar.gz |
added a music view component for displaying directories of mp3 files, and
added a music view component for displaying directories of mp3 files,
and also made a new mechanism for content view components to be
explicitly specified in the metadata for a directory
-rw-r--r-- | ChangeLog-20000414 | 21 | ||||
-rw-r--r-- | components/Makefile.am | 2 | ||||
-rw-r--r-- | components/music/Makefile.am | 33 | ||||
-rw-r--r-- | components/music/main.c | 90 | ||||
-rw-r--r-- | components/music/nautilus-music-view.c | 636 | ||||
-rw-r--r-- | components/music/nautilus-music-view.goad | 11 | ||||
-rw-r--r-- | components/music/nautilus-music-view.h | 65 | ||||
-rw-r--r-- | configure.in | 1 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-metadata.h | 3 | ||||
-rw-r--r-- | libnautilus-private/nautilus-metadata.h | 3 | ||||
-rw-r--r-- | libnautilus/nautilus-metadata.h | 3 | ||||
-rw-r--r-- | src/nautilus-applicable-views.c | 53 | ||||
-rw-r--r-- | src/ntl-uri-map.c | 53 |
13 files changed, 968 insertions, 6 deletions
diff --git a/ChangeLog-20000414 b/ChangeLog-20000414 index 2fd930873..4f0b02752 100644 --- a/ChangeLog-20000414 +++ b/ChangeLog-20000414 @@ -1,3 +1,24 @@ +2000-03-05 Andy Hertzfeld <andy@eazel.com> + + added a music view component for viewing directories of mp3 files. This first cut only handles + only the case when the mp3 files have id3 tags present (most do these days) + + * components/music/nautilus-music-view.c,.h: a new music view component gathers information from + the id3 tags of mp3 files in the target directory and displays them in a list, sorted by track number. + It also displays the album cover if it can find one. For now, it launches xmms to do the playing, + but it will eventually have an integrated player and support other file types. + * components/music/nautilus-music-view.goad: component activation file + * main.c: boiler-plate component stuff + * components/music/Makefile.am: makefile for music component + * configure.in: added music component + * components/Makefile.am: added music component + + * src/ntl-uri-map: added a new way to install content view components, by + having the components explicitly listed in the metadata for the object being displayed + Used this to test the music view, but there's no way to manipulate it through the UI yet + * libnautilus/nautilus-metadata.h: added a "CONTENT_VIEWS" tag for specifying content views + in the metadata + 2000-03-05 Maciej Stachowiak <mjs@eazel.com> * src/ntl-window-msgs.c (nautilus_window_update_internals): Handle diff --git a/components/Makefile.am b/components/Makefile.am index 1d53ec9d0..d832aaaac 100644 --- a/components/Makefile.am +++ b/components/Makefile.am @@ -1 +1 @@ -SUBDIRS=history help html notes sample websearch +SUBDIRS=history help html music notes sample websearch diff --git a/components/music/Makefile.am b/components/music/Makefile.am new file mode 100644 index 000000000..f0ee5b3ab --- /dev/null +++ b/components/music/Makefile.am @@ -0,0 +1,33 @@ + + +CPPFLAGS = \ + -DPREFIX=\"$(prefix)\" + -DG_LOG_DOMAIN=\"Nautilus-Music\" + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(GNOMEUI_CFLAGS) + +gnorbadir = $(sysconfdir)/CORBA/servers + +gnorba_DATA = \ + nautilus-music-view.goad + + +bin_PROGRAMS = \ + nautilus-music-view + +nautilus_music_view_SOURCES = \ + nautilus-music-view.c \ + nautilus-music-view.h \ + main.c + +nautilus_music_view_LDFLAGS = \ + $(top_builddir)/libnautilus/libnautilus.la \ + $(BONOBO_LIBS) \ + $(GNOMEUI_LIBS) \ + $(VFS_LIBS) \ + $(GNORBA_LIBS) + +EXTRA_DIST = nautilus-music-view.goad diff --git a/components/music/main.c b/components/music/main.c new file mode 100644 index 000000000..dfe254240 --- /dev/null +++ b/components/music/main.c @@ -0,0 +1,90 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Copyright (C) 2000 Eazel, Inc + * + * 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 of the + * License, 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. + * + * Author: Andy Hertzfeld + */ + +/* main.c - main function and object activation function for the music view component. */ + +#include <config.h> + +#include "nautilus-music-view.h" + +#include <gnome.h> +#include <libgnorba/gnorba.h> +#include <bonobo.h> + +static int object_count = 0; + +static void +music_view_object_destroyed(GtkObject *obj) +{ + object_count--; + if (object_count <= 0) { + gtk_main_quit (); + } +} + +static BonoboObject * +music_view_make_object (BonoboGenericFactory *factory, + const char *goad_id, + void *closure) +{ + NautilusMusicView *music_view; + NautilusViewFrame *view_frame; + + if (strcmp (goad_id, "nautilus_music_view")) { + return NULL; + } + + music_view = NAUTILUS_MUSIC_VIEW (gtk_object_new (NAUTILUS_TYPE_MUSIC_VIEW, NULL)); + + object_count++; + + gtk_signal_connect (GTK_OBJECT (music_view), "destroy", music_view_object_destroyed, NULL); + + view_frame = NAUTILUS_VIEW_FRAME (nautilus_music_view_get_view_frame (music_view)); + return BONOBO_OBJECT (view_frame); +} + +int main(int argc, char *argv[]) +{ + BonoboGenericFactory *factory; + CORBA_ORB orb; + CORBA_Environment ev; + + CORBA_exception_init(&ev); + + orb = gnome_CORBA_init_with_popt_table ("nautilus-music-view", VERSION, &argc, argv, NULL, 0, NULL, + GNORBA_INIT_SERVER_FUNC, &ev); + + bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL); + + /* initialize gnome-vfs, etc */ + g_thread_init (NULL); + gnome_vfs_init (); + + factory = bonobo_generic_factory_new_multi ("nautilus_music_view_factory", music_view_make_object, NULL); + + do { + bonobo_main (); + } while (object_count > 0); + + return 0; +} diff --git a/components/music/nautilus-music-view.c b/components/music/nautilus-music-view.c new file mode 100644 index 000000000..f03799360 --- /dev/null +++ b/components/music/nautilus-music-view.c @@ -0,0 +1,636 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* + * Copyright (C) 2000 Eazel, Inc. + * + * This library 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 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Andy Hertzfeld <andy@eazel.com> + * + */ + +/* music view - presents the contents of the directory as an album of music */ + +#include <config.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> + +#include "nautilus-music-view.h" + +#include <libnautilus/libnautilus.h> +#include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-file-utilities.h> +#include <libnautilus/nautilus-glib-extensions.h> +#include <libnautilus/nautilus-gtk-macros.h> +#include <libnautilus/nautilus-metadata.h> +#include <libnautilus/nautilus-string.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtksignal.h> +#include <gnome.h> +#include <libgnomevfs/gnome-vfs.h> +#include <libgnorba/gnorba.h> +#include <limits.h> + +struct _NautilusMusicViewDetails { + gchar *current_uri; + NautilusContentViewFrame *view_frame; + + GtkVBox *album_container; + GtkWidget *album_title; + GtkWidget *song_list; + GtkWidget *album_image; + int background_connection; +}; + +/* structure for holding song info */ + +typedef struct { + gint track_number; + gchar *title; + gchar *artist; + gchar *album; + gchar *year; + gchar *comment; + gchar *path_name; +} SongInfo; + +#define MUSIC_VIEW_DEFAULT_BACKGROUND_COLOR "rgb:BBBB/BBBB/FFFF" + +enum { + TARGET_URI_LIST, + TARGET_COLOR, + TARGET_GNOME_URI_LIST +}; + +static GtkTargetEntry music_dnd_target_table[] = { + { "text/uri-list", 0, TARGET_URI_LIST }, + { "application/x-color", 0, TARGET_COLOR }, + { "special/x-gnome-icon-list", 0, TARGET_GNOME_URI_LIST } +}; + +static void nautilus_music_view_background_changed (NautilusMusicView *music_view); +static void nautilus_music_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, + guint info, guint time); + +static void nautilus_music_view_initialize_class (NautilusMusicViewClass *klass); +static void nautilus_music_view_initialize (NautilusMusicView *view); +static void nautilus_music_view_destroy (GtkObject *object); +static void nautilus_music_view_realize (GtkWidget *widget); +static void setup_title_font (NautilusMusicView *music_view); + +NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusMusicView, nautilus_music_view, GTK_TYPE_EVENT_BOX) + +static void +music_view_notify_location_change_cb(NautilusContentViewFrame *view, + Nautilus_NavigationInfo *navinfo, + NautilusMusicView *music_view); +static void selection_callback(GtkCList * clist, gint row, gint column, GdkEventButton * event); + +static void +nautilus_music_view_initialize_class (NautilusMusicViewClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = GTK_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->destroy = nautilus_music_view_destroy; + widget_class->realize = nautilus_music_view_realize; + widget_class->drag_data_received = nautilus_music_view_drag_data_received; +} + +/* initialize ourselves by connecting to the location change signal and allocating our subviews */ + +static void +nautilus_music_view_initialize (NautilusMusicView *music_view) +{ + NautilusBackground *background; + gchar *file_name; + GtkWidget *song_box, *scrollwindow; + gchar *titles[] = {"Track", "Title", "Artist", "Time"}; + + music_view->details = g_new0 (NautilusMusicViewDetails, 1); + + music_view->details->view_frame = nautilus_content_view_frame_new (GTK_WIDGET (music_view)); + + gtk_signal_connect (GTK_OBJECT (music_view->details->view_frame), + "notify_location_change", + GTK_SIGNAL_FUNC (music_view_notify_location_change_cb), + music_view); + + music_view->details->current_uri = NULL; + music_view->details->background_connection = 0; + + /* set up the default background color */ + background = nautilus_get_widget_background (GTK_WIDGET(music_view)); + nautilus_background_set_color (background, MUSIC_VIEW_DEFAULT_BACKGROUND_COLOR); + + /* allocate a vbox to contain all of the views */ + + music_view->details->album_container = GTK_VBOX(gtk_vbox_new(FALSE, 0)); + gtk_container_add(GTK_CONTAINER(music_view), GTK_WIDGET(music_view->details->album_container)); + gtk_widget_show(GTK_WIDGET(music_view->details->album_container)); + + /* allocate a widget for the album title */ + + music_view->details->album_title = gtk_label_new("Album Title"); + gtk_box_pack_start(GTK_BOX(music_view->details->album_container), music_view->details->album_title, 0, 0, 0); + gtk_widget_show(music_view->details->album_title); + + /* allocate an hbox to hold the optional album cover and the song list */ + + song_box = gtk_hbox_new(FALSE, 4); + gtk_box_pack_start(GTK_BOX(music_view->details->album_container), song_box, 0, 0, 2); + gtk_widget_show(song_box); + + /* allocate a placeholder widget for the album cover, but don't show it yet */ + file_name = gnome_pixmap_file ("nautilus/i-directory.png"); + music_view->details->album_image = GTK_WIDGET (gnome_pixmap_new_from_file (file_name)); + gtk_box_pack_start(GTK_BOX(song_box), music_view->details->album_image, 0, 0, 0); + g_free (file_name); + + /* allocate a widget to hold the song list */ + + music_view->details->song_list = gtk_clist_new_with_titles(4, titles); + + gtk_clist_set_column_width(GTK_CLIST(music_view->details->song_list), 0, 32); + gtk_clist_set_column_width(GTK_CLIST(music_view->details->song_list), 1, 176); + gtk_clist_set_column_width(GTK_CLIST(music_view->details->song_list), 2, 96); + gtk_clist_set_column_width(GTK_CLIST(music_view->details->song_list), 3, 42); + + gtk_signal_connect(GTK_OBJECT(music_view->details->song_list), "select_row", GTK_SIGNAL_FUNC(selection_callback), NULL); + + scrollwindow = gtk_scrolled_window_new(NULL, gtk_clist_get_vadjustment(GTK_CLIST(music_view->details->song_list))); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize(scrollwindow, 384, 232); + gtk_container_add(GTK_CONTAINER (scrollwindow), music_view->details->song_list); + gtk_clist_set_selection_mode(GTK_CLIST(music_view->details->song_list), GTK_SELECTION_BROWSE); + + gtk_box_pack_start(GTK_BOX(song_box), scrollwindow, 0, 0, 4); + gtk_widget_show(music_view->details->song_list); + gtk_widget_show(scrollwindow); + + /* prepare ourselves to receive dropped objects */ + gtk_drag_dest_set (GTK_WIDGET (music_view), + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, + music_dnd_target_table, NAUTILUS_N_ELEMENTS (music_dnd_target_table), GDK_ACTION_COPY); + + /* finally, show the view itself */ + gtk_widget_show (GTK_WIDGET (music_view)); +} + +static void +nautilus_music_view_destroy (GtkObject *object) +{ + NautilusMusicView *music_view = NAUTILUS_MUSIC_VIEW (object); + + g_free (music_view->details->current_uri); + g_free (music_view->details); + + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); +} + +/* handle a row being selected in the list view by playing the corresponding song */ +/* FIXME: xmms shouldn't be hardwired */ +static void +selection_callback(GtkCList * clist, gint row, gint column, GdkEventButton * event) +{ + pid_t play_pid; + gchar* song_name = gtk_clist_get_row_data(clist, row); + if (!song_name) + return; + + /* fork off a task to play the sound file */ + if (!(play_pid = fork())) { + execlp("xmms", "xmms", song_name, NULL); + exit(0); + } +} + + +/* Component embedding support */ +NautilusContentViewFrame * +nautilus_music_view_get_view_frame (NautilusMusicView *music_view) +{ + return music_view->details->view_frame; +} + + +/* utility routine to set up the font for the album title, called after we're realized */ +static void +setup_title_font(NautilusMusicView *music_view) +{ + GtkStyle *temp_style = gtk_style_new(); + + gtk_widget_realize(music_view->details->album_title); + temp_style->font = gdk_font_load("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); ; + gtk_widget_set_style(music_view->details->album_title, gtk_style_attach(temp_style, music_view->details->album_title->window)); +} + +/* set up fonts, colors, etc after we're realized */ +void +nautilus_music_view_realize(GtkWidget *widget) +{ + NautilusMusicView *music_view; + NautilusBackground *background; + + music_view = NAUTILUS_MUSIC_VIEW(widget); + NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, realize, (widget)); + + setup_title_font(music_view); + + background = nautilus_get_widget_background (widget); + nautilus_background_set_color (background, MUSIC_VIEW_DEFAULT_BACKGROUND_COLOR); +} + +/* here are some utility routines for reading ID3 tags from mp3 files */ + +/* initialize a songinfo structure */ + +static void +initialize_song_info(SongInfo *info) +{ + info->track_number = -1; + info->title = '\0'; + info->artist = '\0'; + info->album = '\0'; + info->year = '\0'; + info->comment = '\0'; + info->path_name = '\0'; +} + +/* deallocate a songinfo structure */ + +static void +release_song_info(SongInfo *info) +{ + if (info->title) + g_free(info->title); + if (info->artist) + g_free(info->artist); + if (info->album) + g_free(info->album); + if (info->year) + g_free(info->year); + if (info->comment) + g_free(info->comment); + + g_free(info); +} + +/* determine if the passed in filename is an mp3 file by looking at the extension */ +static gboolean +is_mp3_file(gchar *song_path) +{ + gchar *last_dot = strrchr(song_path, '.'); + if (last_dot == NULL) + return FALSE; + return !strcmp(last_dot, ".mp3") || !strcmp(last_dot, ".MP3"); +} + +/* read the id3 tag of the file if present */ +/* FIXME: need to use gnome vfs for this */ + +static gboolean +read_id_tag(gchar* song_path, SongInfo* song_info) +{ + gint mp3_file; + + char tag_buffer[129]; + char temp_str[255]; + + mp3_file = open(song_path, O_RDONLY); + if ( mp3_file == 0 ) + return FALSE; + + lseek(mp3_file, -128, SEEK_END); + + if (read(mp3_file, tag_buffer, 129) <= 0) { + close(mp3_file); + return FALSE; + } + close(mp3_file); + + if ((tag_buffer[0] != 'T') || (tag_buffer[1] != 'A') || (tag_buffer[2] != 'G')) + return FALSE; + + temp_str[31] = '\0'; + strncpy (temp_str, &tag_buffer[3], 30); + song_info->title = strdup(temp_str); + + strncpy (temp_str, &tag_buffer[33], 30); + song_info->artist = strdup(temp_str); + + strncpy (temp_str, &tag_buffer[63], 30); + song_info->album = strdup(temp_str); + + strncpy (temp_str, &tag_buffer[93], 4); + song_info->year = strdup(temp_str); + + strncpy (temp_str, &tag_buffer[97], 30); + song_info->comment = strdup(temp_str); + + if (tag_buffer[97 + 28] == 0) + song_info->track_number = tag_buffer[97 + 29]; + else song_info->track_number = -1; + + return TRUE; +} + +/* allocate a return a song info record, from an mp3 tag if present, or from intrinsic info */ + +static SongInfo* +fetch_song_info(gchar *song_path, gint file_order) +{ + gboolean has_info = FALSE; + SongInfo *info; + + if (!is_mp3_file(song_path)) + return NULL; + + info = g_new0 (SongInfo, 1); + initialize_song_info(info); + + if (is_mp3_file(song_path)) + has_info = read_id_tag(song_path, info); + + /* there was no id3 tag, so set up the info heuristically from the file name and file order */ + if (!has_info) { + } + + return info; +} + +/* format_play_time takes the pathname to a file and returns the play time formated as mm:ss */ +/* FIXME: assumes 128k bits/second. Must read header and factor in bitrate */ + +static gchar* +format_play_time(gchar* song_path_name) +{ + NautilusFile *file = nautilus_file_get(song_path_name); + GnomeVFSFileSize file_size = nautilus_file_get_size(file); + gint seconds = (file_size - 512) / 16384; + gint minutes = seconds / 60; + gint remain_seconds = seconds - (60 * minutes); + gchar *result = g_strdup_printf("%d:%02d", minutes, remain_seconds); + + nautilus_file_unref(file); + return result; +} + +/* sort comparison routine - for now, just sort by track number */ + +static int +sort_by_track_number (gconstpointer ap, gconstpointer bp) +{ + SongInfo *a, *b; + + a = (SongInfo *) ap; + b = (SongInfo *) bp; + + return (int) a->track_number - b->track_number; +} + +/* here's where we do most of the real work of populating the view with info from the new uri */ +/* FIXME: need to use gnome-vfs for iterating the directory */ + +static void +nautilus_music_view_update_from_uri (NautilusMusicView *music_view, const gchar *uri) +{ + DIR *dir; + struct dirent *entry; + char* clist_entry[4]; + char *background_color; + NautilusBackground *background; + NautilusDirectory *directory; + GList *this_song; + GList *song_list = NULL ; + SongInfo *info; + gchar *path_name; + gchar *image_path_name = NULL; + gint file_index = 0; + gint track_index = 0; + /* iterate through the directory, collecting mp3 files and extracting id3 data if present */ + /* soon we'll use gnomevfs, but at first just the standard unix stuff */ + + if (!(dir = opendir(uri + 7))) + g_warning("cant open %s in music_view_update", uri); + else { + while ((entry = readdir(dir))) { + /* skip invisible files, for now */ + + if (entry->d_name[0] == '.') + continue; + + path_name = nautilus_make_path(uri + 7, entry->d_name); + + /* fetch info and queue it if it's an mp3 file */ + info = fetch_song_info(path_name, file_index++); + if (info) { + info->path_name = path_name; + if (song_list) + song_list = g_list_append(song_list, info); + else { + song_list = g_list_alloc(); + song_list->data = info; + } + } + else { + /* it's not an mp3 file, so see if it's an image */ + NautilusFile *file = nautilus_file_get(path_name); + const gchar *mime_type = nautilus_file_get_mime_type (file); + + if (nautilus_has_prefix(mime_type, "image/")) { + /* for now, just keep the first image */ + if (image_path_name == NULL) + image_path_name = strdup(path_name); + } + + nautilus_file_unref(file); + g_free(path_name); + } + } + + closedir(dir); + } + + /* sort by track number */ + song_list = g_list_sort(song_list, sort_by_track_number); + + /* populate the clist */ + + gtk_clist_clear(GTK_CLIST(music_view->details->song_list)); + + this_song = song_list; + while (this_song != NULL) { + info = (SongInfo*) this_song->data; + + clist_entry[0] = malloc(4); + sprintf(clist_entry[0], "%d", info->track_number); + + clist_entry[1] = NULL; + clist_entry[2] = NULL; + clist_entry[3] = NULL; + + if (info->title) + clist_entry[1] = strdup(info->title); + if (info->artist) + clist_entry[2] = strdup(info->artist); + if (info->path_name) + clist_entry[3] = format_play_time(info->path_name); + + gtk_clist_append(GTK_CLIST(music_view->details->song_list), clist_entry); + gtk_clist_set_row_data(GTK_CLIST(music_view->details->song_list), track_index, strdup(info->path_name)); + + track_index += 1; + this_song = this_song->next; + } + + /* install the album cover */ + + if (image_path_name) { + + gnome_pixmap_load_file(GNOME_PIXMAP(music_view->details->album_image), image_path_name); + + /* show the pixmap widget */ + gtk_widget_show(music_view->details->album_image); + g_free(image_path_name); + } + else + gtk_widget_hide(music_view->details->album_image); + + /* set up background color */ + + background = nautilus_get_widget_background (GTK_WIDGET (music_view)); + if (music_view->details->background_connection == 0) + music_view->details->background_connection = + gtk_signal_connect_object (GTK_OBJECT (background), + "changed", + nautilus_music_view_background_changed, + GTK_OBJECT (music_view)); + + /* Set up the background color from the metadata. */ + directory = nautilus_directory_get(music_view->details->current_uri); + background_color = nautilus_directory_get_metadata (directory, + ICON_VIEW_BACKGROUND_COLOR_METADATA_KEY, + MUSIC_VIEW_DEFAULT_BACKGROUND_COLOR); + nautilus_background_set_color (background, background_color); + g_free (background_color); + gtk_object_unref(GTK_OBJECT(directory)); + + /* determine the album title/artist line */ + + /* set up the album title with the uri, for now */ + if (music_view->details->album_title) { + gchar *base_name = g_basename(uri); + gtk_label_set(GTK_LABEL(music_view->details->album_title), base_name); + g_free(base_name); + } + + /* release the song list */ + this_song = song_list; + while (this_song != NULL) { + info = (SongInfo*) this_song->data; + release_song_info(info); + this_song = this_song->next; + } + +} + + +void +nautilus_music_view_load_uri (NautilusMusicView *music_view, const gchar *uri) +{ + if (music_view->details->current_uri != NULL) + g_free(music_view->details->current_uri); + + music_view->details->current_uri = g_strdup (uri); + nautilus_music_view_update_from_uri(music_view, uri); +} + +static void +music_view_notify_location_change_cb (NautilusContentViewFrame *view, + Nautilus_NavigationInfo *navinfo, + NautilusMusicView *music_view) +{ + Nautilus_ProgressRequestInfo pri; + + memset(&pri, 0, sizeof(pri)); + + /* send required PROGRESS_UNDERWAY signal */ + + pri.type = Nautilus_PROGRESS_UNDERWAY; + pri.amount = 0.0; + nautilus_view_frame_request_progress_change (NAUTILUS_VIEW_FRAME (music_view->details->view_frame), &pri); + + /* do the actual work here */ + nautilus_music_view_load_uri (music_view, navinfo->actual_uri); + + /* send the required PROGRESS_DONE signal */ + pri.type = Nautilus_PROGRESS_DONE_OK; + pri.amount = 100.0; + nautilus_view_frame_request_progress_change (NAUTILUS_VIEW_FRAME (music_view->details->view_frame), &pri); +} + +/* handle drag and drop */ + +static void +nautilus_music_view_background_changed (NautilusMusicView *music_view) +{ + NautilusBackground *background; + NautilusDirectory *directory; + char *color_spec; + + background = nautilus_get_widget_background (GTK_WIDGET (music_view)); + color_spec = nautilus_background_get_color (background); + directory = nautilus_directory_get(music_view->details->current_uri); + nautilus_directory_set_metadata (directory, + ICON_VIEW_BACKGROUND_COLOR_METADATA_KEY, + MUSIC_VIEW_DEFAULT_BACKGROUND_COLOR, + color_spec); + g_free (color_spec); + gtk_object_unref(GTK_OBJECT(directory)); +} + +static void +nautilus_music_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, guint info, guint time) +{ + g_return_if_fail (NAUTILUS_IS_MUSIC_VIEW (widget)); + + switch (info) + { + case TARGET_GNOME_URI_LIST: + case TARGET_URI_LIST: + g_message("dropped data on music_view: %s", selection_data->data); + break; + + + case TARGET_COLOR: + /* Let the background change based on the dropped color. */ + nautilus_background_receive_dropped_color(nautilus_get_widget_background (widget), widget, x, y, selection_data); + break; + + default: + g_warning ("unknown drop type"); + break; + } +} diff --git a/components/music/nautilus-music-view.goad b/components/music/nautilus-music-view.goad new file mode 100644 index 000000000..9926a9806 --- /dev/null +++ b/components/music/nautilus-music-view.goad @@ -0,0 +1,11 @@ +[nautilus_music_view_factory] +type=exe +repo_id=IDL:GNOME/GenericFactory:1.0 +description=Factory for music view +location_info=nautilus-music-view + +[nautilus_music_view] +type=factory +repo_id=IDL:GNOME/Control:1.0 IDL:Nautilus/ContentView:1.0 IDL:Nautilus/View:1.0 +description=music view +location_info=nautilus_music_view_factory diff --git a/components/music/nautilus-music-view.h b/components/music/nautilus-music-view.h new file mode 100644 index 000000000..85bb7f637 --- /dev/null +++ b/components/music/nautilus-music-view.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Copyright (C) 2000 Eazel, Inc + * + * 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 of the + * License, 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. + * + * Author: Andy Hertzfeld + */ + +/* header file for the music view component */ + +#ifndef NAUTILUS_MUSIC_VIEW_H +#define NAUTILUS_MUSIC_VIEW_H + +#include <libnautilus/ntl-content-view-frame.h> +#include <gtk/gtkeventbox.h> + + +typedef struct _NautilusMusicView NautilusMusicView; +typedef struct _NautilusMusicViewClass NautilusMusicViewClass; + +#define NAUTILUS_TYPE_MUSIC_VIEW (nautilus_music_view_get_type ()) +#define NAUTILUS_MUSIC_VIEW(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_MUSIC_VIEW, NautilusMusicView)) +#define NAUTILUS_MUSIC_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_MUSIC_VIEW, NautilusMusicViewClass)) +#define NAUTILUS_IS_MUSIC_VIEW(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_MUSIC_VIEW)) +#define NAUTILUS_IS_MUSIC_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), NAUTILUS_TYPE_MUSIC_VIEW)) + +typedef struct _NautilusMusicViewDetails NautilusMusicViewDetails; + +struct _NautilusMusicView { + GtkEventBox parent; + NautilusMusicViewDetails *details; +}; + +struct _NautilusMusicViewClass { + GtkEventBoxClass parent_class; +}; + + + +/* GtkObject support */ +GtkType nautilus_music_view_get_type (void); + +/* Component embedding support */ +NautilusContentViewFrame *nautilus_music_view_get_view_frame (NautilusMusicView *view); + +/* URI handling */ +void nautilus_music_view_load_uri (NautilusMusicView *view, + const char *uri); + + +#endif /* NAUTILUS_MUSIC_VIEW_H */ diff --git a/configure.in b/configure.in index 35cd73a5f..6b0379a52 100644 --- a/configure.in +++ b/configure.in @@ -149,6 +149,7 @@ components/help/converters/gnome-info2html2/Makefile components/help/converters/gnome-man2html2/Makefile components/html/Makefile components/websearch/Makefile +components/music/Makefile components/notes/Makefile components/sample/Makefile ]) diff --git a/libnautilus-extensions/nautilus-metadata.h b/libnautilus-extensions/nautilus-metadata.h index d5e0c913f..6f80db278 100644 --- a/libnautilus-extensions/nautilus-metadata.h +++ b/libnautilus-extensions/nautilus-metadata.h @@ -31,7 +31,8 @@ #define NAUTILUS_CUSTOM_ICON_METADATA_KEY "CUSTOM_ICON" #define NAUTILUS_NOTES_METADATA_KEY "NOTES" -#define NAUTILUS_ANNOTATION_METADATA_KEY "ANNOTATION" +#define NAUTILUS_ANNOTATION_METADATA_KEY "ANNOTATION" +#define NAUTILUS_CONTENT_VIEWS_METADATA_KEY "CONTENT_VIEWS" #define ICON_VIEW_BACKGROUND_COLOR_METADATA_KEY "ICON_VIEW_BACKGROUND_COLOR" #define ICON_VIEW_ZOOM_LEVEL_METADATA_KEY "ICON_VIEW_ZOOM_LEVEL" diff --git a/libnautilus-private/nautilus-metadata.h b/libnautilus-private/nautilus-metadata.h index d5e0c913f..6f80db278 100644 --- a/libnautilus-private/nautilus-metadata.h +++ b/libnautilus-private/nautilus-metadata.h @@ -31,7 +31,8 @@ #define NAUTILUS_CUSTOM_ICON_METADATA_KEY "CUSTOM_ICON" #define NAUTILUS_NOTES_METADATA_KEY "NOTES" -#define NAUTILUS_ANNOTATION_METADATA_KEY "ANNOTATION" +#define NAUTILUS_ANNOTATION_METADATA_KEY "ANNOTATION" +#define NAUTILUS_CONTENT_VIEWS_METADATA_KEY "CONTENT_VIEWS" #define ICON_VIEW_BACKGROUND_COLOR_METADATA_KEY "ICON_VIEW_BACKGROUND_COLOR" #define ICON_VIEW_ZOOM_LEVEL_METADATA_KEY "ICON_VIEW_ZOOM_LEVEL" diff --git a/libnautilus/nautilus-metadata.h b/libnautilus/nautilus-metadata.h index d5e0c913f..6f80db278 100644 --- a/libnautilus/nautilus-metadata.h +++ b/libnautilus/nautilus-metadata.h @@ -31,7 +31,8 @@ #define NAUTILUS_CUSTOM_ICON_METADATA_KEY "CUSTOM_ICON" #define NAUTILUS_NOTES_METADATA_KEY "NOTES" -#define NAUTILUS_ANNOTATION_METADATA_KEY "ANNOTATION" +#define NAUTILUS_ANNOTATION_METADATA_KEY "ANNOTATION" +#define NAUTILUS_CONTENT_VIEWS_METADATA_KEY "CONTENT_VIEWS" #define ICON_VIEW_BACKGROUND_COLOR_METADATA_KEY "ICON_VIEW_BACKGROUND_COLOR" #define ICON_VIEW_ZOOM_LEVEL_METADATA_KEY "ICON_VIEW_ZOOM_LEVEL" diff --git a/src/nautilus-applicable-views.c b/src/nautilus-applicable-views.c index 73892a2e5..af9f4bd42 100644 --- a/src/nautilus-applicable-views.c +++ b/src/nautilus-applicable-views.c @@ -28,12 +28,21 @@ #include "ntl-uri-map.h" #include "ntl-prefs.h" +#include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-metadata.h> + #include <libgnorba/gnorba.h> #include <sys/types.h> #include <dirent.h> #include <limits.h> #include <ctype.h> +/* forward declarations */ + +static void add_components_from_metadata(NautilusNavigationInfo *navinfo); + +/* Nautilus View Identifiers associate a component name with a user displayable name */ + static NautilusViewIdentifier * nautilus_view_identifier_new (const char *iid, const char *name) { @@ -181,6 +190,12 @@ my_notify_when_ready(GnomeVFSAsyncHandle *ah, GnomeVFSResult result, navinfo->content_identifiers = g_slist_append ( navinfo->content_identifiers, nautilus_view_identifier_new ("ntl_file_manager_list_view", "List")); + + /* besides the information in OAF/GConf, we also want to offer components that are specifically refered to in the metadata, + so we ask the metadata for content views here and add them accordingly. */ + + /* FIXME: for now, we just do this for directories but it should apply to all places with available metadata */ + add_components_from_metadata(navinfo); } else { @@ -193,13 +208,49 @@ my_notify_when_ready(GnomeVFSAsyncHandle *ah, GnomeVFSResult result, navinfo->content_identifiers = g_slist_append (navinfo->content_identifiers, nautilus_view_identifier_new ("nautilus_sample_content_view", "Sample")); - + g_slist_foreach(nautilus_prefs.global_meta_views, nautilus_navinfo_append_globals, &navinfo->meta_iids); out: notify_ready(navinfo, notify_ready_data); } +/* The following routine uses metadata associated with the current url to add content view components specified in the metadata */ +/* the content views are specified in the string as "componentname1:label1\ncomponentname2:label2\n..." */ + +static void +add_components_from_metadata(NautilusNavigationInfo *navinfo) +{ + NautilusDirectory *directory = nautilus_directory_get(navinfo->navinfo.requested_uri); + gchar *content_views = nautilus_directory_get_metadata(directory, NAUTILUS_CONTENT_VIEWS_METADATA_KEY, NULL); + + if (content_views) { + char **pieces; + const char *component_str; + gchar *colon_pos; + gint index; + pieces = g_strsplit (content_views, "\n", 0); + for (index = 0; (component_str = pieces[index]) != NULL; index++) { + /* break the component string into the name and label */ + colon_pos = strchr(component_str, ':'); + if (colon_pos) { + *colon_pos++ = '\0'; + + /* add it to the list */ + navinfo->content_identifiers = g_slist_append (navinfo->content_identifiers, + nautilus_view_identifier_new (component_str, colon_pos)); + } + } + g_strfreev (pieces); + g_free(content_views); + } + + gtk_object_unref(GTK_OBJECT(directory)); +} + + +/* navinfo stuff */ + void nautilus_navinfo_init(void) { diff --git a/src/ntl-uri-map.c b/src/ntl-uri-map.c index 73892a2e5..af9f4bd42 100644 --- a/src/ntl-uri-map.c +++ b/src/ntl-uri-map.c @@ -28,12 +28,21 @@ #include "ntl-uri-map.h" #include "ntl-prefs.h" +#include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-metadata.h> + #include <libgnorba/gnorba.h> #include <sys/types.h> #include <dirent.h> #include <limits.h> #include <ctype.h> +/* forward declarations */ + +static void add_components_from_metadata(NautilusNavigationInfo *navinfo); + +/* Nautilus View Identifiers associate a component name with a user displayable name */ + static NautilusViewIdentifier * nautilus_view_identifier_new (const char *iid, const char *name) { @@ -181,6 +190,12 @@ my_notify_when_ready(GnomeVFSAsyncHandle *ah, GnomeVFSResult result, navinfo->content_identifiers = g_slist_append ( navinfo->content_identifiers, nautilus_view_identifier_new ("ntl_file_manager_list_view", "List")); + + /* besides the information in OAF/GConf, we also want to offer components that are specifically refered to in the metadata, + so we ask the metadata for content views here and add them accordingly. */ + + /* FIXME: for now, we just do this for directories but it should apply to all places with available metadata */ + add_components_from_metadata(navinfo); } else { @@ -193,13 +208,49 @@ my_notify_when_ready(GnomeVFSAsyncHandle *ah, GnomeVFSResult result, navinfo->content_identifiers = g_slist_append (navinfo->content_identifiers, nautilus_view_identifier_new ("nautilus_sample_content_view", "Sample")); - + g_slist_foreach(nautilus_prefs.global_meta_views, nautilus_navinfo_append_globals, &navinfo->meta_iids); out: notify_ready(navinfo, notify_ready_data); } +/* The following routine uses metadata associated with the current url to add content view components specified in the metadata */ +/* the content views are specified in the string as "componentname1:label1\ncomponentname2:label2\n..." */ + +static void +add_components_from_metadata(NautilusNavigationInfo *navinfo) +{ + NautilusDirectory *directory = nautilus_directory_get(navinfo->navinfo.requested_uri); + gchar *content_views = nautilus_directory_get_metadata(directory, NAUTILUS_CONTENT_VIEWS_METADATA_KEY, NULL); + + if (content_views) { + char **pieces; + const char *component_str; + gchar *colon_pos; + gint index; + pieces = g_strsplit (content_views, "\n", 0); + for (index = 0; (component_str = pieces[index]) != NULL; index++) { + /* break the component string into the name and label */ + colon_pos = strchr(component_str, ':'); + if (colon_pos) { + *colon_pos++ = '\0'; + + /* add it to the list */ + navinfo->content_identifiers = g_slist_append (navinfo->content_identifiers, + nautilus_view_identifier_new (component_str, colon_pos)); + } + } + g_strfreev (pieces); + g_free(content_views); + } + + gtk_object_unref(GTK_OBJECT(directory)); +} + + +/* navinfo stuff */ + void nautilus_navinfo_init(void) { |