Initial Import
authorPrajwal Mohan <prajwal.karur.mohan@intel.com>
Fri, 27 Apr 2012 22:45:31 +0000 (15:45 -0700)
committerPrajwal Mohan <prajwal.karur.mohan@intel.com>
Fri, 27 Apr 2012 22:45:31 +0000 (15:45 -0700)
525 files changed:
README [new file with mode: 0644]
arc-clock/Makefile [new file with mode: 0644]
arc-clock/arc-clock.c [new file with mode: 0644]
attic/aaina/AUTHORS [new file with mode: 0644]
attic/aaina/ChangeLog [new file with mode: 0644]
attic/aaina/Makefile.am [new file with mode: 0644]
attic/aaina/NEWS [new file with mode: 0644]
attic/aaina/README [new file with mode: 0644]
attic/aaina/TODO [new file with mode: 0644]
attic/aaina/autogen.sh [new file with mode: 0755]
attic/aaina/configure.ac [new file with mode: 0644]
attic/aaina/libaaina/Makefile.am [new file with mode: 0644]
attic/aaina/libaaina/aaina-behave.c [new file with mode: 0644]
attic/aaina/libaaina/aaina-behave.h [new file with mode: 0644]
attic/aaina/libaaina/aaina-library.c [new file with mode: 0644]
attic/aaina/libaaina/aaina-library.h [new file with mode: 0644]
attic/aaina/libaaina/aaina-photo.c [new file with mode: 0644]
attic/aaina/libaaina/aaina-photo.h [new file with mode: 0644]
attic/aaina/libaaina/aaina-source.c [new file with mode: 0644]
attic/aaina/libaaina/aaina-source.h [new file with mode: 0644]
attic/aaina/libaaina/clutter-texture-label.c [new file with mode: 0644]
attic/aaina/libaaina/clutter-texture-label.h [new file with mode: 0644]
attic/aaina/libaaina/eggsequence.c [new file with mode: 0644]
attic/aaina/libaaina/eggsequence.h [new file with mode: 0644]
attic/aaina/libnflick/Makefile.am [new file with mode: 0644]
attic/aaina/libnflick/nflick-api-request-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-api-request.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-api-request.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-api-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-api-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-api-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-auth-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-auth-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-auth-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-flickr.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-get-sizes-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-get-sizes-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-get-sizes-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-gft-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-gft-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-gft-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-info-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-info-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-info-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-info-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-info-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-info-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-no-set-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-no-set-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-no-set-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-data.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-data.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-list-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-list-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-list-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-list-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-list-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-list-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-search-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-search-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-search-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-search-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-search-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-search-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-set-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-set.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-photo-set.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-pixbuf-fetch-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-pixbuf-fetch.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-pixbuf-fetch.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-set-list-response-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-set-list-response.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-set-list-response.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-set-list-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-set-list-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-set-list-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-show-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-show-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-show-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-types.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-worker-private.h [new file with mode: 0644]
attic/aaina/libnflick/nflick-worker.c [new file with mode: 0644]
attic/aaina/libnflick/nflick-worker.h [new file with mode: 0644]
attic/aaina/libnflick/nflick.h [new file with mode: 0644]
attic/aaina/sources/Makefile.am [new file with mode: 0644]
attic/aaina/sources/aaina-source-directory.c [new file with mode: 0644]
attic/aaina/sources/aaina-source-directory.h [new file with mode: 0644]
attic/aaina/sources/aaina-source-flickr.c [new file with mode: 0644]
attic/aaina/sources/aaina-source-flickr.h [new file with mode: 0644]
attic/aaina/src/Makefile.am [new file with mode: 0644]
attic/aaina/src/aaina-slide-show.c [new file with mode: 0644]
attic/aaina/src/aaina-slide-show.h [new file with mode: 0644]
attic/aaina/src/main.c [new file with mode: 0644]
attic/astro-desktop/AUTHORS [new file with mode: 0644]
attic/astro-desktop/ChangeLog [new file with mode: 0644]
attic/astro-desktop/Makefile.am [new file with mode: 0644]
attic/astro-desktop/NEWS [new file with mode: 0644]
attic/astro-desktop/README [new file with mode: 0644]
attic/astro-desktop/applets/Makefile.am [new file with mode: 0644]
attic/astro-desktop/applets/cal.json [new file with mode: 0644]
attic/astro-desktop/applets/cal.png [new file with mode: 0644]
attic/astro-desktop/applets/clock.json [new file with mode: 0644]
attic/astro-desktop/applets/clock.png [new file with mode: 0644]
attic/astro-desktop/applets/clouds.png [new file with mode: 0644]
attic/astro-desktop/applets/mail.json [new file with mode: 0644]
attic/astro-desktop/applets/mail.png [new file with mode: 0644]
attic/astro-desktop/applets/weather.json [new file with mode: 0644]
attic/astro-desktop/applications/Makefile.am [new file with mode: 0644]
attic/astro-desktop/applications/contacts/Makefile.am [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contact-row.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contact-row.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contacts-details.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contacts-details.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contacts-window.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contacts-window.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contacts.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-contacts.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-reflection.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-reflection.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-texture-group.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/astro-texture-group.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/clutter-reflect-texture.c [new file with mode: 0644]
attic/astro-desktop/applications/contacts/clutter-reflect-texture.h [new file with mode: 0644]
attic/astro-desktop/applications/contacts/init.c [new file with mode: 0644]
attic/astro-desktop/applications/example/Makefile.am [new file with mode: 0644]
attic/astro-desktop/applications/example/astro-example.c [new file with mode: 0644]
attic/astro-desktop/applications/example/astro-example.h [new file with mode: 0644]
attic/astro-desktop/applications/example/init.c [new file with mode: 0644]
attic/astro-desktop/applications/images/Makefile.am [new file with mode: 0644]
attic/astro-desktop/applications/images/astro-images-window.c [new file with mode: 0644]
attic/astro-desktop/applications/images/astro-images-window.h [new file with mode: 0644]
attic/astro-desktop/applications/images/astro-images.c [new file with mode: 0644]
attic/astro-desktop/applications/images/astro-images.h [new file with mode: 0644]
attic/astro-desktop/applications/images/clutter-reflect-texture.c [new file with mode: 0644]
attic/astro-desktop/applications/images/clutter-reflect-texture.h [new file with mode: 0644]
attic/astro-desktop/applications/images/init.c [new file with mode: 0644]
attic/astro-desktop/applications/music/Makefile.am [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-music-window.c [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-music-window.h [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-music.c [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-music.h [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-reflection.c [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-reflection.h [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-songs.c [new file with mode: 0644]
attic/astro-desktop/applications/music/astro-songs.h [new file with mode: 0644]
attic/astro-desktop/applications/music/clutter-reflect-texture.c [new file with mode: 0644]
attic/astro-desktop/applications/music/clutter-reflect-texture.h [new file with mode: 0644]
attic/astro-desktop/applications/music/init.c [new file with mode: 0644]
attic/astro-desktop/autogen.sh [new file with mode: 0755]
attic/astro-desktop/configure.ac [new file with mode: 0644]
attic/astro-desktop/data/Makefile.am [new file with mode: 0644]
attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpg [new file with mode: 0644]
attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg [new file with mode: 0644]
attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg [new file with mode: 0644]
attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpg [new file with mode: 0644]
attic/astro-desktop/data/albums/Makefile.am [new file with mode: 0644]
attic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg [new file with mode: 0755]
attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg [new file with mode: 0644]
attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg [new file with mode: 0755]
attic/astro-desktop/data/applet_bg.png [new file with mode: 0644]
attic/astro-desktop/data/background.svg [new file with mode: 0644]
attic/astro-desktop/data/contact-bar.svg [new file with mode: 0644]
attic/astro-desktop/data/contact.png [new file with mode: 0644]
attic/astro-desktop/data/disc_bg.svg [new file with mode: 0644]
attic/astro-desktop/data/face.png [new file with mode: 0644]
attic/astro-desktop/data/icons/Makefile.am [new file with mode: 0644]
attic/astro-desktop/data/icons/bt.png [new file with mode: 0644]
attic/astro-desktop/data/icons/close.png [new file with mode: 0644]
attic/astro-desktop/data/icons/contacts.png [new file with mode: 0644]
attic/astro-desktop/data/icons/exec.png [new file with mode: 0644]
attic/astro-desktop/data/icons/home.png [new file with mode: 0644]
attic/astro-desktop/data/icons/images.png [new file with mode: 0644]
attic/astro-desktop/data/icons/music.png [new file with mode: 0644]
attic/astro-desktop/data/icons/nm.png [new file with mode: 0644]
attic/astro-desktop/data/info_bg.png [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/Makefile.am [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-application.c [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-application.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-behave.c [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-behave.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-defines.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-utils.c [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-utils.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-window.c [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro-window.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/astro.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/tidy-private.h [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/tidy-texture-frame.c [new file with mode: 0644]
attic/astro-desktop/libastro-desktop/tidy-texture-frame.h [new file with mode: 0644]
attic/astro-desktop/src/Makefile.am [new file with mode: 0644]
attic/astro-desktop/src/astro-appicon.c [new file with mode: 0644]
attic/astro-desktop/src/astro-appicon.h [new file with mode: 0644]
attic/astro-desktop/src/astro-applet-manager.c [new file with mode: 0644]
attic/astro-desktop/src/astro-applet-manager.h [new file with mode: 0644]
attic/astro-desktop/src/astro-applet.c [new file with mode: 0644]
attic/astro-desktop/src/astro-applet.h [new file with mode: 0644]
attic/astro-desktop/src/astro-appview.c [new file with mode: 0644]
attic/astro-desktop/src/astro-appview.h [new file with mode: 0644]
attic/astro-desktop/src/astro-desktop.c [new file with mode: 0644]
attic/astro-desktop/src/astro-desktop.h [new file with mode: 0644]
attic/astro-desktop/src/astro-example.c [new file with mode: 0644]
attic/astro-desktop/src/astro-example.h [new file with mode: 0644]
attic/astro-desktop/src/astro-panel.c [new file with mode: 0644]
attic/astro-desktop/src/astro-panel.h [new file with mode: 0644]
attic/astro-desktop/src/astro-systray.c [new file with mode: 0644]
attic/astro-desktop/src/astro-systray.h [new file with mode: 0644]
attic/astro-desktop/src/main.c [new file with mode: 0644]
attic/fluttr/AUTHORS [new file with mode: 0644]
attic/fluttr/COPYING [new file with mode: 0644]
attic/fluttr/ChangeLog [new file with mode: 0644]
attic/fluttr/INSTALL [new file with mode: 0644]
attic/fluttr/Makefile.am [new file with mode: 0644]
attic/fluttr/NEWS [new file with mode: 0644]
attic/fluttr/README [new file with mode: 0644]
attic/fluttr/TODO [new file with mode: 0644]
attic/fluttr/autogen.sh [new file with mode: 0755]
attic/fluttr/config.guess [new symlink]
attic/fluttr/config.sub [new symlink]
attic/fluttr/configure.ac [new file with mode: 0644]
attic/fluttr/data/Makefile.am [new file with mode: 0644]
attic/fluttr/data/background.svg [new file with mode: 0644]
attic/fluttr/data/message.svg [new file with mode: 0644]
attic/fluttr/data/picture.svg [new file with mode: 0644]
attic/fluttr/data/spinner.svg [new file with mode: 0644]
attic/fluttr/libnflick/Makefile.am [new file with mode: 0644]
attic/fluttr/libnflick/nflick-api-request-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-api-request.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-api-request.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-api-response-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-api-response.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-api-response.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-auth-worker-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-auth-worker.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-auth-worker.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-flickr.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-get-sizes-response-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-get-sizes-response.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-get-sizes-response.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-gft-response-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-gft-response.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-gft-response.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-no-set-response-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-no-set-response.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-no-set-response.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-data.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-data.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-list-response-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-list-response.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-list-response.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-list-worker-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-list-worker.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-list-worker.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-set-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-set.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-photo-set.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-pixbuf-fetch-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-pixbuf-fetch.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-pixbuf-fetch.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-set-list-response-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-set-list-response.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-set-list-response.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-set-list-worker-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-set-list-worker.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-set-list-worker.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-show-worker-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-show-worker.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-show-worker.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-types.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-worker-private.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick-worker.c [new file with mode: 0644]
attic/fluttr/libnflick/nflick-worker.h [new file with mode: 0644]
attic/fluttr/libnflick/nflick.h [new file with mode: 0644]
attic/fluttr/ltmain.sh [new symlink]
attic/fluttr/src/Makefile.am [new file with mode: 0644]
attic/fluttr/src/eggsequence.c [new file with mode: 0644]
attic/fluttr/src/eggsequence.h [new file with mode: 0644]
attic/fluttr/src/fluttr-auth.c [new file with mode: 0644]
attic/fluttr/src/fluttr-auth.h [new file with mode: 0644]
attic/fluttr/src/fluttr-behave.c [new file with mode: 0644]
attic/fluttr/src/fluttr-behave.h [new file with mode: 0644]
attic/fluttr/src/fluttr-library-row.c [new file with mode: 0644]
attic/fluttr/src/fluttr-library-row.h [new file with mode: 0644]
attic/fluttr/src/fluttr-library.c [new file with mode: 0644]
attic/fluttr/src/fluttr-library.h [new file with mode: 0644]
attic/fluttr/src/fluttr-list-view.c [new file with mode: 0644]
attic/fluttr/src/fluttr-list-view.h [new file with mode: 0644]
attic/fluttr/src/fluttr-list.c [new file with mode: 0644]
attic/fluttr/src/fluttr-list.h [new file with mode: 0644]
attic/fluttr/src/fluttr-photo.c [new file with mode: 0644]
attic/fluttr/src/fluttr-photo.h [new file with mode: 0644]
attic/fluttr/src/fluttr-set-view.c [new file with mode: 0644]
attic/fluttr/src/fluttr-set-view.h [new file with mode: 0644]
attic/fluttr/src/fluttr-set.c [new file with mode: 0644]
attic/fluttr/src/fluttr-set.h [new file with mode: 0644]
attic/fluttr/src/fluttr-settings.c [new file with mode: 0644]
attic/fluttr/src/fluttr-settings.h [new file with mode: 0644]
attic/fluttr/src/fluttr-spinner.c [new file with mode: 0644]
attic/fluttr/src/fluttr-spinner.h [new file with mode: 0644]
attic/fluttr/src/fluttr-viewer.c [new file with mode: 0644]
attic/fluttr/src/fluttr-viewer.h [new file with mode: 0644]
attic/fluttr/src/main.c [new file with mode: 0644]
attic/gcr/Makefile [new file with mode: 0644]
attic/gcr/README [new file with mode: 0644]
attic/gcr/custom-cursor.c [new file with mode: 0644]
attic/gcr/custom-cursor.h [new file with mode: 0644]
attic/gcr/gcr.c [new file with mode: 0644]
attic/gcr/gcr.h [new file with mode: 0644]
attic/gcr/test.c [new file with mode: 0644]
attic/mallums-magic-browser/Makefile [new file with mode: 0644]
attic/mallums-magic-browser/README-mozilla [new file with mode: 0644]
attic/mallums-magic-browser/assets/back.png [new file with mode: 0755]
attic/mallums-magic-browser/assets/bground.png [new file with mode: 0755]
attic/mallums-magic-browser/assets/document-new.png [new file with mode: 0644]
attic/mallums-magic-browser/assets/forward.png [new file with mode: 0755]
attic/mallums-magic-browser/assets/go-next.png [new file with mode: 0644]
attic/mallums-magic-browser/assets/go-previous.png [new file with mode: 0644]
attic/mallums-magic-browser/assets/tabs.png [new file with mode: 0755]
attic/mallums-magic-browser/assets/toolbar-bg.png [new file with mode: 0644]
attic/mallums-magic-browser/popup-factory.c [new file with mode: 0644]
attic/mallums-magic-browser/popup-factory.h [new file with mode: 0644]
attic/mallums-magic-browser/scroll-frame.c [new file with mode: 0644]
attic/mallums-magic-browser/scroll-frame.h [new file with mode: 0644]
attic/mallums-magic-browser/web-browser-mozilla.c [new file with mode: 0644]
attic/mallums-magic-browser/web-browser-mozilla.h [new file with mode: 0644]
attic/mallums-magic-browser/web-browser.c [new file with mode: 0644]
attic/mallums-magic-browser/web-browser.h [new file with mode: 0644]
attic/sqlite-model/Makefile [new file with mode: 0644]
attic/sqlite-model/clutter-sqlite-model.c [new file with mode: 0644]
attic/sqlite-model/clutter-sqlite-model.h [new file with mode: 0644]
attic/sqlite-model/test-sqlite-model.c [new file with mode: 0644]
attic/table/Makefile [new file with mode: 0644]
attic/table/clutter-dominatrix.c [new file with mode: 0644]
attic/table/clutter-dominatrix.h [new file with mode: 0644]
attic/table/clutter-video-player.c [new file with mode: 0644]
attic/table/clutter-video-player.h [new file with mode: 0644]
attic/table/hand0.png [new file with mode: 0644]
attic/table/hand1.png [new file with mode: 0644]
attic/table/hand2.png [new file with mode: 0644]
attic/table/hand3.png [new file with mode: 0644]
attic/table/hand4.png [new file with mode: 0644]
attic/table/hand5.png [new file with mode: 0644]
attic/table/hand6.png [new file with mode: 0644]
attic/table/hand7.png [new file with mode: 0644]
attic/table/hand8.png [new file with mode: 0644]
attic/table/pause_png.h [new file with mode: 0644]
attic/table/play_png.h [new file with mode: 0644]
attic/table/table.c [new file with mode: 0644]
attic/widgets/Makefile [new file with mode: 0644]
attic/widgets/clutter-reflect-texture.c [new file with mode: 0644]
attic/widgets/clutter-reflect-texture.h [new file with mode: 0644]
attic/widgets/test.c [new file with mode: 0644]
attic/woohaa/AUTHORS [new file with mode: 0644]
attic/woohaa/ChangeLog [new file with mode: 0644]
attic/woohaa/Makefile.am [new file with mode: 0644]
attic/woohaa/NEWS [new file with mode: 0644]
attic/woohaa/README [new file with mode: 0644]
attic/woohaa/autogen.sh [new file with mode: 0755]
attic/woohaa/configure.ac [new file with mode: 0644]
attic/woohaa/data/Makefile.am [new file with mode: 0644]
attic/woohaa/data/arrow-down.svg [new file with mode: 0644]
attic/woohaa/data/arrow-next.svg [new file with mode: 0644]
attic/woohaa/data/arrow-prev.svg [new file with mode: 0644]
attic/woohaa/data/arrow-up.svg [new file with mode: 0644]
attic/woohaa/data/bg.png [new file with mode: 0644]
attic/woohaa/data/busy.png [new file with mode: 0644]
attic/woohaa/data/default-thumb.png [new file with mode: 0644]
attic/woohaa/data/header.svg [new file with mode: 0644]
attic/woohaa/data/play.svg [new file with mode: 0644]
attic/woohaa/data/selected.svg [new file with mode: 0644]
attic/woohaa/data/spinner.svg [new file with mode: 0644]
attic/woohaa/eggsequence.c [new file with mode: 0644]
attic/woohaa/eggsequence.h [new file with mode: 0644]
attic/woohaa/totem-resources.c [new file with mode: 0644]
attic/woohaa/totem-resources.h [new file with mode: 0644]
attic/woohaa/util.c [new file with mode: 0644]
attic/woohaa/util.h [new file with mode: 0644]
attic/woohaa/wh-busy.c [new file with mode: 0644]
attic/woohaa/wh-busy.h [new file with mode: 0644]
attic/woohaa/wh-db.c [new file with mode: 0644]
attic/woohaa/wh-db.h [new file with mode: 0644]
attic/woohaa/wh-screen-video.c [new file with mode: 0644]
attic/woohaa/wh-screen-video.h [new file with mode: 0644]
attic/woohaa/wh-slider-menu.c [new file with mode: 0644]
attic/woohaa/wh-slider-menu.h [new file with mode: 0644]
attic/woohaa/wh-theme.c [new file with mode: 0644]
attic/woohaa/wh-theme.h [new file with mode: 0644]
attic/woohaa/wh-video-model-row.c [new file with mode: 0644]
attic/woohaa/wh-video-model-row.h [new file with mode: 0644]
attic/woohaa/wh-video-model.c [new file with mode: 0644]
attic/woohaa/wh-video-model.h [new file with mode: 0644]
attic/woohaa/wh-video-row-renderer.c [new file with mode: 0644]
attic/woohaa/wh-video-row-renderer.h [new file with mode: 0644]
attic/woohaa/wh-video-thumbnailer.c [new file with mode: 0644]
attic/woohaa/wh-video-view.c [new file with mode: 0644]
attic/woohaa/wh-video-view.h [new file with mode: 0644]
attic/woohaa/woohaa.c [new file with mode: 0644]
attic/youhaa/AUTHORS [new file with mode: 0644]
attic/youhaa/ChangeLog [new file with mode: 0644]
attic/youhaa/Makefile.am [new file with mode: 0644]
attic/youhaa/NEWS [new file with mode: 0644]
attic/youhaa/README [new file with mode: 0644]
attic/youhaa/autogen.sh [new file with mode: 0755]
attic/youhaa/configure.ac [new file with mode: 0644]
attic/youhaa/data/Makefile.am [new file with mode: 0644]
attic/youhaa/data/go-next.svg [new file with mode: 0644]
attic/youhaa/data/go-previous.svg [new file with mode: 0644]
attic/youhaa/libcurl.m4 [new file with mode: 0644]
attic/youhaa/src/Makefile.am [new file with mode: 0644]
attic/youhaa/src/glibcurl.c [new file with mode: 0644]
attic/youhaa/src/glibcurl.h [new file with mode: 0644]
attic/youhaa/src/yh-main.c [new file with mode: 0644]
attic/youhaa/src/yh-theme.c [new file with mode: 0644]
attic/youhaa/src/yh-theme.h [new file with mode: 0644]
attic/youhaa/src/yh-youtube-browser.c [new file with mode: 0644]
attic/youhaa/src/yh-youtube-browser.h [new file with mode: 0644]
attic/youhaa/src/yh-youtube.c [new file with mode: 0644]
attic/youhaa/src/yh-youtube.h [new file with mode: 0644]
circles/Makefile [new file with mode: 0644]
circles/circles.c [new file with mode: 0644]
courasel/Makefile [new file with mode: 0644]
courasel/accessories-text-editor.png [new file with mode: 0644]
courasel/applications-games.png [new file with mode: 0644]
courasel/courasel.c [new file with mode: 0644]
courasel/dates.png [new file with mode: 0644]
courasel/im-client.png [new file with mode: 0644]
courasel/preferences-desktop-theme.png [new file with mode: 0644]
courasel/tasks.png [new file with mode: 0644]
courasel/utilities-terminal.png [new file with mode: 0644]
courasel/web-browser.png [new file with mode: 0644]
foofone/Makefile [new file with mode: 0644]
foofone/button.png [new file with mode: 0644]
foofone/call-background.png [new file with mode: 0644]
foofone/display.png [new file with mode: 0644]
foofone/foofone.c [new file with mode: 0644]
gps-globe/.gitignore [new file with mode: 0644]
gps-globe/AUTHORS [new file with mode: 0644]
gps-globe/COPYING [new file with mode: 0644]
gps-globe/ChangeLog [new file with mode: 0644]
gps-globe/INSTALL [new file with mode: 0644]
gps-globe/Makefile.am [new file with mode: 0644]
gps-globe/NEWS [new file with mode: 0644]
gps-globe/README [new file with mode: 0644]
gps-globe/autogen.sh [new file with mode: 0755]
gps-globe/configure.ac [new file with mode: 0644]
gps-globe/data/visible-earth.jpg [new file with mode: 0644]
gps-globe/src/Makefile.am [new file with mode: 0644]
gps-globe/src/gpsg-enum-types.c.in [new file with mode: 0644]
gps-globe/src/gpsg-enum-types.h.in [new file with mode: 0644]
gps-globe/src/gpsg-main.c [new file with mode: 0644]
gps-globe/src/gpsg-sphere-vertex-shader.glsl [new file with mode: 0644]
gps-globe/src/gpsg-sphere-vertex-shader.h [new file with mode: 0644]
gps-globe/src/gpsg-sphere.c [new file with mode: 0644]
gps-globe/src/gpsg-sphere.h [new file with mode: 0644]
nyancat/Makefile [new file with mode: 0644]
nyancat/nyan.json [new file with mode: 0644]
nyancat/nyancat.c [new file with mode: 0644]
nyancat/star.png [new file with mode: 0644]
object-store/Makefile [new file with mode: 0644]
object-store/foo-object-store-test [new file with mode: 0644]
object-store/foo-object-store.c [new file with mode: 0644]
object-store/foo-object-store.h [new file with mode: 0644]
object-store/foo-test-object.c [new file with mode: 0644]
object-store/foo-test-object.h [new file with mode: 0644]
object-store/object-store-example.c [new file with mode: 0644]
object-store/object-store-test.c [new file with mode: 0644]
odo/Makefile [new file with mode: 0644]
odo/README [new file with mode: 0644]
odo/grid.png [new file with mode: 0644]
odo/neghand.png [new file with mode: 0644]
odo/odo-distort-funcs.c [new file with mode: 0644]
odo/odo-distort-funcs.h [new file with mode: 0644]
odo/odo-texture.c [new file with mode: 0644]
odo/odo-texture.h [new file with mode: 0644]
odo/odo.c [new file with mode: 0644]
odo/oh-logo.png [new file with mode: 0644]
odo/redhand.png [new file with mode: 0644]
opt/.gitignore [new file with mode: 0644]
opt/AUTHORS [new file with mode: 0644]
opt/ChangeLog [new file with mode: 0644]
opt/Makefile.am [new file with mode: 0644]
opt/NEWS [new file with mode: 0644]
opt/README [new file with mode: 0644]
opt/autogen.sh [new file with mode: 0755]
opt/bg.png [new file with mode: 0644]
opt/configure.ac [new file with mode: 0644]
opt/demo.xml [new file with mode: 0644]
opt/hirez/oh-present.xcf [new file with mode: 0644]
opt/kitten.jpg [new file with mode: 0644]
opt/kitten2.jpg [new file with mode: 0644]
opt/opt-config.c [new file with mode: 0644]
opt/opt-menu.c [new file with mode: 0644]
opt/opt-menu.h [new file with mode: 0644]
opt/opt-show.c [new file with mode: 0644]
opt/opt-show.h [new file with mode: 0644]
opt/opt-slide.c [new file with mode: 0644]
opt/opt-slide.h [new file with mode: 0644]
opt/opt-transition.c [new file with mode: 0644]
opt/opt-transition.h [new file with mode: 0644]
opt/opt.c [new file with mode: 0644]
opt/opt.doap [new file with mode: 0644]
opt/opt.dtd [new file with mode: 0644]
opt/opt.h [new file with mode: 0644]
opt/powers.png [new file with mode: 0644]
opt/test.xml [new file with mode: 0644]
packaging/clutter-toys.spec [new file with mode: 0644]
patches/fix-colors.patch [new file with mode: 0644]
patches/fix-image-path.patch [new file with mode: 0644]
patches/map-escape-key-to-quit.patch [new file with mode: 0644]
pong/Makefile [new file with mode: 0644]
pong/pong-ball.png [new file with mode: 0644]
pong/pong-bat.png [new file with mode: 0644]
pong/pong2.c [new file with mode: 0644]
ripples/Makefile [new file with mode: 0644]
ripples/ripples.c [new file with mode: 0644]
script-viewer/.gitignore [new file with mode: 0644]
script-viewer/COPYING [new file with mode: 0644]
script-viewer/ChangeLog [new file with mode: 0644]
script-viewer/Makefile [new file with mode: 0644]
script-viewer/README [new file with mode: 0644]
script-viewer/alphas.json [new file with mode: 0644]
script-viewer/behaviours.json [new file with mode: 0644]
script-viewer/redhand.png [new file with mode: 0644]
script-viewer/script-viewer.c [new file with mode: 0644]
script-viewer/test-script.json [new file with mode: 0644]
script-viewer/text.json [new file with mode: 0644]

diff --git a/README b/README
new file mode 100644 (file)
index 0000000..d1dd823
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+The best way to find out about these toys is to try them out; they're
+all small demos that have few/no dependencies beyond the clutter
+libraries. The following is a summary of each;
+
+arc-clock     - A small clock demo (using the cogl path API)
+circles       - A small spinning circles demo (using the cogl path API)
+nyancat       - A small nyancat made of clutter
+courasel      - A carousel-style menu demo
+foofone       - A mock-up mobile phone interface
+gps-globe     - The start of an app to draw a globe with your GPS pos
+object-store  - A ClutterModel subclass that proxies GObjects
+opt           - A slide-show application
+odo           - A mesh deformation demo set
+pinpoint      - A minimalistic presentation tool
+pong          - An unfinished pong game
+ripples       - A small 'ripples' effect demo (using the cogl vector-drawing
+                API)
+script-viewer - A ClutterScript viewer
+
+Bitrotted toys that do not work with Clutter 1.x API yet have been placed in the attic/
+
+aaina         - A Flickr picture browser
+astro-desktop - A mock-up desktop/palmtop application environment
+fluttr        - Another Flickr picture browser
+gcr           - A Gegl-based clutter video recorder
+mallums-magic-browser - A webkit-clutter based web browser
+sqlite-model  - an sqlite-backed ClutterModel implementation
+table         - A multi-touch table style picture/video viewer (not actually
+                multi-touch)
+widgets       - A texture-reflecting actor demo
+woohaa        - A video browser/player
+youhaa        - A (currently broken) YouTube video browser
diff --git a/arc-clock/Makefile b/arc-clock/Makefile
new file mode 100644 (file)
index 0000000..620bbd9
--- /dev/null
@@ -0,0 +1,17 @@
+LIBS=`pkg-config --libs clutter-x11-1.0`
+INCS=`pkg-config --cflags clutter-x11-1.0`
+
+QUIET_CC=@echo '  CC     '$@;
+QUIET_LD=@echo '  CCLD   '$@;
+QUIET_RM=@echo '  RM     '$@;
+
+.c.o:
+       $(QUIET_CC)$(CC) -g -Wall --std=c99 $(CFLAGS) $(INCS) -c $*.c
+
+all: arc-clock
+
+arc-clock: arc-clock.o
+       $(QUIET_LD)$(CC) -g -Wall --std=c99 $(CFLAGS) -o $@ $< -lm $(LIBS)
+
+clean:
+       @rm -fr *.o arc-clock
diff --git a/arc-clock/arc-clock.c b/arc-clock/arc-clock.c
new file mode 100644 (file)
index 0000000..b455752
--- /dev/null
@@ -0,0 +1,189 @@
+#include <math.h>
+#include <time.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include <clutter/clutter.h>
+#include <clutter/x11/clutter-x11.h>
+
+#define HAND_WIDTH      24
+
+enum
+{
+  PM,
+
+  SECONDS,
+  MINUTES,
+  HOURS,
+
+  DAY,
+  MONTH,
+
+  N_HANDS
+};
+
+static double slices[N_HANDS] = { 0.0, };
+
+static ClutterActor *hands[N_HANDS] = { NULL, };
+
+static const char *colors[N_HANDS] = {
+  "#4e9a06",
+
+  "#edd400",
+  "#ce5c00",
+  "#cc0000",
+
+  "#3465a4",
+  "#75507b"
+};
+
+static gboolean hide_date = FALSE;
+static gboolean hide_seconds = FALSE;
+
+static void
+hand_paint (ClutterActor *hand)
+{
+  guint hand_id;
+
+  hand_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (hand), "hand-id"));
+
+  double end_angle = slices[hand_id];
+
+  float radius = clutter_actor_get_width (hand) / 2.0 + 0.5;
+
+  ClutterColor hand_color;
+  clutter_rectangle_get_color (CLUTTER_RECTANGLE (hand), &hand_color);
+
+  CoglColor fill_color;
+  cogl_color_init_from_4ub (&fill_color,
+                            hand_color.red,
+                            hand_color.green,
+                            hand_color.blue,
+                            hand_color.alpha);
+
+  cogl_set_source_color (&fill_color);
+
+  cogl_path_move_to (radius, 0.0f);
+  cogl_path_arc (radius, radius,
+                 radius, radius,
+                 -90.0,
+                 -90.0 + end_angle * 180.0 / G_PI);
+  cogl_path_arc (radius, radius,
+                 radius - HAND_WIDTH, radius - HAND_WIDTH,
+                 -90.0 + end_angle * 180.0 / G_PI,
+                 -90.0);
+  cogl_path_close ();
+  cogl_path_fill ();
+
+  g_signal_stop_emission_by_name (hand, "paint");
+}
+
+static void
+on_stage_pre_paint (ClutterActor *actor)
+{
+  cogl_set_depth_test_enabled (TRUE);
+}
+
+static void
+on_stage_post_paint (ClutterActor *actor)
+{
+  cogl_set_depth_test_enabled (FALSE);
+}
+
+static gboolean
+update_slices (gpointer data G_GNUC_UNUSED)
+{
+  struct tm *now_tm;
+  time_t now;
+
+  time (&now);
+  now_tm = localtime (&now);
+
+  slices[SECONDS] = now_tm->tm_sec * G_PI / 30;
+  slices[MINUTES] = now_tm->tm_min * G_PI / 30;
+  slices[HOURS]   = (now_tm->tm_hour >= 12 ? now_tm->tm_hour - 12
+                                           : now_tm->tm_hour) * G_PI / 6;
+  slices[DAY]     = now_tm->tm_mday * G_PI / 15;
+  slices[MONTH]   = (now_tm->tm_mon + 1) * G_PI / 6;
+
+  for (int i = SECONDS; i < N_HANDS; i++)
+    clutter_actor_queue_redraw (hands[i]);
+
+  return TRUE;
+}
+
+static GOptionEntry entries[] = {
+  {
+    "hide-seconds", 's',
+    0,
+    G_OPTION_ARG_NONE, &hide_seconds,
+    "Hide the seconds hand", NULL
+  },
+  {
+    "hide-date", 'd',
+    0,
+    G_OPTION_ARG_NONE, &hide_date,
+    "Hide the date hands", NULL
+  },
+  { NULL }
+};
+
+int
+main (int argc, char *argv[])
+{
+#if !CLUTTER_CHECK_VERSION (1, 3, 6)
+#error "You need Clutter >= 1.3.6 to compile arc-clock."
+#endif
+
+  clutter_x11_set_use_argb_visual (TRUE);
+
+  GError *error = NULL;
+  clutter_init_with_args (&argc, &argv,
+                          "Arc Clock",
+                          entries,
+                          NULL,
+                          &error);
+
+  ClutterActor *stage = clutter_stage_new ();
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "Arc Clock");
+  clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+  clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE);
+  clutter_actor_set_opacity (stage, 0);
+
+  g_signal_connect (stage, "paint", G_CALLBACK (on_stage_pre_paint), NULL);
+  g_signal_connect_after (stage, "paint", G_CALLBACK (on_stage_post_paint), NULL);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  for (int i = SECONDS; i < N_HANDS; i++)
+    {
+      ClutterColor color;
+
+      clutter_color_from_string (&color, colors[i]);
+      hands[i] = clutter_rectangle_new_with_color (&color);
+      clutter_actor_set_size (hands[i], (HAND_WIDTH * 3.0) * i, (HAND_WIDTH * 3.0) * i);
+      clutter_actor_add_constraint (hands[i], clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
+      clutter_actor_add_constraint (hands[i], clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
+      g_signal_connect (hands[i], "paint", G_CALLBACK (hand_paint), NULL);
+      g_object_set_data (G_OBJECT (hands[i]), "hand-id", GUINT_TO_POINTER (i));
+      clutter_container_add_actor (CLUTTER_CONTAINER (stage), hands[i]);
+    }
+
+  if (hide_seconds)
+    clutter_actor_hide (hands[SECONDS]);
+
+  if (hide_date)
+    {
+      clutter_actor_hide (hands[DAY]);
+      clutter_actor_hide (hands[MONTH]);
+    }
+
+  g_timeout_add_seconds ((hide_seconds ? 60 : 1), update_slices, NULL);
+
+  update_slices (NULL);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}
diff --git a/attic/aaina/AUTHORS b/attic/aaina/AUTHORS
new file mode 100644 (file)
index 0000000..efdbb94
--- /dev/null
@@ -0,0 +1 @@
+Neil J. Patel <njp@o-hand.com> 
diff --git a/attic/aaina/ChangeLog b/attic/aaina/ChangeLog
new file mode 100644 (file)
index 0000000..07e5bc5
--- /dev/null
@@ -0,0 +1,713 @@
+2008-02-18  Chris Lord  <chris@openedhand.com>
+
+       * configure.ac:
+       Bump clutter version to 0.6
+
+2008-02-07  Chris Lord  <chris@openedhand.com>
+
+       * configure.ac:
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf):
+       * libaaina/clutter-texture-label.c:
+       (clutter_texture_label_make_pixbuf):
+       * src/main.c: (main), (on_key_release_event), (spin_me):
+       Update to latest clutter 0.5 API
+
+2007-08-07  Neil J. Patel  <njp@o-hand.com>
+
+       * configure.ac:
+       Bump to 0.4.
+
+2007-07-13  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (on_photo_added):
+       * src/aaina-slide-show.h:
+       * src/main.c: (im_spinning_around), (main), (on_key_release_event),
+       (spin_me):
+       Move all photos to the slide show group.
+       Left right rotates stage.
+       Up starts the slide show spinning timeline.
+       The slide show will spin at every two minutes.
+
+2007-07-13  Neil J. Patel  <njp@o-hand.com>
+
+       * src/main.c: (main):
+       Change spinning timeout to two minutes.
+
+2007-07-13  Neil J. Patel  <njp@o-hand.com>
+
+       * src/main.c: (im_spinning_around), (main), (on_key_release_event),
+       (spin_me):
+       Added spinning of the stage via arrow keys,
+       Added a 1 minute timeout for spinning (needs work);
+
+2007-07-13  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_alpha_restore),
+       (aaina_photo_set_pixbuf), (aaina_photo_alpha_zoom),
+       (aaina_photo_init):
+       * src/main.c: (main):
+       Change the title and desc showing so they are inline on a black 
+       background.
+
+2007-07-13  Neil J. Patel  <njp@o-hand.com>
+
+       * sources/aaina-source-flickr.c: (on_info_thread_ok),
+       (on_pixbuf_thread_ok), (get_pixbuf):
+       Remove the printfs
+
+2007-07-13  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/clutter-texture-label.c:
+       (clutter_texture_label_make_pixbuf):
+       * sources/aaina-source-flickr.c: (on_info_thread_ok),
+       (on_pixbuf_thread_ok), (get_pixbuf):
+       * src/aaina-slide-show.c: (aaina_slide_show_move):
+       * src/main.c: (main):
+       Added some debugging printf's.
+
+2007-07-11  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_restore),
+       (aaina_photo_alpha_restore), (aaina_photo_set_pixbuf),
+       (aaina_photo_zoom), (aaina_photo_init):
+       Use clutter texture label.
+       Make the panels larger.
+
+       * libaaina/clutter-texture-label.c:
+       (clutter_texture_label_make_pixbuf), (timeline_completed),
+       (clutter_texture_label_show), (clutter_texture_label_hide),
+       (clutter_texture_label_init):
+       Fix error on multiple show/hides.
+
+2007-07-11  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_init):
+       Change fonts.
+       Some spacing fixes.
+
+2007-07-11  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/Makefile.am:
+       * libaaina/aaina-photo.c: (aaina_photo_alpha_restore),
+       (aaina_photo_set_pixbuf), (aaina_photo_zoom),
+       (aaina_photo_alpha_zoom), (aaina_photo_init):
+       Added title and author display on zoom.
+
+       * libaaina/clutter-texture-label.c:
+       (clutter_texture_label_make_pixbuf), (timeline_cb),
+       (clutter_texture_label_show), (clutter_texture_label_hide),
+       (clutter_texture_label_set_property),
+       (clutter_texture_label_get_property),
+       (clutter_texture_label_dispose), (clutter_texture_label_finalize),
+       (clutter_texture_label_class_init), (clutter_texture_label_init),
+       (clutter_texture_label_new_with_text), (clutter_texture_label_new),
+       (clutter_texture_label_get_text), (clutter_texture_label_set_text),
+       (clutter_texture_label_get_font_name),
+       (clutter_texture_label_set_font_name),
+       (clutter_texture_label_set_text_extents),
+       (clutter_texture_label_get_text_extents),
+       (clutter_texture_label_set_color),
+       (clutter_texture_label_get_color):
+       * libaaina/clutter-texture-label.h:
+       Imported Matthews crazy label for use with the zoomed photo.
+
+       * src/main.c: (main):
+       Remove stray printf.
+
+2007-07-11  Neil J. Patel  <njp@o-hand.com>
+
+       * src/main.c: (main), (on_key_release_event):
+       Quit gracefully when Esc is pressed.
+
+2007-07-11  Neil J. Patel  <njp@o-hand.com>
+
+       * sources/aaina-source-flickr.c: (on_pixbuf_thread_ok),
+       (on_thread_ok):
+       Get rid of stray printfs.
+
+2007-07-11  Emmanuele Bassi  <ebassi@o-hand.com>
+
+       * src/main.c: Use the G_OPTION_FILENAME type for the directory
+       command line parameter; also switch to arrays of filenames, to
+       allow multiple unparented directories on the comman line.
+
+2007-07-11  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-library.c: (aaina_library_init),
+       (aaina_library_get_pending), (aaina_library_set_pending),
+       (aaina_library_is_full), (aaina_library_set_max),
+       (aaina_library_photo_count), (aaina_library_append_photo),
+       (aaina_library_remove_photo):
+       * libaaina/aaina-library.h:
+       Added support for a max_photos property and a method to determine if there
+       are photos waiting to be added.
+
+       * sources/aaina-source-flickr.c: (manage_queue),
+       (on_pixbuf_thread_ok), (get_photos):
+       Use new functions to determine whether it is okay to add photos.
+
+       * src/aaina-slide-show.c: (aaina_slide_show_move):
+       Only delete a photo from the stream if there are photos waiting to be
+       input into the library.
+
+2007-07-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (update_rotation), (aaina_photo_set_property),
+       (aaina_photo_get_property), (aaina_photo_class_init):
+       Added rotation and description properties.
+       Honours rotation property on new pixbufs.
+       
+       * libnflick/nflick-info-response.c: (nflick_info_response_get):
+       * libnflick/nflick-info-response.h:
+       * libnflick/nflick-info-worker-private.h:
+       * libnflick/nflick-info-worker.c: (thread_func),
+       (nflick_info_worker_get):
+       * libnflick/nflick-info-worker.h:
+       * libnflick/nflick-types.h:
+       Added *_get functions to retrieve a photos rotation/authors real name and
+       description.
+
+       * sources/aaina-source-flickr.c: (on_info_thread_ok):
+       Gets the rotation/real name/description info and updates the photo with it.
+
+2007-07-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (aaina_photo_init):
+       Do clutter actor_show instead of clutter_actor_show_all.
+       
+       * src/aaina-slide-show.c: (restore_photo):
+       Check priv->zoomed is a AainaPhoto before making calls.
+
+2007-07-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c:
+       Remove the gl.h #include, which made its way back into the file.
+
+2007-07-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (aaina_photo_set_property), (aaina_photo_get_property),
+       (aaina_photo_class_init):
+       Send a GError to clutter_texture_set_pixbuf.
+       Add an extra clutter_actor_show_all on texture.
+       
+       * sources/aaina-source-directory.c: (_load_photos):
+       Send an GError to gdk_pixbuf_new_from_file_at_scale.
+
+2007-07-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-library.c: (aaina_library_init),
+       (aaina_library_photo_count), (aaina_library_get_photo),
+       (aaina_library_append_photo), (aaina_library_remove_photo),
+       (aaina_library_foreach):
+       * libaaina/aaina-library.h:
+       Changed to use GList as a backend as we don't need the power of eggsequence.
+
+       * libaaina/aaina-photo.c: (aaina_photo_restore),
+       (aaina_photo_alpha_restore), (aaina_photo_set_property),
+       (aaina_photo_get_property), (aaina_photo_class_init),
+       (aaina_photo_init):
+       Add the 'realname' and 'desc' properties.
+       Remove unused gl.h #include.
+
+       * libnflick/Makefile.am:
+       * libnflick/nflick-info-response-private.h:
+       * libnflick/nflick-info-response.c:
+       (nflick_info_response_get_type), (nflick_info_response_class_init),
+       (nflick_info_response_init), (private_init), (private_dispose),
+       (nflick_info_response_dispose), (nflick_info_response_finalize),
+       (nflick_info_response_get), (all_fields_valid), (fill_blanks),
+       (parse_func), (nflick_info_response_get_property):
+       * libnflick/nflick-info-response.h:
+       * libnflick/nflick-info-worker-private.h:
+       * libnflick/nflick-info-worker.c: (nflick_info_worker_get_type),
+       (nflick_info_worker_class_init), (nflick_info_worker_init),
+       (private_init), (private_dispose), (nflick_info_worker_dispose),
+       (nflick_info_worker_finalize), (thread_func),
+       (nflick_info_worker_get), (nflick_info_worker_new),
+       (nflick_info_worker_get_property):
+       * libnflick/nflick-info-worker.h:
+       * libnflick/nflick-types.h:
+       Add a worker/response to get information about a photo.
+
+       * sources/aaina-source-flickr.c: (on_info_thread_abort),
+       (on_info_thread_error), (on_info_thread_ok), (manage_queue),
+       (add_to_library), (on_pixbuf_thread_ok), (get_pixbuf),
+       (on_thread_ok), (get_photos), (aaina_source_flickr_init):
+       Limit the amount of photos added to the library to 100. 
+       Wait until library is < 100 before adding anymore.
+       Make sure to unref workers, as they eat up memory.
+
+       * src/aaina-slide-show.c: (on_photo_zoomed), (restore_photo),
+       (aaina_slide_show_move):
+       If a photo has been viewed, delete it.
+
+2007-07-08  Neil J. Patel  <njp@o-hand.com>
+
+       * sources/aaina-source-flickr.c: (manage_queue),
+       (on_pixbuf_thread_abort), (on_pixbuf_thread_error),
+       (on_pixbuf_thread_ok):
+       Keep fecthing pixbufs even when there is an error or abort.
+       Check for new pics eevry 60 seconds.
+
+2007-07-08  Neil J. Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-show-worker.c: (thread_func):
+       Don't add the token as a parameter, as it isn't used for public photos.
+
+       * sources/aaina-source-flickr.c: (on_pixbuf_thread_abort),
+       (on_pixbuf_thread_error), (on_pixbuf_thread_ok), (get_pixbuf),
+       (on_thread_ok), (aaina_source_flickr_init):
+       Added downloading support.
+       Upon download succeeding, it will add the photo to the library, and it'll
+       magically appear in the river.
+       Start aaina with -t tag to test it out.
+
+2007-07-07  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_property),
+       (aaina_photo_get_property), (aaina_photo_class_init):
+       Add an 'id' property.
+
+       * libnflick/nflick-flickr.h:
+       Not sure why this is here, can't remember editing this :-/. Maybe its just
+       been a long day.
+
+       * sources/aaina-source-flickr.c: (on_thread_ok),
+       (aaina_source_flickr_init):
+       Here's an idea, when inserting a string into a hash table, don't free 
+       said string in the next few g_free calls, and then wonder why each call to
+       flickr is doubling the hash table size.
+
+2007-07-07  Neil J. Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-photo-search-worker.c: (thread_func):
+       Don't print a list of the photos it recieved, just store the list.
+       
+       * libnflick/nflick-types.h:
+       Fix typo in type decleration.
+
+       * sources/aaina-source-flickr.c: (on_thread_ok), (get_photos),
+       (aaina_source_flickr_init):
+       Hashtable to store the photos.
+       'take list' from the worker and chek if the photo is already in the list, 
+       otherwise add it,
+
+2007-07-07  Neil J. Patel  <njp@o-hand.com>
+
+       * sources/aaina-source-flickr.c: (on_thread_abort),
+       (on_thread_error), (on_thread_ok), (get_photos):
+       Fix stupid race condition because of wrong function signature.
+       Add data to the nflick worker callbacks.
+
+2007-07-07  Neil J. Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-photo-search-worker.c: (thread_func):
+       Use the passed-in value for the 'tags' attribute.
+       
+       * sources/aaina-source-flickr.c: (on_thread_abort),
+       (on_thread_error), (on_thread_ok), (get_photos),
+       (aaina_source_flickr_class_init), (aaina_source_flickr_init),
+       (aaina_source_flickr_new):
+       * sources/aaina-source-flickr.h:
+       Add a private instance.
+       Store the tags and library in the private instance for later use.
+
+       * src/aaina-slide-show.c: (zoom_photo):
+       Don't go OTT when trying to find a photo, just return TRUE to the timeout,
+       and prevent a segfault.
+
+2007-07-07  Neil J. Patel  <njp@o-hand.com>
+
+       * libnflick/Makefile.am:
+       * libnflick/nflick-flickr.h:
+       * libnflick/nflick-photo-search-response-private.h:
+       * libnflick/nflick-photo-search-response.c:
+       (nflick_photo_search_response_get_type),
+       (nflick_photo_search_response_class_init),
+       (nflick_photo_search_response_init), (private_init),
+       (private_dispose), (nflick_photo_search_response_take_list),
+       (nflick_photo_search_response_dispose),
+       (nflick_photo_search_response_finalize), (parse_func),
+       (nflick_photo_search_response_get_property):
+       * libnflick/nflick-photo-search-response.h:
+       * libnflick/nflick-photo-search-worker-private.h:
+       * libnflick/nflick-photo-search-worker.c:
+       (nflick_photo_search_worker_get_type),
+       (nflick_photo_search_worker_class_init),
+       (nflick_photo_search_worker_init), (private_init),
+       (private_dispose), (nflick_photo_search_worker_dispose),
+       (nflick_photo_search_worker_finalize), (thread_func),
+       (nflick_photo_search_worker_new),
+       (nflick_photo_search_worker_take_list),
+       (nflick_photo_search_worker_get_property):
+       * libnflick/nflick-photo-search-worker.h:
+       * libnflick/nflick-types.h:
+       * libnflick/nflick.h:
+       * sources/Makefile.am:
+       * sources/aaina-source-flickr.c: (aaina_source_flickr_class_init),
+       (aaina_source_flickr_init), (on_thread_abort), (on_thread_error),
+       (on_thread_ok), (get_photos), (aaina_source_flickr_new):
+       * sources/aaina-source-flickr.h:
+       * src/aaina-slide-show.c:
+       * src/main.c: (main):
+       Print a list of photos from flickr for a particular tag, then segfault :-)
+
+2007-07-06  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (restore_photo), (aaina_slide_show_move):
+       Stopped photos being moved when they are zoomed.
+
+2007-07-05  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_get_dim),
+       (aaina_photo_set_dim), (aaina_photo_save),
+       (aaina_photo_alpha_restore), (aaina_photo_alpha_zoom):
+       * libaaina/aaina-photo.h:
+       Fade the dim to 0 when zooming. 
+       Store the dim opacity, and the depth, restore both with un-zomming.
+       
+       * src/aaina-slide-show.c: (on_photo_added):
+       Update for new dim api.
+
+2007-07-05  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (on_photo_added):
+       Tweaked the timelines to make the smaller photos move faster than the larger
+       ones.
+
+2007-07-05  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_dim),
+       (aaina_photo_set_pixbuf), (aaina_photo_init):
+       * libaaina/aaina-photo.h:
+       Added a 'dim' setting which, wait for it, dims the photo. No really, it
+       does.
+
+       * src/aaina-slide-show.c: (on_photo_added):
+       Uses this 'dim' setting and sets small photos to be 'dimmer', so they appear
+       further away.
+       Each lane is sorted by size, and size deducts the photos z-order, so it
+       really does look like big photos are closer, small photos are further.
+
+2007-07-05  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (on_photo_added):
+       Sort by depth using an algorithm a child could develop, yep its that bad, 
+       but it is a start.
+
+2007-07-05  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (on_photo_added):
+       Added z-order (not finished).
+       Increased number of lanes.
+
+2007-07-05  Emmanuele Bassi  <ebassi@openedhand.com>
+
+       * src/main.c: Use clutter_init_with_args() to parse
+       the command line arguments and show the help. Show the
+       correct usage if no directory was specified.
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * Makefile.am:
+       * configure.ac:
+       * libnflick/Makefile.am:
+       * libnflick/nflick-api-request-private.h:
+       * libnflick/nflick-api-request.c:
+       * libnflick/nflick-api-request.h:
+       * libnflick/nflick-api-response-private.h:
+       * libnflick/nflick-api-response.c:
+       * libnflick/nflick-api-response.h:
+       * libnflick/nflick-auth-worker-private.h:
+       * libnflick/nflick-auth-worker.c:
+       * libnflick/nflick-auth-worker.h:
+       * libnflick/nflick-flickr.h:
+       * libnflick/nflick-get-sizes-response-private.h:
+       * libnflick/nflick-get-sizes-response.c:
+       * libnflick/nflick-gft-response.c:
+       * libnflick/nflick-gft-response.h:
+       * libnflick/nflick-no-set-response-private.h:
+       * libnflick/nflick-no-set-response.c:
+       * libnflick/nflick-no-set-response.h:
+       * libnflick/nflick-photo-data.c:
+       * libnflick/nflick-photo-data.h:
+       * libnflick/nflick-photo-list-response-private.h:
+       * libnflick/nflick-photo-list-response.c:
+       * libnflick/nflick-photo-list-response.h:
+       * libnflick/nflick-photo-list-worker-private.h:
+       * libnflick/nflick-photo-list-worker.c:
+       * libnflick/nflick-photo-list-worker.h:
+       * libnflick/nflick-photo-set-private.h:
+       * libnflick/nflick-photo-set.c:
+       * libnflick/nflick-photo-set.h:
+       * libnflick/nflick-pixbuf-fetch-private.h:
+       * libnflick/nflick-pixbuf-fetch.c:
+       * libnflick/nflick-pixbuf-fetch.h:
+       * libnflick/nflick-set-list-response-private.h:
+       * libnflick/nflick-set-list-response.c:
+       * libnflick/nflick-set-list-response.h:
+       * libnflick/nflick-set-list-worker-private.h:
+       * libnflick/nflick-set-list-worker.c:
+       * libnflick/nflick-set-list-worker.h:
+       * libnflick/nflick-show-worker-private.h:
+       * libnflick/nflick-show-worker.c:
+       * libnflick/nflick-show-worker.h:
+       * libnflick/nflick-types.h:
+       * libnflick/nflick-worker-private.h:
+       * libnflick/nflick-worker.c:
+       * libnflick/nflick-worker.h:
+       * libnflick/nflick.h:
+       Import crazy flickr code.
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (aaina_photo_set_property), (aaina_photo_init):
+       Added white border around photos.
+       Fixed some positioning errors.
+
+       * sources/aaina-source-directory.c: (_load_photos):
+       Use the provided get/set mechanisms for pixbufs rather than g_object_set
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_init):
+       Init'd some private variables that I had skipped.
+
+       * src/aaina-slide-show.c: (aaina_slide_show_move),
+       (on_photo_added), (aaina_slide_show_row_foreach),
+       (aaina_slide_show_init), (aaina_slide_show_get_default):
+       * src/aaina-slide-show.h:
+       Converted into a singleton to avoid passing around lots of pointers.
+       Implemented a 'never ending' stream i.e. photos which are not zoomed into,
+       and disappear off the end of the screen, are then moved to the end of the
+       stream so they get a second chance, the poor souls.
+       Moved all the photo adding code into a single function which is called
+       by the initial library-setting call, plus subsequent calls.
+
+       * src/main.c: (main):
+       Updated to reflect the new aaina_slide_show_get_default () call.
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_save),
+       (aaina_photo_alpha_restore), (aaina_photo_alpha_zoom),
+       (aaina_photo_class_init), (aaina_photo_init):
+       * libaaina/aaina-photo.h:
+       Tweak the behaviours to be much smoother, especially in scaling.
+
+       * src/aaina-slide-show.c: (zoom_photo):
+       Don't stop the timelines, as the whole display looks much better when the
+       timelines aren't frozen.
+       
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_restore),
+       (aaina_photo_alpha_restore), (aaina_photo_init):
+       Added a behvaviour to restore the photo to its orignal state.
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/Makefile.am:
+       Remove versioning as this is a static library.
+       
+       * libaaina/aaina-photo.c: (aaina_photo_zoom),
+       (aaina_photo_alpha_zoom), (aaina_photo_init):
+       * libaaina/aaina-photo.h:
+       Add a zoom behaviour.
+
+       * src/aaina-slide-show.c: (zoom_photo):
+       Adjust to use the new AainaPhoto zooming behaviour.
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (restore_photo), (zoom_photo):
+       Comment your code so someone other than yourself has a chance of understanding
+       what you've written.
+       Flag the photo as 'viewed', so we don't zoom it again (when we implement
+       that feature).
+       Move some hardcoded ints into #defines.
+
+2007-07-01  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_save),
+       (aaina_photo_restore):
+       Saves the x, y and scale, and then restores the x, y and scale.
+
+       * src/aaina-slide-show.c: (restore_photo), (zoom_photo),
+       (aaina_slide_show_set_library), (aaina_slide_show_class_init):
+       Implement the beginnings of the photo-zoom feature. Will pause the timelines
+       and zoom a randomly chosen picture for a few seconds. It will then restore the
+       slide show to the previous state, and start a new timeout at a random time
+       for the next zoom.
+
+2007-06-30  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (aaina_photo_init):
+       Remove the wite frame for now, because it isn't working properly.
+
+       * src/aaina-slide-show.c: (aaina_slide_show_move),
+       (aaina_slide_show_row_foreach), (aaina_slide_show_init),
+       (aaina_slide_show_new):
+       * src/aaina-slide-show.h:
+       Add all photos to the stage, instead of AainaSlideShow, as it is easier for 
+       effects to work if they know positions are relative to the stage.
+       
+       Change the AainaSlideShow object to a standard GObject, instead of a
+       ClutterGroup, and this is no longer necessary.
+
+       Convert the lanes to GLists containing pointers to the photos they manage,
+       rather than ClutterGroups (which adds another level to correct positioning
+       for effects).
+
+       * src/main.c: (main):
+       Update to reflect the AainaSlideShow becoming its own object.
+
+2007-06-30  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_save),
+       (aaina_photo_get_viewed), (aaina_photo_set_viewed),
+       (aaina_photo_set_pixbuf), (aaina_photo_set_property),
+       (aaina_photo_get_property), (aaina_photo_class_init),
+       (aaina_photo_init):
+       * libaaina/aaina-photo.h:
+       Add a few more needed functions and properties.
+       
+       * src/aaina-slide-show.c: (aaina_slide_show_row_foreach):
+       Clean up code.
+
+2007-06-30  Neil J. Patel  <njp@o-hand.com>
+
+  * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf):
+       Keep all actors positions at 0, 0
+
+       * src/aaina-slide-show.c: (aaina_slide_show_row_foreach),
+       (aaina_slide_show_set_library):
+       Remove the randomising of the timelines, it doesn't work well enough for
+       proper use.
+
+2007-06-30  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (aaina_photo_class_init), (aaina_photo_init):
+       Removed self-scaling, using clutter_actor_set_scale instead.
+
+       * src/aaina-slide-show.c: (aaina_slide_show_move),
+       (aaina_slide_show_row_foreach), (on_photo_added),
+       (aaina_slide_show_set_library), (aaina_slide_show_init):
+       More tweaks regarding the spacing of pictures, plus added randomised
+       movement to each lane (so each lane has a different speed).
+       
+       * src/main.c: (main):
+       Fixed some spacing.
+
+2007-06-30  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (aaina_slide_show_row_foreach),
+       (aaina_slide_show_set_library):
+       Bring all the positioning into one function, clean up the randomising.
+
+2007-06-29  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_get_scale),
+       (aaina_photo_init):
+       * libaaina/aaina-photo.h:
+       * src/aaina-slide-show.c: (_sort_lanes),
+       (aaina_slide_show_row_foreach), (aaina_slide_show_set_library),
+       (aaina_slide_show_init):
+       Randomise the photo arrangement, however keep them in 'lanes', which group
+       the photos horizontally, so we can now implement movement of those lanes at
+       different speeds, and different orders.
+
+2007-06-29  Neil J. Patel  <njp@o-hand.com>
+
+       * src/aaina-slide-show.c: (aaina_slide_show_row_foreach),
+       (aaina_slide_show_set_library), (aaina_slide_show_init):
+       Switch to adding photos into 'lanes' depending on their y position on the
+       stage.
+
+2007-06-28  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_scale),
+       (aaina_photo_paint), (aaina_photo_class_init):
+       * libaaina/aaina-photo.h:
+       * src/aaina-slide-show.c: (aaina_slide_show_row_foreach):
+       Implement proper center-scaling for photos.
+
+2007-06-28  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/aaina-photo.c: (aaina_photo_set_pixbuf),
+       (aaina_photo_set_property), (aaina_photo_class_init),
+       (aaina_photo_init), (aaina_photo_new):
+       * libaaina/aaina-photo.h:
+       Fix setting of texture, plus add backgorund tetxure.
+       
+       * sources/aaina-source-directory.c: (_load_photos):
+       Load photos at half the stage dimensions.
+
+       * src/aaina-slide-show.c: (aaina_slide_show_remove_rows),
+       (aaina_slide_show_row_foreach), (on_photo_added),
+       (aaina_slide_show_set_library), (aaina_slide_show_set_property):
+       Fix to actually add photos from the library, and to randomly position them.
+
+       * src/main.c: (main):
+       Load the the directory source and show the stage at 1/4 size (to check the
+       randomness of the placement)
+
+
+2007-06-27  Neil J. Patel  <njp@o-hand.com>
+
+       * src/Makefile.am:
+       * src/main.c: (main):
+       Create something that resembles a main.c
+
+2007-06-27  Neil J. Patel  <njp@o-hand.com>
+
+       * Makefile.am:
+       * configure.ac:
+       * libaaina/aaina-source.h:
+       Inheriting from the wrong object. 
+
+       * sources/Makefile.am:
+       * sources/aaina-source-directory.c: (_load_photos),
+       (aaina_source_directory_class_init), (aaina_source_directory_init),
+       (aaina_source_directory_new):
+       * sources/aaina-source-directory.h:
+       Added a sources directory.
+       Created a basic directory-based source.
+
+       * src/aaina-slide-show.c: (aaina_slide_show_class_init):
+       Removed over-riding clutter_actor_paint (), but needed at the moment,
+
+2007-06-27  Neil J. Patel  <njp@o-hand.com>
+
+       * libaaina/Makefile.am:
+       * libaaina/aaina-source.c: (aaina_source_class_init),
+       (aaina_source_init), (aaina_source_new):
+       * libaaina/aaina-source.h:
+       Added a source class, for different backends.
+
+2007-06-27  Neil J. Patel  <njp@o-hand.com>
+
+       * AUTHORS:
+       * Makefile.am:
+       * autogen.sh:
+       * configure.ac:
+       * libaaina/Makefile.am:
+       * libaaina/aaina-behave.c:
+       * libaaina/aaina-behave.h:
+       * libaaina/aaina-library.c:
+       * libaaina/aaina-library.h:
+       * libaaina/aaina-photo.c:
+       * libaaina/aaina-photo.h:
+       * libaaina/eggsequence.c:
+       * libaaina/eggsequence.h:
+       * src/Makefile.am:
+       * src/aaina-slide-show.c:
+       * src/aaina-slide-show.h:
+       * src/main.c:
+       Initial import.
diff --git a/attic/aaina/Makefile.am b/attic/aaina/Makefile.am
new file mode 100644 (file)
index 0000000..c777c14
--- /dev/null
@@ -0,0 +1,7 @@
+SUBDIRS = libnflick libaaina sources src
+
+#MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub configure depcomp install-sh ltmain.sh Makefile.in missing
+
+snapshot:
+       $(MAKE) dist distdir=$(PACKAGE)-snap`date +"%Y%m%d"`
+
diff --git a/attic/aaina/NEWS b/attic/aaina/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/aaina/README b/attic/aaina/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/aaina/TODO b/attic/aaina/TODO
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/aaina/autogen.sh b/attic/aaina/autogen.sh
new file mode 100755 (executable)
index 0000000..b1376df
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/attic/aaina/configure.ac b/attic/aaina/configure.ac
new file mode 100644 (file)
index 0000000..6e18348
--- /dev/null
@@ -0,0 +1,29 @@
+AC_PREREQ(2.53)
+AC_INIT(aaina, 0.1, [])
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/main.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES(DEPS, clutter-0.8 gdk-2.0 gtk+-2.0 neon >= 0.26 libxml-2.0)
+AC_SUBST(DEPS_CFLAGS)
+AC_SUBST(DEPS_LIBS)
+
+if test "x$GCC" = "xyes"; then
+        GCC_FLAGS="-g -Wall -Werror"
+fi
+
+AC_SUBST(GCC_FLAGS)
+
+AC_OUTPUT([
+Makefile
+libnflick/Makefile
+libaaina/Makefile
+sources/Makefile
+src/Makefile
+])
diff --git a/attic/aaina/libaaina/Makefile.am b/attic/aaina/libaaina/Makefile.am
new file mode 100644 (file)
index 0000000..db9f285
--- /dev/null
@@ -0,0 +1,28 @@
+noinst_LTLIBRARIES = libaaina.la
+
+INCLUDES = \
+       $(DEPS_CFLAGS)
+       -I$(top_srcdir)                                 \
+       -I$(top_builddir)                               \
+       $(GCC_CFLAGS)                                   \
+       -DDATADIR=\""$(datadir)"\"                      \
+       -DSYSCONFDIR=\""$(sysconfdir)"\"                \
+       -Werror                                         \
+       $(NULL) 
+
+libaaina_la_SOURCES =  \
+       aaina-behave.c                                  \
+       aaina-behave.h                                  \
+       aaina-library.c                                 \
+       aaina-library.h                                 \
+       aaina-photo.c                                   \
+       aaina-photo.h                                   \
+       aaina-source.c                                  \
+       aaina-source.h                                  \
+       clutter-texture-label.c \
+       clutter-texture-label.h \
+       eggsequence.c                                   \
+       eggsequence.h
+
+libaaina_la_LIBADD = $(DEPS_LIBS)
+libaaina_la_LDFLAGS = 
diff --git a/attic/aaina/libaaina/aaina-behave.c b/attic/aaina/libaaina/aaina-behave.c
new file mode 100644 (file)
index 0000000..24c5936
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+
+/* This is a utility ClutterBehaviour-derived class, in which you can set the
+   alphanotify function. It is useful for situations where you do not need the
+   full capabilities of the ClutterBehvaiour class, you just want a function to
+   be called for each iteration along the timeline
+*/
+
+#include "aaina-behave.h"
+
+#include "math.h"
+
+G_DEFINE_TYPE (AainaBehave, aaina_behave, CLUTTER_TYPE_BEHAVIOUR);
+
+#define AAINA_BEHAVE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       AAINA_TYPE_BEHAVE, \
+       AainaBehavePrivate))
+
+struct _AainaBehavePrivate
+{
+       AainaBehaveAlphaFunc     func;
+       gpointer                data;
+};
+
+guint32 
+alpha_sine_inc_func (ClutterAlpha *alpha,
+                    gpointer      dummy)
+{
+       ClutterTimeline *timeline;
+       gint current_frame_num, n_frames;
+       gdouble x, sine;
+  
+       timeline = clutter_alpha_get_timeline (alpha);
+
+       current_frame_num = clutter_timeline_get_current_frame (timeline);
+       n_frames = clutter_timeline_get_n_frames (timeline);
+
+       x = (gdouble) (current_frame_num * 0.5f * M_PI) / n_frames ;
+       /* sine = (sin (x - (M_PI / 0.5f)) + 1.0f) * 0.5f; */
+  
+       sine = (sin (x - (M_PI / 0.5f))) ;
+  
+       return (guint32)(sine * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);
+}
+
+guint32 
+alpha_linear_inc_func (ClutterAlpha *alpha,
+                      gpointer      dummy)
+{
+       ClutterTimeline *timeline;
+       gint current_frame_num, n_frames;
+       gdouble x;
+  
+       timeline = clutter_alpha_get_timeline (alpha);
+
+       current_frame_num = clutter_timeline_get_current_frame (timeline);
+       n_frames = clutter_timeline_get_n_frames (timeline);
+
+       x = (gdouble) (current_frame_num) / n_frames ;
+       /* sine = (sin (x - (M_PI / 0.5f)) + 1.0f) * 0.5f; */
+  
+       return (guint32)(x * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);      
+}
+
+static void
+aaina_behave_alpha_notify (ClutterBehaviour *behave, guint32 alpha_value)
+{
+       AainaBehave *aaina_behave = AAINA_BEHAVE(behave);
+       AainaBehavePrivate *priv;
+       
+       priv = AAINA_BEHAVE_GET_PRIVATE (aaina_behave);
+       
+       if (priv->func != NULL) {
+               priv->func (behave, alpha_value, priv->data);
+       }
+}
+
+static void
+aaina_behave_class_init (AainaBehaveClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
+
+       behave_class->alpha_notify = aaina_behave_alpha_notify;
+       
+       g_type_class_add_private (gobject_class, sizeof (AainaBehavePrivate));
+}
+
+static void
+aaina_behave_init (AainaBehave *self)
+{
+       AainaBehavePrivate *priv;
+       
+       priv = AAINA_BEHAVE_GET_PRIVATE (self);
+       
+       priv->func = NULL;
+       priv->data = NULL;
+}
+
+ClutterBehaviour*
+aaina_behave_new (ClutterAlpha                 *alpha,
+                AainaBehaveAlphaFunc    func,
+                gpointer                data)
+{
+       AainaBehave *behave;
+       AainaBehavePrivate *priv;
+       
+       behave = g_object_new (AAINA_TYPE_BEHAVE, 
+                              "alpha", alpha,
+                              NULL);
+
+       priv = AAINA_BEHAVE_GET_PRIVATE (behave);  
+       
+       priv->func = func;
+       priv->data = data;
+               
+       return CLUTTER_BEHAVIOUR(behave);
+}
diff --git a/attic/aaina/libaaina/aaina-behave.h b/attic/aaina/libaaina/aaina-behave.h
new file mode 100644 (file)
index 0000000..dee6649
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+/* This is a utility ClutterBehaviour-derived class, in which you can set the
+   alphanotify function. It is useful for situations where you do not need the
+   full capabilities of the ClutterBehvaiour class, you just want a function to
+   be called for each iteration along the timeline
+*/
+
+#ifndef _AAINA_BEHAVE_H_
+#define _AAINA_BEHAVE_H_
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+#define AAINA_TYPE_BEHAVE (aaina_behave_get_type ())
+
+#define AAINA_BEHAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+       AAINA_TYPE_BEHAVE, \
+       AainaBehave))
+
+#define AAINA_BEHAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_BEHAVE, \
+       AainaBehaveClass))
+
+#define CLUTTER_IS_BEHAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+       AAINA_TYPE_BEHAVE))
+
+#define CLUTTER_IS_BEHAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+       AAINA_TYPE_BEHAVE))
+
+#define AAINA_BEHAVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_BEHAVE, \
+       AainaBehaveClass))
+
+typedef struct _AainaBehave        AainaBehave;
+typedef struct _AainaBehaveClass   AainaBehaveClass;
+typedef struct _AainaBehavePrivate AainaBehavePrivate;
+struct _AainaBehave
+{
+       ClutterBehaviour        parent; 
+};
+
+struct _AainaBehaveClass
+{
+       ClutterBehaviourClass   parent_class;
+};
+
+typedef void (*AainaBehaveAlphaFunc) (ClutterBehaviour  *behave, 
+                                    guint32            alpha_value,
+                                    gpointer           data);
+
+GType aaina_behave_get_type (void) G_GNUC_CONST;
+
+ClutterBehaviour* 
+aaina_behave_new (ClutterAlpha                 *alpha,
+                AainaBehaveAlphaFunc    func,
+                gpointer                data);
+
+guint32 
+alpha_sine_inc_func (ClutterAlpha *alpha,
+                    gpointer      dummy);      
+                    
+guint32 
+alpha_linear_inc_func (ClutterAlpha *alpha,
+                      gpointer      dummy);                     
+
+#endif /* _AAINA_BEHAVE_H_ */
+
diff --git a/attic/aaina/libaaina/aaina-library.c b/attic/aaina/libaaina/aaina-library.c
new file mode 100644 (file)
index 0000000..0b6aedf
--- /dev/null
@@ -0,0 +1,375 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Matthew Allum  <mallum@openedhand.com>
+ */
+
+#include "aaina-library.h"
+#include <string.h>
+
+G_DEFINE_TYPE (AainaLibrary, aaina_library, G_TYPE_OBJECT);
+
+#define LIBRARY_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), AAINA_TYPE_LIBRARY, AainaLibraryPrivate))
+
+typedef struct _AainaLibraryPrivate AainaLibraryPrivate;
+
+enum
+{
+       REORDERED,
+       PHOTO_CHANGED,
+       PHOTO_ADDED,
+       FILTER,
+       LAST_SIGNAL
+};
+
+static guint _library_signals[LAST_SIGNAL] = { 0 };
+
+struct _AainaLibraryPrivate
+{
+       AainaFilterRowFunc      filter;
+       gpointer                filter_data;
+       AainaCompareRowFunc     sort;
+       gpointer                sort_data;
+       EggSequence             *photos;
+  GList             *list;
+  guint              size;
+  guint              max_photos;
+  gboolean           pending;
+};
+
+static void
+aaina_library_get_property (GObject *object, guint property_id,
+                            GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, 
+                                                          pspec);
+       }
+}
+
+static void
+aaina_library_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, 
+                                                          pspec);
+       }
+}
+
+static void
+aaina_library_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (aaina_library_parent_class)->dispose)
+               G_OBJECT_CLASS (aaina_library_parent_class)->dispose (object);
+}
+
+static void
+aaina_library_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (aaina_library_parent_class)->finalize (object);
+}
+
+static void
+aaina_library_class_init (AainaLibraryClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (AainaLibraryPrivate));
+
+       object_class->get_property = aaina_library_get_property;
+       object_class->set_property = aaina_library_set_property;
+       object_class->dispose = aaina_library_dispose;
+       object_class->finalize = aaina_library_finalize;
+
+       _library_signals[REORDERED] =
+               g_signal_new ("photos-reordered",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (AainaLibraryClass, reordered),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
+       _library_signals[FILTER] =
+               g_signal_new ("filter-changed",
+                            G_OBJECT_CLASS_TYPE (object_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (AainaLibraryClass, filter_change),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
+
+       _library_signals[PHOTO_CHANGED] =
+               g_signal_new ("photo-changed",
+                            G_OBJECT_CLASS_TYPE (object_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (AainaLibraryClass, photo_change),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__OBJECT,
+                            G_TYPE_NONE, 1, AAINA_TYPE_PHOTO);
+
+       _library_signals[PHOTO_ADDED] =
+               g_signal_new ("photo-added",
+                            G_OBJECT_CLASS_TYPE (object_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (AainaLibraryClass, photo_added),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__OBJECT,
+                            G_TYPE_NONE, 1, AAINA_TYPE_PHOTO);
+
+}
+
+static void
+aaina_library_init (AainaLibrary *self)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(self);
+
+       priv->photos = egg_sequence_new (NULL);
+  priv->list = NULL;
+  priv->size = 0;
+  priv->max_photos = 100;
+  priv->pending = FALSE;
+}
+
+static gboolean 
+check_filter (AainaLibrary *library, EggSequenceIter *iter)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);  
+       gboolean res;
+
+       if (priv->filter == NULL)
+               return TRUE;
+
+       res = priv->filter(library, (AainaPhoto*)egg_sequence_get (iter), 
+                          priv->filter_data); 
+       return res;
+}
+
+gboolean
+aaina_library_get_pending (AainaLibrary *library)
+{
+  AainaLibraryPrivate *priv;
+
+  g_return_val_if_fail (AAINA_IS_LIBRARY (library), FALSE);
+  priv = LIBRARY_PRIVATE (library);
+
+  return priv->pending;
+}
+
+void
+aaina_library_set_pending (AainaLibrary *library, gboolean pending)
+{
+  AainaLibraryPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_LIBRARY (library));
+  priv = LIBRARY_PRIVATE (library);
+
+  priv->pending = pending;
+}
+
+gboolean
+aaina_library_is_full (AainaLibrary *library)
+{
+  AainaLibraryPrivate *priv;
+
+  g_return_val_if_fail (AAINA_IS_LIBRARY (library), FALSE);
+  priv = LIBRARY_PRIVATE (library);
+
+  if (priv->size >= priv->max_photos)
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+void
+aaina_library_set_max (AainaLibrary *library, gint max_photos)
+{
+  AainaLibraryPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_LIBRARY (library));
+  priv = LIBRARY_PRIVATE (library);
+
+  priv->max_photos = max_photos;
+}
+  
+guint
+aaina_library_photo_count (AainaLibrary *library)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);  
+       EggSequenceIter     *iter;
+       gint                 n = 0;
+
+  return priv->size;
+  return g_list_length (priv->list);
+
+       if (priv->filter == NULL)
+               return egg_sequence_get_length (priv->photos);    
+
+       iter = egg_sequence_get_begin_iter (priv->photos);
+
+       while (!egg_sequence_iter_is_end (iter)) {
+               if (check_filter (library, iter))
+                       n++;
+               iter = egg_sequence_iter_next (iter);
+       }
+
+       return n;
+}
+
+AainaPhoto*
+aaina_library_get_photo (AainaLibrary *library, gint index)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       EggSequenceIter     *iter;
+       gint                 n = 0;
+
+       return (AainaPhoto*)g_list_nth_data (priv->list, index);
+
+  if (priv->filter == NULL)
+               return (AainaPhoto*)egg_sequence_get 
+                            (egg_sequence_get_iter_at_pos (priv->photos, index));
+
+       iter = egg_sequence_get_begin_iter (priv->photos);
+
+       while (!egg_sequence_iter_is_end (iter)) {
+               if (check_filter (library, iter)) {
+                       if (n == index)
+                               return (AainaPhoto*)egg_sequence_get (iter);
+                       n++;
+               }
+               iter = egg_sequence_iter_next (iter);
+       }
+
+       return NULL;
+}
+
+static void
+on_photo_changed (GObject *obj, GParamSpec   *arg1,
+                                  gpointer      data)
+{
+       return;
+       AainaLibrary        *library = AAINA_LIBRARY(data);
+       AainaLibraryPrivate *priv;
+
+       priv = LIBRARY_PRIVATE(library);
+
+       /* thumbnail changing does not effect ordering */
+       if (!strcmp(g_param_spec_get_name(arg1), "thumbnail"))
+               return;
+
+       if (priv->sort) {
+               egg_sequence_sort (priv->photos, 
+                               (GCompareDataFunc)priv->sort, priv->sort_data);
+               g_signal_emit (library, _library_signals[REORDERED], 0);
+       }
+
+       g_signal_emit (library, _library_signals[PHOTO_CHANGED], 0, 
+                                                       AAINA_PHOTO(obj));
+} 
+
+void
+aaina_library_append_photo (AainaLibrary *library, AainaPhoto *photo)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       EggSequenceIter     *iter;
+
+       g_signal_connect (photo, "notify", G_CALLBACK (on_photo_changed), library);
+
+       /*
+
+       if (priv->sort)
+               iter = egg_sequence_insert_sorted (priv->photos, (gpointer)photo,
+                                                 (GCompareDataFunc)priv->sort,
+                                                  priv->sort_data);
+       else
+               iter = egg_sequence_append (priv->photos, (gpointer)photo);
+  */
+       priv->list = g_list_append (priv->list, photo);
+  priv->size++;
+  g_signal_emit (library, _library_signals[PHOTO_ADDED], 0, photo);
+}
+
+void
+aaina_library_remove_photo (AainaLibrary *library, const AainaPhoto *photo)
+{
+  AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+
+  priv->list = g_list_remove (priv->list, (gconstpointer)photo);
+  priv->size--;
+}
+
+
+void
+aaina_library_foreach (AainaLibrary      *library, 
+                       AainaForeachRowFunc   func,
+                       gpointer           data)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       EggSequenceIter     *iter;
+  GList *l;
+
+  for (l = priv->list; l != NULL; l = l->next)
+  {
+    if (AAINA_IS_PHOTO (l->data))
+      func (library, (AainaPhoto*)l->data, data );
+  }
+  return;
+/*
+  iter = egg_sequence_get_begin_iter (priv->photos);
+       while (!egg_sequence_iter_is_end (iter)) {
+               if (check_filter (library, iter))
+                       if (func (library, 
+                                 (AainaPhoto*)egg_sequence_get (iter, data) == FALSE)
+                               return;
+       
+               iter = egg_sequence_iter_next (iter);
+       }
+  */
+}
+
+void
+aaina_library_set_sort_func (AainaLibrary     *library, 
+                             AainaCompareRowFunc  func, 
+                             gpointer          userdata)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+
+       priv->sort      = func;
+       priv->sort_data = userdata;
+
+       if (func) {
+               egg_sequence_sort (priv->photos, (GCompareDataFunc)func, userdata);
+               g_signal_emit (library, _library_signals[REORDERED], 0);
+       }
+}
+
+void
+aaina_library_set_filter (AainaLibrary    *library,
+                          AainaFilterRowFunc  filter, 
+                          gpointer         data)
+{
+       AainaLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       AainaFilterRowFunc      prev_filter;
+
+       prev_filter = priv->filter;
+
+       priv->filter      = filter;
+       priv->filter_data = data;
+
+       if (prev_filter != priv->filter)
+               g_signal_emit (library, _library_signals[FILTER], 0);
+}
+
+AainaLibrary*
+aaina_library_new ()
+{
+       return g_object_new (AAINA_TYPE_LIBRARY, NULL);
+}
+
diff --git a/attic/aaina/libaaina/aaina-library.h b/attic/aaina/libaaina/aaina-library.h
new file mode 100644 (file)
index 0000000..725fd96
--- /dev/null
@@ -0,0 +1,111 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Matthew Allum  <mallum@openedhand.com>
+ */
+
+#ifndef _AAINA_LIBRARY
+#define _AAINA_LIBRARY
+
+#include <glib-object.h>
+#include "aaina-photo.h"
+#include "eggsequence.h"
+
+G_BEGIN_DECLS
+
+#define AAINA_TYPE_LIBRARY aaina_library_get_type()
+
+#define AAINA_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       AAINA_TYPE_LIBRARY, \
+       AainaLibrary))
+
+#define AAINA_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_LIBRARY, \
+       AainaLibraryClass))
+
+#define AAINA_IS_LIBRARY(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       AAINA_TYPE_LIBRARY))
+
+#define AAINA_IS_LIBRARY_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       AAINA_TYPE_LIBRARY))
+
+#define AAINA_LIBRARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_LIBRARY, \
+       AainaLibraryClass))
+
+typedef struct {
+       GObject         parent;
+
+} AainaLibrary;
+
+typedef struct {
+       GObjectClass parent_class;
+
+       void (*reordered) (AainaLibrary *library);
+       void (*filter_change) (AainaLibrary *library);
+       void (*photo_change) (AainaLibrary *library, AainaPhoto *photo);
+       void (*photo_added) (AainaLibrary *library, AainaPhoto *photo);
+
+} AainaLibraryClass;
+
+typedef gint (*AainaCompareRowFunc) (AainaPhoto *a,
+                                    AainaPhoto *b,
+                                    gpointer        data);
+
+typedef gboolean  (*AainaFilterRowFunc) (AainaLibrary    *library,
+                                        AainaPhoto *photo,
+                                        gpointer         data);
+
+typedef gboolean (*AainaForeachRowFunc) (AainaLibrary    *library,
+                                        AainaPhoto *photo,
+                                        gpointer         data);
+
+GType aaina_library_get_type (void);
+
+AainaLibrary*
+aaina_library_new ();
+
+guint
+aaina_library_photo_count (AainaLibrary *library);
+
+AainaPhoto*
+aaina_library_get_photo (AainaLibrary *library, gint index);
+
+void
+aaina_library_append_photo (AainaLibrary *library, AainaPhoto *photo);
+
+void
+aaina_library_remove_photo (AainaLibrary *library, const AainaPhoto *photo);
+
+void
+aaina_library_set_filter (AainaLibrary    *library,
+                         AainaFilterRowFunc  filter, 
+                         gpointer         data);
+
+void
+aaina_library_set_sort_func (AainaLibrary     *library, 
+                            AainaCompareRowFunc  func, 
+                            gpointer          userdata);
+
+void
+aaina_library_foreach (AainaLibrary      *library, 
+                     AainaForeachRowFunc   func,
+                     gpointer           data);
+
+gboolean
+aaina_library_get_pending (AainaLibrary *library);
+void
+aaina_library_set_pending (AainaLibrary *library, gboolean pending);
+
+gboolean
+aaina_library_is_full (AainaLibrary *library);
+void
+aaina_library_set_max (AainaLibrary *library, gint max_photos);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/libaaina/aaina-photo.c b/attic/aaina/libaaina/aaina-photo.c
new file mode 100644 (file)
index 0000000..664a4b8
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "clutter-texture-label.h"
+
+#include "aaina-behave.h"
+
+#include "aaina-photo.h"
+
+G_DEFINE_TYPE (AainaPhoto, aaina_photo, CLUTTER_TYPE_GROUP);
+
+#define AAINA_PHOTO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       AAINA_TYPE_PHOTO, \
+       AainaPhotoPrivate))
+
+#define DIV 9
+       
+static GdkPixbuf       *default_pic = NULL;
+
+struct _AainaPhotoPrivate
+{
+  GdkPixbuf    *pixbuf;
+  gboolean      visible;
+
+  gchar        *id;
+  gchar        *title;
+  gchar        *author;
+  gchar        *date;
+  gint          rotation;
+  gchar        *desc;
+
+  gboolean      viewed;
+
+  ClutterActor *dim;
+  ClutterActor *texture; 
+  ClutterActor *bg;
+
+  ClutterActor *title_bg;
+  ClutterActor *title_text;
+
+  ClutterActor *desc_bg;
+  ClutterActor *desc_text;
+
+  gdouble       scale;
+
+  /* Variables for aaina_photo_save/restore */
+  gdouble       save_scale;
+  gint          save_x;
+  gint          save_y;
+  guint8        save_dim;
+  gint          save_depth;
+
+  
+  ClutterTimeline *zoom_time;
+  ClutterTimeline *restore_time;
+  gint          temp_x;
+  gint          temp_y;
+};
+
+enum
+{
+  PROP_0,
+  PROP_PIXBUF,
+  PROP_ID,
+  PROP_TITLE,
+  PROP_DATE,
+  PROP_AUTHOR,
+  PROP_VIEWED,
+  PROP_ROTATION,
+  PROP_DESC
+};
+
+enum
+{
+  PHOTO_ZOOMED,
+  PHOTO_RESTORED,
+
+  LAST_SIGNAL
+};
+
+static guint _photo_signals[LAST_SIGNAL] = { 0 };
+
+guint8
+aaina_photo_get_dim (AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  return clutter_actor_get_opacity (priv->dim);
+}
+
+void
+aaina_photo_set_dim (AainaPhoto *photo, guint8 dim_level)
+{
+  AainaPhotoPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  clutter_actor_set_opacity (priv->dim, dim_level);
+}
+
+void
+aaina_photo_save (AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+  
+  /* Make the x value slightly more the the left as it is constantly moving */
+  priv->save_x = clutter_actor_get_x (CLUTTER_ACTOR (photo)) - 150;
+  priv->save_y = clutter_actor_get_y (CLUTTER_ACTOR (photo));
+  clutter_actor_get_scale (CLUTTER_ACTOR (photo), 
+                           &priv->save_scale, 
+                           &priv->save_scale);
+  priv->save_dim = clutter_actor_get_opacity (priv->dim);
+  priv->save_depth = clutter_actor_get_depth (CLUTTER_ACTOR (photo));
+}
+
+void
+aaina_photo_restore (AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  priv->temp_x = clutter_actor_get_x (CLUTTER_ACTOR (photo));
+  priv->temp_y = clutter_actor_get_y (CLUTTER_ACTOR (photo));
+
+  clutter_actor_hide (priv->title_text);
+  clutter_actor_hide (priv->desc_text);
+
+  clutter_timeline_start (priv->restore_time);
+}
+
+static void
+aaina_photo_alpha_restore (ClutterBehaviour *behave, 
+                           guint32 alpha_value, 
+                           AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+  gfloat factor;
+  gdouble scale, new_scale;
+  gint x, y;
+  guint width, height;
+  gint new_x, new_y;
+  
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+
+  x = priv->temp_x; //clutter_actor_get_x (CLUTTER_ACTOR (photo));
+  y = priv->temp_y; //clutter_actor_get_y (CLUTTER_ACTOR (photo));
+  clutter_actor_get_size (CLUTTER_ACTOR (priv->texture), &width, &height);
+  clutter_actor_get_scale (CLUTTER_ACTOR (photo), &scale, &scale);
+
+  new_x = priv->save_x;
+  new_y = priv->save_y;
+
+  if (x > new_x)
+    new_x = x - ((x - new_x) * factor);
+  else
+    new_x = x + ((new_x - x) * factor);
+
+  if (y > new_y)
+    new_y = y - ((y - new_y) * factor);
+  else
+    new_y = y + ((new_y - y) * factor);
+
+  //new_scale = scale - ((scale - priv->save_scale) * factor);
+  new_scale = 1.0 - ((1-priv->save_scale) * factor);
+
+  clutter_actor_set_position (CLUTTER_ACTOR (photo), new_x, new_y);
+  clutter_actor_set_scale (CLUTTER_ACTOR (photo), new_scale, new_scale);
+  
+  clutter_actor_set_opacity (priv->dim, priv->save_dim *factor);
+  /* This is the title y */
+  //height += 20;
+  //new_y = ((height/DIV) - ((height/DIV) * factor)) * -1;
+  //g_object_set (priv->title_bg, "y", new_y, NULL);
+  //clutter_actor_set_position (priv->title_text, 20, new_y+5);
+  clutter_actor_set_opacity (priv->title_bg, 150 - (150*factor));
+  
+  //new_y = (height) - ((height/DIV)*factor);
+  //g_object_set (priv->desc_bg, "y", new_y, NULL);
+  //clutter_actor_set_position (priv->desc_text, 20, new_y);
+  //clutter_actor_set_opacity (priv->desc_bg, 255 - (255 *factor));
+  
+  if (factor == 1)
+  {
+    clutter_actor_set_opacity (priv->title_text, 0);
+    clutter_actor_set_opacity (priv->desc_text, 0);
+  }
+
+  if (factor == 1)
+  {
+    clutter_actor_set_opacity (priv->dim, priv->save_dim);
+    clutter_actor_set_depth (CLUTTER_ACTOR (photo), priv->save_depth);
+    g_signal_emit (G_OBJECT (photo), _photo_signals[PHOTO_RESTORED], 0);
+  }
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (photo));
+}
+gdouble
+aaina_photo_get_scale (AainaPhoto *photo)
+{
+  g_return_val_if_fail (AAINA_IS_PHOTO (photo), 1.0);
+  return photo->priv->scale;
+}
+void
+aaina_photo_set_scale (AainaPhoto *photo, gdouble scale)
+{
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  photo->priv->scale = scale;
+
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (photo));
+}
+
+gboolean
+aaina_photo_get_viewed (AainaPhoto *photo)
+{
+  g_return_val_if_fail (AAINA_IS_PHOTO (photo), TRUE);
+
+  return photo->priv->viewed;
+}
+
+void
+aaina_photo_set_viewed (AainaPhoto *photo, gboolean viewed)
+{
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+
+  photo->priv->viewed = viewed;
+}
+
+void
+aaina_photo_set_pixbuf (AainaPhoto *photo, GdkPixbuf *pixbuf)
+{
+  AainaPhotoPrivate *priv;
+  gint width, height;
+  gint w, h;
+  GError *err = NULL;
+    
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+  priv = photo->priv;
+
+  if (priv->rotation)
+  {
+    GdkPixbuf *old = pixbuf;
+    pixbuf = gdk_pixbuf_rotate_simple (old, 360-priv->rotation);
+    g_object_unref (G_OBJECT (old));
+  }
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  w = width + 20;
+  h = height + 20;
+
+  /* Set up the title & desc */
+  clutter_actor_set_size (priv->title_bg, width, height/4);
+  clutter_actor_set_position (priv->title_bg, 
+                              10,
+                              10 + ( height- (height/4)));
+
+  //clutter_actor_set_size (priv->title_text, w, h/2);
+  clutter_actor_set_position (priv->title_text, 20, (height-(height/4))+15);
+  clutter_actor_set_clip (priv->title_text, 0, 0, width, CLUTTER_STAGE_HEIGHT ());
+
+  //clutter_actor_set_size (priv->desc_bg, w, h/DIV);
+  //clutter_actor_set_position (priv->desc_bg, 0, (h - (h/9))+10);
+
+  //clutter_actor_set_size (priv->desc_text, w, h/2);
+  clutter_actor_set_position (priv->desc_text, 20,(height-(height/4))+42);
+
+  /* The 'dimming' back rectangle */
+  clutter_actor_set_size (priv->dim, width+20, height+20);
+  clutter_actor_set_position (priv->dim, 0, 0);
+  
+  clutter_actor_set_size (priv->bg, width+20, height+20);
+  clutter_actor_set_position (priv->bg, 0, 0);
+
+  clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (priv->texture),
+                                       gdk_pixbuf_get_pixels (pixbuf),
+                                       gdk_pixbuf_get_has_alpha (pixbuf),
+                                       gdk_pixbuf_get_width (pixbuf),
+                                       gdk_pixbuf_get_height (pixbuf),
+                                       gdk_pixbuf_get_rowstride (pixbuf),
+                                       4, 0,
+                                       &err);
+
+  clutter_actor_set_size (priv->texture, width, height);
+  if (err)
+    g_warning ("%s\n", err->message);
+  
+  clutter_actor_set_position (priv->texture, 10, 10);
+  clutter_actor_show (priv->texture);
+}
+
+static void
+update_rotation (AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+  GdkPixbuf *old;
+  GdkPixbuf *new;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  old = clutter_texture_get_pixbuf (CLUTTER_TEXTURE (priv->texture));
+
+  if (!old)
+  {
+    g_print ("No pixbuf\n");
+    return;
+  }
+  new = gdk_pixbuf_rotate_simple (old, priv->rotation);
+
+  aaina_photo_set_pixbuf (photo, new);
+
+  if (G_IS_OBJECT (old))
+    g_object_unref (G_OBJECT (old));
+}
+
+void
+aaina_photo_zoom (AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  if (priv->title)
+  {
+    clutter_texture_label_set_text (CLUTTER_TEXTURE_LABEL (priv->title_text), 
+                            priv->title);
+  }
+  if (priv->author)
+  {
+    clutter_texture_label_set_text (CLUTTER_TEXTURE_LABEL (priv->desc_text),
+                            priv->author);
+   }
+  clutter_actor_hide (priv->title_text);
+  clutter_actor_hide (priv->desc_text);
+
+  clutter_timeline_start (priv->zoom_time);
+}
+
+static void
+aaina_photo_alpha_zoom (ClutterBehaviour *behave, 
+                        guint32 alpha_value, 
+                        AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+  gfloat factor;
+  gdouble scale, new_scale;
+  gint x, y;
+  guint width, height;
+  gint new_x, new_y;
+  
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = photo->priv;
+
+  factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+
+  x = clutter_actor_get_x (CLUTTER_ACTOR (photo));
+  y = clutter_actor_get_y (CLUTTER_ACTOR (photo));
+  clutter_actor_get_size (priv->texture, &width, &height);
+  clutter_actor_get_scale (CLUTTER_ACTOR (photo), &scale, &scale);
+
+  new_x = CLUTTER_STAGE_WIDTH () / 4;
+  new_y = CLUTTER_STAGE_HEIGHT () /4;
+
+
+  if (x > new_x)
+    new_x = x - ((x - new_x) * factor);
+  else
+    new_x = x + ((new_x - x) * factor);
+
+  if (y > new_y)
+    new_y = y - ((y - new_y) * factor);
+  else
+    new_y = y + ((new_y - y) * factor);
+
+  new_scale = scale + ((1 - scale) * factor);
+  if (new_scale < scale)
+    new_scale = scale;
+
+  clutter_actor_set_position (CLUTTER_ACTOR (photo), new_x, new_y);
+  clutter_actor_set_scale (CLUTTER_ACTOR (photo), new_scale, new_scale);
+  clutter_actor_set_opacity (priv->dim,
+                            clutter_actor_get_opacity (priv->dim)
+      -(clutter_actor_get_opacity (priv->dim))*factor);
+
+  /* This is the title y 
+  height += 20;
+  new_y = (height/DIV) * factor * -1;
+  g_object_set (priv->title_bg, "y", new_y, NULL);
+  //g_object_set (priv->title_text, "y", (-1*(height/DIV))*factor, NULL);
+  clutter_actor_set_position (priv->title_text, 20, new_y+5);
+  */
+  clutter_actor_set_opacity (priv->title_bg, 150*factor);
+  /*
+  new_y = (height- (height/DIV)) + ((height/DIV)*factor);
+  g_object_set (priv->desc_bg, "y", new_y, NULL);
+  g_object_set (priv->desc_text, "y", new_y, NULL);
+  clutter_actor_set_position (priv->desc_text, 20, new_y);
+  clutter_actor_set_opacity (priv->desc_bg, 255 *factor);
+  */
+  if (factor == 1)
+  {
+    clutter_actor_set_opacity (priv->title_text, 255);
+    clutter_actor_set_opacity (priv->desc_text, 255);
+    clutter_actor_show (priv->title_text);
+    clutter_actor_show (priv->desc_text);
+    g_signal_emit (G_OBJECT (photo), _photo_signals[PHOTO_ZOOMED], 0);
+  }
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (photo));
+}
+
+/* GObject stuff */
+/*
+static void
+aaina_photo_paint (ClutterActor *actor)
+{
+  AainaPhotoPrivate *priv;
+
+  priv = AAINA_PHOTO (actor)->priv;
+
+  glPushMatrix ();
+
+  gfloat x, y;
+  guint width = CLUTTER_STAGE_WIDTH ()/2;
+  guint height = CLUTTER_STAGE_HEIGHT ()/2;
+
+  clutter_actor_get_scale (actor, &priv->scale, &priv->scale);
+
+  x = (priv->scale *width) - (width);
+  x /= 2;
+  x *= -1;
+
+  y = (priv->scale *height) - (height);
+  y /= 2;
+  y *= -1;
+
+  glTranslatef (x, y, 0);
+  glScalef (priv->scale, priv->scale, 1);
+
+  gint i;
+  gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor));
+  for (i = 0; i <len; i++)
+  {
+    ClutterActor *child;
+    child = clutter_group_get_nth_child (CLUTTER_GROUP (actor), i);
+
+    if (child)
+      clutter_actor_paint (child);
+  }
+  glPopMatrix ();
+}
+*/
+static void
+aaina_photo_set_property (GObject      *object, 
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  AainaPhotoPrivate *priv;
+  
+  g_return_if_fail (AAINA_IS_PHOTO (object));
+  priv = AAINA_PHOTO (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_PIXBUF:
+      priv->pixbuf = g_value_get_object (value);
+      if (priv->pixbuf)
+        aaina_photo_set_pixbuf (AAINA_PHOTO (object), priv->pixbuf);
+      break;
+
+    case PROP_ID:
+      if (priv->id)
+        g_free (priv->id);
+      priv->id = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_TITLE:
+      if (priv->title)
+        g_free (priv->title);
+      priv->title = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_AUTHOR:
+      if (priv->author)
+        g_free (priv->author);
+      priv->author = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_DATE:
+      if (priv->date)
+        g_free (priv->date);
+      priv->date = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_VIEWED:
+        priv->viewed = g_value_get_boolean (value);
+        break;
+    case PROP_ROTATION:
+        priv->rotation = g_value_get_int (value);
+        break;
+    case PROP_DESC:
+        priv->desc = g_strdup (g_value_get_string (value));
+        break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+aaina_photo_get_property (GObject    *object, 
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  AainaPhotoPrivate *priv;
+  
+  g_return_if_fail (AAINA_IS_PHOTO (object));
+  priv = AAINA_PHOTO (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_PIXBUF:
+      g_value_set_object (value, G_OBJECT (priv->pixbuf));
+      break;
+    case PROP_ID:
+      g_value_set_string (value, priv->id);
+      break;
+    case PROP_TITLE:
+      g_value_set_string (value, priv->title);
+      break;
+    case PROP_AUTHOR:
+      g_value_set_string (value, priv->author);
+      break;
+    case PROP_DATE:
+      g_value_set_string (value, priv->date);
+      break;
+    case PROP_VIEWED:
+      g_value_set_boolean (value, priv->viewed);
+      break;
+    case PROP_ROTATION:
+      g_value_set_int (value, priv->rotation);
+      break;
+    case PROP_DESC:
+      g_value_set_string (value, priv->desc);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+  static void
+aaina_photo_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (aaina_photo_parent_class)->dispose (object);
+}
+
+static void
+aaina_photo_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (aaina_photo_parent_class)->finalize (object);
+}
+
+static void
+aaina_photo_class_init (AainaPhotoClass *klass)
+{
+  GObjectClass    *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  //actor_class->paint          = aaina_photo_paint;
+
+  gobject_class->finalize     = aaina_photo_finalize;
+  gobject_class->dispose      = aaina_photo_dispose;
+  gobject_class->get_property = aaina_photo_get_property;
+  gobject_class->set_property = aaina_photo_set_property;
+
+  g_type_class_add_private (gobject_class, sizeof (AainaPhotoPrivate));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_PIXBUF,
+    g_param_spec_object ("pixbuf",
+                         "The pixbuf!",
+                         "The GdkPixbuf to be shown",
+                         GDK_TYPE_PIXBUF,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_ID,
+    g_param_spec_string ("id",
+                         "The id",
+                         "The id of the photo",
+                         NULL,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+    gobject_class,
+    PROP_TITLE,
+    g_param_spec_string ("title",
+                         "The title",
+                         "The title of the photo",
+                         NULL,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_DATE,
+    g_param_spec_string ("date",
+                         "The date",
+                         "The date the photo was taken",
+                         NULL,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+  g_object_class_install_property (
+    gobject_class,
+    PROP_AUTHOR,
+    g_param_spec_string ("author",
+                         "The author",
+                         "The athor of the photo",
+                         NULL,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+  
+  g_object_class_install_property (
+    gobject_class,
+    PROP_VIEWED,
+    g_param_spec_boolean ("viewed",
+                         "If viewed",
+                         "The photo has been view",
+                         FALSE,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_ROTATION,
+    g_param_spec_int ("rotation",
+                      "Rotation",
+                      "The photos rotation",
+                      0, 360, 0,
+                      G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+    gobject_class,
+    PROP_DESC,
+    g_param_spec_string ("desc",
+                         "Description",
+                         "The photos description",
+                         NULL,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+  _photo_signals[PHOTO_ZOOMED] = 
+    g_signal_new ("photo_zoomed",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (AainaPhotoClass, photo_zoomed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  
+  _photo_signals[PHOTO_RESTORED] = 
+    g_signal_new ("photo_restored",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (AainaPhotoClass, photo_restored),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+static void
+aaina_photo_init (AainaPhoto *photo)
+{
+  AainaPhotoPrivate *priv;
+  ClutterColor white = {0xff, 0xff, 0xff, 0xff};
+  ClutterColor black = {0x00, 0x00, 0x00, 0x00};
+  ClutterColor title = {0x00, 0x00, 0x00, 0xff};
+  ClutterColor desc  = {0xff, 0xff, 0xff, 0xdd};
+  gint width, height;
+  ClutterAlpha *alpha;
+  ClutterBehaviour *behave;
+  GdkPixbuf *pixbuf;
+  gchar *title_font;
+  gint font_size;
+  gchar *desc_font;
+
+  g_return_if_fail (AAINA_IS_PHOTO (photo));
+  priv = AAINA_PHOTO_GET_PRIVATE (photo);
+
+  photo->priv = priv;
+
+  priv->pixbuf = NULL;
+  priv->title = priv->author = priv->date = NULL;
+  priv->visible = TRUE;
+
+  width = CLUTTER_STAGE_WIDTH ()/2;
+  height = CLUTTER_STAGE_HEIGHT ()/2;
+
+  /* The font */
+  font_size = height/12;
+  title_font = g_strdup_printf ("Coolvetica %d", font_size-4);
+  desc_font = g_strdup_printf ("Coolvetica %d", font_size-8); 
+
+  
+  priv->bg = clutter_rectangle_new_with_color (&white);
+  clutter_group_add (CLUTTER_GROUP (photo), priv->bg);
+  clutter_actor_show (priv->bg);
+    
+  priv->texture = clutter_texture_new ();
+  clutter_actor_set_size (priv->texture, width, height);
+  clutter_actor_set_position (priv->texture, 0, 0);
+  clutter_group_add (CLUTTER_GROUP (photo), priv->texture);
+
+  priv->dim = clutter_rectangle_new_with_color (&black);
+  clutter_group_add (CLUTTER_GROUP (photo), priv->dim);
+  clutter_actor_show (priv->dim);
+
+  clutter_actor_show (CLUTTER_ACTOR (photo));
+
+  /* Add the title and description actors */
+  priv->title_bg = clutter_rectangle_new_with_color (&black);
+  clutter_actor_set_opacity (priv->title_bg, 0);
+  clutter_group_add (CLUTTER_GROUP (photo), priv->title_bg);
+  clutter_actor_show (priv->title_bg);
+  clutter_actor_set_opacity (priv->title_bg, 0);
+  
+  priv->title_text = clutter_texture_label_new_with_text (title_font, 
+                                                          "Title");
+  clutter_texture_label_set_color (CLUTTER_TEXTURE_LABEL (priv->title_text),
+                                   &white);
+  clutter_actor_set_opacity (priv->title_text, 0);
+  /*
+  priv->title_text = clutter_label_new_full (title_font, " ", &title);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->title_text), FALSE);
+  */
+  clutter_group_add (CLUTTER_GROUP (photo), priv->title_text);
+
+  priv->desc_text = clutter_texture_label_new_with_text (desc_font, 
+                                                          "Desc");
+  clutter_texture_label_set_color (CLUTTER_TEXTURE_LABEL (priv->desc_text),
+                                   &desc);
+  clutter_actor_set_opacity (priv->desc_text, 0);
+  /*
+  priv->desc_text = clutter_label_new_full (desc_font, " ", &desc);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->desc_text), FALSE);
+  clutter_label_set_alignment (CLUTTER_LABEL (priv->desc_text),
+                               PANGO_ALIGN_CENTER);
+  */
+  clutter_group_add (CLUTTER_GROUP (photo), priv->desc_text);
+  priv->zoom_time = clutter_timeline_new (60, 30);
+  alpha = clutter_alpha_new_full (priv->zoom_time,
+                                  alpha_sine_inc_func,
+                                  NULL, NULL);
+  behave = aaina_behave_new (alpha, 
+                             (AainaBehaveAlphaFunc)aaina_photo_alpha_zoom,
+                             (gpointer)photo);
+
+  priv->restore_time = clutter_timeline_new (120, 30);
+  alpha = clutter_alpha_new_full (priv->restore_time,
+                                  alpha_sine_inc_func,
+                                  NULL, NULL);
+  behave = aaina_behave_new (alpha, 
+                             (AainaBehaveAlphaFunc)aaina_photo_alpha_restore,
+                             (gpointer)photo);
+}
+
+ClutterActor*
+aaina_photo_new (void)
+{
+  AainaPhoto         *photo;
+
+  photo = g_object_new (AAINA_TYPE_PHOTO, NULL);
+  
+  return CLUTTER_ACTOR (photo);
+}
+
diff --git a/attic/aaina/libaaina/aaina-photo.h b/attic/aaina/libaaina/aaina-photo.h
new file mode 100644 (file)
index 0000000..ec3d7db
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_AAINA_PHOTO_H
+#define _HAVE_AAINA_PHOTO_H
+
+G_BEGIN_DECLS
+
+#define AAINA_TYPE_PHOTO aaina_photo_get_type()
+
+#define AAINA_PHOTO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       AAINA_TYPE_PHOTO, \
+       AainaPhoto))
+
+#define AAINA_PHOTO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_PHOTO, \
+       AainaPhotoClass))
+
+#define AAINA_IS_PHOTO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       AAINA_TYPE_PHOTO))
+
+#define AAINA_IS_PHOTO_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       AAINA_TYPE_PHOTO))
+
+#define AAINA_PHOTO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_PHOTO, \
+       AainaPhotoClass))
+
+typedef struct _AainaPhoto AainaPhoto;
+typedef struct _AainaPhotoClass AainaPhotoClass;
+typedef struct _AainaPhotoPrivate AainaPhotoPrivate;
+
+struct _AainaPhoto
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       AainaPhotoPrivate   *priv;
+};
+
+struct _AainaPhotoClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+  void (*photo_zoomed)   (AainaPhoto *photo);
+  void (*photo_restored) (AainaPhoto *photo);
+
+  void (*_aaina_photo_1) (void);
+  void (*_aaina_photo_2) (void);
+  void (*_aaina_photo_3) (void);
+  void (*_aaina_photo_4) (void);
+}; 
+
+GType aaina_photo_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+aaina_photo_new (void);
+
+void
+aaina_photo_set_pixbuf (AainaPhoto *photo, GdkPixbuf *pixbuf);
+
+void
+aaina_photo_save (AainaPhoto *photo);
+void
+aaina_photo_restore (AainaPhoto *photo);
+
+gdouble
+aaina_photo_get_scale (AainaPhoto *photo);
+void
+aaina_photo_set_scale (AainaPhoto *photo, gdouble scale);
+
+gboolean
+aaina_photo_get_viewed (AainaPhoto *photo);
+void
+aaina_photo_set_viewed (AainaPhoto *photo, gboolean viewed);
+
+void
+aaina_photo_zoom (AainaPhoto *photo);
+
+void
+aaina_photo_set_visible (AainaPhoto *photo, gboolean visible);
+
+guint8
+aaina_photo_get_dim (AainaPhoto *photo);
+void
+aaina_photo_set_dim (AainaPhoto *photo, guint8 dim_level);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/libaaina/aaina-source.c b/attic/aaina/libaaina/aaina-source.c
new file mode 100644 (file)
index 0000000..e51f340
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "aaina-source.h"
+
+G_DEFINE_ABSTRACT_TYPE (AainaSource, aaina_source, G_TYPE_OBJECT);
+       
+/* GObject stuff */
+static void
+aaina_source_class_init (AainaSourceClass *klass)
+{
+  ;
+}
+
+
+static void
+aaina_source_init (AainaSource *source)
+{
+  ;
+}
+
+AainaSource*
+aaina_source_new (AainaLibrary *library)
+{
+  AainaSource         *source;
+
+  source = g_object_new (AAINA_TYPE_SOURCE, NULL);
+  
+  return source;
+}
+
diff --git a/attic/aaina/libaaina/aaina-source.h b/attic/aaina/libaaina/aaina-source.h
new file mode 100644 (file)
index 0000000..707f4b3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+
+#include "aaina-library.h"
+
+#ifndef _HAVE_AAINA_SOURCE_H
+#define _HAVE_AAINA_SOURCE_H
+
+G_BEGIN_DECLS
+
+#define AAINA_TYPE_SOURCE aaina_source_get_type()
+
+#define AAINA_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       AAINA_TYPE_SOURCE, \
+       AainaSource))
+
+#define AAINA_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_SOURCE, \
+       AainaSourceClass))
+
+#define AAINA_IS_SOURCE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       AAINA_TYPE_SOURCE))
+
+#define AAINA_IS_SOURCE_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       AAINA_TYPE_SOURCE))
+
+#define AAINA_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_SOURCE, \
+       AainaSourceClass))
+
+typedef struct _AainaSource AainaSource;
+typedef struct _AainaSourceClass AainaSourceClass;
+
+struct _AainaSource
+{
+       GObject         parent;
+};
+
+struct _AainaSourceClass 
+{
+       
+       GObjectClass parent_class;
+
+  void (*_aaina_source_1) (void);
+  void (*_aaina_source_2) (void);
+  void (*_aaina_source_3) (void);
+  void (*_aaina_source_4) (void);
+}; 
+
+GType aaina_source_get_type (void) G_GNUC_CONST;
+
+AainaSource* 
+aaina_source_new (AainaLibrary *library);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/libaaina/clutter-texture-label.c b/attic/aaina/libaaina/clutter-texture-label.c
new file mode 100644 (file)
index 0000000..4c90101
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:clutter-label
+ * @short_description: Actor for displaying text
+ *
+ * #ClutterTextureLabel is a #ClutterTexture that displays text.
+ */
+
+#include "clutter-texture-label.h"
+
+#include <pango/pangoft2.h>
+
+#define DEFAULT_FONT_NAME      "Sans 10"
+
+G_DEFINE_TYPE (ClutterTextureLabel, clutter_texture_label, CLUTTER_TYPE_TEXTURE);
+
+enum
+{
+  PROP_0,
+  PROP_FONT_NAME,
+  PROP_TEXT,
+  PROP_COLOR
+};
+
+#define CLUTTER_TEXTURE_LABEL_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXTURE_LABEL, ClutterTextureLabelPrivate))
+
+struct _ClutterTextureLabelPrivate
+{
+  PangoLayout          *layout;
+  PangoContext         *context;
+  PangoFontDescription *desc;
+  
+  ClutterColor          fgcol;
+  
+  gchar                *text;
+  gchar                *font_name;
+  
+  gint                  extents_width;
+  gint                  extents_height;
+
+  gint                  detail;
+  gint                  detail_direction;
+  ClutterTimeline      *timeline;
+
+  gboolean              visible;
+};
+
+static void
+clutter_texture_label_make_pixbuf (ClutterTextureLabel *label)
+{
+  gint                 bx, by, w, h;
+  FT_Bitmap            ft_bitmap;
+  guint8 const         *ps;
+  guint8               *pd;
+  ClutterTextureLabelPrivate  *priv;
+  ClutterTexture       *texture;
+  GdkPixbuf            *pixbuf;
+  
+  priv  = label->priv;
+
+  texture = CLUTTER_TEXTURE(label);
+
+  if (priv->layout == NULL || priv->desc == NULL || priv->text == NULL)
+    {
+      //g_debug("*** FAIL: layout: %p , desc: %p, text %p ***",
+           //  priv->layout, priv->desc, priv->text);
+      return;
+    }
+
+  pango_layout_set_font_description (priv->layout, priv->desc);
+  pango_layout_set_text (priv->layout, priv->text, -1);
+
+  if (priv->extents_width != 0)
+    {
+      pango_layout_set_width (priv->layout, PANGO_SCALE * priv->extents_width);
+      pango_layout_set_wrap  (priv->layout, PANGO_WRAP_WORD);
+    }
+
+  pango_layout_get_pixel_size (priv->layout, 
+                              &w, 
+                              &h);
+
+  if (w == 0 || h == 0)
+    {
+      //g_debug("aborting w:%i , h:%i", w, h);
+      return;
+    }
+
+  ft_bitmap.rows         = h;
+  ft_bitmap.width        = w;
+  ft_bitmap.pitch        = (w+3) & ~3;
+  ft_bitmap.buffer       = g_malloc0 (ft_bitmap.rows * ft_bitmap.pitch);
+  ft_bitmap.num_grays    = 256;
+  ft_bitmap.pixel_mode   = ft_pixel_mode_grays;
+  ft_bitmap.palette_mode = 0;
+  ft_bitmap.palette      = NULL;
+
+  pango_ft2_render_layout (&ft_bitmap, priv->layout, 0, 0);
+
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
+                          TRUE, 
+                          8,
+                          ft_bitmap.width, 
+                          ft_bitmap.rows);
+
+  for (by = 0; by < ft_bitmap.rows; by++) 
+    {
+      guint8  alpha;
+      gint    i = 0;
+
+      pd = gdk_pixbuf_get_pixels (pixbuf)
+       + by * gdk_pixbuf_get_rowstride (pixbuf);
+      ps = ft_bitmap.buffer + by * ft_bitmap.pitch;
+
+      alpha = *ps;
+
+      for (bx = 0; bx < ft_bitmap.width; bx++) 
+       {
+         *pd++ = priv->fgcol.red;
+         *pd++ = priv->fgcol.green;
+         *pd++ = priv->fgcol.blue;
+         //*pd++ = *ps++;
+         *pd++ = alpha;
+         ps++;
+         if (++i >= priv->detail)
+           {
+             i = 0; alpha = *ps;
+           }
+       }
+    }
+
+  g_free (ft_bitmap.buffer);
+
+  /*
+  g_debug("Calling set_pixbuf with text : '%s' , pixb %ix%i"
+         " rendered with color %i,%i,%i,%i", 
+         priv->text, w, h, 
+         priv->fgcol.red,
+         priv->fgcol.green,
+         priv->fgcol.blue,
+         priv->fgcol.alpha);
+  */
+  clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (label),
+                                       gdk_pixbuf_get_pixels (pixbuf),
+                                       gdk_pixbuf_get_has_alpha (pixbuf),
+                                       gdk_pixbuf_get_width (pixbuf),
+                                       gdk_pixbuf_get_height (pixbuf),
+                                       gdk_pixbuf_get_rowstride (pixbuf),
+                                       4, 0,
+                                       NULL);
+
+
+  g_object_set (G_OBJECT (label), "sync-size", TRUE, NULL);
+  
+  /* Texture has the ref now */
+  g_object_unref (pixbuf); 
+}
+
+static void
+timeline_cb (ClutterTimeline     *timeline, 
+            gint                 frame_num, 
+            ClutterTextureLabel *label)
+{
+  ClutterTextureLabelPrivate *priv;
+
+  priv = label->priv;
+
+  if (priv->detail_direction > 0)
+    priv->detail /= 2;
+  else
+    priv->detail *= 2;
+
+  clutter_texture_label_make_pixbuf (label);
+}
+
+static void
+timeline_completed (ClutterTimeline *timeline,
+                    ClutterActor    *label)
+{
+  ClutterTextureLabelPrivate *priv;
+  
+  g_return_if_fail (CLUTTER_IS_TEXTURE_LABEL (label));
+  priv = CLUTTER_TEXTURE_LABEL (label)->priv;
+
+  if (!priv->visible)
+  {
+    CLUTTER_ACTOR_CLASS (clutter_texture_label_parent_class)->hide (label);
+  }
+}
+
+static void
+clutter_texture_label_show (ClutterActor *actor)
+{
+  ClutterTextureLabel        *label;
+  ClutterTextureLabelPrivate *priv;
+
+  label = CLUTTER_TEXTURE_LABEL(actor);
+  priv = label->priv;
+
+  priv->detail = 512;
+  priv->detail_direction = 1;
+  priv->visible = TRUE;
+
+  clutter_timeline_start (priv->timeline);
+
+  CLUTTER_ACTOR_CLASS (clutter_texture_label_parent_class)->show (actor);
+}
+
+static void
+clutter_texture_label_hide (ClutterActor *actor)
+{
+  ClutterTextureLabel        *label;
+  ClutterTextureLabelPrivate *priv;
+
+  label = CLUTTER_TEXTURE_LABEL(actor);
+  priv = label->priv;
+
+  priv->detail = 1;
+  priv->detail_direction = -1;
+  priv->visible = FALSE;
+
+  clutter_timeline_rewind (priv->timeline);
+  clutter_timeline_start (priv->timeline);
+  
+  //CLUTTER_ACTOR_CLASS (clutter_texture_label_parent_class)->hide (actor);
+}
+
+static void
+clutter_texture_label_set_property (GObject      *object, 
+                                   guint         prop_id,
+                                   const GValue *value, 
+                                   GParamSpec   *pspec)
+{
+  ClutterTextureLabel        *label;
+  ClutterTextureLabelPrivate *priv;
+
+  label = CLUTTER_TEXTURE_LABEL(object);
+  priv = label->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_FONT_NAME:
+      clutter_texture_label_set_font_name (label, g_value_get_string (value));
+      break;
+    case PROP_TEXT:
+      clutter_texture_label_set_text (label, g_value_get_string (value));
+      break;
+    case PROP_COLOR:
+      clutter_texture_label_set_color (label, g_value_get_boxed (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+clutter_texture_label_get_property (GObject    *object, 
+                           guint       prop_id,
+                           GValue     *value, 
+                           GParamSpec *pspec)
+{
+  ClutterTextureLabel        *label;
+  ClutterTextureLabelPrivate *priv;
+  ClutterColor         color;
+
+  label = CLUTTER_TEXTURE_LABEL(object);
+  priv = label->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_FONT_NAME:
+      g_value_set_string (value, priv->font_name);
+      break;
+    case PROP_TEXT:
+      g_value_set_string (value, priv->text);
+      break;
+    case PROP_COLOR:
+      clutter_texture_label_get_color (label, &color);
+      g_value_set_boxed (value, &color);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    } 
+}
+
+
+static void 
+clutter_texture_label_dispose (GObject *object)
+{
+  ClutterTextureLabel         *self = CLUTTER_TEXTURE_LABEL(object);
+  ClutterTextureLabelPrivate  *priv;  
+
+  priv = self->priv;
+  
+  if (priv->layout)
+    {
+      g_object_unref (priv->layout);
+      priv->layout = NULL;
+    }
+  
+  if (priv->desc)
+    {
+      pango_font_description_free (priv->desc);    
+      priv->desc = NULL;
+    }
+
+  g_free (priv->text);
+  priv->text = NULL;
+
+  g_free (priv->font_name);
+  priv->font_name = NULL;
+      
+  if (priv->context)
+    {
+      g_object_unref (priv->context);
+      priv->context = NULL;
+    }
+
+  G_OBJECT_CLASS (clutter_texture_label_parent_class)->dispose (object);
+}
+
+static void 
+clutter_texture_label_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (clutter_texture_label_parent_class)->finalize (object);
+}
+
+static void
+clutter_texture_label_class_init (ClutterTextureLabelClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  ClutterActorClass   *parent_class = CLUTTER_ACTOR_CLASS (clutter_texture_label_parent_class);
+
+  actor_class->paint      = parent_class->paint;
+  actor_class->realize    = parent_class->realize;
+  actor_class->unrealize  = parent_class->unrealize;
+
+  actor_class->show       = clutter_texture_label_show;
+  actor_class->hide       = clutter_texture_label_hide;
+
+  gobject_class->finalize   = clutter_texture_label_finalize;
+  gobject_class->dispose    = clutter_texture_label_dispose;
+  gobject_class->set_property = clutter_texture_label_set_property;
+  gobject_class->get_property = clutter_texture_label_get_property;
+
+  g_object_class_install_property
+    (gobject_class, PROP_FONT_NAME,
+     g_param_spec_string ("font-name",
+                         "Font Name",
+                         "Pango font description",
+                         NULL,
+                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (gobject_class, PROP_TEXT,
+     g_param_spec_string ("text",
+                         "Text",
+                         "Text to render",
+                         NULL,
+                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (gobject_class, PROP_COLOR,
+     g_param_spec_boxed ("color",
+                        "Font Colour",
+                        "Font Colour",
+                        CLUTTER_TYPE_COLOR,
+                        G_PARAM_READWRITE));
+
+  g_type_class_add_private (gobject_class, sizeof (ClutterTextureLabelPrivate));
+}
+
+static void
+clutter_texture_label_init (ClutterTextureLabel *self)
+{
+  ClutterTextureLabelPrivate *priv;
+  PangoFT2FontMap     *font_map;
+
+  self->priv = priv = CLUTTER_TEXTURE_LABEL_GET_PRIVATE (self);
+
+  priv->fgcol.red   = 0;
+  priv->fgcol.green = 0;
+  priv->fgcol.blue  = 0;
+  priv->fgcol.alpha = 255;
+
+  priv->text = NULL;
+  priv->font_name = g_strdup (DEFAULT_FONT_NAME);
+  priv->desc = pango_font_description_from_string (priv->font_name);
+  
+  font_map = PANGO_FT2_FONT_MAP (pango_ft2_font_map_new ());
+  pango_ft2_font_map_set_resolution (font_map, 96.0, 96.0);
+  priv->context = pango_ft2_font_map_create_context (font_map);
+
+  priv->layout  = pango_layout_new (priv->context);
+
+  /* See http://bugzilla.gnome.org/show_bug.cgi?id=143542  ?? 
+  pango_ft2_font_map_substitute_changed (font_map);
+  g_object_unref (font_map);
+  */
+
+  priv->timeline = clutter_timeline_new (8, 20);
+
+  g_signal_connect (priv->timeline, 
+                   "new-frame", 
+                   G_CALLBACK (timeline_cb), 
+                   self);
+
+  g_signal_connect (priv->timeline,
+        "completed",
+        G_CALLBACK (timeline_completed),
+        self);
+
+#if 0
+  g_signal_connect (self,
+                   "show",
+                   G_CALLBACK (show_handler),
+                   NULL);
+
+  g_signal_connect (self,
+                   "hide",
+                   G_CALLBACK (hide_handler),
+                   NULL);
+#endif
+
+  priv->detail = 512;
+}
+
+/**
+ * clutter_texture_label_new_with_text:
+ * @font_name: the name (and size) of the font to be used
+ * @text: the text to be displayed
+ *
+ * Creates a new #ClutterTextureLabel displaying @text using @font_name.
+ *
+ * Return value: a #ClutterTextureLabel
+ */
+ClutterActor*
+clutter_texture_label_new_with_text (const gchar *font_name,
+                                    const gchar *text)
+{
+  ClutterActor *label;
+
+  label = clutter_texture_label_new ();
+  clutter_texture_label_set_font_name (CLUTTER_TEXTURE_LABEL(label), font_name);
+  clutter_texture_label_set_text (CLUTTER_TEXTURE_LABEL(label), text);
+
+  /*  FIXME: Why does calling like;
+   *  return g_object_new (CLUTTER_TYPE_TEXTURE_LABEL, 
+   *                  "font-name", font_name,
+   *                  "text", text,
+   *                  NULL);
+   *  mean text does not get rendered without color being set
+   *  ( seems to need extra clutter_texture_label_make_pixbuf() call )
+  */
+
+  return label;
+}
+
+/**
+ * clutter_texture_label_new:
+ *
+ * Creates a new, empty #ClutterTextureLabel.
+ *
+ * Returns: the newly created #ClutterTextureLabel
+ */
+ClutterActor *
+clutter_texture_label_new (void)
+{
+  return g_object_new (CLUTTER_TYPE_TEXTURE_LABEL, NULL);
+}
+
+/**
+ * clutter_texture_label_get_text:
+ * @label: a #ClutterTextureLabel
+ *
+ * Retrieves the text displayed by @label
+ *
+ * Return value: the text of the label.  The returned string is
+ *   owned by #ClutterTextureLabel and should not be modified or freed.
+ */
+G_CONST_RETURN gchar *
+clutter_texture_label_get_text (ClutterTextureLabel *label)
+{
+  g_return_val_if_fail (CLUTTER_IS_TEXTURE_LABEL (label), NULL);
+
+  return label->priv->text;
+}
+
+/**
+ * clutter_texture_label_set_text:
+ * @label: a #ClutterTextureLabel
+ * @text: the text to be displayed
+ *
+ * Sets @text as the text to be displayed by @label.
+ */
+void
+clutter_texture_label_set_text (ClutterTextureLabel *label,
+                       const gchar  *text)
+{
+  ClutterTextureLabelPrivate  *priv;  
+
+  g_return_if_fail (CLUTTER_IS_TEXTURE_LABEL (label));
+
+  priv = label->priv;
+  
+  g_free (priv->text);
+  priv->text = g_strdup (text);
+
+  clutter_texture_label_make_pixbuf (label);
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
+    clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
+
+  g_object_notify (G_OBJECT (label), "text");
+}
+
+/**
+ * clutter_texture_label_get_font_name:
+ * @label: a #ClutterTextureLabel
+ *
+ * Retrieves the font used by @label.
+ *
+ * Return value: a string containing the font name, in a format
+ *   understandable by pango_font_description_from_string().  The
+ *   string is owned by #ClutterTextureLabel and should not be modified
+ *   or freed.
+ */
+G_CONST_RETURN gchar *
+clutter_texture_label_get_font_name (ClutterTextureLabel *label)
+{
+  g_return_val_if_fail (CLUTTER_IS_TEXTURE_LABEL (label), NULL);
+  
+  return label->priv->font_name;
+}
+
+/**
+ * clutter_texture_label_set_font_name:
+ * @label: a #ClutterTextureLabel
+ * @font_name: a font name and size, or %NULL for the default font
+ *
+ * Sets @font_name as the font used by @label.
+ *
+ * @font_name must be a string containing the font name and its
+ * size, similarly to what you would feed to the
+ * pango_font_description_from_string() function.
+ */
+void
+clutter_texture_label_set_font_name (ClutterTextureLabel *label,
+                                    const gchar  *font_name)
+{
+  ClutterTextureLabelPrivate  *priv;  
+
+  g_return_if_fail (CLUTTER_IS_TEXTURE_LABEL (label));
+  
+  if (!font_name || font_name[0] == '\0')
+    font_name = DEFAULT_FONT_NAME;
+
+  priv = label->priv;
+
+  if (priv->desc)
+    pango_font_description_free (priv->desc);
+
+  g_free (priv->font_name);
+  priv->font_name = g_strdup (font_name);
+
+  priv->desc = pango_font_description_from_string (priv->font_name);
+  if (!priv->desc)
+    {
+      g_warning ("Attempting to create a PangoFontDescription for "
+                "font name `%s', but failed.",
+                priv->font_name);
+      return;
+    }
+
+  if (label->priv->text && label->priv->text[0] != '\0')
+    {
+      clutter_texture_label_make_pixbuf (label);
+
+      if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
+       clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
+    }
+  
+  g_object_notify (G_OBJECT (label), "font-name");
+}
+
+/**
+ * clutter_texture_label_set_text_extents:
+ * @label: a #ClutterTextureLabel
+ * @width: the width of the text
+ * @height: the height of the text
+ *
+ * Sets the maximum extents of the label's text.
+ */
+void
+clutter_texture_label_set_text_extents (ClutterTextureLabel *label, 
+                               gint          width,
+                               gint          height)
+{
+  /* FIXME: height extents is broken.... 
+  */
+
+  label->priv->extents_width = width;
+  label->priv->extents_height = height;
+
+  clutter_texture_label_make_pixbuf (label);
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
+    clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
+}
+
+/**
+ * clutter_texture_label_get_text_extents:
+ * @label: a #ClutterTextureLabel
+ * @width: return location for the width of the extents or %NULL
+ * @height: return location for the height of the extents or %NULL
+ *
+ * Gets the extents of the label.
+ */
+void
+clutter_texture_label_get_text_extents (ClutterTextureLabel *label,
+                                       gint         *width,
+                                       gint         *height)
+{
+  g_return_if_fail (CLUTTER_IS_TEXTURE_LABEL (label));
+
+  if (width)
+    *width = label->priv->extents_width;
+
+  if (height)
+    *height = label->priv->extents_height;
+}
+
+/**
+ * clutter_texture_label_set_color:
+ * @label: a #ClutterTextureLabel
+ * @color: a #ClutterColor
+ *
+ * Sets the color of @label.
+ */
+void
+clutter_texture_label_set_color (ClutterTextureLabel       *label,
+                                const ClutterColor        *color)
+{
+  ClutterActor *actor;
+  ClutterTextureLabelPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_TEXTURE_LABEL (label));
+  g_return_if_fail (color != NULL);
+
+  priv = label->priv;
+  priv->fgcol.red = color->red;
+  priv->fgcol.green = color->green;
+  priv->fgcol.blue = color->blue;
+  priv->fgcol.alpha = color->alpha;
+
+  clutter_texture_label_make_pixbuf (label);
+
+  actor = CLUTTER_ACTOR (label);
+  clutter_actor_set_opacity (actor, priv->fgcol.alpha);
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+    clutter_actor_queue_redraw (actor);
+
+  g_object_notify (G_OBJECT (label), "color");
+
+}
+
+/**
+ * clutter_texture_label_get_color:
+ * @label: a #ClutterTextureLabel
+ * @color: return location for a #ClutterColor
+ *
+ * Retrieves the color of @label.
+ */
+void
+clutter_texture_label_get_color (ClutterTextureLabel *label,
+                                ClutterColor        *color)
+{
+  ClutterTextureLabelPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_TEXTURE_LABEL (label));
+  g_return_if_fail (color != NULL);
+
+  priv = label->priv;
+
+  color->red = priv->fgcol.red;
+  color->green = priv->fgcol.green;
+  color->blue = priv->fgcol.blue;
+  color->alpha = priv->fgcol.alpha;
+}
diff --git a/attic/aaina/libaaina/clutter-texture-label.h b/attic/aaina/libaaina/clutter-texture-label.h
new file mode 100644 (file)
index 0000000..eada401
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_TEXTURE_LABEL_H
+#define _HAVE_CLUTTER_TEXTURE_LABEL_H
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_TEXTURE_LABEL clutter_texture_label_get_type()
+
+#define CLUTTER_TEXTURE_LABEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_TEXTURE_LABEL, ClutterTextureLabel))
+
+#define CLUTTER_TEXTURE_LABEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_TYPE_TEXTURE_LABEL, ClutterTextureLabelClass))
+
+#define CLUTTER_IS_TEXTURE_LABEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_TEXTURE_LABEL))
+
+#define CLUTTER_IS_TEXTURE_LABEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_TYPE_TEXTURE_LABEL))
+
+#define CLUTTER_TEXTURE_LABEL_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_TYPE_TEXTURE_LABEL, ClutterTextureLabelClass))
+
+typedef struct _ClutterTextureLabel ClutterTextureLabel;
+typedef struct _ClutterTextureLabelClass ClutterTextureLabelClass;
+typedef struct _ClutterTextureLabelPrivate ClutterTextureLabelPrivate;
+
+struct _ClutterTextureLabel
+{
+  ClutterTexture         parent;
+
+  /*< private >*/
+  ClutterTextureLabelPrivate   *priv;
+};
+
+struct _ClutterTextureLabelClass 
+{
+  /*< private >*/
+  ClutterTextureClass parent_class;
+
+  void (*_clutter_texture_label_1) (void);
+  void (*_clutter_texture_label_2) (void);
+  void (*_clutter_texture_label_3) (void);
+  void (*_clutter_texture_label_4) (void);
+}; 
+
+GType clutter_texture_label_get_type (void) G_GNUC_CONST;
+
+ClutterActor *      clutter_texture_label_new              (void);
+ClutterActor *      clutter_texture_label_new_with_text    (const gchar        *font_name,
+                                                           const gchar        *text);
+
+void                  clutter_texture_label_set_text         (ClutterTextureLabel       *label,
+                                                             const gchar        *text);
+G_CONST_RETURN gchar *clutter_texture_label_get_text         (ClutterTextureLabel       *label);
+void                  clutter_texture_label_set_font_name    (ClutterTextureLabel       *label,
+                                                             const gchar        *font_name);
+G_CONST_RETURN gchar *clutter_texture_label_get_font_name    (ClutterTextureLabel       *label);
+void                  clutter_texture_label_set_color        (ClutterTextureLabel       *label,
+                                                             const ClutterColor *color);
+void                  clutter_texture_label_get_color        (ClutterTextureLabel       *label,
+                                                             ClutterColor       *color);
+void                  clutter_texture_label_set_text_extents (ClutterTextureLabel       *label,
+                                                             gint                width,
+                                                             gint                height);
+void                  clutter_texture_label_get_text_extents (ClutterTextureLabel       *label,
+                                                             gint               *width,
+                                                             gint               *height);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/libaaina/eggsequence.c b/attic/aaina/libaaina/eggsequence.c
new file mode 100644 (file)
index 0000000..979a512
--- /dev/null
@@ -0,0 +1,1709 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#include "eggsequence.h"
+
+typedef struct _EggSequenceNode EggSequenceNode;
+
+struct _EggSequence
+{
+    EggSequenceNode *   end_node;
+    GDestroyNotify      data_destroy_notify;
+    gboolean            access_prohibited;
+};
+
+struct _EggSequenceNode
+{
+    gint n_nodes;
+    EggSequenceNode *parent;    
+    EggSequenceNode *left;
+    EggSequenceNode *right;
+    gpointer data;             /* For the end node, this field points
+                                * to the sequence
+                                */
+};
+
+static EggSequenceNode *node_new           (gpointer           data);
+static EggSequenceNode *node_get_first     (EggSequenceNode   *node);
+static EggSequenceNode *node_get_last      (EggSequenceNode   *node);
+static EggSequenceNode *node_get_prev      (EggSequenceNode   *node);
+static EggSequenceNode *node_get_next      (EggSequenceNode   *node);
+static gint             node_get_pos       (EggSequenceNode   *node);
+static EggSequenceNode *node_get_by_pos    (EggSequenceNode   *node,
+                                           gint               pos);
+static EggSequenceNode *node_find_closest  (EggSequenceNode   *haystack,
+                                           EggSequenceNode   *needle,
+                                           EggSequenceNode   *end,
+                                           EggSequenceIterCompareFunc cmp,
+                                           gpointer           user_data);
+static gint             node_get_length    (EggSequenceNode   *node);
+static void             node_free          (EggSequenceNode   *node,
+                                           EggSequence       *seq);
+static void             node_cut           (EggSequenceNode   *split);
+static void             node_insert_after  (EggSequenceNode   *node,
+                                           EggSequenceNode   *second);
+static void             node_insert_before (EggSequenceNode   *node,
+                                           EggSequenceNode   *new);
+static void             node_unlink        (EggSequenceNode   *node);
+static void             node_insert_sorted (EggSequenceNode   *node,
+                                           EggSequenceNode   *new,
+                                           EggSequenceNode   *end,
+                                           EggSequenceIterCompareFunc cmp_func,
+                                           gpointer           cmp_data);
+
+static EggSequence *
+get_sequence (EggSequenceNode *node)
+{
+    return (EggSequence *)node_get_last (node)->data;
+}
+
+static void
+check_seq_access (EggSequence *seq)
+{
+    if (G_UNLIKELY (seq->access_prohibited))
+    {
+       g_warning ("Accessing a sequence while it is "
+                  "being sorted or searched is not allowed");
+    }
+}
+
+static void
+check_iter_access (EggSequenceIter *iter)
+{
+    check_seq_access (get_sequence (iter));
+}
+
+static gboolean
+is_end (EggSequenceIter *iter)
+{
+    EggSequence *seq = get_sequence (iter);
+    
+    return seq->end_node == iter;
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * egg_sequence_new:
+ * @data_destroy: A #GDestroyNotify function, or %NULL
+ * 
+ * Creates a new EggSequence. The @data_destroy function will be called
+ * on all items when the sequence is destroyed and on items that are
+ * removed from the sequence.
+ * 
+ * Return value: A new #EggSequence
+ * 
+ * Since: 2.14
+ **/
+EggSequence *
+egg_sequence_new (GDestroyNotify data_destroy)
+{
+    EggSequence *seq = g_new (EggSequence, 1);
+    seq->data_destroy_notify = data_destroy;
+    
+    seq->end_node = node_new (seq);
+    
+    seq->access_prohibited = FALSE;
+    
+    return seq;
+}
+
+/**
+ * egg_sequence_free:
+ * @seq: a #EggSequence
+ * 
+ * Frees the memory allocated for @seq. If @seq has a destroy notify
+ * function associated with it, that function is called on all items in
+ * @seq.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_free (EggSequence *seq)
+{
+    g_return_if_fail (seq != NULL);
+    
+    check_seq_access (seq);
+    
+    node_free (seq->end_node, seq);
+    
+    g_free (seq);
+}
+
+/**
+ * egg_sequence_foreach_range:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * @func: a #GFunc
+ * @user_data: user data passed to @func
+ * 
+ * Calls @func for each item in the range (@begin, @end) passing
+ * @user_data to the function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_foreach_range (EggSequenceIter *begin,
+                           EggSequenceIter *end,
+                           GFunc            func,
+                           gpointer         user_data)
+{
+    EggSequence *seq;
+    EggSequenceIter *iter;
+    
+    g_return_if_fail (func != NULL);
+    g_return_if_fail (begin != NULL);
+    g_return_if_fail (end != NULL);
+    
+    seq = get_sequence (begin);
+    
+    seq->access_prohibited = TRUE;
+    
+    iter = begin;
+    while (iter != end)
+    {
+       EggSequenceIter *next = node_get_next (iter);
+       
+       func (iter->data, user_data);
+       
+       iter = next;
+    }
+    
+    seq->access_prohibited = FALSE;
+}
+
+/**
+ * egg_sequence_foreach:
+ * @seq: a #EggSequence
+ * @func: the function to call for each item in @seq
+ * @data: user data passed to @func
+ * 
+ * Calls @func for each item in the sequence passing @user_data
+ * to the function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_foreach (EggSequence *seq,
+                     GFunc        func,
+                     gpointer     data)
+{
+    EggSequenceIter *begin, *end;
+    
+    check_seq_access (seq);
+    
+    begin = egg_sequence_get_begin_iter (seq);
+    end   = egg_sequence_get_end_iter (seq);
+    
+    egg_sequence_foreach_range (begin, end, func, data);
+}
+
+/**
+ * egg_sequence_range_get_midpoint:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Finds an iterator somewhere in the range (@begin, @end). This
+ * iterator will be close to the middle of the range, but is not
+ * guaranteed to be <emphasize>exactly</emphasize> in the middle.
+ *
+ * The @begin and @end iterators must both point to the same sequence and
+ * @begin must come before or be equal to @end in the sequence.
+ * 
+ * Return value: A #EggSequenceIter which is close to the middle of
+ * the (@begin, @end) range.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_range_get_midpoint (EggSequenceIter *begin,
+                                EggSequenceIter *end)
+{
+    int begin_pos, end_pos, mid_pos;
+    
+    g_return_val_if_fail (begin != NULL, NULL);
+    g_return_val_if_fail (end != NULL, NULL);
+    g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL);
+
+    begin_pos = node_get_pos (begin);
+    end_pos = node_get_pos (end);
+
+    g_return_val_if_fail (end_pos >= begin_pos, NULL);
+    
+    mid_pos = begin_pos + (end_pos - begin_pos) / 2;
+
+    return node_get_by_pos (begin, mid_pos);
+}
+
+/**
+ * egg_sequence_iter_compare:
+ * @a: a #EggSequenceIter
+ * @b: a #EggSequenceIter
+ * 
+ * Returns a negative number if @a comes before @b, 0 if they are equal,
+ * and a positive number if @a comes after @b.
+ *
+ * The @a and @b iterators must point into the same sequence.
+ * 
+ * Return value: A negative number if @a comes before @b, 0 if they are
+ * equal, and a positive number if @a comes after @b.
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_iter_compare (EggSequenceIter *a,
+                          EggSequenceIter *b)
+{
+    gint a_pos, b_pos;
+    
+    g_return_val_if_fail (a != NULL, 0);
+    g_return_val_if_fail (b != NULL, 0);
+    g_return_val_if_fail (get_sequence (a) == get_sequence (b), 0);
+    
+    check_iter_access (a);
+    check_iter_access (b);
+    
+    a_pos = node_get_pos (a);
+    b_pos = node_get_pos (b);
+    
+    if (a_pos == b_pos)
+       return 0;
+    else if (a_pos > b_pos)
+       return 1;
+    else
+       return -1;
+}
+
+/**
+ * egg_sequence_append:
+ * @seq: a #EggSequencePointer
+ * @data: the data for the new item
+ * 
+ * Adds a new item to the end of @seq.
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_append (EggSequence *seq,
+                    gpointer     data)
+{
+    EggSequenceNode *node;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    node = node_new (data);
+    node_insert_before (seq->end_node, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_prepend:
+ * @seq: a #EggSequence
+ * @data: the data for the new item
+ * 
+ * Adds a new item to the front of @seq
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_prepend (EggSequence *seq,
+                     gpointer     data)
+{
+    EggSequenceNode *node, *first;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    node = node_new (data);
+    first = node_get_first (seq->end_node);
+    
+    node_insert_before (first, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_insert_before:
+ * @iter: a #EggSequenceIter
+ * @data: the data for the new item
+ * 
+ * Inserts a new item just before the item pointed to by @iter.
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_before (EggSequenceIter *iter,
+                           gpointer         data)
+{
+    EggSequenceNode *node;
+    
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    check_iter_access (iter);
+    
+    node = node_new (data);
+    
+    node_insert_before (iter, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_remove:
+ * @iter: a #EggSequenceIter
+ * 
+ * Removes the item pointed to by @iter. It is an error to pass the
+ * end iterator to this function.
+ *
+ * If the sequnce has a data destroy function associated with it, this
+ * function is called on the data for the removed item.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_remove (EggSequenceIter *iter)
+{
+    EggSequence *seq;
+    
+    g_return_if_fail (iter != NULL);
+    g_return_if_fail (!is_end (iter));
+    
+    check_iter_access (iter);
+    
+    seq = get_sequence (iter); 
+    
+    node_unlink (iter);
+    node_free (iter, seq);
+}
+
+/**
+ * egg_sequence_remove_range:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Removes all items in the (@begin, @end) range.
+ *
+ * If the sequence has a data destroy function associated with it, this
+ * function is called on the data for the removed items.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_remove_range (EggSequenceIter *begin,
+                          EggSequenceIter *end)
+{
+    g_return_if_fail (get_sequence (begin) == get_sequence (end));
+
+    check_iter_access (begin);
+    check_iter_access (end);
+    
+    egg_sequence_move_range (NULL, begin, end);
+}
+
+/**
+ * egg_sequence_move_range:
+ * @dest: a #EggSequenceIter
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Inserts the (@begin, @end) range at the destination pointed to by ptr.
+ * The @begin and @end iters must point into the same sequence. It is
+ * allowed for @dest to point to a different sequence than the one pointed
+ * into by @begin and @end.
+ * 
+ * If @dest is NULL, the range indicated by @begin and @end is
+ * removed from the sequence. If @dest iter points to a place within
+ * the (@begin, @end) range, the range does not move.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_move_range (EggSequenceIter *dest,
+                        EggSequenceIter *begin,
+                        EggSequenceIter *end)
+{
+    EggSequence *src_seq;
+    EggSequenceNode *first;
+    
+    g_return_if_fail (begin != NULL);
+    g_return_if_fail (end != NULL);
+    
+    check_iter_access (begin);
+    check_iter_access (end);
+    if (dest)
+       check_iter_access (dest);
+    
+    src_seq = get_sequence (begin);
+    
+    g_return_if_fail (src_seq == get_sequence (end));
+
+    /* Dest points to begin or end? */
+    if (dest == begin || dest == end)
+       return;
+
+    /* begin comes after end? */
+    if (egg_sequence_iter_compare (begin, end) >= 0)
+       return;
+
+    /* dest points somewhere in the (begin, end) range? */
+    if (dest && get_sequence (dest) == src_seq &&
+       egg_sequence_iter_compare (dest, begin) > 0 &&
+       egg_sequence_iter_compare (dest, end) < 0)
+    {
+       return;
+    }
+    
+    src_seq = get_sequence (begin);
+
+    first = node_get_first (begin);
+
+    node_cut (begin);
+
+    node_cut (end);
+
+    if (first != begin)
+       node_insert_after (node_get_last (first), end);
+
+    if (dest)
+       node_insert_before (dest, begin);
+    else
+       node_free (begin, src_seq);
+}
+
+typedef struct
+{
+    GCompareDataFunc    cmp_func;
+    gpointer           cmp_data;
+    EggSequenceNode    *end_node;
+} SortInfo;
+
+/* This function compares two iters using a normal compare
+ * function and user_data passed in in a SortInfo struct
+ */
+static gint
+iter_compare (EggSequenceIter *node1,
+             EggSequenceIter *node2,
+             gpointer data)
+{
+    const SortInfo *info = data;
+    gint retval;
+    
+    if (node1 == info->end_node)
+       return 1;
+    
+    if (node2 == info->end_node)
+       return -1;
+    
+    retval = info->cmp_func (node1->data, node2->data, info->cmp_data);
+    
+    return retval;
+}
+
+/**
+ * egg_sequence_sort:
+ * @seq: a #EggSequence
+ * @cmp_func: the #GCompareDataFunc used to sort @seq. This function is
+ *       passed two items of @seq and should return 0 if they are equal,
+ *       a negative value fi the first comes before the second, and a
+ *       positive value if the second comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ * 
+ * Sorts @seq using @cmp_func.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort (EggSequence      *seq,
+                  GCompareDataFunc  cmp_func,
+                  gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, seq->end_node };
+    
+    check_seq_access (seq);
+    
+    egg_sequence_sort_iter (seq, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_insert_sorted:
+ * @seq: a #EggSequence
+ * @data: the data to insert
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ *
+ * Inserts @data into @queue using @func to determine the new position.
+ * @seq must already be sorted according to @cmp_func; otherwise the
+ * new position of is undefined.
+ *
+ * Return value: A #EggSequenceIter pointing to the new item.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_sorted (EggSequence       *seq,
+                           gpointer           data,
+                           GCompareDataFunc   cmp_func,
+                           gpointer           cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    g_return_val_if_fail (cmp_func != NULL, NULL);
+    
+    info.end_node = seq->end_node;
+    check_seq_access (seq);
+    
+    return egg_sequence_insert_sorted_iter (seq, data, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_sort_changed:
+ * @iter: A #EggSequenceIter
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ *
+ * Moves the data pointed to a new position as indicated by @cmp_func. This
+ * function should be called for items in a sequence already sorted according
+ * to @cmp_func whenever some aspect of an item changes so that @cmp_func
+ * may return different values for that item.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_changed (EggSequenceIter  *iter,
+                          GCompareDataFunc  cmp_func,
+                          gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_if_fail (!is_end (iter));
+    
+    info.end_node = get_sequence (iter)->end_node;
+    check_iter_access (iter);
+    
+    egg_sequence_sort_changed_iter (iter, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_search:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ * 
+ * Returns an iterator pointing to the position where @data would
+ * be inserted according to @cmp_func and @cmp_data.
+ * 
+ * Return value: An #EggSequenceIter pointing to the position where @data
+ * would have been inserted according to @cmp_func and @cmp_data.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_search (EggSequence      *seq,
+                    gpointer          data,
+                    GCompareDataFunc  cmp_func,
+                    gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    info.end_node = seq->end_node;
+    check_seq_access (seq);
+    
+    return egg_sequence_search_iter (seq, data, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_sort_iter:
+ * @seq: a #EggSequence
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_sort(), but uses a #EggSequenceIterCompareFunc instead
+ * of a GCompareDataFunc as the compare function
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_iter (EggSequence                *seq,
+                       EggSequenceIterCompareFunc  cmp_func,
+                       gpointer                    cmp_data)
+{
+    EggSequence *tmp;
+    EggSequenceNode *begin, *end;
+    
+    g_return_if_fail (seq != NULL);
+    g_return_if_fail (cmp_func != NULL);
+    
+    check_seq_access (seq);
+    
+    begin = egg_sequence_get_begin_iter (seq);
+    end   = egg_sequence_get_end_iter (seq);
+    
+    tmp = egg_sequence_new (NULL);
+    
+    egg_sequence_move_range (egg_sequence_get_begin_iter (tmp), begin, end);
+    
+    tmp->access_prohibited = TRUE;
+    seq->access_prohibited = TRUE;
+    
+    while (egg_sequence_get_length (tmp) > 0)
+    {
+       EggSequenceNode *node = egg_sequence_get_begin_iter (tmp);
+       
+       node_unlink (node);
+       
+       node_insert_sorted (seq->end_node, node, seq->end_node, cmp_func, cmp_data);
+    }
+    
+    tmp->access_prohibited = FALSE;
+    seq->access_prohibited = FALSE;
+    
+    egg_sequence_free (tmp);
+}
+
+/**
+ * egg_sequence_sort_changed_iter:
+ * @iter: a #EggSequenceIter
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_sort_changed(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_changed_iter (EggSequenceIter            *iter,
+                               EggSequenceIterCompareFunc  iter_cmp,
+                               gpointer                    cmp_data)
+{
+    EggSequence *seq;
+    EggSequenceIter *next, *prev;
+    
+    g_return_if_fail (!is_end (iter));
+    
+    check_iter_access (iter);
+
+    /* If one of the neighbours is equal to iter, then
+     * don't move it. This ensures that sort_changed() is
+     * a stable operation.
+     */
+
+    next = node_get_next (iter);
+    prev = node_get_prev (iter);
+
+    if (prev != iter && iter_cmp (prev, iter, cmp_data) == 0)
+       return;
+
+    if (!is_end (next) && iter_cmp (next, iter, cmp_data) == 0)
+       return;
+    
+    seq = get_sequence (iter);
+    
+    seq->access_prohibited = TRUE;
+    
+    node_unlink (iter);
+    node_insert_sorted (seq->end_node, iter, seq->end_node, iter_cmp, cmp_data);
+    
+    seq->access_prohibited = FALSE;
+}
+
+/**
+ * egg_sequence_insert_sorted_iter:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ * 
+ * Like egg_sequence_insert_sorted(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Return value: A #EggSequenceIter pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_sorted_iter   (EggSequence                *seq,
+                                  gpointer                    data,
+                                  EggSequenceIterCompareFunc  iter_cmp,
+                                  gpointer                    cmp_data)
+{
+    EggSequenceNode *new_node;
+    EggSequence *tmp_seq;
+    
+    check_seq_access (seq);
+
+    /* Create a new temporary sequence and put the new node into
+     * that. The reason for this is that the user compare function
+     * will be called with the new node, and if it dereferences, 
+     * "is_end" will be called on it. But that will crash if the
+     * node is not actually in a sequence.
+     *
+     * node_insert_sorted() makes sure the node is unlinked before
+     * is is inserted.
+     *
+     * The reason we need the "iter" versions at all is that that
+     * is the only kind of compare functions GtkTreeView can use.
+     */
+    tmp_seq = egg_sequence_new (NULL);
+    new_node = egg_sequence_append (tmp_seq, data);
+
+    node_insert_sorted (seq->end_node, new_node,
+                       seq->end_node, iter_cmp, cmp_data);
+
+    egg_sequence_free (tmp_seq);
+    
+    return new_node;
+}
+
+/**
+ * egg_sequence_search_iter:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_search(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Return value: A #EggSequenceIter pointing to the position in @seq
+ * where @data would have been inserted according to @cmp_func and @cmp_data.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_search_iter (EggSequence                *seq,
+                         gpointer                    data,
+                         EggSequenceIterCompareFunc  cmp_func,
+                         gpointer                    cmp_data)
+{
+    EggSequenceNode *node;
+    EggSequenceNode *dummy;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    seq->access_prohibited = TRUE;
+
+    dummy = node_new (data);
+    
+    node = node_find_closest (seq->end_node, dummy,
+                             seq->end_node, cmp_func, cmp_data);
+
+    node_free (dummy, NULL);
+    
+    seq->access_prohibited = FALSE;
+    
+    return node;
+}
+
+/**
+ * egg_sequence_iter_get_sequence:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the #EggSequence that @iter points into.
+ * 
+ * Return value: The #EggSequence that @iter points into.
+ * 
+ * Since: 2.14
+ **/
+EggSequence *
+egg_sequence_iter_get_sequence (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return get_sequence (iter);
+}
+
+/**
+ * egg_sequence_get:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the data that @iter points to.
+ * 
+ * Return value: The data that @iter points to
+ * 
+ * Since: 2.14
+ **/
+gpointer
+egg_sequence_get (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    g_return_val_if_fail (!is_end (iter), NULL);
+    
+    return iter->data;
+}
+
+/**
+ * egg_sequence_set:
+ * @iter: a #EggSequenceIter
+ * @data: new data for the item
+ * 
+ * Changes the data for the item pointed to by @iter to be @data. If
+ * the sequence has a data destroy function associated with it, that
+ * function is called on the existing data that @iter pointed to.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_set (EggSequenceIter *iter,
+                 gpointer         data)
+{
+    EggSequence *seq;
+    
+    g_return_if_fail (iter != NULL);
+    g_return_if_fail (!is_end (iter));
+    
+    seq = get_sequence (iter);
+
+    /* If @data is identical to iter->data, it is destroyed
+     * here. This will work right in case of ref-counted objects. Also
+     * it is similar to what ghashtables do.
+     *
+     * For non-refcounted data it's a little less convenient, but
+     * code relying on self-setting not destroying would be
+     * pretty dubious anyway ...
+     */
+    
+    if (seq->data_destroy_notify)
+       seq->data_destroy_notify (iter->data);
+    
+    iter->data = data;
+}
+
+/**
+ * egg_sequence_get_length:
+ * @seq: a #EggSequence
+ * 
+ * Returns the length of @seq
+ * 
+ * Return value: The length of @seq
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_get_length (EggSequence *seq)
+{
+    return node_get_length (seq->end_node) - 1;
+}
+
+/**
+ * egg_sequence_get_end_iter:
+ * @seq: a #EggSequence 
+ * 
+ * Returns the end iterator for @seg
+ * 
+ * Return value: The end iterator for @seq
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_end_iter (EggSequence *seq)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    g_assert (is_end (seq->end_node));
+    
+    return seq->end_node;
+}
+
+/**
+ * egg_sequence_get_begin_iter:
+ * @seq: a #EggSequence
+ * 
+ * Returns the begin iterator for @seq.
+ * 
+ * Return value: The begin iterator for @seq.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_begin_iter (EggSequence *seq)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    return node_get_first (seq->end_node);
+}
+
+static int
+clamp_position (EggSequence *seq,
+               int          pos)
+{
+    gint len = egg_sequence_get_length (seq);
+    
+    if (pos > len || pos < 0)
+       pos = len;
+    
+    return pos;
+}
+
+/*
+ * if pos > number of items or -1, will return end pointer
+ */
+/**
+ * egg_sequence_get_iter_at_pos:
+ * @seq: a #EggSequence
+ * @pos: a position in @seq, or -1 for the end.
+ * 
+ * Returns the iterator as position @pos. If @pos is negative or larger
+ * than the number of items in @seq, the end iterator is returned.
+ * 
+ * Return value: The #EggSequenceIter at position @pos
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_iter_at_pos (EggSequence *seq,
+                             gint         pos)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    pos = clamp_position (seq, pos);
+    
+    return node_get_by_pos (seq->end_node, pos);
+}
+
+/**
+ * egg_sequence_move:
+ * @src: a #EggSequenceIter pointing to the item to move
+ * @dest: a #EggSequenceIter pointing to the position to which
+ *        the item is moved.
+ *
+ * Move the item pointed to by @src to the position indicated by @dest.
+ * After calling this function @dest will point to the position immediately
+ * after @src.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_move (EggSequenceIter *src,
+                  EggSequenceIter *dest)
+{
+    g_return_if_fail (src != NULL);
+    g_return_if_fail (dest != NULL);
+    g_return_if_fail (!is_end (src));
+    
+    if (src == dest)
+       return;
+    
+    node_unlink (src);
+    node_insert_before (dest, src);
+}
+
+/* EggSequenceIter */
+
+/**
+ * egg_sequence_iter_is_end:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns whether @iter is the end iterator
+ * 
+ * Return value: Whether @iter is the end iterator.
+ * 
+ * Since: 2.14
+ **/
+gboolean
+egg_sequence_iter_is_end (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, FALSE);
+    
+    return is_end (iter);
+}
+
+/**
+ * egg_sequence_iter_is_begin:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns whether @iter is the begin iterator
+ * 
+ * Return value: Whether @iter is the begin iterator
+ * 
+ * Since: 2.14
+ **/
+gboolean
+egg_sequence_iter_is_begin (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, FALSE);
+    
+    return (node_get_prev (iter) == iter);
+}
+
+/**
+ * egg_sequence_iter_get_position:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the position of @iter
+ * 
+ * Return value: The position of @iter
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_iter_get_position (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, -1);
+    
+    return node_get_pos (iter);
+}
+
+/**
+ * egg_sequence_iter_next:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns an iterator pointing to the next position after @iter. If
+ * @iter is the end iterator, the end iterator is returned.
+ * 
+ * Return value: A #EggSequenceIter pointing to the next position after @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_next (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return node_get_next (iter);
+}
+
+/**
+ * egg_sequence_iter_prev:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns an iterator pointing to the previous position before @iter. If
+ * @iter is the begin iterator, the begin iterator is returned.
+ * 
+ * Return value: A #EggSequenceIter pointing to the previous position before
+ * @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_prev (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return node_get_prev (iter);
+}
+
+/**
+ * egg_sequence_iter_move:
+ * @iter: a #EggSequenceIter
+ * @delta: A positive or negative number indicating how many positions away
+ *    from @iter the returned #EggSequenceIter will be.
+ *
+ * Returns the #EggSequenceIter which is @delta positions away from @iter.
+ * If @iter is closer than -@delta positions to the beginning of the sequence,
+ * the begin iterator is returned. If @iter is closer than @delta positions
+ * to the end of the queue, the end iterator is returned.
+ *
+ * Return value: a #EggSequenceIter which is @delta positions away from @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_move (EggSequenceIter *iter,
+                       gint             delta)
+{
+    gint new_pos;
+    
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    new_pos = node_get_pos (iter) + delta;
+    
+    new_pos = clamp_position (get_sequence (iter), new_pos);
+    
+    return node_get_by_pos (iter, new_pos);
+}
+
+/**
+ * egg_sequence_swap:
+ * @a: a #EggSequenceIter
+ * @b: a #EggSequenceIter
+ * 
+ * Swaps the items pointed to by @a and @b
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_swap (EggSequenceIter *a,
+                  EggSequenceIter *b)
+{
+    EggSequenceNode *leftmost, *rightmost, *rightmost_next;
+    int a_pos, b_pos;
+    
+    g_return_if_fail (!egg_sequence_iter_is_end (a));
+    g_return_if_fail (!egg_sequence_iter_is_end (b));
+    
+    if (a == b)
+       return;
+    
+    a_pos = egg_sequence_iter_get_position (a);
+    b_pos = egg_sequence_iter_get_position (b);
+    
+    if (a_pos > b_pos)
+    {
+       leftmost = b;
+       rightmost = a;
+    }
+    else
+    {
+       leftmost = a;
+       rightmost = b;
+    }
+    
+    rightmost_next = node_get_next (rightmost);
+    
+    /* Situation is now like this:
+     *
+     *     ..., leftmost, ......., rightmost, rightmost_next, ...
+     *
+     */
+    egg_sequence_move (rightmost, leftmost);
+    egg_sequence_move (leftmost, rightmost_next);
+}
+
+/*
+ * Implementation of the node_* methods
+ */
+static void
+node_update_fields (EggSequenceNode *node)
+{
+    g_assert (node != NULL);
+    
+    node->n_nodes = 1;
+    
+    if (node->left)
+       node->n_nodes += node->left->n_nodes;
+    
+    if (node->right)
+       node->n_nodes += node->right->n_nodes;
+}
+
+#define NODE_LEFT_CHILD(n)  (((n)->parent) && ((n)->parent->left) == (n))
+#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
+
+static void
+node_rotate (EggSequenceNode *node)
+{
+    EggSequenceNode *tmp, *old;
+    
+    g_assert (node->parent);
+    g_assert (node->parent != node);
+    
+    if (NODE_LEFT_CHILD (node))
+    {
+       /* rotate right */
+       tmp = node->right;
+       
+       node->right = node->parent;
+       node->parent = node->parent->parent;
+       if (node->parent)
+       {
+           if (node->parent->left == node->right)
+               node->parent->left = node;
+           else
+               node->parent->right = node;
+       }
+       
+       g_assert (node->right);
+       
+       node->right->parent = node;
+       node->right->left = tmp;
+       
+       if (node->right->left)
+           node->right->left->parent = node->right;
+       
+       old = node->right;
+    }
+    else
+    {
+       /* rotate left */
+       tmp = node->left;
+       
+       node->left = node->parent;
+       node->parent = node->parent->parent;
+       if (node->parent)
+       {
+           if (node->parent->right == node->left)
+               node->parent->right = node;
+           else
+               node->parent->left = node;
+       }
+       
+       g_assert (node->left);
+       
+       node->left->parent = node;
+       node->left->right = tmp;
+       
+       if (node->left->right)
+           node->left->right->parent = node->left;
+       
+       old = node->left;
+    }
+    
+    node_update_fields (old);
+    node_update_fields (node);
+}
+
+static EggSequenceNode *
+splay (EggSequenceNode *node)
+{
+    while (node->parent)
+    {
+       if (!node->parent->parent)
+       {
+           /* zig */
+           node_rotate (node);
+       }
+       else if ((NODE_LEFT_CHILD (node) && NODE_LEFT_CHILD (node->parent)) ||
+                (NODE_RIGHT_CHILD (node) && NODE_RIGHT_CHILD (node->parent)))
+       {
+           /* zig-zig */
+           node_rotate (node->parent);
+           node_rotate (node);
+       }
+       else
+       {
+           /* zig-zag */
+           node_rotate (node);
+           node_rotate (node);
+       }
+    }
+    
+    return node;
+}
+
+static EggSequenceNode *
+node_new (gpointer data)
+{
+    EggSequenceNode *node = g_slice_new0 (EggSequenceNode);
+
+    node->parent = NULL;
+    node->parent = NULL;
+    node->left = NULL;
+    node->right = NULL;
+    
+    node->data = data;
+    node->n_nodes = 1;
+    
+    return node;
+}
+
+static EggSequenceNode *
+find_min (EggSequenceNode *node)
+{
+    splay (node);
+    
+    while (node->left)
+       node = node->left;
+    
+    return node;
+}
+
+static EggSequenceNode *
+find_max (EggSequenceNode *node)
+{
+    splay (node);
+    
+    while (node->right)
+       node = node->right;
+    
+    return node;
+}
+
+static EggSequenceNode *
+node_get_first   (EggSequenceNode    *node)
+{
+    return splay (find_min (node));
+}
+
+static EggSequenceNode *
+node_get_last    (EggSequenceNode    *node)
+{
+    return splay (find_max (node));
+}
+
+static gint
+get_n_nodes (EggSequenceNode *node)
+{
+    if (node)
+       return node->n_nodes;
+    else
+       return 0;
+}
+
+static EggSequenceNode *
+node_get_by_pos  (EggSequenceNode *node,
+                 gint             pos)
+{
+    gint i;
+    
+    g_assert (node != NULL);
+    
+    splay (node);
+    
+    while ((i = get_n_nodes (node->left)) != pos)
+    {
+       if (i < pos)
+       {
+           node = node->right;
+           pos -= (i + 1);
+       }
+       else
+       {
+           node = node->left;
+           g_assert (node->parent != NULL);
+       }
+    }
+    
+    return splay (node);
+}
+
+static EggSequenceNode *
+node_get_prev  (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    if (node->left)
+    {
+       node = node->left;
+       while (node->right)
+           node = node->right;
+    }
+    
+    return splay (node);
+}
+
+static EggSequenceNode *
+node_get_next         (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    if (node->right)
+    {
+       node = node->right;
+       while (node->left)
+           node = node->left;
+    }
+    
+    return splay (node);
+}
+
+static gint
+node_get_pos (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    return get_n_nodes (node->left);
+}
+
+/* Return closest node _strictly_ bigger than @needle (does always exist because
+ * there is an end_node)
+ */
+static EggSequenceNode *
+node_find_closest (EggSequenceNode           *haystack,
+                  EggSequenceNode            *needle,
+                  EggSequenceNode            *end,
+                  EggSequenceIterCompareFunc  cmp_func,
+                  gpointer                    cmp_data)
+{
+    EggSequenceNode *best;
+    gint c;
+    
+    g_assert (haystack);
+    
+    haystack = splay (haystack);
+    
+    do
+    {
+       best = haystack;
+
+       /* cmp_func can't be called with the end node (it may be user-supplied) */
+       if (haystack == end)
+           c = 1;
+       else
+           c = cmp_func (haystack, needle, cmp_data);
+
+       /* In the following we don't break even if c == 0. Instaed we go on searching
+        * along the 'bigger' nodes, so that we find the last one that is equal
+        * to the needle.
+        */
+       if (c > 0)
+           haystack = haystack->left;
+       else
+           haystack = haystack->right;
+    }
+    while (haystack != NULL);
+    
+     /* If the best node is smaller or equal to the data, then move one step
+     * to the right to make sure the best one is strictly bigger than the data
+     */
+    if (best != end && c <= 0)
+       best = node_get_next (best);
+    
+    return best;
+}
+
+static void
+node_free (EggSequenceNode *node,
+          EggSequence     *seq)
+{
+    GQueue *stack = g_queue_new ();
+
+    splay (node);
+    
+    g_queue_push_head (stack, node);
+    
+    while (!g_queue_is_empty (stack))
+    {
+       node = g_queue_pop_head (stack);
+       
+       if (node)
+       {
+           g_queue_push_head (stack, node->right);
+           g_queue_push_head (stack, node->left);
+           
+           if (seq && seq->data_destroy_notify && node != seq->end_node)
+               seq->data_destroy_notify (node->data);
+           
+           g_slice_free (EggSequenceNode, node);
+       }
+    }
+    
+    g_queue_free (stack);
+}
+
+/* Splits into two trees, left and right. 
+ * @node will be part of the right tree
+ */
+
+static void
+node_cut (EggSequenceNode *node)
+{
+    splay (node);
+
+    g_assert (node->parent == NULL);
+    
+    if (node->left)
+       node->left->parent = NULL;
+    
+    node->left = NULL;
+    node_update_fields (node);
+}
+
+static void
+node_insert_before (EggSequenceNode *node,
+                   EggSequenceNode *new)
+{
+    g_assert (node != NULL);
+    g_assert (new != NULL);
+    
+    splay (node);
+    
+    new = splay (find_min (new));
+    g_assert (new->left == NULL);
+    
+    if (node->left)
+       node->left->parent = new;
+    
+    new->left = node->left;
+    new->parent = node;
+    
+    node->left = new;
+    
+    node_update_fields (new);
+    node_update_fields (node);
+}
+
+static void
+node_insert_after (EggSequenceNode *node,
+                  EggSequenceNode *new)
+{
+    g_assert (node != NULL);
+    g_assert (new != NULL);
+    
+    splay (node);
+    
+    new = splay (find_max (new));
+    g_assert (new->right == NULL);
+    g_assert (node->parent == NULL);
+    
+    if (node->right)
+       node->right->parent = new;
+    
+    new->right = node->right;
+    new->parent = node;
+    
+    node->right = new;
+    
+    node_update_fields (new);
+    node_update_fields (node);
+}
+
+static gint
+node_get_length (EggSequenceNode    *node)
+{
+    g_assert (node != NULL);
+    
+    splay (node);
+    return node->n_nodes;
+}
+
+static void
+node_unlink (EggSequenceNode *node)
+{
+    EggSequenceNode *right, *left;
+    
+    splay (node);
+    
+    left = node->left;
+    right = node->right;
+    
+    node->parent = node->left = node->right = NULL;
+    node_update_fields (node);
+    
+    if (right)
+    {
+       right->parent = NULL;
+       
+       right = node_get_first (right);
+       g_assert (right->left == NULL);
+       
+       right->left = left;
+       if (left)
+       {
+           left->parent = right;
+           node_update_fields (right);
+       }
+    }
+    else if (left)
+    {
+       left->parent = NULL;
+    }
+}
+
+static void
+node_insert_sorted (EggSequenceNode *node,
+                   EggSequenceNode *new,
+                   EggSequenceNode *end,
+                   EggSequenceIterCompareFunc cmp_func,
+                   gpointer cmp_data)
+{
+    EggSequenceNode *closest;
+    
+    closest = node_find_closest (node, new, end, cmp_func, cmp_data);
+
+    node_unlink (new);
+    
+    node_insert_before (closest, new);
+}
+
+static gint
+node_calc_height (EggSequenceNode *node)
+{
+    gint left_height;
+    gint right_height;
+    
+    if (node)
+    {
+       left_height = 0;
+       right_height = 0;
+       
+       if (node->left)
+           left_height = node_calc_height (node->left);
+       
+       if (node->right)
+           right_height = node_calc_height (node->right);
+       
+       return MAX (left_height, right_height) + 1;
+    }
+    
+    return 0;
+}
+
+/* Self test functions */
+
+static void
+check_node (EggSequenceNode *node)
+{
+    if (node)
+    {
+       g_assert (node->parent != node);
+       g_assert (node->n_nodes ==
+                 1 + get_n_nodes (node->left) + get_n_nodes (node->right));
+       check_node (node->left);
+       check_node (node->right);
+    }
+}
+
+void
+egg_sequence_self_test (EggSequence *seq)
+{
+    EggSequenceNode *node = splay (seq->end_node);
+    
+    check_node (node);
+}
diff --git a/attic/aaina/libaaina/eggsequence.h b/attic/aaina/libaaina/eggsequence.h
new file mode 100644 (file)
index 0000000..107db47
--- /dev/null
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __GSEQUENCE_H__
+#define __GSEQUENCE_H__
+
+typedef struct _EggSequence      EggSequence;
+typedef struct _EggSequenceNode  EggSequenceIter;
+
+
+
+typedef gint (* EggSequenceIterCompareFunc) (EggSequenceIter *a,
+                                            EggSequenceIter *b,
+                                            gpointer         data);
+
+/* EggSequence */
+EggSequence *   egg_sequence_new                  (GDestroyNotify          data_destroy);
+void            egg_sequence_free                 (EggSequence            *seq);
+gint            egg_sequence_get_length           (EggSequence            *seq);
+void           egg_sequence_foreach              (EggSequence            *seq,
+                                                  GFunc                   func,
+                                                  gpointer                data);
+void           egg_sequence_foreach_range        (EggSequenceIter        *begin,
+                                                  EggSequenceIter        *end,
+                                                  GFunc                   func,
+                                                  gpointer                data);
+void            egg_sequence_sort                 (EggSequence            *seq,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_iter            (EggSequence            *seq,
+                                                  EggSequenceIterCompareFunc      cmp_func,
+                                                  gpointer                cmp_data);
+
+/* Getting iters */
+EggSequenceIter *egg_sequence_get_begin_iter       (EggSequence            *seq);
+EggSequenceIter *egg_sequence_get_end_iter         (EggSequence            *seq);
+EggSequenceIter *egg_sequence_get_iter_at_pos      (EggSequence            *seq,
+                                                   gint                    pos);
+EggSequenceIter *egg_sequence_append               (EggSequence            *seq,
+                                                  gpointer                data);
+EggSequenceIter *egg_sequence_prepend              (EggSequence            *seq,
+                                                  gpointer                data);
+EggSequenceIter *egg_sequence_insert_before        (EggSequenceIter *        iter,
+                                                  gpointer                data);
+void            egg_sequence_move                (EggSequenceIter *       src,
+                                                  EggSequenceIter *       dest);
+void            egg_sequence_swap                (EggSequenceIter *       a,
+                                                  EggSequenceIter *       b);
+EggSequenceIter *egg_sequence_insert_sorted        (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+EggSequenceIter *egg_sequence_insert_sorted_iter   (EggSequence                  *seq,
+                                                  gpointer                data,
+                                                  EggSequenceIterCompareFunc      iter_cmp,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_changed         (EggSequenceIter *       iter,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_changed_iter    (EggSequenceIter *       iter,
+                                                  EggSequenceIterCompareFunc      iter_cmp,
+                                                  gpointer                cmp_data);
+
+void            egg_sequence_remove               (EggSequenceIter *        iter);
+void            egg_sequence_remove_range         (EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+void            egg_sequence_move_range           (EggSequenceIter *        iter,
+                                                  EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+EggSequenceIter *egg_sequence_search               (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+EggSequenceIter *egg_sequence_search_iter         (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  EggSequenceIterCompareFunc     cmp_func,
+                                                  gpointer                cmp_data);
+
+/* dereferencing */
+gpointer        egg_sequence_get                  (EggSequenceIter *        iter);
+void           egg_sequence_set                  (EggSequenceIter *       iter,
+                                                  gpointer                data);
+
+
+/* operations on EggSequenceIter * */
+gboolean        egg_sequence_iter_is_begin        (EggSequenceIter *        iter);
+gboolean        egg_sequence_iter_is_end          (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_next            (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_prev            (EggSequenceIter *        iter);
+gint            egg_sequence_iter_get_position    (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_move            (EggSequenceIter *        iter,
+                                                  gint                    leap);
+EggSequence *   egg_sequence_iter_get_sequence    (EggSequenceIter *        iter);
+
+
+/* search */
+gint            egg_sequence_iter_compare         (EggSequenceIter *a,
+                                                  EggSequenceIter *        b);
+EggSequenceIter *egg_sequence_range_get_midpoint   (EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+
+#endif /* __GSEQUENCE_H__ */
diff --git a/attic/aaina/libnflick/Makefile.am b/attic/aaina/libnflick/Makefile.am
new file mode 100644 (file)
index 0000000..344968d
--- /dev/null
@@ -0,0 +1,75 @@
+noinst_LTLIBRARIES = libnflick.la
+
+INCLUDES = \
+       $(DEPS_CFLAGS)
+       -I$(top_srcdir)                                 \
+       -I$(top_builddir)                               \
+       $(DEPS_CFLAGS)                                  \
+       -DDATADIR=\""$(datadir)"\"                      \
+       -DSYSCONFDIR=\""$(sysconfdir)"\"                \
+       -Wall                                                                                                   \
+       $(NULL) 
+
+libnflick_la_SOURCES = \
+       nflick.h                                \
+       nflick-api-request.c                    \
+       nflick-api-request.h                    \
+       nflick-api-request-private.h            \
+       nflick-api-response.c                   \
+       nflick-api-response.h                   \
+       nflick-api-response-private.h           \
+       nflick-auth-worker.c                    \
+       nflick-auth-worker.h                    \
+       nflick-auth-worker-private.h            \
+       nflick-flickr.h                         \
+       nflick-get-sizes-response.c             \
+       nflick-get-sizes-response.h             \
+       nflick-get-sizes-response-private.h     \
+       nflick-gft-response.c                   \
+       nflick-gft-response.h                   \
+       nflick-gft-response-private.h           \
+       nflick-info-response.c                  \
+       nflick-info-response.h                  \
+       nflick-info-response-private.h \
+       nflick-info-worker.c                    \
+       nflick-info-worker.h                    \
+       nflick-info-worker-private.h \
+       nflick-no-set-response.c                \
+       nflick-no-set-response.h                \
+       nflick-no-set-response-private.h        \
+       nflick-photo-data.c                     \
+       nflick-photo-data.h                     \
+       nflick-photo-list-response.c            \
+       nflick-photo-list-response.h            \
+       nflick-photo-list-response-private.h    \
+       nflick-photo-list-worker.c              \
+       nflick-photo-list-worker.h              \
+       nflick-photo-list-worker-private.h      \
+       nflick-photo-search-worker.h    \
+       nflick-photo-search-worker.c    \
+       nflick-photo-search-worker-private.h    \
+       nflick-photo-search-response.c  \
+       nflick-photo-search-response.h  \
+       nflick-photo-search-response-private.h  \
+       nflick-photo-set.c                      \
+       nflick-photo-set.h                      \
+       nflick-photo-set-private.h              \
+       nflick-pixbuf-fetch.c                   \
+       nflick-pixbuf-fetch.h                   \
+       nflick-pixbuf-fetch-private.h           \
+       nflick-set-list-response.c              \
+       nflick-set-list-response.h              \
+       nflick-set-list-response-private.h      \
+       nflick-set-list-worker.c                \
+       nflick-set-list-worker.h                \
+       nflick-set-list-worker-private.h        \
+       nflick-show-worker.c                    \
+       nflick-show-worker.h                    \
+       nflick-show-worker-private.h            \
+       nflick-types.h                          \
+       nflick-worker.c                         \
+       nflick-worker.h                         \
+       nflick-worker-private.h
+
+libnflick_la_LIBADD = $(DEPS_LIBS)
+libnflick_la_LDFLAGS = 
diff --git a/attic/aaina/libnflick/nflick-api-request-private.h b/attic/aaina/libnflick/nflick-api-request-private.h
new file mode 100644 (file)
index 0000000..99f84dd
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObjectClass*            ParentClass = NULL;
+
+struct                          _NFlickApiRequestPrivate
+{
+        GHashTable *Hash;
+        gchar *Buffer;
+        gint32 BytesRead;
+};
+
+static void                     nflick_api_request_class_init (NFlickApiRequestClass *klass);
+
+static void                     nflick_api_request_init (NFlickApiRequest *self);
+
+static gboolean                 private_init (NFlickApiRequest *self, NFlickApiRequestPrivate *private);
+
+static void                     private_dispose (NFlickApiRequestPrivate *private);
+
+static void                     nflick_api_request_dispose (NFlickApiRequest *self);
+
+static void                     nflick_api_request_finalize (NFlickApiRequest *self);
+
+static gchar*                   get_path (NFlickApiRequest *self);
+
+static void                     foreach_composer_list (gchar *param, gchar *val, GList **list);
+
+static void                     foreach_composer_str (gchar *val, gchar **str);
+
+static gchar*                   get_path_sig (NFlickApiRequest *self);
+
+static void                     foreach_composer_list_sig (gchar *param, gchar *val, GList **list);
+
+static void                     foreach_composer_str_sig (gchar *val, gchar **str);
+
+static int                      block_reader (NFlickApiRequest *self, gchar *buffer, int len);
+
diff --git a/attic/aaina/libnflick/nflick-api-request.c b/attic/aaina/libnflick/nflick-api-request.c
new file mode 100644 (file)
index 0000000..9986143
--- /dev/null
@@ -0,0 +1,396 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-api-request.h"
+#include "nflick-api-request-private.h"
+
+GType                           nflick_api_request_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickApiRequestClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_api_request_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickApiRequest), 
+                        4, 
+                        (GInstanceInitFunc) nflick_api_request_init,
+                };
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickApiRequest",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_api_request_class_init (NFlickApiRequestClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_api_request_dispose;
+        gobjectclass->finalize = (gpointer) nflick_api_request_finalize;
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+}
+
+static void                     nflick_api_request_init (NFlickApiRequest *self)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+
+        self->Private = NULL;
+
+        NFlickApiRequestPrivate *priv = g_new0 (NFlickApiRequestPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickApiRequest *self, NFlickApiRequestPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+        g_return_val_if_fail (private->Hash != NULL, FALSE);
+
+        private->Buffer = NULL;
+        private->BytesRead = 0;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickApiRequestPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Hash != NULL) {
+                g_hash_table_destroy (private->Hash);
+                private->Hash = NULL;
+        }
+
+        if (private->Buffer != NULL) {
+                g_free (private->Buffer);
+                private->Buffer = NULL;
+        }
+}
+
+static void                     nflick_api_request_dispose (NFlickApiRequest *self)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_api_request_finalize (NFlickApiRequest *self)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+NFlickApiRequest*               nflick_api_request_new (const gchar *method)
+{
+        g_return_val_if_fail (method != NULL, NULL);
+
+        NFlickApiRequest *self = g_object_new (NFLICK_TYPE_API_REQUEST, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        nflick_api_request_add_parameter (self, NFLICK_FLICKR_API_PARAM_METHOD, method);
+        nflick_api_request_add_parameter (self, NFLICK_FLICKR_API_PARAM_KEY, NFLICK_FLICKR_API_KEY);
+
+        return self;
+}
+
+void                            nflick_api_request_add_parameter (NFlickApiRequest *self, 
+                                                                  const gchar *param, const gchar *val)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+        g_return_if_fail (param != NULL);
+
+        g_hash_table_insert (self->Private->Hash, g_strdup (param), g_strdup (val));
+}
+
+static gchar*                   get_path (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), NULL);
+
+        GList *list = NULL;
+        gchar *str = NULL;
+        g_hash_table_foreach (self->Private->Hash, (GHFunc) foreach_composer_list, &list);
+        g_list_foreach (list, (GFunc) foreach_composer_str, &str);
+        g_list_foreach (list, (GFunc) g_free, NULL);
+
+        return str;
+}
+
+static gchar*                   get_path_sig (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), NULL);
+
+        GList *list = NULL;
+        gchar *str = g_strdup_printf ("%s", NFLICK_FLICKR_SHARED_SECRET);
+        g_hash_table_foreach (self->Private->Hash, (GHFunc) foreach_composer_list_sig, &list);
+        g_list_foreach (list, (GFunc) foreach_composer_str_sig, &str);
+        g_list_foreach (list, (GFunc) g_free, NULL);
+
+        return str;
+}
+
+static void                     foreach_composer_list (gchar *param, gchar *val, GList **list)
+{
+         /* Silently ignore empty vals */
+        if (param == NULL || list == NULL)
+                return;
+
+        gchar *str = g_strdup_printf ("%s=%s", param, val);
+        g_return_if_fail (str != NULL);
+
+        *list = g_list_insert_sorted (*list, str, (GCompareFunc) strcmp);
+}
+
+static void                     foreach_composer_str (gchar *val, gchar **str)
+{
+        /* Silently ignore empty vals */
+        if (val == NULL)
+                return;
+
+        gchar *old = *str;
+
+        if (*str != NULL) { 
+                *str = g_strdup_printf ("%s&%s", *str, val);
+                g_free (old);
+        } else
+                *str = g_strdup_printf ("%s", val);
+}
+
+static void                     foreach_composer_list_sig (gchar *param, gchar *val, GList **list)
+{
+         /* Silently ignore empty vals */
+        if (param == NULL || list == NULL)
+                return;
+
+        gchar *str = g_strdup_printf ("%s%s", param, val);
+        g_return_if_fail (str != NULL);
+
+        *list = g_list_insert_sorted (*list, str, (GCompareFunc) strcmp);
+}
+
+static void                     foreach_composer_str_sig (gchar *val, gchar **str)
+{
+        /* Silently ignore empty vals */
+        if (val == NULL)
+                return;
+
+        gchar *old = *str;
+
+        if (*str != NULL) { 
+                *str = g_strdup_printf ("%s%s", *str, val);
+                g_free (old);
+        } else
+                *str = g_strdup_printf ("%s", val);
+}
+
+gboolean                        nflick_api_request_sign (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), FALSE);
+
+        gchar *path_sig = NULL;
+        gpointer ctx = NULL;
+        gpointer ctx_output = NULL;
+        gchar *ascii = NULL;
+        gboolean res = TRUE;
+
+        path_sig = get_path_sig (self); 
+        if (path_sig == NULL)
+                goto Failure;
+
+        ctx = ne_md5_create_ctx ();
+        if (ctx == NULL)
+                goto Failure;
+
+        ne_md5_process_bytes (path_sig, strlen (path_sig), ctx);
+        ctx_output = g_malloc (16);
+        if (ctx_output == NULL)
+                goto Failure;
+
+        ne_md5_finish_ctx (ctx, ctx_output);
+        ascii = g_malloc (33);
+        if (ascii == NULL)
+                goto Failure;
+
+        ne_md5_to_ascii (ctx_output, ascii);
+        if (ascii [32] != 0)
+                goto Failure;
+
+        /* Now it's time to sign it... */
+        nflick_api_request_add_parameter (self, NFLICK_FLICKR_API_PARAM_SIGNATURE, ascii);
+
+        goto Finish;
+
+Failure:
+        res = FALSE;
+        g_warning ("Failure during md5 computation/signing");
+
+Finish:
+        if (path_sig != NULL)
+                g_free (path_sig);
+        if (ctx != NULL)
+                g_free (ctx);
+        if (ctx_output != NULL)
+                g_free (ctx_output);
+        if (ascii != NULL)
+                g_free (ascii);
+
+        return res;
+}
+
+static int                      block_reader (NFlickApiRequest *self, gchar *buffer, int len)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), -1);
+
+        if (self->Private->Buffer == NULL) {
+                self->Private->Buffer = g_malloc (len + 1);
+                memcpy (self->Private->Buffer, buffer, len);
+                self->Private->Buffer [len] = 0;
+                self->Private->BytesRead = 0;
+        } else {
+                gchar *old_ptr = self->Private->Buffer;
+                self->Private->Buffer = g_malloc (self->Private->BytesRead + len + 1);
+                memcpy (self->Private->Buffer, old_ptr, self->Private->BytesRead);
+                memcpy (self->Private->Buffer + self->Private->BytesRead, buffer, len);
+                self->Private->Buffer [len + self->Private->BytesRead] = 0;
+                
+                g_free (old_ptr);
+        }
+
+        self->Private->BytesRead += len;
+        return 0; 
+}
+
+gboolean                        nflick_api_request_exec (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), FALSE);
+
+        gchar *path_str = NULL;     /* The full path */
+        gchar *uri_str = NULL;      /* The actual uri to use */
+        ne_uri *uri = NULL;         /* Neon uri */
+        ne_request *request = NULL; /* Http request */
+        ne_session *session = NULL; /* Neon session */
+        gboolean result = TRUE;     /* result */
+
+        path_str = get_path (self);
+        if (path_str == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+        
+        uri_str = g_strdup_printf ("%s?%s", NFLICK_FLICKR_REST_END_POINT, path_str);
+        if (uri_str == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        uri = g_new0 (ne_uri, 1);
+        if (uri == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Fill-out the params */
+        uri->scheme = "http";
+        uri->port = ne_uri_defaultport (uri->scheme);  
+        uri->host = NFLICK_FLICKR_HOST;
+        uri->path = uri_str;
+
+        /* Create the session */
+        session = ne_session_create (uri->scheme, uri->host, uri->port);
+        if (session == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Create the request */
+        request = ne_request_create (session, "GET", uri->path);
+        if (request == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        ne_add_response_body_reader (request, ne_accept_always, (gpointer) block_reader, self);
+
+        result == (ne_request_dispatch (request) == NE_OK) ? TRUE : FALSE;
+        if (self->Private->Buffer == NULL)
+                result = FALSE;
+
+Done:
+        if (path_str != NULL)
+                g_free (path_str);
+
+        if (uri_str != NULL)
+                g_free (uri_str);
+
+        if (uri != NULL)
+                g_free (uri);
+
+        if (session != NULL)
+                ne_session_destroy (session);
+
+        if (request != NULL)
+                ne_request_destroy (request);
+
+        return result;
+}
+
+gchar*                          nflick_api_request_take_buffer (NFlickApiRequest *self)
+
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), NULL);
+
+        gchar *buf = self->Private->Buffer;
+        self->Private->Buffer = NULL;
+
+        return buf;
+}
diff --git a/attic/aaina/libnflick/nflick-api-request.h b/attic/aaina/libnflick/nflick-api-request.h
new file mode 100644 (file)
index 0000000..8853e46
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKAPIREQUEST_H__
+#define __NFLICKAPIREQUEST_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <ne_uri.h>
+#include <ne_session.h>
+#include <ne_basic.h>
+#include <ne_utils.h>
+#include <ne_md5.h>
+#include <string.h>
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickApiRequest
+{
+        GObject Parent;
+        NFlickApiRequestPrivate *Private;
+};
+
+struct                          _NFlickApiRequestClass 
+{
+        GObjectClass ParentClass;
+};
+
+GType                           nflick_api_request_get_type (void);
+
+NFlickApiRequest*               nflick_api_request_new (const gchar *method);
+
+void                            nflick_api_request_add_parameter (NFlickApiRequest *self, 
+                                                                  const gchar *param, const gchar *val);
+
+gboolean                        nflick_api_request_exec (NFlickApiRequest *self);
+
+gboolean                        nflick_api_request_sign (NFlickApiRequest *self);
+
+gchar*                          nflick_api_request_take_buffer (NFlickApiRequest *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-api-response-private.h b/attic/aaina/libnflick/nflick-api-response-private.h
new file mode 100644 (file)
index 0000000..38bb074
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObjectClass*            ParentClass = NULL;
+
+struct                          _NFlickApiResponsePrivate
+{
+        gchar *Xml;
+        gchar *Error;
+        gboolean Success;
+        gboolean ParseError;
+};
+
+enum
+{
+        ARG_0,
+        ARG_ERROR,
+        ARG_PARSE_ERROR, 
+        ARG_XML, 
+        ARG_SUCCESS
+};
+
+static void                     nflick_api_response_class_init (NFlickApiResponseClass *klass);
+
+static void                     nflick_api_response_init (NFlickApiResponse *self);
+
+static gboolean                 private_init (NFlickApiResponse *self, NFlickApiResponsePrivate *private);
+
+static void                     private_dispose (NFlickApiResponsePrivate *private);
+
+static void                     nflick_api_response_dispose (NFlickApiResponse *self);
+
+static void                     nflick_api_response_finalize (NFlickApiResponse *self);
+
+static void                     nflick_api_response_get_property (NFlickApiResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec);
+
+
diff --git a/attic/aaina/libnflick/nflick-api-response.c b/attic/aaina/libnflick/nflick-api-response.c
new file mode 100644 (file)
index 0000000..244cd81
--- /dev/null
@@ -0,0 +1,337 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-api-response.h"
+#include "nflick-api-response-private.h"
+
+GType                           nflick_api_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickApiResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_api_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickApiResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_api_response_init,
+                };
+                /* FIXME Make abstract type */
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickApiResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_api_response_class_init (NFlickApiResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_api_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_api_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_api_response_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_ERROR,
+                                         g_param_spec_string
+                                         ("error", "Error", "Message describing the error",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_SUCCESS,
+                                         g_param_spec_boolean 
+                                         ("success", "Success", "If the response is succesfull",
+                                         TRUE, G_PARAM_READABLE));
+        g_object_class_install_property (gobjectclass, ARG_PARSE_ERROR,
+                                         g_param_spec_boolean 
+                                         ("parseerror", "ParseError", "If the error was an xml parsing error",
+                                         FALSE, G_PARAM_READABLE));
+                                        
+        g_object_class_install_property (gobjectclass, ARG_XML,
+                                         g_param_spec_string
+                                         ("xml", "Xml", "Xml message source",
+                                         NULL, G_PARAM_READABLE));
+
+        klass->ParseFunc = NULL;
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+}
+
+static void                     nflick_api_response_init (NFlickApiResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+
+        self->Private = NULL;
+
+        NFlickApiResponsePrivate *priv = g_new0 (NFlickApiResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickApiResponse *self, NFlickApiResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_API_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Error = NULL;
+        private->Xml = NULL;
+        private->Success = TRUE;
+
+        return TRUE;
+}
+
+NFlickApiResponse*              nflick_api_response_new_from_request (GType type, NFlickApiRequest *request)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (request), NULL);
+
+        NFlickApiResponse *self = NULL;
+
+        gchar *buffer = nflick_api_request_take_buffer (request);
+        if (buffer == NULL)
+                goto Done;
+
+        self = g_object_new (type, NULL);
+        if (self == NULL)
+                goto Done;
+                
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                self = NULL;
+                goto Done;
+        }
+
+        nflick_api_response_parse (self, buffer);
+
+Done:
+        if (buffer != NULL)
+                g_free (buffer);
+
+        if (self != NULL)
+                return self;
+        else
+                g_return_val_if_reached (NULL);
+}
+
+static void                     private_dispose (NFlickApiResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Error != NULL) {
+                g_free (private->Error);
+                private->Error = NULL;
+        }
+
+        if (private->Xml != NULL) {
+                g_free (private->Xml);
+                private->Xml = NULL;
+        }
+}
+
+static void                     nflick_api_response_dispose (NFlickApiResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_api_response_finalize (NFlickApiResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+void                            nflick_api_response_set_error (NFlickApiResponse *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+        
+        if (self->Private->Error != NULL)
+                g_free (self->Private->Error);
+
+        self->Private->Error = (error != NULL) ? g_strdup (error) : NULL;
+}
+
+void                            nflick_api_response_add_error (NFlickApiResponse *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+
+        if (self->Private->Error == NULL)
+                nflick_api_response_set_error (self, error);
+        else if (error != NULL) {
+                gchar *sum = g_strdup_printf ("%s\n%s", self->Private->Error, error);
+                g_free (self->Private->Error);
+                self->Private->Error = sum;
+        } else
+                self->Private->Error = NULL;
+}
+
+gboolean                        nflick_api_response_parse (NFlickApiResponse *self, const gchar *xml)
+{
+        g_return_val_if_fail (NFLICK_IS_API_RESPONSE (self), FALSE);
+        g_return_val_if_fail (xml != NULL, FALSE);
+        g_return_val_if_fail (self->Private->Xml == NULL, FALSE);
+        g_return_val_if_fail (NFLICK_API_RESPONSE_GET_CLASS (self)->ParseFunc != NULL, FALSE);
+
+        self->Private->Xml = g_strdup (xml);
+
+        xmlDoc *doc = NULL;           /* The xml tree element */
+        xmlNode *root_element = NULL; /* Root element to start parsing */
+        gboolean result = TRUE;       /* If we were sucesfull */
+        gboolean parse_error = FALSE; /* If the error was a parsing error */
+        gchar *stat = NULL;           /* Response stat */
+        
+        /* Start here */
+        doc = xmlReadMemory (xml, strlen (xml), NULL, NULL, 0); 
+        if (doc == NULL) {
+                nflick_api_response_add_error (self, gettext ("Couldn't create the xml tree."));
+                result = FALSE;
+                parse_error = TRUE;
+                goto Done;
+        }
+
+        root_element = xmlDocGetRootElement(doc);
+        if (root_element == NULL) {
+                nflick_api_response_add_error (self, gettext ("Couldn't get xml root element."));
+                result = FALSE;
+                parse_error = TRUE;
+                goto Done;
+        }
+
+        if (root_element->type != XML_ELEMENT_NODE || 
+            strcmp (root_element->name, "rsp") != 0) {
+                nflick_api_response_add_error (self, gettext ("Rsp xml root expected, but was not found."));
+                parse_error = TRUE;
+                result = FALSE;
+                goto Done;
+        }
+
+        stat = xmlGetProp (root_element, "stat");
+        if (stat == NULL) {
+                nflick_api_response_add_error (self, gettext ("Response has not stat property."));
+                parse_error = TRUE;
+                result = FALSE;
+                goto Done;
+        }
+        
+        if (strcmp (stat, "ok") == 0) 
+                result = TRUE;
+        else if (strcmp (stat, "fail") == 0) 
+                result = FALSE;
+        else {
+                nflick_api_response_add_error (self, gettext ("Unknown response."));
+                parse_error = TRUE;
+                result = FALSE;
+                goto Done;
+        }
+
+        if (root_element->children == NULL)
+                goto Done;
+
+        xmlNode *cur_node = NULL;
+
+        /* Do the main parsing */
+        for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "err") == 0) {
+                        gchar *err = xmlGetProp (cur_node, "msg");
+                        result = FALSE;
+                        if (err != NULL) { 
+                                nflick_api_response_set_error (self, err);
+                                g_free (err);
+                        }
+                }
+        }
+
+        if (result == FALSE)
+                goto Done;
+
+        /* Forward to our parse func */
+        NFLICK_API_RESPONSE_GET_CLASS (self)->ParseFunc (self, doc, root_element->children, &result, &parse_error);
+
+Done:
+        /* Free */
+        if (doc != NULL) 
+                xmlFreeDoc (doc);
+
+        if (stat != NULL)
+                g_free (stat);
+
+        if (result == FALSE && self->Private->Error == NULL)
+                nflick_api_response_set_error (self, gettext ("Failed to parse xml tree. Unknown error"));
+
+        if (result == FALSE && parse_error == TRUE)
+                g_warning ("Failed to parse xml tree. Error: %s", self->Private->Error);
+        
+        self->Private->Success = result;
+        self->Private->ParseError = parse_error;
+        return result;
+}
+
+static void                     nflick_api_response_get_property (NFlickApiResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec)
+
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_ERROR:
+                        g_value_set_string (value, self->Private->Error);
+                break;
+        
+                case ARG_PARSE_ERROR:
+                        g_value_set_boolean (value, self->Private->ParseError);
+                break;
+                case ARG_SUCCESS:
+                        g_value_set_boolean (value, self->Private->Success);
+                break;
+       
+                case ARG_XML:
+                        g_value_set_string (value, self->Private->Xml);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-api-response.h b/attic/aaina/libnflick/nflick-api-response.h
new file mode 100644 (file)
index 0000000..9778872
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKAPIRESPONSE_H__
+#define __NFLICKAPIRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-api-request.h"
+
+struct                          _NFlickApiResponse
+{
+        GObject Parent;
+        NFlickApiResponsePrivate *Private;
+};
+
+struct                          _NFlickApiResponseClass 
+{
+        GObjectClass ParentClass;
+        NFlickApiRequestParseFunc ParseFunc;
+};
+
+GType                           nflick_api_response_get_type (void);
+
+void                            nflick_api_response_set_error (NFlickApiResponse *self, const gchar *error);
+
+void                            nflick_api_response_add_error (NFlickApiResponse *self, const gchar *error);
+
+gboolean                        nflick_api_response_parse (NFlickApiResponse *self, const gchar *xml);
+
+NFlickApiResponse*              nflick_api_response_new_from_request (GType type, NFlickApiRequest *request);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-auth-worker-private.h b/attic/aaina/libnflick/nflick-auth-worker-private.h
new file mode 100644 (file)
index 0000000..dfdbdac
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickAuthWorkerPrivate
+{
+        gchar *MiniToken;
+        gchar *UserName;
+        gchar *FullName;
+        gchar *Token;
+        gchar *UserNsid;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_USER_NAME,
+        ARG_FULL_NAME,
+        ARG_TOKEN,
+        ARG_USER_NSID
+};
+
+static void                     nflick_auth_worker_class_init (NFlickAuthWorkerClass *klass);
+
+static void                     nflick_auth_worker_init (NFlickAuthWorker *self);
+
+static gboolean                 private_init (NFlickAuthWorker *self, NFlickAuthWorkerPrivate *private);
+
+static void                     private_dispose (NFlickAuthWorkerPrivate *private);
+
+static void                     nflick_auth_worker_dispose (NFlickAuthWorker *self);
+
+static void                     nflick_auth_worker_finalize (NFlickAuthWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickAuthWorker *self);
+
+static void                     nflick_auth_worker_get_property (NFlickAuthWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-auth-worker.c b/attic/aaina/libnflick/nflick-auth-worker.c
new file mode 100644 (file)
index 0000000..c23d610
--- /dev/null
@@ -0,0 +1,278 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-auth-worker.h"
+#include "nflick-auth-worker-private.h"
+
+GType                           nflick_auth_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickAuthWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_auth_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickAuthWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_auth_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickAuthWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_auth_worker_class_init (NFlickAuthWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_auth_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_auth_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_auth_worker_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_TOKEN,
+                                         g_param_spec_string
+                                         ("token", "Token", "Unique flick full token",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NAME,
+                                         g_param_spec_string
+                                         ("username", "UserName", "Flickr user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_FULL_NAME,
+                                         g_param_spec_string
+                                         ("fullname", "FullName", "Flickr full user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NSID,
+                                         g_param_spec_string
+                                         ("usernsid", "UserNsid", "Unique nsid identyfying user in flickr",
+                                         NULL, G_PARAM_READABLE));
+
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_auth_worker_init (NFlickAuthWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickAuthWorkerPrivate *priv = g_new0 (NFlickAuthWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Authorizing token..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickAuthWorker *self, NFlickAuthWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_AUTH_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->MiniToken = NULL;
+        private->UserName = NULL;
+        private->FullName = NULL;
+        private->UserNsid = NULL;
+        private->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickAuthWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->MiniToken != NULL) {
+                g_free (private->MiniToken);
+                private->MiniToken = NULL;
+        }
+
+        if (private->UserName != NULL) {
+                g_free (private->UserName);
+                private->UserName = NULL;
+        }
+
+        if (private->FullName != NULL) {
+                g_free (private->FullName);
+                private->FullName = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->UserNsid != NULL) {
+                g_free (private->UserNsid);
+                private->UserNsid = NULL;
+        }
+}
+
+static void                     nflick_auth_worker_dispose (NFlickAuthWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_auth_worker_finalize (NFlickAuthWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickAuthWorker *self)
+{
+        NFlickApiRequest *full_token_request = NULL; 
+        NFlickApiResponse *full_token_response = NULL;
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+
+        full_token_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_GET_FULL_TOKEN);
+        if (full_token_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (full_token_request, 
+                                          NFLICK_FLICKR_API_PARAM_MINI_TOKEN, 
+                                          self->Private->MiniToken);
+
+        nflick_api_request_sign (full_token_request);
+        
+        if (nflick_api_request_exec (full_token_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        full_token_response = nflick_api_response_new_from_request (NFLICK_TYPE_GFT_RESPONSE, full_token_request);
+        if (full_token_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, full_token_response) == FALSE)
+                goto Error;
+
+        /* Get out variables */
+        g_object_get (G_OBJECT (full_token_response), 
+                      "username", &self->Private->UserName,
+                      "fullname", &self->Private->FullName,
+                      "usernsid", &self->Private->UserNsid,
+                      "token", &self->Private->Token, NULL);
+
+        if (self->Private->UserName == NULL ||
+            self->Private->FullName == NULL ||
+            self->Private->Token == NULL ||
+            self->Private->UserNsid == NULL)
+                goto Error;
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (full_token_request != NULL) 
+                g_object_unref (full_token_request);
+
+        if (full_token_response != NULL) 
+                g_object_unref (full_token_response);
+
+        return status;
+}
+
+NFlickAuthWorker*               nflick_auth_worker_new (const gchar *minitoken)
+{
+        g_return_val_if_fail (minitoken != NULL, NULL);
+
+        NFlickAuthWorker *self = g_object_new (NFLICK_TYPE_AUTH_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->MiniToken = g_strdup (minitoken);
+        
+        return self;
+}
+
+static void                     nflick_auth_worker_get_property (NFlickAuthWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_USER_NAME:
+                        g_value_set_string (value, self->Private->UserName);
+                break;
+        
+                case ARG_FULL_NAME:
+                        g_value_set_string (value, self->Private->FullName);
+                break;
+                case ARG_TOKEN:
+                        g_value_set_string (value, self->Private->Token);
+                break;
+       
+                case ARG_USER_NSID:
+                        g_value_set_string (value, self->Private->UserNsid);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-auth-worker.h b/attic/aaina/libnflick/nflick-auth-worker.h
new file mode 100644 (file)
index 0000000..807e4ec
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKAUTHWORKER_H__
+#define __NFLICKAUTHWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-gft-response.h"
+#include "nflick-types.h"
+
+struct                          _NFlickAuthWorker
+{
+        NFlickWorker Parent;
+        NFlickAuthWorkerPrivate *Private;
+};
+
+struct                          _NFlickAuthWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_auth_worker_get_type (void);
+
+NFlickAuthWorker*               nflick_auth_worker_new (const gchar *minitoken);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-flickr.h b/attic/aaina/libnflick/nflick-flickr.h
new file mode 100644 (file)
index 0000000..67d88d1
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKFLICKR_H__
+#define __NFLICKFLICKR_H__
+
+/* Some stock stuff obtained from flickr. That's public, really */
+
+#define                         NFLICK_FLICKR_API_KEY "97f40c6445ca8243d52fff461308fb18"
+
+#define                         NFLICK_FLICKR_SHARED_SECRET "2d434592f898e1ab"
+
+#define                         NFLICK_FLICKR_HOST "www.flickr.com"
+
+#define                         NFLICK_FLICKR_REST_END_POINT "/services/rest/"
+
+/* Request parameters */
+
+#define                         NFLICK_FLICKR_API_PARAM_KEY "api_key"
+
+#define                         NFLICK_FLICKR_API_PARAM_METHOD "method"
+
+#define                         NFLICK_FLICKR_API_PARAM_MINI_TOKEN "mini_token"
+
+#define                         NFLICK_FLICKR_API_PARAM_TOKEN "auth_token"
+
+#define                         NFLICK_FLICKR_API_PARAM_SIGNATURE "api_sig"
+
+#define                         NFLICK_FLICKR_API_PARAM_USER_ID "user_id"
+
+#define                         NFLICK_FLICKR_API_PARAM_PHOTOSET_ID "photoset_id"
+
+#define                         NFLICK_FLICKR_API_PARAM_PHOTO_ID "photo_id"
+
+#define                         NFLICK_FLICKR_API_PARAM_PER_PAGE "per_page"
+
+#define                        NFLICK_FLICKR_API_PARAM_TAGSS "tags"
+
+/* Possible methods */
+
+#define                         NFLICK_FLICKR_API_METHOD_GET_FULL_TOKEN "flickr.auth.getFullToken"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_LIST "flickr.photosets.getList"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_PHOTOS "flickr.photosets.getPhotos"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOS_GET_SIZES "flickr.photos.getSizes"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOS_NOT_IN_SET "flickr.photos.getNotInSet"
+
+#define NFLICK_FLICKR_API_METHOD_SEARCH_PHOTOS "flickr.photos.search"
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-get-sizes-response-private.h b/attic/aaina/libnflick/nflick-get-sizes-response-private.h
new file mode 100644 (file)
index 0000000..4853bd5
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickGetSizesResponsePrivate
+{
+        GList *SizesList;
+};
+
+struct                          _SizeData
+{
+        gchar *Uri;
+        gint32 Width;
+        gint32 Height;
+} typedef SizeData;
+
+static void                     nflick_get_sizes_response_class_init (NFlickGetSizesResponseClass *klass);
+
+static void                     nflick_get_sizes_response_init (NFlickGetSizesResponse *self);
+
+static gboolean                 private_init (NFlickGetSizesResponse *self, NFlickGetSizesResponsePrivate *private);
+
+static void                     private_dispose (NFlickGetSizesResponsePrivate *private);
+
+static void                     nflick_get_sizes_response_dispose (NFlickGetSizesResponse *self);
+
+static void                     nflick_get_sizes_response_finalize (NFlickGetSizesResponse *self);
+
+static void                     parse_func (NFlickGetSizesResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
diff --git a/attic/aaina/libnflick/nflick-get-sizes-response.c b/attic/aaina/libnflick/nflick-get-sizes-response.c
new file mode 100644 (file)
index 0000000..d7cf12a
--- /dev/null
@@ -0,0 +1,304 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-get-sizes-response.h"
+#include "nflick-get-sizes-response-private.h"
+
+GType                           nflick_get_sizes_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickGetSizesResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_get_sizes_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickGetSizesResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_get_sizes_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickGetSizesResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_get_sizes_response_class_init (NFlickGetSizesResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_get_sizes_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_get_sizes_response_finalize;
+
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_get_sizes_response_init (NFlickGetSizesResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickGetSizesResponsePrivate *priv = g_new0 (NFlickGetSizesResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickGetSizesResponse *self, NFlickGetSizesResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->SizesList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickGetSizesResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->SizesList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->SizesList; iterator; iterator = g_list_next (iterator)) {
+                        SizeData *data = (SizeData *) iterator->data;
+                        if (data != NULL) {
+                                if (data->Uri != NULL)
+                                        g_free (data->Uri);
+
+                                g_free (data);
+                        }
+                }
+
+                g_list_free (private->SizesList);
+                private->SizesList = NULL;
+        }
+}
+
+static void                     nflick_get_sizes_response_dispose (NFlickGetSizesResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_get_sizes_response_finalize (NFlickGetSizesResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickGetSizesResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "sizes") == 0) {
+
+                        xmlNode *sizes_node = NULL;
+                        for (sizes_node = cur_node->children; sizes_node; sizes_node = sizes_node->next) {
+                                
+                                if (sizes_node->type == XML_ELEMENT_NODE && strcmp (sizes_node->name, "size") == 0) {
+
+                                        gint32 width_val = -1;
+                                        gint32 height_val = -1;
+                                        gchar *width = xmlGetProp (sizes_node, "width");
+                                        gchar *height = xmlGetProp (sizes_node, "height");
+                                        gchar *source = xmlGetProp (sizes_node, "source");
+
+                                        if (width != NULL)
+                                                width_val = atoi (width);
+
+                                        if (height != NULL)
+                                                height_val = atoi (height);
+
+                                        if (width != NULL && height != NULL && source != NULL && 
+                                            width_val > 0 && height_val > 0) {
+                                                SizeData *data = g_new0 (SizeData, 1);
+                                                data->Uri = g_strdup (source);
+                                                data->Width = width_val;
+                                                data->Height = height_val;
+                                                self->Private->SizesList = g_list_append (self->Private->SizesList, data);
+                                        }
+
+                                        if (width != NULL)
+                                                g_free (width);
+                                        if (height != NULL)
+                                                g_free (height);
+                                        if (source != NULL)
+                                                g_free (source);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+/* FIXME: Make private */
+gint32                          nflick_get_sizes_response_height_for (gint32 width, gint32 height, gint32 fit_width)
+{
+        g_return_val_if_fail (width > 0, -1);
+        g_return_val_if_fail (height > 0, -1);
+        g_return_val_if_fail (fit_width > 0, -1);
+
+        gdouble aspect = (gdouble) height / (gdouble) width;
+        return aspect * (gdouble) fit_width;
+}
+
+/* FIXME: Make private */
+gint32                          nflick_get_sizes_response_width_for (gint32 width, gint32 height, gint32 fit_height)
+{
+        g_return_val_if_fail (width > 0, -1);
+        g_return_val_if_fail (height > 0, -1);
+        g_return_val_if_fail (fit_height > 0, -1);
+
+        gdouble aspect = (gdouble) width / (gdouble) height;
+        return aspect * (gdouble) fit_height;
+}
+
+gchar*                          nflick_get_sizes_response_find_match (NFlickGetSizesResponse *self, gint32 *width, gint32 *height, gboolean *rotated)
+{
+        g_return_val_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self), NULL);
+        g_return_val_if_fail (width != NULL, NULL);
+        g_return_val_if_fail (height != NULL, NULL);
+        g_return_val_if_fail (rotated != NULL, NULL);
+        g_return_val_if_fail (*width > 0, NULL);
+        g_return_val_if_fail (*height > 0, NULL);
+
+        GList *iterator;
+        gchar *current_source = NULL;
+        gint32 current_distance = 10000; /* FIXME: Max int */
+        gdouble out_aspect = (gdouble) *height / (gdouble) *width;
+        gint32 out_width = -1;
+        gint32 out_height = -1;
+        gboolean out_rotated = FALSE;
+        
+        for (iterator = self->Private->SizesList; iterator; iterator = g_list_next (iterator)) {
+                SizeData *data = (SizeData *) iterator->data;
+                g_assert (data != NULL);
+
+                gdouble in_aspect = (gdouble) data->Height / (gdouble) data->Width;
+
+                gint32 x_distance = 0;
+                gint32 y_distance = 0;
+                gint32 distance = 0;
+
+                // FIXME: We should analyze the input width and height here!
+                if (in_aspect > 1.0) {
+                        x_distance = abs (data->Width - *height);
+                        y_distance = abs (data->Height - *width);
+
+                        if (data->Width < *height)
+                                x_distance *= 2;
+                        if (data->Height < *width)
+                                y_distance *= 2;
+
+                        distance = x_distance + y_distance;
+
+                        if (distance < current_distance) {
+                                current_distance = distance;
+                                current_source = data->Uri;
+                                out_rotated = TRUE;
+
+                                /* Now let's try doing the fitting */
+                                in_aspect = (gdouble) data->Width / (gdouble) data->Height;
+                                if (in_aspect > out_aspect) {
+                                        out_width = *height;
+                                        out_height = nflick_get_sizes_response_height_for (data->Width, data->Height, out_width);
+                                } else {
+                                        out_height = *width;
+                                        out_width= nflick_get_sizes_response_width_for (data->Width, data->Height, out_height);
+                                }
+                        }
+                } else {
+                        x_distance = abs (data->Width - *width);
+                        y_distance = abs (data->Height - *height);
+
+                        if (data->Width < *width)
+                                x_distance *= 2;
+                        if (data->Height < *height)
+                                y_distance *= 2;
+
+                        distance = x_distance + y_distance;
+
+                        if (distance < current_distance) {
+                                current_distance = distance;
+                                current_source = data->Uri;
+                                out_rotated = FALSE;
+                                
+                                /* Now let's try doing the fitting */
+                                if (in_aspect > out_aspect) {
+                                        out_height = *height;
+                                        out_width = nflick_get_sizes_response_width_for (data->Width, data->Height, out_height);
+                                } else {
+                                        out_width = *width;
+                                        out_height = nflick_get_sizes_response_height_for (data->Width, data->Height, out_width);
+                                }
+                        }
+
+
+                }
+        }
+
+        *width = out_width;
+        *height = out_height;
+        *rotated = out_rotated;
+
+        if (current_source != NULL)
+                return g_strdup (current_source);
+        else
+                return NULL;
+}
diff --git a/attic/aaina/libnflick/nflick-get-sizes-response.h b/attic/aaina/libnflick/nflick-get-sizes-response.h
new file mode 100644 (file)
index 0000000..bf2a304
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKGETSIZESRESPONSE_H__
+#define __NFLICKGETSIZESRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickGetSizesResponse
+{
+        NFlickApiResponse Parent;
+        NFlickGetSizesResponsePrivate *Private;
+};
+
+struct                          _NFlickGetSizesResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_get_sizes_response_get_type (void);
+
+gchar*                          nflick_get_sizes_response_find_match (NFlickGetSizesResponse *self, gint32 *width, gint32 *height, gboolean *rotated);
+
+gint32                          nflick_get_sizes_response_height_for (gint32 width, gint32 height, gint32 fit_width);
+
+gint32                          nflick_get_sizes_response_width_for (gint32 width, gint32 height, gint32 fit_height);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-gft-response-private.h b/attic/aaina/libnflick/nflick-gft-response-private.h
new file mode 100644 (file)
index 0000000..dd8a54d
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickGftResponsePrivate
+{
+        gchar *UserName;
+        gchar *UserNsid;
+        gchar *FullName;
+        gchar *Token;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_USER_NAME,
+        ARG_FULL_NAME,
+        ARG_TOKEN,
+        ARG_USER_NSID
+};
+
+static void                     nflick_gft_response_class_init (NFlickGftResponseClass *klass);
+
+static void                     nflick_gft_response_init (NFlickGftResponse *self);
+
+static gboolean                 private_init (NFlickGftResponse *self, NFlickGftResponsePrivate *private);
+
+static void                     private_dispose (NFlickGftResponsePrivate *private);
+
+static void                     nflick_gft_response_dispose (NFlickGftResponse *self);
+
+static void                     nflick_gft_response_finalize (NFlickGftResponse *self);
+
+static void                     parse_func (NFlickGftResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static gboolean                 all_fields_valid (NFlickGftResponse *self);
+
+static void                     fill_blanks (NFlickGftResponse *self);
+
+static void                     nflick_gft_response_get_property (NFlickGftResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec);
diff --git a/attic/aaina/libnflick/nflick-gft-response.c b/attic/aaina/libnflick/nflick-gft-response.c
new file mode 100644 (file)
index 0000000..a38e04d
--- /dev/null
@@ -0,0 +1,281 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-gft-response.h"
+#include "nflick-gft-response-private.h"
+
+GType                           nflick_gft_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickGftResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_gft_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickGftResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_gft_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickGftResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_gft_response_class_init (NFlickGftResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_gft_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_gft_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_gft_response_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_TOKEN,
+                                         g_param_spec_string
+                                         ("token", "Token", "Unique flick full token",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NAME,
+                                         g_param_spec_string
+                                         ("username", "UserName", "Flickr user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_FULL_NAME,
+                                         g_param_spec_string
+                                         ("fullname", "FullName", "Flickr full user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NSID,
+                                         g_param_spec_string
+                                         ("usernsid", "UserNsid", "Unique nsid identyfying user in flickr",
+                                         NULL, G_PARAM_READABLE));
+
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_gft_response_init (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickGftResponsePrivate *priv = g_new0 (NFlickGftResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickGftResponse *self, NFlickGftResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_GFT_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->UserName = NULL;
+        private->FullName = NULL;
+        private->Token = NULL;
+        private->UserNsid = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickGftResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->UserName != NULL) {
+                g_free (private->UserName);
+                private->UserName = NULL;
+        }
+
+        if (private->FullName != NULL) {
+                g_free (private->FullName);
+                private->FullName = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->UserNsid != NULL) {
+                g_free (private->UserNsid);
+                private->UserNsid = NULL;
+        }
+}
+
+
+static void                     nflick_gft_response_dispose (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_gft_response_finalize (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static gboolean                 all_fields_valid (NFlickGftResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_GFT_RESPONSE (self), FALSE);
+
+        if (self->Private->UserNsid != NULL && self->Private->Token != NULL)
+                return TRUE;
+        else
+                return FALSE;
+}
+
+static void                     fill_blanks (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+
+        if (self->Private->UserName == NULL)
+                self->Private->UserName = g_strdup (gettext ("anonymous"));
+        
+        if (self->Private->FullName == NULL)
+                self->Private->FullName = g_strdup (gettext ("Anonymous"));
+}
+
+static void                     parse_func (NFlickGftResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "auth") == 0) {
+                        
+                        xmlNode *auth_node = NULL;
+                        for (auth_node = cur_node->children; auth_node; auth_node = auth_node->next) {
+                                
+                                /* <user> */
+                                if (auth_node->type == XML_ELEMENT_NODE && strcmp (auth_node->name, "user") == 0) {
+
+                                        /* Nsid */
+                                        gchar *nsid = xmlGetProp (auth_node, "nsid");
+                                        if (nsid != NULL) {
+                                                if (self->Private->UserNsid != NULL)
+                                                        g_free (self->Private->UserNsid);
+                                                self->Private->UserNsid = nsid;
+                                        }
+
+                                        /* UserName */
+                                        gchar *username = xmlGetProp (auth_node, "username");
+                                        if (username != NULL) {
+                                                if (self->Private->UserName != NULL)
+                                                        g_free (self->Private->UserName);
+                                                self->Private->UserName = username;
+                                        }
+
+                                        /* FullName */
+                                        gchar *fullname = xmlGetProp (auth_node, "fullname");
+                                        if (fullname != NULL) {
+                                                if (self->Private->FullName != NULL)
+                                                        g_free (self->Private->FullName);
+                                                self->Private->FullName = fullname;
+                                        }
+                                }
+
+                                /* <token> */
+                                if (auth_node->type == XML_ELEMENT_NODE && strcmp (auth_node->name, "token") == 0) {
+                                        char *token = xmlNodeListGetString (doc, auth_node->xmlChildrenNode, 1);
+                                        if (token != NULL) {
+                                                if (self->Private->Token != NULL)
+                                                        g_free (self->Private->Token);
+                                                self->Private->Token = token;
+                                        }
+                                }               
+                        }
+                }
+        }
+
+        /* Finished */
+        if (all_fields_valid (self) == TRUE) {
+                fill_blanks (self);
+                *result = TRUE;
+                *parse_error = FALSE;
+        } else {
+                *result = FALSE;
+                *parse_error = TRUE;
+                nflick_api_response_add_error ((NFlickApiResponse *) self, 
+                                               gettext ("Some of the required info is missing from the response!"));
+        }
+}
+
+static void                     nflick_gft_response_get_property (NFlickGftResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_USER_NAME:
+                        g_value_set_string (value, self->Private->UserName);
+                break;
+        
+                case ARG_FULL_NAME:
+                        g_value_set_string (value, self->Private->FullName);
+                break;
+                case ARG_TOKEN:
+                        g_value_set_string (value, self->Private->Token);
+                break;
+       
+                case ARG_USER_NSID:
+                        g_value_set_string (value, self->Private->UserNsid);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-gft-response.h b/attic/aaina/libnflick/nflick-gft-response.h
new file mode 100644 (file)
index 0000000..cd67b4a
--- /dev/null
@@ -0,0 +1,49 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKGFTRESPONSE_H__
+#define __NFLICKGFTRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickGftResponse
+{
+        NFlickApiResponse Parent;
+        NFlickGftResponsePrivate *Private;
+};
+
+struct                          _NFlickGftResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_gft_response_get_type (void);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-info-response-private.h b/attic/aaina/libnflick/nflick-info-response-private.h
new file mode 100644 (file)
index 0000000..f2c7fbf
--- /dev/null
@@ -0,0 +1,66 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickInfoResponsePrivate
+{
+        gchar *UserName;
+        gchar *UserNsid;
+        gchar *FullName;
+        gchar *Token;
+
+        gchar *rotation;
+        gchar *realname;
+        gchar *desc;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_USER_NAME,
+        ARG_FULL_NAME,
+        ARG_TOKEN,
+        ARG_USER_NSID
+};
+
+static void                     nflick_info_response_class_init (NFlickInfoResponseClass *klass);
+
+static void                     nflick_info_response_init (NFlickInfoResponse *self);
+
+static gboolean                 private_init (NFlickInfoResponse *self, NFlickInfoResponsePrivate *private);
+
+static void                     private_dispose (NFlickInfoResponsePrivate *private);
+
+static void                     nflick_info_response_dispose (NFlickInfoResponse *self);
+
+static void                     nflick_info_response_finalize (NFlickInfoResponse *self);
+
+static void                     parse_func (NFlickInfoResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static gboolean                 all_fields_valid (NFlickInfoResponse *self);
+
+static void                     fill_blanks (NFlickInfoResponse *self);
+
+static void                     nflick_info_response_get_property (NFlickInfoResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec);
diff --git a/attic/aaina/libnflick/nflick-info-response.c b/attic/aaina/libnflick/nflick-info-response.c
new file mode 100644 (file)
index 0000000..dc94fa9
--- /dev/null
@@ -0,0 +1,272 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-info-response.h"
+#include "nflick-info-response-private.h"
+
+GType                           
+nflick_info_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickInfoResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_info_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickInfoResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_info_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickInfoResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     
+nflick_info_response_class_init (NFlickInfoResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_info_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_info_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_info_response_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_TOKEN,
+                                         g_param_spec_string
+                                         ("token", "Token", "Unique flick full token",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NAME,
+                                         g_param_spec_string
+                                         ("username", "UserName", "Flickr user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_FULL_NAME,
+                                         g_param_spec_string
+                                         ("fullname", "FullName", "Flickr full user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NSID,
+                                         g_param_spec_string
+                                         ("usernsid", "UserNsid", "Unique nsid identyfying user in flickr",
+                                         NULL, G_PARAM_READABLE));
+
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     
+nflick_info_response_init (NFlickInfoResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickInfoResponsePrivate *priv = g_new0 (NFlickInfoResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 
+private_init (NFlickInfoResponse *self, NFlickInfoResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_INFO_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->UserName = NULL;
+        private->FullName = NULL;
+        private->Token = NULL;
+        private->UserNsid = NULL;
+
+        return TRUE;
+}
+
+static void                     
+private_dispose (NFlickInfoResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->UserName != NULL) {
+                g_free (private->UserName);
+                private->UserName = NULL;
+        }
+
+        if (private->FullName != NULL) {
+                g_free (private->FullName);
+                private->FullName = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->UserNsid != NULL) {
+                g_free (private->UserNsid);
+                private->UserNsid = NULL;
+        }
+}
+
+
+static void                     
+nflick_info_response_dispose (NFlickInfoResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     
+nflick_info_response_finalize (NFlickInfoResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+void
+nflick_info_response_get (NFlickInfoResponse *self,
+                          gchar **rotation,
+                          gchar **realname,
+                          gchar **desc)
+{
+  g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+
+  *rotation = self->Private->rotation;
+  *realname = self->Private->realname;
+  *desc = self->Private->desc;
+}
+
+
+static gboolean                 
+all_fields_valid (NFlickInfoResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_INFO_RESPONSE (self), FALSE);
+
+        if (self->Private->UserNsid != NULL && self->Private->Token != NULL)
+                return TRUE;
+        else
+                return FALSE;
+}
+
+static void                     
+fill_blanks (NFlickInfoResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+
+        if (self->Private->UserName == NULL)
+                self->Private->UserName = g_strdup (gettext ("anonymous"));
+        
+        if (self->Private->FullName == NULL)
+                self->Private->FullName = g_strdup (gettext ("Anonymous"));
+}
+
+static void                     
+parse_func (NFlickInfoResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+  g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+  g_return_if_fail (children != NULL);
+  g_return_if_fail (doc != NULL);
+  g_return_if_fail (result != NULL && parse_error != NULL);
+
+  xmlNode *cur_node = NULL;
+
+  for (cur_node = children; cur_node; cur_node = cur_node->next) 
+  {
+    if (cur_node->type == XML_ELEMENT_NODE 
+      && strcmp (cur_node->name, "photo") == 0) 
+    {
+      xmlNode *auth_node = NULL;
+      self->Private->rotation = xmlGetProp (cur_node, "rotation");
+            
+      for (auth_node = cur_node->children; auth_node; auth_node = auth_node->next) 
+      {
+        if (auth_node->type == XML_ELEMENT_NODE 
+              && strcmp (auth_node->name, "owner") == 0) 
+        {
+          /* Nsid */
+          self->Private->realname = xmlGetProp (auth_node, "realname");
+        }
+
+        /* <token> */
+        if (auth_node->type == XML_ELEMENT_NODE 
+          && strcmp (auth_node->name, "description") == 0) 
+        {
+          self->Private->desc=xmlNodeListGetString (doc, auth_node->xmlChildrenNode, 1);
+        }                
+      }
+    }
+  }
+}
+static void                     
+nflick_info_response_get_property (NFlickInfoResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_INFO_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_USER_NAME:
+                        g_value_set_string (value, self->Private->UserName);
+                break;
+        
+                case ARG_FULL_NAME:
+                        g_value_set_string (value, self->Private->FullName);
+                break;
+                case ARG_TOKEN:
+                        g_value_set_string (value, self->Private->Token);
+                break;
+       
+                case ARG_USER_NSID:
+                        g_value_set_string (value, self->Private->UserNsid);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-info-response.h b/attic/aaina/libnflick/nflick-info-response.h
new file mode 100644 (file)
index 0000000..5de6787
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKINFORESPONSE_H__
+#define __NFLICKINFORESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickInfoResponse
+{
+        NFlickApiResponse Parent;
+        NFlickInfoResponsePrivate *Private;
+};
+
+struct                          _NFlickInfoResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_info_response_get_type (void);
+  
+void
+nflick_info_response_get (NFlickInfoResponse *self,
+                          gchar **rotation,
+                          gchar **realname,
+                          gchar **desc);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-info-worker-private.h b/attic/aaina/libnflick/nflick-info-worker-private.h
new file mode 100644 (file)
index 0000000..104da49
--- /dev/null
@@ -0,0 +1,63 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickInfoWorkerPrivate
+{
+        gchar *PhotoId;
+        gchar *Token;
+        gint32 Width;
+        gint32 Height;
+        GdkPixbuf *Pixbuf;
+        gchar *rotation;
+        gchar *realname;
+        gchar *desc;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_PIXBUF,
+        ARG_ROTATION,
+        ARG_REALNAME,
+        ARG_DESC
+};
+
+static void                     nflick_info_worker_class_init (NFlickInfoWorkerClass *klass);
+
+static void                     nflick_info_worker_init (NFlickInfoWorker *self);
+
+static gboolean                 private_init (NFlickInfoWorker *self, NFlickInfoWorkerPrivate *private);
+
+static void                     private_dispose (NFlickInfoWorkerPrivate *private);
+
+static void                     nflick_info_worker_dispose (NFlickInfoWorker *self);
+
+static void                     nflick_info_worker_finalize (NFlickInfoWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickInfoWorker *self);
+
+static void                     nflick_info_worker_get_property (NFlickInfoWorker *self, guint propid, 
+                                                                GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-info-worker.c b/attic/aaina/libnflick/nflick-info-worker.c
new file mode 100644 (file)
index 0000000..9c211d2
--- /dev/null
@@ -0,0 +1,275 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-info-worker.h"
+#include "nflick-info-worker-private.h"
+
+GType                           
+nflick_info_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickInfoWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_info_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickInfoWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_info_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickInfoWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     
+nflick_info_worker_class_init (NFlickInfoWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_info_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_info_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_info_worker_get_property;
+
+        g_object_class_install_property (gobjectclass, ARG_PIXBUF,
+                                         g_param_spec_object 
+                                         ("pixbuf", "Pixbuf", "Pixbuf",
+                                         GDK_TYPE_PIXBUF, G_PARAM_READABLE));
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     
+nflick_info_worker_init (NFlickInfoWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickInfoWorkerPrivate *priv = g_new0 (NFlickInfoWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, 
+                                           gettext ("Loading photo..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 
+private_init (NFlickInfoWorker *self, NFlickInfoWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_INFO_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoId = NULL;
+        private->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     
+private_dispose (NFlickInfoWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->PhotoId != NULL) {
+                g_free (private->PhotoId);
+                private->PhotoId = NULL;
+        }
+
+        if (private->Pixbuf != NULL) {
+                g_object_unref (private->Pixbuf);
+                private->Pixbuf = NULL;
+        }
+}
+
+static void                     
+nflick_info_worker_dispose (NFlickInfoWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                    
+nflick_info_worker_finalize (NFlickInfoWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_INFO_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       
+thread_func (NFlickInfoWorker *self)
+{
+        NFlickApiRequest *get_sizes_request = NULL; 
+        NFlickApiResponse *get_sizes_response = NULL;
+        gchar *uri = NULL;
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        gdouble vbox_aspect = (gdouble) self->Private->Width / (gdouble) self->Private->Height;
+        gdouble pixbuf_aspect = -1;
+        gint32 final_width = -1;
+        gint32 final_height = -1;
+        gboolean rotated = FALSE;
+
+        get_sizes_request = nflick_api_request_new ("flickr.photos.getinfo");
+        if (get_sizes_request == NULL)
+                goto Error;
+
+        nflick_api_request_add_parameter (get_sizes_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTO_ID, 
+                                          self->Private->PhotoId);
+
+        nflick_api_request_sign (get_sizes_request);
+        if (nflick_api_request_exec (get_sizes_request) != TRUE) 
+        {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        get_sizes_response = 
+              nflick_api_response_new_from_request (NFLICK_TYPE_INFO_RESPONSE, 
+                                                    get_sizes_request);
+
+        if (get_sizes_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, 
+                                              get_sizes_response) == FALSE)
+                goto Error;
+        
+        nflick_info_response_get ((NFlickInfoResponse*)get_sizes_response,
+                                  &self->Private->rotation,
+                                  &self->Private->realname,
+                                  &self->Private->desc);
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (get_sizes_request != NULL) 
+                g_object_unref (get_sizes_request);
+
+        if (get_sizes_response != NULL) 
+                g_object_unref (get_sizes_response);
+
+        if (uri != NULL)
+                g_free (uri);
+
+        return status;
+}
+
+void
+nflick_info_worker_get (NFlickInfoWorker    *self,
+                        gchar              **rotation,
+                        gchar              **realname,
+                        gchar              **desc)
+{
+  g_return_if_fail (NFLICK_IS_INFO_WORKER (self));
+
+  *rotation = self->Private->rotation;
+  *realname = self->Private->realname;
+  *desc = self->Private->desc;
+}
+
+NFlickInfoWorker*               
+nflick_info_worker_new (const gchar *photoid, gint32 width, gint32 height, const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+        g_return_val_if_fail (photoid != NULL, NULL);
+
+        NFlickInfoWorker *self = g_object_new (NFLICK_TYPE_INFO_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Token = g_strdup (token);
+        self->Private->PhotoId= g_strdup (photoid);
+        self->Private->Width = width;
+        self->Private->Height = height;
+
+        return self;
+}
+
+static void                     
+nflick_info_worker_get_property (NFlickInfoWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_INFO_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+               
+                case ARG_PIXBUF:
+                        g_value_set_object (value, self->Private->Pixbuf);
+                break;
+
+                case ARG_ROTATION:
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-info-worker.h b/attic/aaina/libnflick/nflick-info-worker.h
new file mode 100644 (file)
index 0000000..92ce505
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKINFOWORKER_H__
+#define __NFLICKINFOWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-get-sizes-response.h"
+#include "nflick-set-list-response.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-types.h"
+#include "nflick-pixbuf-fetch.h"
+
+struct                          _NFlickInfoWorker
+{
+        NFlickWorker Parent;
+        NFlickInfoWorkerPrivate *Private;
+};
+
+struct                          _NFlickInfoWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_info_worker_get_type (void);
+
+NFlickInfoWorker*               nflick_info_worker_new (const gchar *photoid, gint32 width, gint32 height, const gchar *token);
+
+void
+nflick_info_worker_get (NFlickInfoWorker    *self,
+                        gchar              **rotation,
+                        gchar              **realname,
+                        gchar              **desc);
+#endif
diff --git a/attic/aaina/libnflick/nflick-no-set-response-private.h b/attic/aaina/libnflick/nflick-no-set-response-private.h
new file mode 100644 (file)
index 0000000..e71c6aa
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickNoSetResponsePrivate
+{
+        GList *PhotoDataList;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_no_set_response_class_init (NFlickNoSetResponseClass *klass);
+
+static void                     nflick_no_set_response_init (NFlickNoSetResponse *self);
+
+static gboolean                 private_init (NFlickNoSetResponse *self, NFlickNoSetResponsePrivate *private);
+
+static void                     private_dispose (NFlickNoSetResponsePrivate *private);
+
+static void                     nflick_no_set_response_dispose (NFlickNoSetResponse *self);
+
+static void                     nflick_no_set_response_finalize (NFlickNoSetResponse *self);
+
+static void                     parse_func (NFlickNoSetResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_no_set_response_get_property (NFlickNoSetResponse *self, guint propid, 
+                                                                     GValue *value, GParamSpec *pspec);
diff --git a/attic/aaina/libnflick/nflick-no-set-response.c b/attic/aaina/libnflick/nflick-no-set-response.c
new file mode 100644 (file)
index 0000000..b215c4e
--- /dev/null
@@ -0,0 +1,199 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-no-set-response.h"
+#include "nflick-no-set-response-private.h"
+
+GType                           nflick_no_set_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickNoSetResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_no_set_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickNoSetResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_no_set_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickNoSetResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_no_set_response_class_init (NFlickNoSetResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_no_set_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_no_set_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_no_set_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_no_set_response_init (NFlickNoSetResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickNoSetResponsePrivate *priv = g_new0 (NFlickNoSetResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickNoSetResponse *self, NFlickNoSetResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_NO_SET_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickNoSetResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_no_set_response_dispose (NFlickNoSetResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_no_set_response_finalize (NFlickNoSetResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickNoSetResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "photos") == 0) {
+
+                        xmlNode *set_node = NULL;
+                        for (set_node = cur_node->children; set_node; set_node = set_node->next) {
+                                
+                                if (set_node->type == XML_ELEMENT_NODE && strcmp (set_node->name, "photo") == 0) {
+
+                                        gchar *id = xmlGetProp (set_node, "id");
+                                        gchar *name = xmlGetProp (set_node, "title");
+
+                                        if (id != NULL && name != NULL) {
+                                                NFlickPhotoData *photo_data = nflick_photo_data_new (id, name);
+
+                                                /* We prepend to add photos in reverse order. Flickr seems to return
+                                                 * photos in oldest-to-newest order */
+
+                                                if (photo_data != NULL) 
+                                                        self->Private->PhotoDataList = g_list_prepend (self->Private->PhotoDataList, photo_data);
+                                        }
+
+                                        if (id != NULL)
+                                                g_free (id);
+                                        if (name != NULL)
+                                                g_free (name);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+static void                     nflick_no_set_response_get_property (NFlickNoSetResponse *self, guint propid, 
+                                                                     GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
+
+GList*                          nflick_no_set_response_take_list (NFlickNoSetResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_NO_SET_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoDataList;
+        self->Private->PhotoDataList = NULL;
+
+        return lst;
+}
+
+
diff --git a/attic/aaina/libnflick/nflick-no-set-response.h b/attic/aaina/libnflick/nflick-no-set-response.h
new file mode 100644 (file)
index 0000000..623c42f
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKNOSETRESPONSE_H__
+#define __NFLICKNOSETRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-data.h"
+
+struct                          _NFlickNoSetResponse
+{
+        NFlickApiResponse Parent;
+        NFlickNoSetResponsePrivate *Private;
+};
+
+struct                          _NFlickNoSetResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_no_set_response_get_type (void);
+
+GList*                          nflick_no_set_response_take_list (NFlickNoSetResponse *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-photo-data.c b/attic/aaina/libnflick/nflick-photo-data.c
new file mode 100644 (file)
index 0000000..9954732
--- /dev/null
@@ -0,0 +1,75 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-data.h"
+
+GType                           nflick_photo_data_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+                objecttype = g_boxed_type_register_static 
+                        ("NFlickPhotoData", 
+                         (GBoxedCopyFunc) nflick_photo_data_copy,
+                         (GBoxedFreeFunc) nflick_photo_data_free);
+        }
+        
+        return objecttype;
+}
+
+NFlickPhotoData*                nflick_photo_data_copy (const NFlickPhotoData *self)
+{
+        g_return_val_if_fail (self != NULL, NULL);
+
+        NFlickPhotoData *new = g_new (NFlickPhotoData, 1);
+        g_return_val_if_fail (new != NULL, NULL);
+
+        new->Id = (self->Id != NULL) ? g_strdup (self->Id) : NULL;
+        new->Name = (self->Name != NULL) ? g_strdup (self->Name) : NULL;
+        return new;
+}
+
+void                            nflick_photo_data_free (NFlickPhotoData *self)
+{
+        if (self == NULL)
+                return;
+        else {
+                if (self->Id != NULL)
+                        g_free (self->Id);
+                if (self->Name != NULL)
+                        g_free (self->Name);
+                g_free (self);
+        }
+}
+
+NFlickPhotoData*                nflick_photo_data_new (const gchar *id, const gchar *name)
+{
+        NFlickPhotoData *self = g_new (NFlickPhotoData, 1);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        self->Id = (id != NULL) ? g_strdup (id) : NULL;
+        self->Name = (name != NULL) ? g_strdup (name) : NULL;
+
+        return self;
+}
diff --git a/attic/aaina/libnflick/nflick-photo-data.h b/attic/aaina/libnflick/nflick-photo-data.h
new file mode 100644 (file)
index 0000000..5a156d2
--- /dev/null
@@ -0,0 +1,44 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTODATA_H__
+#define __NFLICKPHOTODATA_H__
+
+#include <gtk/gtk.h>
+#include "nflick-types.h"
+
+struct _NFlickPhotoData
+{
+        gchar *Id;
+        gchar *Name;
+};
+
+GType                           nflick_photo_data_get_type (void);
+
+NFlickPhotoData*                nflick_photo_data_copy (const NFlickPhotoData *self);
+
+void                            nflick_photo_data_free (NFlickPhotoData *self);
+
+NFlickPhotoData*                nflick_photo_data_new (const gchar *id, const gchar *name);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-photo-list-response-private.h b/attic/aaina/libnflick/nflick-photo-list-response-private.h
new file mode 100644 (file)
index 0000000..c8920ab
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickPhotoListResponsePrivate
+{
+        GList *PhotoDataList;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_photo_list_response_class_init (NFlickPhotoListResponseClass *klass);
+
+static void                     nflick_photo_list_response_init (NFlickPhotoListResponse *self);
+
+static gboolean                 private_init (NFlickPhotoListResponse *self, NFlickPhotoListResponsePrivate *private);
+
+static void                     private_dispose (NFlickPhotoListResponsePrivate *private);
+
+static void                     nflick_photo_list_response_dispose (NFlickPhotoListResponse *self);
+
+static void                     nflick_photo_list_response_finalize (NFlickPhotoListResponse *self);
+
+static void                     parse_func (NFlickPhotoListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_photo_list_response_get_property (NFlickPhotoListResponse *self, guint propid, 
+                                                                         GValue *value, GParamSpec *pspec);
diff --git a/attic/aaina/libnflick/nflick-photo-list-response.c b/attic/aaina/libnflick/nflick-photo-list-response.c
new file mode 100644 (file)
index 0000000..0941181
--- /dev/null
@@ -0,0 +1,195 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-list-response.h"
+#include "nflick-photo-list-response-private.h"
+
+GType                           nflick_photo_list_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoListResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_list_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoListResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_list_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickPhotoListResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_photo_list_response_class_init (NFlickPhotoListResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_list_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_list_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_list_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_photo_list_response_init (NFlickPhotoListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickPhotoListResponsePrivate *priv = g_new0 (NFlickPhotoListResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoListResponse *self, NFlickPhotoListResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickPhotoListResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_photo_list_response_dispose (NFlickPhotoListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_list_response_finalize (NFlickPhotoListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickPhotoListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "photoset") == 0) {
+
+                        xmlNode *set_node = NULL;
+                        for (set_node = cur_node->children; set_node; set_node = set_node->next) {
+                                
+                                if (set_node->type == XML_ELEMENT_NODE && strcmp (set_node->name, "photo") == 0) {
+
+                                        gchar *id = xmlGetProp (set_node, "id");
+                                        gchar *name = xmlGetProp (set_node, "title");
+
+                                        if (id != NULL && name != NULL) {
+                                                NFlickPhotoData *photo_data = nflick_photo_data_new (id, name);
+                                                if (photo_data != NULL) 
+                                                        self->Private->PhotoDataList = g_list_append (self->Private->PhotoDataList, photo_data);
+                                        }
+
+                                        if (id != NULL)
+                                                g_free (id);
+                                        if (name != NULL)
+                                                g_free (name);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+static void                     nflick_photo_list_response_get_property (NFlickPhotoListResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
+
+GList*                          nflick_photo_list_response_take_list (NFlickPhotoListResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoDataList;
+        self->Private->PhotoDataList = NULL;
+
+        return lst;
+}
+
+
diff --git a/attic/aaina/libnflick/nflick-photo-list-response.h b/attic/aaina/libnflick/nflick-photo-list-response.h
new file mode 100644 (file)
index 0000000..2b6b3f7
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOLISTRESPONSE_H__
+#define __NFLICKPHOTOLISTRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-data.h"
+
+struct                          _NFlickPhotoListResponse
+{
+        NFlickApiResponse Parent;
+        NFlickPhotoListResponsePrivate *Private;
+};
+
+struct                          _NFlickPhotoListResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_photo_list_response_get_type (void);
+
+GList*                          nflick_photo_list_response_take_list (NFlickPhotoListResponse *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-photo-list-worker-private.h b/attic/aaina/libnflick/nflick-photo-list-worker-private.h
new file mode 100644 (file)
index 0000000..b2b84ab
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickPhotoListWorkerPrivate
+{
+        gchar *Id;
+        gchar *Token;
+        GList *PhotoDataList;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_photo_list_worker_class_init (NFlickPhotoListWorkerClass *klass);
+
+static void                     nflick_photo_list_worker_init (NFlickPhotoListWorker *self);
+
+static gboolean                 private_init (NFlickPhotoListWorker *self, NFlickPhotoListWorkerPrivate *private);
+
+static void                     private_dispose (NFlickPhotoListWorkerPrivate *private);
+
+static void                     nflick_photo_list_worker_dispose (NFlickPhotoListWorker *self);
+
+static void                     nflick_photo_list_worker_finalize (NFlickPhotoListWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickPhotoListWorker *self);
+
+static void                     nflick_photo_list_worker_get_property (NFlickPhotoListWorker *self, guint propid, 
+                                                                       GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-photo-list-worker.c b/attic/aaina/libnflick/nflick-photo-list-worker.c
new file mode 100644 (file)
index 0000000..9d75c17
--- /dev/null
@@ -0,0 +1,240 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-list-worker.h"
+#include "nflick-photo-list-worker-private.h"
+
+GType                           nflick_photo_list_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoListWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_list_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoListWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_list_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickPhotoListWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_photo_list_worker_class_init (NFlickPhotoListWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_list_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_list_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_list_worker_get_property;
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_photo_list_worker_init (NFlickPhotoListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickPhotoListWorkerPrivate *priv = g_new0 (NFlickPhotoListWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Loading photoset data..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoListWorker *self, NFlickPhotoListWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Id = NULL;
+        private->Token = NULL;
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickPhotoListWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Id != NULL) {
+                g_free (private->Id);
+                private->Id = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_photo_list_worker_dispose (NFlickPhotoListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_list_worker_finalize (NFlickPhotoListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickPhotoListWorker *self)
+{
+        NFlickApiRequest *get_photolist_request = NULL; 
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        NFlickApiResponse *photo_list_response = NULL;
+
+        get_photolist_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_PHOTOS);
+        if (get_photolist_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (get_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        nflick_api_request_add_parameter (get_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTOSET_ID, 
+                                          self->Private->Id);
+
+        nflick_api_request_sign (get_photolist_request);
+        if (nflick_api_request_exec (get_photolist_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        photo_list_response = nflick_api_response_new_from_request (NFLICK_TYPE_PHOTO_LIST_RESPONSE, get_photolist_request);
+        if (photo_list_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, photo_list_response) == FALSE)
+                goto Error;
+
+        self->Private->PhotoDataList = nflick_photo_list_response_take_list ((NFlickPhotoListResponse *) photo_list_response);
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (get_photolist_request != NULL) 
+                g_object_unref (get_photolist_request);
+
+        if (photo_list_response != NULL) 
+                g_object_unref (photo_list_response);
+
+        return status;
+}
+
+NFlickPhotoListWorker*         nflick_photo_list_worker_new (const gchar *id, const gchar *token)
+{
+        g_return_val_if_fail (id != NULL, NULL);
+
+        NFlickPhotoListWorker *self = g_object_new (NFLICK_TYPE_PHOTO_LIST_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Id = g_strdup (id);
+        self->Private->Token = g_strdup (token);
+        
+        return self;
+}
+
+static void                     nflick_photo_list_worker_get_property (NFlickPhotoListWorker *self, guint propid, 
+                                                                       GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
+
+GList*                          nflick_photo_list_worker_take_list (NFlickPhotoListWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self), NULL);
+
+        GList *lst = self->Private->PhotoDataList;
+        self->Private->PhotoDataList = NULL;
+
+        return lst;
+}
diff --git a/attic/aaina/libnflick/nflick-photo-list-worker.h b/attic/aaina/libnflick/nflick-photo-list-worker.h
new file mode 100644 (file)
index 0000000..03de657
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOLISTWORKER_H__
+#define __NFLICKPHOTOLISTWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-types.h"
+#include "nflick-photo-list-response.h"
+
+struct                          _NFlickPhotoListWorker
+{
+        NFlickWorker Parent;
+        NFlickPhotoListWorkerPrivate *Private;
+};
+
+struct                          _NFlickPhotoListWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                                 nflick_photo_list_worker_get_type (void);
+
+NFlickPhotoListWorker*                nflick_photo_list_worker_new (const gchar *id, const gchar *token);
+
+GList*                                nflick_photo_list_worker_take_list (NFlickPhotoListWorker *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-photo-search-response-private.h b/attic/aaina/libnflick/nflick-photo-search-response-private.h
new file mode 100644 (file)
index 0000000..64cd6bd
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickPhotoSearchResponsePrivate
+{
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_photo_search_response_class_init (NFlickPhotoSearchResponseClass *klass);
+
+static void                     nflick_photo_search_response_init (NFlickPhotoSearchResponse *self);
+
+static gboolean                 private_init (NFlickPhotoSearchResponse *self, NFlickPhotoSearchResponsePrivate *private);
+
+static void                     private_dispose (NFlickPhotoSearchResponsePrivate *private);
+
+static void                     nflick_photo_search_response_dispose (NFlickPhotoSearchResponse *self);
+
+static void                     nflick_photo_search_response_finalize (NFlickPhotoSearchResponse *self);
+
+static void                     parse_func (NFlickPhotoSearchResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_photo_search_response_get_property (NFlickPhotoSearchResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec);
diff --git a/attic/aaina/libnflick/nflick-photo-search-response.c b/attic/aaina/libnflick/nflick-photo-search-response.c
new file mode 100644 (file)
index 0000000..130119a
--- /dev/null
@@ -0,0 +1,207 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-search-response.h"
+#include "nflick-photo-search-response-private.h"
+
+
+GType                           nflick_photo_search_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoSearchResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_search_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoSearchResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_search_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickPhotoSearchResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+
+static void                     nflick_photo_search_response_class_init (NFlickPhotoSearchResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_search_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_search_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_search_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_photo_search_response_init (NFlickPhotoSearchResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickPhotoSearchResponsePrivate *priv = g_new0 (NFlickPhotoSearchResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoSearchResponse *self, NFlickPhotoSearchResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoSets = NULL;
+
+        return TRUE;
+}
+
+static void                     
+private_dispose (NFlickPhotoSearchResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+        return;
+
+        if (private->PhotoSets != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoSets; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                g_object_unref (iterator->data);
+                
+                g_list_free (private->PhotoSets);
+                private->PhotoSets = NULL;
+        }
+}
+
+GList*                          
+nflick_photo_search_response_take_list (NFlickPhotoSearchResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoSets;
+        self->Private->PhotoSets = NULL;
+
+        return lst;
+}
+
+static void                     nflick_photo_search_response_dispose (NFlickPhotoSearchResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_search_response_finalize (NFlickPhotoSearchResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     
+parse_func (NFlickPhotoSearchResponse *self, 
+            xmlDoc *doc, 
+            xmlNode *children, 
+            gboolean *result, 
+            gboolean *parse_error)
+{
+  g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self));
+  g_return_if_fail (children != NULL);
+  g_return_if_fail (doc != NULL);
+  g_return_if_fail (result != NULL && parse_error != NULL);
+
+  xmlNode *cur_node = NULL;
+
+  for (cur_node = children; cur_node; cur_node = cur_node->next) 
+  {
+      
+    if (cur_node->type == XML_ELEMENT_NODE 
+          && strcmp (cur_node->name, "photos") == 0) 
+    {
+                        
+      xmlNode *sets_node = NULL;
+      for (sets_node = cur_node->children; sets_node;
+                                                sets_node = sets_node->next) 
+      {
+                                
+        if (sets_node->type == XML_ELEMENT_NODE 
+                                  && strcmp (sets_node->name, "photo") == 0) 
+        {
+
+          gchar *id = xmlGetProp (sets_node, "id");
+          gchar *title = xmlGetProp (sets_node, "title");
+          gchar *user = xmlGetProp (sets_node, "owner");
+
+          FlickrPhoto *photo = g_new0 (FlickrPhoto, 1);
+          photo->id = id;
+          photo->title = title;
+          photo->user = user;
+
+          self->Private->PhotoSets = g_list_append (self->Private->PhotoSets,
+                                                      photo);
+        }
+      }
+    }
+  }
+  /* Finished */
+  *result = TRUE;
+  *parse_error = FALSE;
+}
+
+static void                     nflick_photo_search_response_get_property (NFlickPhotoSearchResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-photo-search-response.h b/attic/aaina/libnflick/nflick-photo-search-response.h
new file mode 100644 (file)
index 0000000..7a7227a
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOSEARCHRESPONSE_H__
+#define __NFLICKPHOTOSEARCHRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-set.h"
+struct                          _NFlickPhotoSearchResponse
+{
+        NFlickApiResponse Parent;
+        NFlickPhotoSearchResponsePrivate *Private;
+};
+
+struct                          _NFlickPhotoSearchResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_photo_search_response_get_type (void);
+
+GList*                          nflick_photo_search_response_take_list (NFlickPhotoSearchResponse *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-photo-search-worker-private.h b/attic/aaina/libnflick/nflick-photo-search-worker-private.h
new file mode 100644 (file)
index 0000000..c07f371
--- /dev/null
@@ -0,0 +1,64 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorkerClass*       ParentClass = NULL;
+
+struct                          _NFlickPhotoSearchWorkerPrivate
+{
+        gchar *UserNsid;
+        gchar *Token;
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     
+nflick_photo_search_worker_class_init (NFlickPhotoSearchWorkerClass *klass);
+
+static void                     
+nflick_photo_search_worker_init (NFlickPhotoSearchWorker *self);
+
+static gboolean                 
+private_init (NFlickPhotoSearchWorker *self, 
+              NFlickPhotoSearchWorkerPrivate *priv);
+
+static void                     
+private_dispose (NFlickPhotoSearchWorkerPrivate *priv);
+
+static void                     
+nflick_photo_search_worker_dispose (NFlickPhotoSearchWorker *self);
+
+static void                     
+nflick_photo_search_worker_finalize (NFlickPhotoSearchWorker *self);
+
+static NFlickWorkerStatus       
+thread_func (NFlickPhotoSearchWorker *self);
+
+static void                     
+nflick_photo_search_worker_get_property (NFlickPhotoSearchWorker *self, 
+                                         guint propid, 
+                                         GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-photo-search-worker.c b/attic/aaina/libnflick/nflick-photo-search-worker.c
new file mode 100644 (file)
index 0000000..f21adbd
--- /dev/null
@@ -0,0 +1,324 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-search-worker.h"
+#include "nflick-photo-search-response.h"
+
+static NFlickWorkerClass*       ParentClass = NULL;
+
+struct                          _NFlickPhotoSearchWorkerPrivate
+{
+        gchar *UserNsid;
+        gchar *Token;
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     
+nflick_photo_search_worker_class_init (NFlickPhotoSearchWorkerClass *klass);
+
+static void                     
+nflick_photo_search_worker_init (NFlickPhotoSearchWorker *self);
+
+static gboolean                 
+private_init (NFlickPhotoSearchWorker *self, 
+              NFlickPhotoSearchWorkerPrivate *priv);
+
+static void                     
+private_dispose (NFlickPhotoSearchWorkerPrivate *priv);
+
+static void                     
+nflick_photo_search_worker_dispose (NFlickPhotoSearchWorker *self);
+
+static void                     
+nflick_photo_search_worker_finalize (NFlickPhotoSearchWorker *self);
+
+static NFlickWorkerStatus       
+thread_func (NFlickPhotoSearchWorker *self);
+
+static void                     
+nflick_photo_search_worker_get_property (NFlickPhotoSearchWorker *self, 
+                                         guint propid, 
+                                         GValue *value, GParamSpec *pspec);
+GType                           
+nflick_photo_search_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoSearchWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_search_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoSearchWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_search_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickPhotoSearchWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     
+nflick_photo_search_worker_class_init (NFlickPhotoSearchWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_search_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_search_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_search_worker_get_property;
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     
+nflick_photo_search_worker_init (NFlickPhotoSearchWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickPhotoSearchWorkerPrivate *priv = g_new0 (NFlickPhotoSearchWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Parsing photosets..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 
+private_init (NFlickPhotoSearchWorker *self, NFlickPhotoSearchWorkerPrivate *priv)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_SEARCH_WORKER (self), FALSE);
+        g_return_val_if_fail (priv != NULL, FALSE);
+
+        priv->UserNsid = NULL;
+        priv->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     
+private_dispose (NFlickPhotoSearchWorkerPrivate *priv)
+{
+        g_return_if_fail (priv != NULL);
+
+        if (priv->Token != NULL) {
+                g_free (priv->Token);
+                priv->Token = NULL;
+        }
+
+        if (priv->UserNsid != NULL) {
+                g_free (priv->UserNsid);
+                priv->UserNsid = NULL;
+        }
+
+        if (priv->PhotoSets != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = priv->PhotoSets; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                g_object_unref (iterator->data);
+                
+                g_list_free (priv->PhotoSets);
+                priv->PhotoSets = NULL;
+        }
+}
+
+static void                     
+nflick_photo_search_worker_dispose (NFlickPhotoSearchWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     
+nflick_photo_search_worker_finalize (NFlickPhotoSearchWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       
+thread_func (NFlickPhotoSearchWorker *self)
+{
+        NFlickApiRequest *get_photosets_request = NULL; 
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        NFlickApiResponse *photo_search_response = NULL;
+        gchar *first_id = NULL;
+        NFlickPhotoSet *first_set = NULL;
+        NFlickApiRequest *first_photolist_request = NULL; 
+        NFlickApiResponse *first_photo_list_response = NULL;
+        GList *first_list = NULL;
+        NFlickApiRequest *unsetted_request = NULL; 
+        NFlickApiResponse *unsetted_response = NULL;
+        GList *unsetted_list = NULL;
+        NFlickPhotoSet *unsetted_set = NULL;
+
+        get_photosets_request = nflick_api_request_new ("flickr.photos.search");
+        if (get_photosets_request == NULL)
+                g_error ("request did not equal NULL, run for the hills\n");
+        
+        nflick_api_request_add_parameter (get_photosets_request, 
+                                          "tags", self->Private->UserNsid);
+        nflick_api_request_add_parameter (get_photosets_request,
+                                          "sort", "date-posted-desc");
+
+        nflick_api_request_sign (get_photosets_request);
+        if (nflick_api_request_exec (get_photosets_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+        //gchar *buffer = nflick_api_request_take_buffer (get_photosets_request);
+        //g_print ("%s\n", buffer);
+        
+        photo_search_response = nflick_api_response_new_from_request (
+                     NFLICK_TYPE_PHOTO_SEARCH_RESPONSE, get_photosets_request);
+        if (photo_search_response == NULL)
+                goto Error;
+        
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, photo_search_response) == FALSE)
+                goto Error;
+        
+        self->Private->PhotoSets = nflick_photo_search_response_take_list ((NFlickPhotoSearchResponse *) photo_search_response);
+        /*
+        GList *l;
+        for (l = self->Private->PhotoSets; l != NULL; l = l->next)
+        {
+          FlickrPhoto *photo = (FlickrPhoto*)l->data;
+          g_print ("%s %s %s\n", photo->id, photo->title, photo->user);
+        }
+        */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        g_print ("Abort\n");
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+        g_print ("Error\n");
+Done:
+        if (get_photosets_request != NULL) 
+                g_object_unref (get_photosets_request);
+
+        if (photo_search_response != NULL) 
+                g_object_unref (photo_search_response);
+
+        if (first_photolist_request != NULL) 
+                g_object_unref (first_photolist_request);
+
+        if (unsetted_response != NULL) 
+                g_object_unref (unsetted_response);
+
+        if (unsetted_request != NULL) 
+                g_object_unref (unsetted_request);
+
+        if (first_photo_list_response != NULL) 
+                g_object_unref (first_photo_list_response);
+
+        if (first_id != NULL)
+                g_free (first_id);
+
+        return status;
+}
+
+NFlickPhotoSearchWorker*            
+nflick_photo_search_worker_new (const gchar *usernsid, const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+        g_return_val_if_fail (usernsid != NULL, NULL);
+
+        NFlickPhotoSearchWorker *self = g_object_new (NFLICK_TYPE_PHOTO_SEARCH_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Token = g_strdup (token);
+        self->Private->UserNsid = g_strdup (usernsid);
+        self->Private->PhotoSets = NULL;
+
+        return self;
+}
+
+GList*                          
+nflick_photo_search_worker_take_list (NFlickPhotoSearchWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_SEARCH_WORKER (self), NULL);
+
+        GList *lst = self->Private->PhotoSets;
+        self->Private->PhotoSets = NULL;
+
+        return lst;
+}
+
+static void                     
+nflick_photo_search_worker_get_property (NFlickPhotoSearchWorker *self, 
+                                         guint propid, 
+                                         GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SEARCH_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-photo-search-worker.h b/attic/aaina/libnflick/nflick-photo-search-worker.h
new file mode 100644 (file)
index 0000000..6d8764b
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.com>                          */
+/*      Neil J. Patel      <njp@o-hand.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSETLISTWORKER_H__
+#define __NFLICKSETLISTWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-set-list-response.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-types.h"
+#include "nflick-no-set-response.h"
+
+typedef struct _NFlickPhotoSearchWorker NFlickPhotoSearchWorker;
+typedef struct _NFlickPhotoSearchWorkerClass NFlickPhotoSearchWorkerClass;
+typedef struct _NFlickPhotoSearchWorkerPrivate NFlickPhotoSearchWorkerPrivate;
+
+struct _NFlickPhotoSearchWorker
+{
+        NFlickWorker Parent;
+        NFlickPhotoSearchWorkerPrivate *Private;
+};
+
+struct _NFlickPhotoSearchWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType nflick_photo_search_worker_get_type (void);
+
+NFlickPhotoSearchWorker*            
+nflick_photo_search_worker_new (const gchar *usernsid, const gchar *token);
+
+GList*
+nflick_photo_search_worker_take_list (NFlickPhotoSearchWorker *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-photo-set-private.h b/attic/aaina/libnflick/nflick-photo-set-private.h
new file mode 100644 (file)
index 0000000..4c6e745
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObjectClass*            ParentClass = NULL;
+
+struct                          _NFlickPhotoSetPrivate
+{
+        gchar *Name;
+        gint32 Count;
+        gchar *Id;
+        gboolean Fetched;
+        GList *PhotoDataList;
+};
+
+enum
+{
+        ARG_0,
+        ARG_COMBO_TEXT,
+        ARG_COUNT,
+        ARG_ID,
+        ARG_FETCHED,
+        ARG_LIST
+};
+
+static void                     nflick_photo_set_class_init (NFlickPhotoSetClass *klass);
+
+static void                     nflick_photo_set_init (NFlickPhotoSet *self);
+
+static gboolean                 private_init (NFlickPhotoSet *self, NFlickPhotoSetPrivate *private);
+
+static void                     private_dispose (NFlickPhotoSetPrivate *private);
+
+static void                     nflick_photo_set_dispose (NFlickPhotoSet *self);
+
+static void                     nflick_photo_set_finalize (NFlickPhotoSet *self);
+
+static void                     nflick_photo_set_get_property (NFlickPhotoSet *self, guint propid, 
+                                                               GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-photo-set.c b/attic/aaina/libnflick/nflick-photo-set.c
new file mode 100644 (file)
index 0000000..5bd4483
--- /dev/null
@@ -0,0 +1,242 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-set.h"
+#include "nflick-photo-set-private.h"
+
+GType                           nflick_photo_set_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoSetClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_set_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoSet), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_set_init,
+                };
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickPhotoSet",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_photo_set_class_init (NFlickPhotoSetClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_set_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_set_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_set_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_COMBO_TEXT,
+                                         g_param_spec_string
+                                         ("combotext", "ComboText", "A text to put in combobox",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_ID,
+                                         g_param_spec_string
+                                         ("id", "Id", "Photoset id",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_COUNT,
+                                         g_param_spec_int 
+                                         ("count", "Count", "Number of items",
+                                         -5000, 5000, 0, G_PARAM_READABLE));
+        /* FIXME Use actual max/min vals for int */
+
+        g_object_class_install_property (gobjectclass, ARG_FETCHED,
+                                         g_param_spec_boolean 
+                                         ("fetched", "Fetched", "If the photoset information was fetched",
+                                         FALSE, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_LIST,
+                                         g_param_spec_pointer 
+                                         ("list", "List", "A list of all the pointers",
+                                         G_PARAM_READABLE));
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+}
+
+static void                     nflick_photo_set_init (NFlickPhotoSet *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+
+        self->Private = NULL;
+
+        NFlickPhotoSetPrivate *priv = g_new0 (NFlickPhotoSetPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoSet *self, NFlickPhotoSetPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_SET (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Name = NULL;
+        private->Count = 0;
+        private->Id = NULL;
+        private->Fetched = FALSE;
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickPhotoSetPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Name != NULL) {
+                g_free (private->Name);
+                private->Name = NULL;
+        }
+        
+        if (private->Id != NULL) {
+                g_free (private->Id);
+                private->Id = NULL;
+        }
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_photo_set_dispose (NFlickPhotoSet *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_set_finalize (NFlickPhotoSet *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+NFlickPhotoSet*                 nflick_photo_set_new_no_set (gint32 count)
+{
+        g_return_val_if_fail (count >= 0, NULL);
+
+        return nflick_photo_set_new (gettext ("Photos without a set"), NULL, count);
+}
+
+NFlickPhotoSet*                 nflick_photo_set_new (const gchar *name, const gchar *id, gint32 count)
+{
+        g_return_val_if_fail (name != NULL, NULL);
+        g_return_val_if_fail (count >= 0, NULL);
+
+        NFlickPhotoSet *self = g_object_new (NFLICK_TYPE_PHOTO_SET, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Name = g_strdup (name);
+
+        if (id != NULL)
+                self->Private->Id = g_strdup (id);
+
+        self->Private->Count = count;
+        
+        return self;
+}
+
+void                            nflick_photo_set_give_list (NFlickPhotoSet *self, GList *list)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+        if (self->Private->Fetched != FALSE)
+                return;
+
+        self->Private->PhotoDataList = list;
+        self->Private->Fetched = TRUE;
+        self->Private->Count = g_list_length (list);
+}
+
+static void                     nflick_photo_set_get_property (NFlickPhotoSet *self, guint propid, 
+                                                               GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_COMBO_TEXT: {
+                        gchar *str = g_strdup_printf ("%s (%d)", self->Private->Name, self->Private->Count);
+                        g_value_take_string (value, str);
+                } break;
+   
+                case ARG_COUNT: {
+                        g_value_set_int (value, self->Private->Count);
+                } break;
+    
+                case ARG_ID: {
+                        g_value_set_string (value, self->Private->Id);
+                } break;
+
+                case ARG_FETCHED: {
+                        g_value_set_boolean (value, self->Private->Fetched);
+                } break;
+
+                case ARG_LIST: {
+                        g_value_set_pointer (value, self->Private->PhotoDataList);
+                } break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-photo-set.h b/attic/aaina/libnflick/nflick-photo-set.h
new file mode 100644 (file)
index 0000000..a322962
--- /dev/null
@@ -0,0 +1,53 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOSET_H__
+#define __NFLICKPHOTOSET_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-data.h"
+
+struct                          _NFlickPhotoSet
+{
+        GObject Parent;
+        NFlickPhotoSetPrivate *Private;
+};
+
+struct                          _NFlickPhotoSetClass 
+{
+        GObjectClass ParentClass;
+};
+
+GType                           nflick_photo_set_get_type (void);
+
+NFlickPhotoSet*                 nflick_photo_set_new (const gchar *name, const gchar *id, gint32 count);
+
+void                            nflick_photo_set_give_list (NFlickPhotoSet *self, GList *list);
+
+NFlickPhotoSet*                 nflick_photo_set_new_no_set (gint32 count);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-pixbuf-fetch-private.h b/attic/aaina/libnflick/nflick-pixbuf-fetch-private.h
new file mode 100644 (file)
index 0000000..460b369
--- /dev/null
@@ -0,0 +1,37 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+struct                          _PixbufFetchHelper 
+{
+        gint32 Width;
+        gint32 Height;
+        GdkPixbufLoader *Loader;
+        FILE *CacheFile;
+} typedef PixbufFetchHelper;
+
+static int                      block_reader (PixbufFetchHelper *helper, gchar *buffer, int len);
+
+static void                     on_size_prepared (GdkPixbufLoader *loader, gint width, gint height, PixbufFetchHelper *helper);
+
+static gchar*                   get_cache_file (const gchar *token);
+
diff --git a/attic/aaina/libnflick/nflick-pixbuf-fetch.c b/attic/aaina/libnflick/nflick-pixbuf-fetch.c
new file mode 100644 (file)
index 0000000..8892907
--- /dev/null
@@ -0,0 +1,172 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-pixbuf-fetch.h"
+#include "nflick-pixbuf-fetch-private.h"
+
+GdkPixbuf*                      nflick_pixbuf_fetch_try_cache (const gchar *token)
+{
+        return NULL;
+}
+
+GdkPixbuf*                      nflick_pixbuf_fetch (const gchar *url, gint32 width, gint32 height, const gchar *cache_token)
+{
+        g_return_val_if_fail (url != NULL, NULL);
+
+        ne_uri *uri = NULL;         /* Neon uri */
+        ne_request *request = NULL; /* Http request */
+        ne_session *session = NULL; /* Neon session */
+        gboolean result = TRUE;     
+        GdkPixbuf *pixbuf = NULL;
+
+        /* Allocate new neon uri */
+        uri = g_new0 (ne_uri, 1);
+        if (uri == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Parse the incoming url into valid neon uri */
+        if (ne_uri_parse (url, uri) || uri->host == NULL || uri->path == NULL) {
+               result = FALSE;
+                goto Done;
+        }
+
+        /* Set defaults. */
+        if (uri->scheme == NULL)
+                uri->scheme = g_strdup ("http");
+        if (uri->port == 0)
+                uri->port = ne_uri_defaultport (uri->scheme);
+
+        /* Create the session */
+        session = ne_session_create (uri->scheme, uri->host, uri->port);
+        if (session == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Create the request */
+        request = ne_request_create (session, "GET", uri->path);
+        if (request == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Allocate our struct */
+        PixbufFetchHelper *helper = g_new0 (PixbufFetchHelper, 1);
+        if (helper == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+        
+        helper->Loader = gdk_pixbuf_loader_new ();
+        if (helper->Loader == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        // Open the cache file if applies...
+        // FIXME: Move this shit as func param
+        
+        if (cache_token != NULL && 1) {
+                gchar *file_name = NULL;
+                file_name = get_cache_file (cache_token);
+                if (file_name != NULL) {
+                        helper->CacheFile = fopen (file_name, "wb");
+                        g_free (file_name);
+                }
+        }
+       
+        g_signal_connect (G_OBJECT (helper->Loader), "size-prepared", (gpointer) on_size_prepared, helper);
+
+        helper->Width = width;
+        helper->Height = height;
+
+        ne_add_response_body_reader (request, ne_accept_always, (gpointer) block_reader, helper);
+
+        result = (ne_request_dispatch (request) == NE_OK) ? TRUE : FALSE;
+
+        if (helper->CacheFile != NULL)
+                fclose (helper->CacheFile);
+        gdk_pixbuf_loader_close (helper->Loader, NULL); 
+        
+        if (result == TRUE) {
+                pixbuf = gdk_pixbuf_loader_get_pixbuf (helper->Loader);
+                if (pixbuf)
+                        g_object_ref (pixbuf);
+        } else {
+                // FIXME: Remove the cached file
+        }
+
+Done:
+        if (uri != NULL) {
+                ne_uri_free (uri);
+                g_free (uri);
+        }
+
+        if (session != NULL)
+                ne_session_destroy (session);
+
+        if (request != NULL)
+                ne_request_destroy (request);
+
+        if (helper != NULL) {
+                if (helper->Loader != NULL)
+                        g_object_unref (helper->Loader);
+                g_free (helper);
+        }
+
+        return pixbuf;
+}
+
+static gchar*                   get_cache_file (const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+
+        return g_build_filename ("cache", token, NULL);
+}
+
+static int                      block_reader (PixbufFetchHelper *helper, gchar *buffer, int len)
+{
+        g_return_val_if_fail (helper != NULL, -1);
+        g_return_val_if_fail (helper->Loader != NULL, -1);
+
+        if (helper->CacheFile != NULL)
+                fwrite (buffer, 1, len, helper->CacheFile);
+
+        gdk_pixbuf_loader_write (helper->Loader, buffer, len, NULL);
+        
+        return 0; 
+}
+
+static void                     on_size_prepared (GdkPixbufLoader *loader, gint width, gint height, PixbufFetchHelper *helper)
+{
+        g_return_if_fail (helper != NULL);
+
+        if (helper->Width == 0 && helper->Height == 0)
+                return;
+
+        if (width != helper->Width && height != helper->Height)
+                gdk_pixbuf_loader_set_size (loader, helper->Width, helper->Height);
+}
+
diff --git a/attic/aaina/libnflick/nflick-pixbuf-fetch.h b/attic/aaina/libnflick/nflick-pixbuf-fetch.h
new file mode 100644 (file)
index 0000000..8def879
--- /dev/null
@@ -0,0 +1,40 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPIXBUFFETCH_H__
+#define __NFLICKPIXBUFFETCH_H__
+
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <ne_uri.h>
+#include <ne_session.h>
+#include <ne_basic.h>
+#include <ne_utils.h>
+#include <string.h>
+#include <stdio.h>
+
+GdkPixbuf*                      nflick_pixbuf_fetch (const gchar *url, int width, int height, const gchar *token);
+
+GdkPixbuf*                      nflick_pixbuf_fetch_try_cache (const gchar *token);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-set-list-response-private.h b/attic/aaina/libnflick/nflick-set-list-response-private.h
new file mode 100644 (file)
index 0000000..0634c58
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickSetListResponsePrivate
+{
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_set_list_response_class_init (NFlickSetListResponseClass *klass);
+
+static void                     nflick_set_list_response_init (NFlickSetListResponse *self);
+
+static gboolean                 private_init (NFlickSetListResponse *self, NFlickSetListResponsePrivate *private);
+
+static void                     private_dispose (NFlickSetListResponsePrivate *private);
+
+static void                     nflick_set_list_response_dispose (NFlickSetListResponse *self);
+
+static void                     nflick_set_list_response_finalize (NFlickSetListResponse *self);
+
+static void                     parse_func (NFlickSetListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_set_list_response_get_property (NFlickSetListResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec);
diff --git a/attic/aaina/libnflick/nflick-set-list-response.c b/attic/aaina/libnflick/nflick-set-list-response.c
new file mode 100644 (file)
index 0000000..abaa761
--- /dev/null
@@ -0,0 +1,212 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-set-list-response.h"
+#include "nflick-set-list-response-private.h"
+
+GType                           nflick_set_list_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickSetListResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_set_list_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickSetListResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_set_list_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickSetListResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_set_list_response_class_init (NFlickSetListResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_set_list_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_set_list_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_set_list_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_set_list_response_init (NFlickSetListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickSetListResponsePrivate *priv = g_new0 (NFlickSetListResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickSetListResponse *self, NFlickSetListResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoSets = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickSetListResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->PhotoSets != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoSets; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                g_object_unref (iterator->data);
+                
+                g_list_free (private->PhotoSets);
+                private->PhotoSets = NULL;
+        }
+}
+
+GList*                          nflick_set_list_response_take_list (NFlickSetListResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoSets;
+        self->Private->PhotoSets = NULL;
+
+        return lst;
+}
+
+static void                     nflick_set_list_response_dispose (NFlickSetListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_set_list_response_finalize (NFlickSetListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickSetListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "photosets") == 0) {
+                        
+                        xmlNode *sets_node = NULL;
+                        for (sets_node = cur_node->children; sets_node; sets_node = sets_node->next) {
+                                
+                                if (sets_node->type == XML_ELEMENT_NODE && strcmp (sets_node->name, "photoset") == 0) {
+
+                                        gchar *id = xmlGetProp (sets_node, "id");
+                                        gchar *count = xmlGetProp (sets_node, "photos");
+                                        gchar *title = NULL;
+                                        gint32 count_val = 0;
+                                        NFlickPhotoSet *photo_set = NULL;
+
+                                        xmlNode *this_node = NULL;
+                                        for (this_node = sets_node->children; this_node; this_node = this_node->next) {
+                                                if (this_node->type == XML_ELEMENT_NODE && strcmp (this_node->name, "title") == 0) {
+                                                        if (title != NULL)
+                                                                g_free (title);
+                                                        title = xmlNodeListGetString (doc, this_node->xmlChildrenNode, 1);
+                                                }
+                                        }
+
+                                        count_val = atoi (count);
+
+                                        if (count_val != 0 &&
+                                            id != NULL &&
+                                            title != NULL)
+                                                photo_set = nflick_photo_set_new (title, id, count_val);
+
+                                        if (photo_set != NULL)
+                                                self->Private->PhotoSets = g_list_append (self->Private->PhotoSets, photo_set);
+
+                                        /* Free */
+                                        if (id != NULL)
+                                                g_free (id);
+                                        if (count != NULL)
+                                                g_free (count);
+                                        if (title != NULL)
+                                                g_free (title);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+static void                     nflick_set_list_response_get_property (NFlickSetListResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-set-list-response.h b/attic/aaina/libnflick/nflick-set-list-response.h
new file mode 100644 (file)
index 0000000..6e0d45d
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSETLISTRESPONSE_H__
+#define __NFLICKSETLISTRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-set.h"
+
+struct                          _NFlickSetListResponse
+{
+        NFlickApiResponse Parent;
+        NFlickSetListResponsePrivate *Private;
+};
+
+struct                          _NFlickSetListResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_set_list_response_get_type (void);
+
+GList*                          nflick_set_list_response_take_list (NFlickSetListResponse *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-set-list-worker-private.h b/attic/aaina/libnflick/nflick-set-list-worker-private.h
new file mode 100644 (file)
index 0000000..7dc1742
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorkerClass*       ParentClass = NULL;
+
+struct                          _NFlickSetListWorkerPrivate
+{
+        gchar *UserNsid;
+        gchar *Token;
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_set_list_worker_class_init (NFlickSetListWorkerClass *klass);
+
+static void                     nflick_set_list_worker_init (NFlickSetListWorker *self);
+
+static gboolean                 private_init (NFlickSetListWorker *self, NFlickSetListWorkerPrivate *priv);
+
+static void                     private_dispose (NFlickSetListWorkerPrivate *priv);
+
+static void                     nflick_set_list_worker_dispose (NFlickSetListWorker *self);
+
+static void                     nflick_set_list_worker_finalize (NFlickSetListWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickSetListWorker *self);
+
+static void                     nflick_set_list_worker_get_property (NFlickSetListWorker *self, guint propid, 
+                                                                     GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-set-list-worker.c b/attic/aaina/libnflick/nflick-set-list-worker.c
new file mode 100644 (file)
index 0000000..024ab1f
--- /dev/null
@@ -0,0 +1,362 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-set-list-worker.h"
+#include "nflick-set-list-worker-private.h"
+
+GType                           nflick_set_list_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickSetListWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_set_list_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickSetListWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_set_list_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickSetListWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_set_list_worker_class_init (NFlickSetListWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_set_list_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_set_list_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_set_list_worker_get_property;
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_set_list_worker_init (NFlickSetListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickSetListWorkerPrivate *priv = g_new0 (NFlickSetListWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Parsing photosets..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickSetListWorker *self, NFlickSetListWorkerPrivate *priv)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_WORKER (self), FALSE);
+        g_return_val_if_fail (priv != NULL, FALSE);
+
+        priv->UserNsid = NULL;
+        priv->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickSetListWorkerPrivate *priv)
+{
+        g_return_if_fail (priv != NULL);
+
+        if (priv->Token != NULL) {
+                g_free (priv->Token);
+                priv->Token = NULL;
+        }
+
+        if (priv->UserNsid != NULL) {
+                g_free (priv->UserNsid);
+                priv->UserNsid = NULL;
+        }
+
+        if (priv->PhotoSets != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = priv->PhotoSets; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                g_object_unref (iterator->data);
+                
+                g_list_free (priv->PhotoSets);
+                priv->PhotoSets = NULL;
+        }
+}
+
+static void                     nflick_set_list_worker_dispose (NFlickSetListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_set_list_worker_finalize (NFlickSetListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickSetListWorker *self)
+{
+        NFlickApiRequest *get_photosets_request = NULL; 
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        NFlickApiResponse *set_list_response = NULL;
+        gchar *first_id = NULL;
+        NFlickPhotoSet *first_set = NULL; /* Do not dispose, it's not reffed */
+        NFlickApiRequest *first_photolist_request = NULL; 
+        NFlickApiResponse *first_photo_list_response = NULL;
+        GList *first_list = NULL;
+        NFlickApiRequest *unsetted_request = NULL; 
+        NFlickApiResponse *unsetted_response = NULL;
+        GList *unsetted_list = NULL;
+        NFlickPhotoSet *unsetted_set = NULL; /* Do not dispose, it's not reffed */
+
+        get_photosets_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_LIST);
+        if (get_photosets_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (get_photosets_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        nflick_api_request_add_parameter (get_photosets_request, 
+                                          NFLICK_FLICKR_API_PARAM_USER_ID, 
+                                          self->Private->UserNsid);
+
+        nflick_api_request_sign (get_photosets_request);
+        if (nflick_api_request_exec (get_photosets_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        set_list_response = nflick_api_response_new_from_request (NFLICK_TYPE_SET_LIST_RESPONSE, get_photosets_request);
+        if (set_list_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, set_list_response) == FALSE)
+                goto Error;
+
+        self->Private->PhotoSets = nflick_set_list_response_take_list ((NFlickSetListResponse *) set_list_response);
+
+        /* Let's fetch information about the unsetted photos */
+        nflick_worker_set_message ((NFlickWorker *) self, gettext ("Parsing photos without set..."));
+
+        unsetted_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOS_NOT_IN_SET);
+        if (unsetted_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (unsetted_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        /* We try to get 500 photos per page. 500 is a maximum value. 
+         * FIXME: We should check if 500 is enough. Someone might have more than 
+         * 500 photos */
+
+        nflick_api_request_add_parameter (unsetted_request, 
+                                          NFLICK_FLICKR_API_PARAM_PER_PAGE,
+                                          "500");
+
+        nflick_api_request_sign (unsetted_request);
+        if (nflick_api_request_exec (unsetted_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        unsetted_response = nflick_api_response_new_from_request (NFLICK_TYPE_NO_SET_RESPONSE, unsetted_request);
+        if (unsetted_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, unsetted_response) == FALSE)
+                goto Error;
+
+        unsetted_list = nflick_no_set_response_take_list ((NFlickNoSetResponse *) unsetted_response);
+        /* FIXME: Here we could expose the "count" property on the PhotoSetResponse and NoSetResponse */
+        unsetted_set = nflick_photo_set_new_no_set (g_list_length (unsetted_list)); 
+        nflick_photo_set_give_list (unsetted_set, unsetted_list);
+
+        /* Append the set to our set list... */
+        self->Private->PhotoSets = g_list_append (self->Private->PhotoSets, 
+                                                   unsetted_set);
+
+        /* If the user has not sets, finish now */
+        if (self->Private->PhotoSets->data == (gpointer) unsetted_set) {
+                goto Done;
+        }
+        /* Now let's try fetching the photos for first photo set */
+        nflick_worker_set_message ((NFlickWorker *) self, gettext ("Loading photoset data..."));
+        
+        GList *sets = self->Private->PhotoSets;
+        GList *set;
+        gint i = g_list_length (sets);
+        
+        for (set = sets; set != NULL; set = set->next) {
+               first_set = (NFlickPhotoSet*)set->data;
+        
+               g_object_get (G_OBJECT (first_set), "id", &first_id, NULL);
+
+               first_photolist_request = nflick_api_request_new
+                                (NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_PHOTOS);
+               if (first_photolist_request == NULL)
+                       goto Error;
+        
+               nflick_api_request_add_parameter (first_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+               nflick_api_request_add_parameter (first_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTOSET_ID, 
+                                          first_id);
+
+               nflick_api_request_sign (first_photolist_request);
+               if (nflick_api_request_exec (first_photolist_request) != TRUE) {
+                       nflick_worker_set_network_error ((NFlickWorker *) self);
+                       g_warning ("Error : %s", first_id);
+               }
+
+               if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                       g_warning ("Abort : %s", first_id);
+
+               first_photo_list_response = nflick_api_response_new_from_request 
+                    (NFLICK_TYPE_PHOTO_LIST_RESPONSE, first_photolist_request);
+               if (first_photo_list_response == NULL)
+                       g_warning ("No photos : %s", first_id);
+
+               if (nflick_worker_parse_api_response ((NFlickWorker*) self, 
+                                       first_photo_list_response) == FALSE)
+                       ;
+
+               first_list = nflick_photo_list_response_take_list
+                       ((NFlickPhotoListResponse *) first_photo_list_response);
+               nflick_photo_set_give_list (first_set, first_list);
+        }
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        g_print ("Abort\n");
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+        g_print ("Error\n");
+Done:
+        if (get_photosets_request != NULL) 
+                g_object_unref (get_photosets_request);
+
+        if (set_list_response != NULL) 
+                g_object_unref (set_list_response);
+
+        if (first_photolist_request != NULL) 
+                g_object_unref (first_photolist_request);
+
+        if (unsetted_response != NULL) 
+                g_object_unref (unsetted_response);
+
+        if (unsetted_request != NULL) 
+                g_object_unref (unsetted_request);
+
+        if (first_photo_list_response != NULL) 
+                g_object_unref (first_photo_list_response);
+
+        if (first_id != NULL)
+                g_free (first_id);
+
+        return status;
+}
+
+NFlickSetListWorker*            nflick_set_list_worker_new (const gchar *usernsid, const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+        g_return_val_if_fail (usernsid != NULL, NULL);
+
+        NFlickSetListWorker *self = g_object_new (NFLICK_TYPE_SET_LIST_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Token = g_strdup (token);
+        self->Private->UserNsid = g_strdup (usernsid);
+        self->Private->PhotoSets = NULL;
+
+        return self;
+}
+
+GList*                          nflick_set_list_worker_take_list (NFlickSetListWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_WORKER (self), NULL);
+
+        GList *lst = self->Private->PhotoSets;
+        self->Private->PhotoSets = NULL;
+
+        return lst;
+}
+
+static void                     nflick_set_list_worker_get_property (NFlickSetListWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-set-list-worker.h b/attic/aaina/libnflick/nflick-set-list-worker.h
new file mode 100644 (file)
index 0000000..d7105c7
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSETLISTWORKER_H__
+#define __NFLICKSETLISTWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-set-list-response.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-types.h"
+#include "nflick-no-set-response.h"
+
+struct                          _NFlickSetListWorker
+{
+        NFlickWorker Parent;
+        NFlickSetListWorkerPrivate *Private;
+};
+
+struct                          _NFlickSetListWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_set_list_worker_get_type (void);
+
+NFlickSetListWorker*            nflick_set_list_worker_new (const gchar *usernsid, const gchar *token);
+
+GList*                          nflick_set_list_worker_take_list (NFlickSetListWorker *self);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-show-worker-private.h b/attic/aaina/libnflick/nflick-show-worker-private.h
new file mode 100644 (file)
index 0000000..417fa75
--- /dev/null
@@ -0,0 +1,57 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickShowWorkerPrivate
+{
+        gchar *PhotoId;
+        gchar *Token;
+        gint32 Width;
+        gint32 Height;
+        GdkPixbuf *Pixbuf;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_PIXBUF,
+};
+
+static void                     nflick_show_worker_class_init (NFlickShowWorkerClass *klass);
+
+static void                     nflick_show_worker_init (NFlickShowWorker *self);
+
+static gboolean                 private_init (NFlickShowWorker *self, NFlickShowWorkerPrivate *private);
+
+static void                     private_dispose (NFlickShowWorkerPrivate *private);
+
+static void                     nflick_show_worker_dispose (NFlickShowWorker *self);
+
+static void                     nflick_show_worker_finalize (NFlickShowWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickShowWorker *self);
+
+static void                     nflick_show_worker_get_property (NFlickShowWorker *self, guint propid, 
+                                                                GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-show-worker.c b/attic/aaina/libnflick/nflick-show-worker.c
new file mode 100644 (file)
index 0000000..e2ab692
--- /dev/null
@@ -0,0 +1,264 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-show-worker.h"
+#include "nflick-show-worker-private.h"
+
+GType                           nflick_show_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickShowWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_show_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickShowWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_show_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickShowWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_show_worker_class_init (NFlickShowWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_show_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_show_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_show_worker_get_property;
+
+        g_object_class_install_property (gobjectclass, ARG_PIXBUF,
+                                         g_param_spec_object 
+                                         ("pixbuf", "Pixbuf", "Pixbuf",
+                                         GDK_TYPE_PIXBUF, G_PARAM_READABLE));
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_show_worker_init (NFlickShowWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickShowWorkerPrivate *priv = g_new0 (NFlickShowWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, 
+                                           gettext ("Loading photo..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickShowWorker *self, NFlickShowWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_SHOW_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoId = NULL;
+        private->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickShowWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->PhotoId != NULL) {
+                g_free (private->PhotoId);
+                private->PhotoId = NULL;
+        }
+
+        if (private->Pixbuf != NULL) {
+                g_object_unref (private->Pixbuf);
+                private->Pixbuf = NULL;
+        }
+}
+
+static void                     nflick_show_worker_dispose (NFlickShowWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_show_worker_finalize (NFlickShowWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickShowWorker *self)
+{
+        NFlickApiRequest *get_sizes_request = NULL; 
+        NFlickApiResponse *get_sizes_response = NULL;
+        gchar *uri = NULL;
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        gdouble vbox_aspect = (gdouble) self->Private->Width / (gdouble) self->Private->Height;
+        gdouble pixbuf_aspect = -1;
+        gint32 final_width = -1;
+        gint32 final_height = -1;
+        gboolean rotated = FALSE;
+
+        get_sizes_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOS_GET_SIZES);
+        if (get_sizes_request == NULL)
+                goto Error;
+
+        /*nflick_api_request_add_parameter (get_sizes_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+        */
+        nflick_api_request_add_parameter (get_sizes_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTO_ID, 
+                                          self->Private->PhotoId);
+
+        nflick_api_request_sign (get_sizes_request);
+        if (nflick_api_request_exec (get_sizes_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        get_sizes_response = nflick_api_response_new_from_request (NFLICK_TYPE_GET_SIZES_RESPONSE, get_sizes_request);
+        if (get_sizes_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, get_sizes_response) == FALSE)
+                goto Error;
+
+        final_width = self->Private->Width;
+        final_height = self->Private->Height;
+
+        uri = nflick_get_sizes_response_find_match ((NFlickGetSizesResponse *) get_sizes_response, 
+                                                    &final_width, &final_height, &rotated);
+
+        if (uri == NULL)
+                goto Error;
+
+        self->Private->Pixbuf = nflick_pixbuf_fetch (uri, final_width, final_height, NULL);
+        if (self->Private->Pixbuf == NULL)
+                goto Error;
+
+        if (rotated == TRUE) {
+                GdkPixbuf *pxbuf = gdk_pixbuf_rotate_simple (self->Private->Pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
+                if (pxbuf != NULL) {
+                        g_object_unref (self->Private->Pixbuf);
+                        self->Private->Pixbuf = pxbuf;
+                }
+        }
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (get_sizes_request != NULL) 
+                g_object_unref (get_sizes_request);
+
+        if (get_sizes_response != NULL) 
+                g_object_unref (get_sizes_response);
+
+        if (uri != NULL)
+                g_free (uri);
+
+        return status;
+}
+
+NFlickShowWorker*               nflick_show_worker_new (const gchar *photoid, gint32 width, gint32 height, const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+        g_return_val_if_fail (photoid != NULL, NULL);
+
+        NFlickShowWorker *self = g_object_new (NFLICK_TYPE_SHOW_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Token = g_strdup (token);
+        self->Private->PhotoId= g_strdup (photoid);
+        self->Private->Width = width;
+        self->Private->Height = height;
+
+        return self;
+}
+
+static void                     nflick_show_worker_get_property (NFlickShowWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+               
+                case ARG_PIXBUF:
+                        g_value_set_object (value, self->Private->Pixbuf);
+                break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-show-worker.h b/attic/aaina/libnflick/nflick-show-worker.h
new file mode 100644 (file)
index 0000000..a17faf9
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSHOWWORKER_H__
+#define __NFLICKSHOWWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-get-sizes-response.h"
+#include "nflick-set-list-response.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-types.h"
+#include "nflick-pixbuf-fetch.h"
+
+struct                          _NFlickShowWorker
+{
+        NFlickWorker Parent;
+        NFlickShowWorkerPrivate *Private;
+};
+
+struct                          _NFlickShowWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_show_worker_get_type (void);
+
+NFlickShowWorker*               nflick_show_worker_new (const gchar *photoid, gint32 width, gint32 height, const gchar *token);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-types.h b/attic/aaina/libnflick/nflick-types.h
new file mode 100644 (file)
index 0000000..11566cd
--- /dev/null
@@ -0,0 +1,591 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKTYPES_H__
+#define __NFLICKTYPES_H__
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+/* Window */
+
+typedef struct                  _NFlickWindowClass NFlickWindowClass;
+
+typedef struct                  _NFlickWindow NFlickWindow;
+
+typedef struct                  _NFlickWindowPrivate NFlickWindowPrivate;
+
+#define                         NFLICK_TYPE_WINDOW (nflick_window_get_type ())
+
+#define                         NFLICK_IS_WINDOW(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WINDOW))
+
+#define                         NFLICK_WINDOW(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WINDOW, NFlickWindow))
+
+#define                         NFLICK_WINDOW_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WINDOW, NFlickWindowClass))
+
+/* Wait dialog */
+
+#define                         NFLICK_WAIT_DIALOG_RESPONSE_ABORTED 1000
+
+#define                         NFLICK_WAIT_DIALOG_RESPONSE_ERROR 1001
+
+#define                         NFLICK_WAIT_DIALOG_RESPONSE_OK 1002
+
+typedef struct                  _NFlickWaitDialogClass NFlickWaitDialogClass;
+
+typedef struct                  _NFlickWaitDialog NFlickWaitDialog;
+
+typedef struct                  _NFlickWaitDialogPrivate NFlickWaitDialogPrivate;
+
+#define                         NFLICK_TYPE_WAIT_DIALOG (nflick_wait_dialog_get_type ())
+
+#define                         NFLICK_IS_WAIT_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WAIT_DIALOG))
+
+#define                         NFLICK_WAIT_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WAIT_DIALOG, NFlickWaitDialog))
+
+#define                         NFLICK_WAIT_DIALOG_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WAIT_DIALOG, NFlickWaitDialogClass))
+
+/* Token dialog */
+
+typedef struct                  _NFlickTokenDialogClass NFlickTokenDialogClass;
+
+typedef struct                  _NFlickTokenDialog NFlickTokenDialog;
+
+typedef struct                  _NFlickTokenDialogPrivate NFlickTokenDialogPrivate;
+
+#define                         NFLICK_TYPE_TOKEN_DIALOG (nflick_token_dialog_get_type ())
+
+#define                         NFLICK_IS_TOKEN_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_TOKEN_DIALOG))
+
+#define                         NFLICK_TOKEN_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_TOKEN_DIALOG, NFlickTokenDialog))
+
+#define                         NFLICK_TOKEN_DIALOG_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_TOKEN_DIALOG, NFlickTokenDialogClass))
+
+/* Cache dialog */
+
+typedef struct                  _NFlickCacheDialogClass NFlickCacheDialogClass;
+
+typedef struct                  _NFlickCacheDialog NFlickCacheDialog;
+
+typedef struct                  _NFlickCacheDialogPrivate NFlickCacheDialogPrivate;
+
+#define                         NFLICK_TYPE_CACHE_DIALOG (nflick_cache_dialog_get_type ())
+
+#define                         NFLICK_IS_CACHE_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_CACHE_DIALOG))
+
+#define                         NFLICK_CACHE_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_CACHE_DIALOG, NFlickCacheDialog))
+
+#define                         NFLICK_CACHE_DIALOG_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_CACHE_DIALOG, NFlickCacheDialogClass))
+
+/* Welcome VBox */
+
+typedef struct                  _NFlickWelcomeVBoxClass NFlickWelcomeVBoxClass;
+
+typedef struct                  _NFlickWelcomeVBox NFlickWelcomeVBox;
+
+typedef struct                  _NFlickWelcomeVBoxPrivate NFlickWelcomeVBoxPrivate;
+
+#define                         NFLICK_TYPE_WELCOME_VBOX (nflick_welcome_vbox_get_type ())
+
+#define                         NFLICK_IS_WELCOME_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WELCOME_VBOX))
+
+#define                         NFLICK_WELCOME_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WELCOME_VBOX, NFlickWelcomeVBox)
+
+#define                         NFLICK_WELCOME_VBOX_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WELCOME_VBOX, NFlickWelcomeVBoxClass))
+
+/* Show VBox */
+
+typedef struct                  _NFlickShowVBoxClass NFlickShowVBoxClass;
+
+typedef struct                  _NFlickShowVBox NFlickShowVBox;
+
+typedef struct                  _NFlickShowVBoxPrivate NFlickShowVBoxPrivate;
+
+#define                         NFLICK_TYPE_SHOW_VBOX (nflick_show_vbox_get_type ())
+
+#define                         NFLICK_IS_SHOW_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SHOW_VBOX))
+
+#define                         NFLICK_SHOW_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SHOW_VBOX, NFlickShowVBox)
+
+#define                         NFLICK_SHOW_VBOX_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SHOW_VBOX, NFlickShowVBoxClass))
+
+/* Worker */
+
+typedef struct                  _NFlickWorkerClass NFlickWorkerClass;
+
+typedef struct                  _NFlickWorker NFlickWorker;
+
+typedef struct                  _NFlickWorkerPrivate NFlickWorkerPrivate;
+
+#define                         NFLICK_TYPE_WORKER (nflick_worker_get_type ())
+
+#define                         NFLICK_IS_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WORKER))
+
+#define                         NFLICK_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WORKER, NFlickWorker)
+
+#define                         NFLICK_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WORKER, NFlickWorkerClass))
+
+enum                            
+{
+        NFLICK_WORKER_STATUS_IDLE,
+        NFLICK_WORKER_STATUS_OK,
+        NFLICK_WORKER_STATUS_ABORTED,
+        NFLICK_WORKER_STATUS_RUNNING,
+        NFLICK_WORKER_STATUS_ERROR
+
+}                               typedef NFlickWorkerStatus;
+
+typedef                         NFlickWorkerStatus (*NFlickWorkerThreadFunc) (NFlickWorker *self);
+
+typedef                         gboolean (*NFlickWorkerIdleFunc) (NFlickWorker *self);
+
+/* Api request */
+
+typedef struct                  _NFlickApiRequestClass NFlickApiRequestClass;
+
+typedef struct                  _NFlickApiRequest NFlickApiRequest;
+
+typedef struct                  _NFlickApiRequestPrivate NFlickApiRequestPrivate;
+
+#define                         NFLICK_TYPE_API_REQUEST (nflick_api_request_get_type ())
+
+#define                         NFLICK_IS_API_REQUEST(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_API_REQUEST))
+
+#define                         NFLICK_API_REQUEST(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_API_REQUEST, NFlickApiRequest)
+
+#define                         NFLICK_API_REQUEST_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_API_REQUEST, NFlickApiRequestClass))
+
+/* Api response */
+
+typedef struct                  _NFlickApiResponseClass NFlickApiResponseClass;
+
+typedef struct                  _NFlickApiResponse NFlickApiResponse;
+
+typedef struct                  _NFlickApiResponsePrivate NFlickApiResponsePrivate;
+
+#define                         NFLICK_TYPE_API_RESPONSE (nflick_api_response_get_type ())
+
+#define                         NFLICK_IS_API_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_API_RESPONSE))
+
+#define                         NFLICK_API_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_API_RESPONSE, NFlickApiResponse)
+
+typedef                         void (*NFlickApiRequestParseFunc) \
+                                (NFlickApiResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+#define                         NFLICK_API_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_API_RESPONSE, NFlickApiResponseClass))
+
+/* Gft response */
+
+typedef struct                  _NFlickGftResponseClass NFlickGftResponseClass;
+
+typedef struct                  _NFlickGftResponse NFlickGftResponse;
+
+typedef struct                  _NFlickGftResponsePrivate NFlickGftResponsePrivate;
+
+#define                         NFLICK_TYPE_GFT_RESPONSE (nflick_gft_response_get_type ())
+
+#define                         NFLICK_IS_GFT_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_GFT_RESPONSE))
+
+#define                         NFLICK_GFT_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_GFT_RESPONSE, NFlickGftResponse)
+
+#define                         NFLICK_GFT_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_GFT_RESPONSE, NFlickGftResponseClass))
+                                
+                                /* Info response */
+
+typedef struct                  _NFlickInfoResponseClass NFlickInfoResponseClass;
+
+typedef struct                  _NFlickInfoResponse NFlickInfoResponse;
+
+typedef struct                  _NFlickInfoResponsePrivate NFlickInfoResponsePrivate;
+
+#define                         NFLICK_TYPE_INFO_RESPONSE (nflick_info_response_get_type ())
+
+#define                         NFLICK_IS_INFO_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_INFO_RESPONSE))
+
+#define                         NFLICK_INFO_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+                                NFLICK_TYPE_INFO_RESPONSE, NFlickInfoResponse)
+
+#define                         NFLICK_INFO_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_INFO_RESPONSE, NFlickInfoResponseClass))
+
+/* Photo set */
+
+typedef struct                  _NFlickPhotoSetClass NFlickPhotoSetClass;
+
+typedef struct                  _NFlickPhotoSet NFlickPhotoSet;
+
+typedef struct                  _NFlickPhotoSetPrivate NFlickPhotoSetPrivate;
+
+#define                         NFLICK_TYPE_PHOTO_SET (nflick_photo_set_get_type ())
+
+#define                         NFLICK_IS_PHOTO_SET(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_SET))
+
+#define                         NFLICK_PHOTO_SET(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_SET, NFlickPhotoSet)
+
+#define                         NFLICK_PHOTO_SET_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_SET, NFlickPhotoSetClass))
+
+/* Thmb table */
+
+typedef struct                  _NFlickThmbTableClass NFlickThmbTableClass;
+
+typedef struct                  _NFlickThmbTable NFlickThmbTable;
+
+typedef struct                  _NFlickThmbTablePrivate NFlickThmbTablePrivate;
+
+#define                         NFLICK_TYPE_THMB_TABLE (nflick_thmb_table_get_type ())
+
+#define                         NFLICK_IS_THMB_TABLE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_THMB_TABLE))
+
+#define                         NFLICK_THMB_TABLE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_THMB_TABLE, NFlickThmbTable)
+
+#define                         NFLICK_THMB_TABLE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_THMB_TABLE, NFlickThmbTableClass))
+
+/* Thmb image */
+
+typedef struct                  _NFlickThmbImageClass NFlickThmbImageClass;
+
+typedef struct                  _NFlickThmbImage NFlickThmbImage;
+
+typedef struct                  _NFlickThmbImagePrivate NFlickThmbImagePrivate;
+
+#define                         NFLICK_TYPE_THMB_IMAGE (nflick_thmb_image_get_type ())
+
+#define                         NFLICK_IS_THMB_IMAGE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_THMB_IMAGE))
+
+#define                         NFLICK_THMB_IMAGE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_THMB_IMAGE, NFlickThmbImage)
+
+#define                         NFLICK_THMB_IMAGE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_THMB_IMAGE, NFlickThmbImageClass))
+
+/* Set list response */
+
+typedef struct                  _NFlickSetListResponseClass NFlickSetListResponseClass;
+
+typedef struct                  _NFlickSetListResponse NFlickSetListResponse;
+
+typedef struct                  _NFlickSetListResponsePrivate NFlickSetListResponsePrivate;
+
+#define                         NFLICK_TYPE_SET_LIST_RESPONSE (nflick_set_list_response_get_type ())
+
+#define                         NFLICK_IS_SET_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SET_LIST_RESPONSE))
+
+#define                         NFLICK_SET_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SET_LIST_RESPONSE, NFlickSetListResponse)
+
+#define                         NFLICK_SET_LIST_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SET_LIST_RESPONSE, NFlickSetListResponseClass))
+                                
+                                
+/* Photo search response */
+
+typedef struct                  _NFlickPhotoSearchResponseClass NFlickPhotoSearchResponseClass;
+
+typedef struct                  _NFlickPhotoSearchResponse NFlickPhotoSearchResponse;
+
+typedef struct                  _NFlickPhotoSearchResponsePrivate NFlickPhotoSearchResponsePrivate;
+
+#define NFLICK_TYPE_PHOTO_SEARCH_RESPONSE (nflick_photo_search_response_get_type ())
+
+#define                         NFLICK_IS_PHOTO_SEARCH_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_SEARCH_RESPONSE))
+
+#define                         NFLICK_PHOTO_SEARCH_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_SEARCH_RESPONSE, NFlickPhotoSearchResponse)
+
+#define                         NFLICK_PHOTO_SEARCH_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_SEARCH_RESPONSE, NFlickPhotoSearchResponseClass))
+
+/* Photo list response */
+
+typedef struct                  _NFlickPhotoListResponseClass NFlickPhotoListResponseClass;
+
+typedef struct                  _NFlickPhotoListResponse NFlickPhotoListResponse;
+
+typedef struct                  _NFlickPhotoListResponsePrivate NFlickPhotoListResponsePrivate;
+
+#define                         NFLICK_TYPE_PHOTO_LIST_RESPONSE (nflick_photo_list_response_get_type ())
+
+#define                         NFLICK_IS_PHOTO_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_LIST_RESPONSE))
+
+#define                         NFLICK_PHOTO_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_LIST_RESPONSE, NFlickPhotoListResponse)
+
+#define                         NFLICK_PHOTO_LIST_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_LIST_RESPONSE, NFlickPhotoListResponseClass))
+
+/* No set response */
+
+typedef struct                  _NFlickNoSetResponseClass NFlickNoSetResponseClass;
+
+typedef struct                  _NFlickNoSetResponse NFlickNoSetResponse;
+
+typedef struct                  _NFlickNoSetResponsePrivate NFlickNoSetResponsePrivate;
+
+#define                         NFLICK_TYPE_NO_SET_RESPONSE (nflick_no_set_response_get_type ())
+
+#define                         NFLICK_IS_NO_SET_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_NO_SET_RESPONSE))
+
+#define                         NFLICK_NO_SET_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_NO_SET_RESPONSE, NFlickNoSetResponse)
+
+#define                         NFLICK_NO_SET_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_NO_SET_RESPONSE, NFlickNoSetResponseClass))
+
+/* GetSizes response */
+
+typedef struct                  _NFlickGetSizesResponseClass NFlickGetSizesResponseClass;
+
+typedef struct                  _NFlickGetSizesResponse NFlickGetSizesResponse;
+
+typedef struct                  _NFlickGetSizesResponsePrivate NFlickGetSizesResponsePrivate;
+
+#define                         NFLICK_TYPE_GET_SIZES_RESPONSE (nflick_get_sizes_response_get_type ())
+
+#define                         NFLICK_IS_GET_SIZES_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_GET_SIZES_RESPONSE))
+
+#define                         NFLICK_GET_SIZES_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_GET_SIZES_RESPONSE, NFlickGetSizesResponse)
+
+#define                         NFLICK_GET_SIZES_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_GET_SIZES_RESPONSE, NFlickGetSizesResponseClass))
+
+/* Auth worker */
+
+typedef struct                  _NFlickAuthWorkerClass NFlickAuthWorkerClass;
+
+typedef struct                  _NFlickAuthWorker NFlickAuthWorker;
+
+typedef struct                  _NFlickAuthWorkerPrivate NFlickAuthWorkerPrivate;
+
+#define                         NFLICK_TYPE_AUTH_WORKER (nflick_auth_worker_get_type ())
+
+#define                         NFLICK_IS_AUTH_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_AUTH_WORKER))
+
+#define                         NFLICK_AUTH_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_AUTH_WORKER, NFlickAuthWorker)
+
+#define                         NFLICK_AUTH_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_AUTH_WORKER, NFlickAuthWorkerClass))
+
+/* Show worker */
+
+typedef struct                  _NFlickShowWorkerClass NFlickShowWorkerClass;
+
+typedef struct                  _NFlickShowWorker NFlickShowWorker;
+
+typedef struct                  _NFlickShowWorkerPrivate NFlickShowWorkerPrivate;
+
+#define                         NFLICK_TYPE_SHOW_WORKER (nflick_show_worker_get_type ())
+
+#define                         NFLICK_IS_SHOW_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SHOW_WORKER))
+
+#define                         NFLICK_SHOW_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SHOW_WORKER, NFlickShowWorker)
+
+#define                         NFLICK_SHOW_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SHOW_WORKER, NFlickShowWorkerClass))
+
+/* Set worker */
+
+typedef struct                  _NFlickSetListWorkerClass NFlickSetListWorkerClass;
+
+typedef struct                  _NFlickSetListWorker NFlickSetListWorker;
+
+typedef struct                  _NFlickSetListWorkerPrivate NFlickSetListWorkerPrivate;
+
+#define                         NFLICK_TYPE_SET_LIST_WORKER (nflick_set_list_worker_get_type ())
+
+#define                         NFLICK_IS_SET_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SET_LIST_WORKER))
+
+#define                         NFLICK_SET_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SET_LIST_WORKER, NFlickSetListWorker)
+
+#define                         NFLICK_SET_LIST_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SET_LIST_WORKER, NFlickSetListWorkerClass))
+                                
+                                
+                                /* Info worker */
+
+typedef struct                  _NFlickInfoWorkerClass NFlickInfoWorkerClass;
+
+typedef struct                  _NFlickInfoWorker NFlickInfoWorker;
+
+typedef struct                  _NFlickInfoWorkerPrivate NFlickInfoWorkerPrivate;
+
+#define                         NFLICK_TYPE_INFO_WORKER (nflick_info_worker_get_type ())
+
+#define                         NFLICK_IS_INFO_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_INFO_WORKER))
+
+#define                         NFLICK_INFO_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_INFO_WORKER, NFlickInfoWorker)
+
+#define                         NFLICK_INFO_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_INFO_WORKER, NFlickInfoWorkerClass))
+/* Photo search worked */
+#define                         NFLICK_TYPE_PHOTO_SEARCH_WORKER (nflick_photo_search_worker_get_type ())
+
+#define                         NFLICK_IS_PHOTO_SEARCH_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_SEARCH_WORKER))
+
+#define  NFLICK_PHOTO_SEARCH_WORKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+        NFLICK_TYPE_PHOTO_SEARCH_WORKER, NFlickPhotoSearchWorker))
+
+#define                         NFLICK_PHOTO_SEARCH_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_SEARCH_WORKER, NFlickPhotoSearchWorkerClass))
+
+/* Photo list worker */
+
+typedef struct                  _NFlickPhotoListWorkerClass NFlickPhotoListWorkerClass;
+
+typedef struct                  _NFlickPhotoListWorker NFlickPhotoListWorker;
+
+typedef struct                  _NFlickPhotoListWorkerPrivate NFlickPhotoListWorkerPrivate;
+
+#define                         NFLICK_TYPE_PHOTO_LIST_WORKER (nflick_photo_list_worker_get_type ())
+
+#define                         NFLICK_IS_PHOTO_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_LIST_WORKER))
+
+#define                         NFLICK_PHOTO_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_LIST_WORKER, NFlickPhotoListWorker)
+
+#define                         NFLICK_PHOTO_LIST_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_LIST_WORKER, NFlickPhotoListWorkerClass))
+
+/* Photos vbox */
+
+typedef struct                  _NFlickPhotosVBoxClass NFlickPhotosVBoxClass;
+
+typedef struct                  _NFlickPhotosVBox NFlickPhotosVBox;
+
+typedef struct                  _NFlickPhotosVBoxPrivate NFlickPhotosVBoxPrivate;
+
+#define                         NFLICK_TYPE_PHOTOS_VBOX (nflick_photos_vbox_get_type ())
+
+#define                         NFLICK_IS_PHOTOS_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTOS_VBOX))
+
+#define                         NFLICK_PHOTOS_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTOS_VBOX, NFlickPhotosVBox)
+
+#define                         NFLICK_PHOTOS_VBOX_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTOS_VBOX, NFlickPhotosVBoxClass))
+
+/* Set Combo */
+
+typedef struct                  _NFlickSetComboClass NFlickSetComboClass;
+
+typedef struct                  _NFlickSetCombo NFlickSetCombo;
+
+typedef struct                  _NFlickSetComboPrivate NFlickSetComboPrivate;
+
+#define                         NFLICK_TYPE_SET_COMBO (nflick_set_combo_get_type ())
+
+#define                         NFLICK_IS_SET_COMBO(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SET_COMBO))
+
+#define                         NFLICK_SET_COMBO(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SET_COMBO, NFlickSetCombo)
+
+#define                         NFLICK_SET_COMBO_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SET_COMBO, NFlickSetComboClass))
+
+/* Processor */
+
+typedef                         void (*NFlickProcessorFreeFunc) (gpointer data);
+
+typedef                         gboolean (*NFlickProcessorJobFunc) (gpointer data, gchar **error);
+
+typedef                         gboolean (*NFlickProcessorErrorFunc) (gchar *msg);
+
+typedef                         gboolean (*NFlickProcessorDoneFunc) (gpointer data);
+
+typedef struct                  _NFlickProcessorResult NFlickProcessorResult;
+
+/* Model */
+
+typedef struct                  _NFlickModel NFlickModel;
+
+/* Photo data */
+
+typedef struct                  _NFlickPhotoData NFlickPhotoData;
+
+#define                         NFLICK_TYPE_PHOTO_DATA (nflick_photo_data_get_type ())
+
+typedef struct {
+       gchar *id;
+       gchar *title;
+       gchar *user;
+} FlickrPhoto;
+
+/* End */
+
+#endif
diff --git a/attic/aaina/libnflick/nflick-worker-private.h b/attic/aaina/libnflick/nflick-worker-private.h
new file mode 100644 (file)
index 0000000..884f364
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObject*                 ParentClass = NULL;
+
+struct                          _NFlickWorkerPrivate
+{
+        GThread *Thread;
+        gboolean Started;
+        GMutex *Mutex;
+        NFlickWorkerStatus Status;
+        gchar *Error;
+        gchar *Message;
+
+        NFlickWorkerIdleFunc AbortedIdle;
+        NFlickWorkerIdleFunc OkIdle;
+        NFlickWorkerIdleFunc ErrorIdle;
+        NFlickWorkerIdleFunc MsgChangeIdle;
+        gpointer CustomData;
+        
+        gboolean AbortRequested;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_ERROR,
+        ARG_MESSAGE,
+        ARG_STATUS
+};
+
+#define                         WORKER_LOCK(obj) (g_mutex_lock (obj->Private->Mutex))
+
+#define                         WORKER_UNLOCK(obj) (g_mutex_unlock (obj->Private->Mutex))
+
+static void                     nflick_worker_class_init (NFlickWorkerClass *klass);
+
+static void                     nflick_worker_init (NFlickWorker *self);
+
+static gboolean                 private_init (NFlickWorker *self, NFlickWorkerPrivate *private);
+
+static void                     private_dispose (NFlickWorkerPrivate *private);
+
+static void                     nflick_worker_dispose (NFlickWorker *self);
+
+static void                     nflick_worker_finalize (NFlickWorker *self);
+
+static void                     thread_start (NFlickWorker *self);
+
+static void                     set_error_no_lock (NFlickWorker *self, const gchar *error);
+
+static void                     nflick_worker_get_property (NFlickWorker *self, guint propid, 
+                                                            GValue *value, GParamSpec *pspec);
+
diff --git a/attic/aaina/libnflick/nflick-worker.c b/attic/aaina/libnflick/nflick-worker.c
new file mode 100644 (file)
index 0000000..b618a72
--- /dev/null
@@ -0,0 +1,454 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-worker.h"
+#include "nflick-worker-private.h"
+
+GType                           nflick_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_worker_init,
+                };
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_worker_class_init (NFlickWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_worker_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_ERROR,
+                                         g_param_spec_string
+                                         ("error", "Error", "Message describing the error",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_STATUS,
+                                         g_param_spec_int 
+                                         ("status", "Status", "Current worker status",
+                                         -5000, 5000, NFLICK_WORKER_STATUS_IDLE, G_PARAM_READABLE));
+        /* FIXME Use actual max/min vals for int */
+                                         
+        g_object_class_install_property (gobjectclass, ARG_MESSAGE,
+                                         g_param_spec_string
+                                         ("message", "Message", "Message describing the thread status",
+                                         NULL, G_PARAM_READABLE));
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+
+        klass->ThreadFunc = NULL;
+}
+
+static void                     nflick_worker_init (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickWorkerPrivate *priv = g_new0 (NFlickWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickWorker *self, NFlickWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Thread = NULL;
+
+        private->Mutex = g_mutex_new ();
+        g_return_val_if_fail (private->Mutex != NULL, FALSE);
+
+        private->Started = FALSE;
+        private->Status = NFLICK_WORKER_STATUS_IDLE;
+        private->Error = NULL;
+        private->AbortRequested = FALSE;
+        
+        /* Null the idle functions */
+        private->OkIdle = NULL;
+        private->AbortedIdle = NULL;
+        private->MsgChangeIdle = NULL;
+        private->ErrorIdle = NULL;
+        private->CustomData = NULL;
+        
+        /* Initialize the message to a stubby one */
+        private->Message = g_strdup (gettext ("Working..."));
+        
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Thread != NULL) {
+                g_thread_join (private->Thread);
+                private->Thread = NULL;
+        }
+
+        if (private->Mutex != NULL) {
+                g_mutex_free (private->Mutex);
+                private->Mutex = NULL;
+        }
+
+        if (private->Error != NULL) {
+                g_free (private->Error);
+                private->Error = NULL;
+        }
+
+        if (private->Message != NULL) {
+                g_free (private->Message);
+                private->Message = NULL;
+        }
+}
+
+void                            nflick_worker_start (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        WORKER_LOCK (self);
+        if (self->Private->Started == TRUE) {
+                g_warning ("Worker was already started");
+        } else {
+                self->Private->Thread = g_thread_create ((GThreadFunc) thread_start, self, TRUE, NULL);
+                /* FIXME Check for NULL */
+        }
+
+        WORKER_UNLOCK (self);
+}
+
+static void                     thread_start (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        WORKER_LOCK (self);
+
+        /* Get the class and call the proper function */
+        NFlickWorkerClass *klass = (NFlickWorkerClass *) G_OBJECT_GET_CLASS (self);
+        g_assert (klass != NULL);
+
+        if (klass->ThreadFunc == NULL) {
+                g_warning ("No thread func");
+                set_error_no_lock (self, gettext ("Internal threading error, no thread function. "
+                                                  "Please file a bug report."));
+                self->Private->Status = NFLICK_WORKER_STATUS_ERROR;
+                
+                if (self->Private->ErrorIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->ErrorIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+                                    
+
+                WORKER_UNLOCK (self);
+                goto Done;
+        }
+
+        self->Private->Status = NFLICK_WORKER_STATUS_RUNNING;
+        WORKER_UNLOCK (self);
+
+        /* Here we're waiting, waiting, waiting... */
+        NFlickWorkerStatus status = klass->ThreadFunc (self);
+        
+        WORKER_LOCK (self);
+        
+        /* Our last chance for an abort */
+        if (self->Private->AbortRequested == TRUE)
+                status = NFLICK_WORKER_STATUS_ABORTED;
+        
+        self->Private->Status = status;
+        
+        switch (status) {
+                
+                case NFLICK_WORKER_STATUS_RUNNING:
+                case NFLICK_WORKER_STATUS_IDLE:
+                self->Private->Status = NFLICK_WORKER_STATUS_ERROR;
+                set_error_no_lock (self, gettext ("Internal threading error, thread in running after function done. "
+                                                  "Please file a bug report."));
+                /* Fire error func */
+                if (self->Private->ErrorIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->ErrorIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+                break;
+                
+                case NFLICK_WORKER_STATUS_ERROR:
+                if (self->Private->Error == NULL)
+                        set_error_no_lock (self, gettext ("Error in thread, but no error was set. "
+                                                          "Please file a bug report."));
+                /* Fire error func */
+                if (self->Private->ErrorIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->ErrorIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+                break;
+                
+                case NFLICK_WORKER_STATUS_OK:
+                /* Fire ok func */
+                if (self->Private->OkIdle != NULL) 
+                        /*g_idle_add ((GSourceFunc) self->Private->OkIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);*/
+                       g_timeout_add_full (G_PRIORITY_HIGH_IDLE,
+                                            1000,
+                                            (GSourceFunc) self->Private->OkIdle,
+                                            (self->Private->CustomData 
+                                            != NULL) ? self->Private->CustomData 
+                                               : self,
+                                            NULL);
+
+                break;
+                
+                case NFLICK_WORKER_STATUS_ABORTED:
+                /* Fire aborted func */
+                if (self->Private->AbortedIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->AbortedIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+
+                break;
+        }
+        
+        WORKER_UNLOCK (self);
+
+        Done:
+        return;
+}
+
+static void                     set_error_no_lock (NFlickWorker *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        if (self->Private->Error != NULL)
+                g_free (self->Private->Error);
+
+        self->Private->Error = g_strdup (error);
+}
+
+void                            nflick_worker_set_message (NFlickWorker *self, const gchar *msg)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        WORKER_LOCK (self);
+        if (self->Private->Message != NULL)
+                g_free (self->Private->Message);
+        
+        self->Private->Message = g_strdup (msg);
+        
+        /* Notify */
+        if (self->Private->MsgChangeIdle != NULL) 
+                g_idle_add ((GSourceFunc) self->Private->MsgChangeIdle, 
+                            (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+        
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_network_error (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        nflick_worker_set_error (self, gettext ("A network error occured while trying to connect to flickr. "
+                                                "Please check your connection settings."));
+}
+
+gboolean                        nflick_worker_parse_api_response (NFlickWorker *self, NFlickApiResponse *response)
+{
+        g_return_val_if_fail (NFLICK_IS_WORKER (self), FALSE);
+        g_return_val_if_fail (NFLICK_IS_API_RESPONSE (response), FALSE);
+
+        gboolean success = FALSE;
+
+        g_object_get (G_OBJECT (response), "success", &success, NULL);
+
+        if (success == TRUE)
+                return TRUE;
+        else {
+                gboolean parse_error = FALSE;
+                gchar *error = NULL;
+
+                g_object_get (G_OBJECT (response), "error", &error, "parseerror", &parse_error, NULL);
+                
+                if (parse_error == TRUE) {
+                        gchar *e = g_strdup_printf ("%s\n\n%s", 
+                                                    gettext ("An error occurred while parsing the flickr api response. "
+                                                             "Please file a bug report. Error details: "), error);
+                        nflick_worker_set_error (self, e);
+                        if (e != NULL)
+                                g_free (e);
+                } else 
+                        nflick_worker_set_error (self, error);
+                
+                if (error != NULL)
+                        g_free (error);
+
+                return FALSE;
+        }
+}
+
+void                            nflick_worker_set_error (NFlickWorker *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        g_return_if_fail (error != NULL);
+
+        WORKER_LOCK (self);
+        set_error_no_lock (self, error);
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_custom_data (NFlickWorker *self, gpointer data)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->CustomData = data;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_aborted_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->AbortedIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_ok_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->OkIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_error_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->ErrorIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_request_abort (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->AbortRequested = TRUE;
+        WORKER_UNLOCK (self);
+}
+
+gboolean                        nflick_worker_is_aborted (NFlickWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_WORKER (self), FALSE);
+        
+        WORKER_LOCK (self);
+        gboolean ret = self->Private->AbortRequested;
+        WORKER_UNLOCK (self);
+        
+        return ret;
+}
+
+void                            nflick_worker_set_msg_change_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->MsgChangeIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+static void                     nflick_worker_dispose (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_worker_finalize (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     nflick_worker_get_property (NFlickWorker *self, guint propid, 
+                                                            GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_ERROR:
+                        WORKER_LOCK (self);
+                        g_value_set_string (value, self->Private->Error);
+                        WORKER_UNLOCK (self);
+                break;
+        
+                case ARG_STATUS:
+                        WORKER_LOCK (self);
+                        g_value_set_int (value, self->Private->Status);
+                        WORKER_UNLOCK (self);
+                break;
+        
+                case ARG_MESSAGE:
+                        WORKER_LOCK (self);
+                        g_value_set_string (value, self->Private->Message);
+                        WORKER_UNLOCK (self);
+                        break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/aaina/libnflick/nflick-worker.h b/attic/aaina/libnflick/nflick-worker.h
new file mode 100644 (file)
index 0000000..b1c1a4f
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKWORKER_H__
+#define __NFLICKWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-api-response.h"
+#include "nflick-types.h"
+
+struct                          _NFlickWorker
+{
+        GObject Parent;
+        NFlickWorkerPrivate *Private;
+};
+
+struct                          _NFlickWorkerClass 
+{
+        GObjectClass ParentClass;
+        NFlickWorkerThreadFunc ThreadFunc;
+};
+
+GType                           nflick_worker_get_type (void);
+
+void                            nflick_worker_start (NFlickWorker *self);
+
+void                            nflick_worker_set_error (NFlickWorker *self, const gchar *error);
+
+void                            nflick_worker_set_custom_data (NFlickWorker *self, gpointer data);
+
+void                            nflick_worker_set_aborted_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_ok_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_error_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_msg_change_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_message (NFlickWorker *self, const gchar *msg);
+
+void                            nflick_worker_request_abort (NFlickWorker *self);
+
+gboolean                        nflick_worker_is_aborted (NFlickWorker *self);
+
+void                            nflick_worker_set_network_error (NFlickWorker *self);
+
+gboolean                        nflick_worker_parse_api_response (NFlickWorker *self, NFlickApiResponse *response);
+
+#endif
diff --git a/attic/aaina/libnflick/nflick.h b/attic/aaina/libnflick/nflick.h
new file mode 100644 (file)
index 0000000..027ea59
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+/* A simple header file which includes all of the necessary nflick headers */
+
+#ifndef NFLICK_H
+#define NFLICK_H
+
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-auth-worker.h"
+#include "nflick-flickr.h"
+#include "nflick-get-sizes-response.h"
+#include "nflick-gft-response.h"
+#include "nflick-no-set-response.h"
+#include "nflick-photo-data.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-list-worker.h"
+#include "nflick-photo-search-worker.h"
+#include "nflick-photo-search-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-pixbuf-fetch.h"
+#include "nflick-set-list-response.h"
+#include "nflick-set-list-worker.h"
+#include "nflick-show-worker.h"
+#include "nflick-types.h"
+#include "nflick-worker.h"
+
+
+#endif
diff --git a/attic/aaina/sources/Makefile.am b/attic/aaina/sources/Makefile.am
new file mode 100644 (file)
index 0000000..d6c2b13
--- /dev/null
@@ -0,0 +1,24 @@
+noinst_LTLIBRARIES = libsources.la
+
+INCLUDES = \
+       $(DEPS_CFLAGS)
+       -I$(top_srcdir)                                 \
+       -I$(top_builddir)                               \
+       $(GCC_CFLAGS)                                   \
+       -DDATADIR=\""$(datadir)"\"                      \
+       -DSYSCONFDIR=\""$(sysconfdir)"\"                \
+       -Werror                                         \
+       $(NULL) 
+
+libsources_la_SOURCES =        \
+       aaina-source-directory.c                        \
+       aaina-source-directory.h                        \
+       aaina-source-flickr.c                           \
+       aaina-source-flickr.h                           
+
+libsources_la_LIBADD = \
+       $(DEPS_LIBS)                                    \
+       $(top_builddir)/libaaina/libaaina.la            \
+       $(top_builddir)/libnflick/libnflick.la  
+
+libsources_la_LDFLAGS = -version-info 0:1:0
diff --git a/attic/aaina/sources/aaina-source-directory.c b/attic/aaina/sources/aaina-source-directory.c
new file mode 100644 (file)
index 0000000..8a73039
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libaaina/aaina-photo.h>
+
+#include "aaina-source-directory.h"
+
+G_DEFINE_TYPE (AainaSourceDirectory, aaina_source_directory, AAINA_TYPE_SOURCE);
+       
+static void
+_load_photos (AainaLibrary *library, const gchar *directory)
+{
+  GDir *dir;
+  const gchar *name;
+  
+  g_print ("Scanning : %s\n", directory);
+
+  dir = g_dir_open (directory, 0, NULL);
+  while ((name = g_dir_read_name (dir)))
+  {
+    gchar *path = g_build_filename (directory, name, NULL);
+
+    if (g_file_test (path, G_FILE_TEST_IS_DIR))
+    {
+      _load_photos (library, path);
+    }
+    else
+    {
+      GdkPixbuf *pixbuf = NULL;
+      GError *err = NULL;
+
+      pixbuf = gdk_pixbuf_new_from_file_at_scale (path, 
+                                                  CLUTTER_STAGE_WIDTH ()/2,
+                                                  CLUTTER_STAGE_HEIGHT ()/2,
+                                                  TRUE,
+                                                  &err);
+      if (pixbuf)
+      {
+        ClutterActor *photo = aaina_photo_new ();
+        //g_object_set (G_OBJECT (photo), "pixbuf", pixbuf, NULL);
+        aaina_photo_set_pixbuf (AAINA_PHOTO (photo), pixbuf);
+        aaina_library_append_photo (library, AAINA_PHOTO (photo));
+
+      } else if (err)
+      {
+        g_warning ("Error: %s\n", err->message);
+      }
+      else
+        ;
+    }
+    g_free (path);
+  }
+  g_dir_close (dir);
+}
+
+/* GObject stuff */
+static void
+aaina_source_directory_class_init (AainaSourceDirectoryClass *klass)
+{
+  ;
+}
+
+
+static void
+aaina_source_directory_init (AainaSourceDirectory *source_directory)
+{
+  ;
+}
+
+AainaSource*
+aaina_source_directory_new (AainaLibrary *library, const gchar *dir)
+{
+  AainaSourceDirectory         *source_directory;
+
+  source_directory = g_object_new (AAINA_TYPE_SOURCE_DIRECTORY, 
+                                   NULL);
+
+  _load_photos (library, dir);
+  
+  return AAINA_SOURCE (source_directory);
+}
+
diff --git a/attic/aaina/sources/aaina-source-directory.h b/attic/aaina/sources/aaina-source-directory.h
new file mode 100644 (file)
index 0000000..fe19ed1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+
+#include <libaaina/aaina-library.h>
+#include <libaaina/aaina-source.h>
+
+#ifndef _HAVE_AAINA_SOURCE_DIRECTORY_H
+#define _HAVE_AAINA_SOURCE_DIRECTORY_H
+
+G_BEGIN_DECLS
+
+#define AAINA_TYPE_SOURCE_DIRECTORY aaina_source_directory_get_type()
+
+#define AAINA_SOURCE_DIRECTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       AAINA_TYPE_SOURCE_DIRECTORY, \
+       AainaSourceDirectory))
+
+#define AAINA_SOURCE_DIRECTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_SOURCE_DIRECTORY, \
+       AainaSourceDirectoryClass))
+
+#define AAINA_IS_SOURCE_DIRECTORY(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       AAINA_TYPE_SOURCE_DIRECTORY))
+
+#define AAINA_IS_SOURCE_DIRECTORY_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       AAINA_TYPE_SOURCE_DIRECTORY))
+
+#define AAINA_SOURCE_DIRECTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_SOURCE_DIRECTORY, \
+       AainaSourceDirectoryClass))
+
+typedef struct _AainaSourceDirectory AainaSourceDirectory;
+typedef struct _AainaSourceDirectoryClass AainaSourceDirectoryClass;
+
+struct _AainaSourceDirectory
+{
+       AainaSource         parent;
+};
+
+struct _AainaSourceDirectoryClass 
+{
+       
+       AainaSourceClass parent_class;
+
+  void (*_aaina_source_directory_1) (void);
+  void (*_aaina_source_directory_2) (void);
+  void (*_aaina_source_directory_3) (void);
+  void (*_aaina_source_directory_4) (void);
+}; 
+
+GType aaina_source_directory_get_type (void) G_GNUC_CONST;
+
+AainaSource* 
+aaina_source_directory_new (AainaLibrary *library, const gchar *directory);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/sources/aaina-source-flickr.c b/attic/aaina/sources/aaina-source-flickr.c
new file mode 100644 (file)
index 0000000..2fec200
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libaaina/aaina-photo.h>
+#include <libnflick/nflick-photo-search-worker.h>
+#include <libnflick/nflick-info-worker.h>
+#include <libnflick/nflick.h>
+#include "aaina-source-flickr.h"
+
+G_DEFINE_TYPE (AainaSourceFlickr, aaina_source_flickr, AAINA_TYPE_SOURCE);
+
+#define AAINA_SOURCE_FLICKR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       AAINA_TYPE_SOURCE_FLICKR, \
+       AainaSourceFlickrPrivate))
+
+#define CHECK_TIMEOUT 60000
+#define MAX_PHOTOS 100
+
+struct _AainaSourceFlickrPrivate
+{
+  AainaLibrary *library;
+  gchar        *tags;
+
+  /* table of already downloaded photos */
+  GHashTable   *table;
+
+  /* Queue of photos to download */
+  GQueue       *queue;
+  gboolean      running;
+  NFlickWorker *pix_worker;
+
+  AainaPhoto   *current;
+
+  NFlickWorker *worker;
+
+  /* Queue of photos to add to library */
+  GQueue       *add_queue;
+  gboolean      add_running;
+};
+
+static GQuark   worker_quark = 0;
+
+static gboolean get_photos (AainaSourceFlickr *source);
+static gboolean get_pixbuf (AainaSourceFlickr *source);
+
+
+static gboolean
+on_info_thread_abort (AainaPhoto *photo)
+{
+  g_print ("abort\n");
+  return FALSE;
+}
+
+static gboolean
+on_info_thread_error (AainaPhoto *photo)
+{
+  NFlickWorker *worker;
+  worker = (NFlickWorker*)g_object_get_qdata (G_OBJECT (photo), worker_quark);
+  gchar *error = NULL;
+
+  g_object_get (G_OBJECT (worker), "error", &error, NULL);
+  if (error)
+  {
+    g_warning ("%s\n", error);
+  }
+  else
+    g_print ("error\n");
+  g_object_unref (G_OBJECT (worker)); 
+  
+  return FALSE;
+}
+
+static gboolean
+on_info_thread_ok (AainaPhoto *photo)
+{
+  NFlickWorker *worker;
+  gchar *rotation = NULL;
+  gint rot;
+  gchar *realname = NULL;
+  gchar *desc = NULL;
+
+  worker = (NFlickWorker*)g_object_get_qdata (G_OBJECT (photo), worker_quark);
+    
+  nflick_info_worker_get ((NFlickInfoWorker*)worker,
+                          &rotation,
+                          &realname,
+                          &desc);
+  /* find the rotation */
+  rot = atoi (rotation);
+  
+  if (!realname)
+    g_object_get (G_OBJECT (photo), "author", &realname, NULL);
+  g_object_set (G_OBJECT (photo),
+                "rotation", rot,
+                "author", realname,
+                "desc", desc,
+                NULL);
+
+  g_object_unref (G_OBJECT (worker));  
+  return FALSE;
+}
+
+static void
+manage_queue (AainaSourceFlickr *source)
+{
+  AainaSourceFlickrPrivate *priv;
+  
+  g_return_if_fail (AAINA_IS_SOURCE_FLICKR (source));
+  priv = source->priv;
+
+  /* Now we do the work for the next one */
+  if (g_queue_get_length (priv->queue))
+  {
+    priv->current = AAINA_PHOTO (g_queue_pop_head (priv->queue));
+    g_timeout_add (100, (GSourceFunc)get_pixbuf, (gpointer)source);
+
+    priv->running = TRUE;
+    aaina_library_set_pending (priv->library, TRUE);
+  }
+  else
+  {
+    priv->running = FALSE;
+    aaina_library_set_pending (priv->library, FALSE);
+  }
+
+}
+
+static gboolean
+on_pixbuf_thread_abort (AainaSourceFlickr *source)
+{
+  g_print ("abort\n");
+  manage_queue (source);
+
+  return FALSE;
+}
+
+static gboolean
+on_pixbuf_thread_error (AainaSourceFlickr *source)
+{
+  AainaSourceFlickrPrivate *priv;
+  gchar *error = NULL;
+
+  g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
+  priv = source->priv;
+
+  g_object_get (G_OBJECT (priv->pix_worker), "error", &error, NULL);
+  if (error)
+  {
+    g_warning ("%s\n", error);
+  }
+  else
+    g_print ("error\n");
+
+  manage_queue (source);
+  return FALSE;
+}
+
+static gboolean
+add_to_library (AainaSourceFlickr *source)
+{
+  AainaSourceFlickrPrivate *priv;
+  AainaPhoto *photo = NULL;
+
+  g_return_val_if_fail (AAINA_IS_SOURCE (source), FALSE);
+  priv = source->priv;
+
+  if (aaina_library_is_full (priv->library))
+  {
+    aaina_library_set_pending (priv->library, TRUE);
+    return TRUE;
+  }
+  photo = AAINA_PHOTO (g_queue_pop_head (priv->add_queue));
+
+  if (photo)
+  {
+    aaina_library_append_photo (priv->library, (gpointer)photo);
+    return TRUE;
+  }
+  else
+  {
+    aaina_library_set_pending (priv->library, FALSE);
+    priv->add_running = FALSE;
+    return FALSE;
+  }
+}
+
+static gboolean
+on_pixbuf_thread_ok (AainaSourceFlickr *source)
+{
+
+  AainaSourceFlickrPrivate *priv;
+  GdkPixbuf *pixbuf;
+  
+  g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
+  priv = source->priv;
+
+  g_object_get (G_OBJECT (priv->pix_worker), "pixbuf", &pixbuf, NULL);
+
+  /* Set the current photo's pixbuf and add it to the library */
+  if (pixbuf)
+  {
+    aaina_photo_set_pixbuf (priv->current, pixbuf);
+
+    if (priv->add_running || aaina_library_is_full (priv->library))
+    {
+      g_queue_push_tail (priv->add_queue, (gpointer)priv->current);
+
+      if (!priv->add_running)
+      {
+        g_timeout_add (1000, (GSourceFunc)add_to_library, (gpointer)source);
+        priv->add_running = TRUE;
+        aaina_library_set_pending (priv->library, TRUE);
+      }
+    }
+    else
+      aaina_library_append_photo (priv->library, priv->current);
+
+    priv->current = NULL;
+  }
+  manage_queue (source);
+
+  static gint i = 0;
+  i++;
+  return FALSE;
+}
+
+static gboolean
+get_pixbuf (AainaSourceFlickr *source)
+{
+
+  AainaSourceFlickrPrivate *priv;
+  NFlickWorker *worker;
+  AainaPhoto *photo;
+  gchar *id;
+
+  g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
+  priv = source->priv;
+
+  if (priv->current == NULL)
+    return FALSE;
+
+  photo = priv->current;
+  g_object_get (G_OBJECT (photo), "id", &id, NULL);
+
+  worker = (NFlickWorker*)nflick_show_worker_new (id,
+                                                  CLUTTER_STAGE_WIDTH ()/2,
+                                                  CLUTTER_STAGE_HEIGHT ()/2,
+                                                  " ");
+  if (G_IS_OBJECT (priv->pix_worker))
+    g_object_unref (G_OBJECT (priv->pix_worker));
+  priv->pix_worker = worker;
+
+  nflick_worker_set_custom_data (worker, source);
+  nflick_worker_set_aborted_idle (worker, 
+                                  (NFlickWorkerIdleFunc)on_pixbuf_thread_abort);
+  nflick_worker_set_error_idle (worker, 
+                                (NFlickWorkerIdleFunc)on_pixbuf_thread_error);
+  nflick_worker_set_ok_idle (worker,
+                             (NFlickWorkerIdleFunc)on_pixbuf_thread_ok);
+  
+  nflick_worker_start (worker);  
+
+
+  worker = (NFlickWorker*)nflick_info_worker_new (id, 22, 22, " ");
+  nflick_worker_start (worker);
+
+  priv->running = TRUE;
+  
+  nflick_worker_set_custom_data (worker, photo);
+  nflick_worker_set_aborted_idle (worker, 
+                                  (NFlickWorkerIdleFunc)on_info_thread_abort);
+  nflick_worker_set_error_idle (worker, 
+                                (NFlickWorkerIdleFunc)on_info_thread_error);
+  nflick_worker_set_ok_idle (worker,
+                             (NFlickWorkerIdleFunc)on_info_thread_ok);
+
+  g_object_set_qdata (G_OBJECT (photo), worker_quark, (gpointer)worker);
+
+
+  return FALSE;
+}
+
+
+static gboolean
+on_thread_abort (AainaSourceFlickr *source)
+{
+  g_print ("abort\n");
+  return FALSE;
+}
+
+static gboolean
+on_thread_error (AainaSourceFlickr *source)
+{
+  g_print ("error\n");
+  return FALSE;
+}
+
+static gboolean
+on_thread_ok (AainaSourceFlickr *source)
+{
+  AainaSourceFlickrPrivate *priv;
+  GList *list = NULL, *l;
+
+  g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
+  priv = source->priv;
+
+  /* Grab the list of photos from the worker */
+  list = nflick_photo_search_worker_take_list (NFLICK_PHOTO_SEARCH_WORKER 
+                                                                (priv->worker));
+  for (l = list; l != NULL; l = l->next)
+  {
+    FlickrPhoto *photo = (FlickrPhoto*)l->data;
+    ClutterActor *aphoto = NULL;
+    gpointer res;
+
+    if (!photo)
+      continue;
+
+    /* If the photo is already present, return */
+    if (g_hash_table_lookup (priv->table, photo->id) != NULL)
+      continue;
+    
+    /* Insert into the hash table */
+    g_hash_table_insert (priv->table, 
+                         g_strdup (photo->id), 
+                         GINT_TO_POINTER (1));
+
+    /* Create a aaina photo objec, but don't add it to the library yet */
+    aphoto = aaina_photo_new ();
+    g_object_set (G_OBJECT (aphoto),
+                  "id", photo->id,
+                  "title", photo->title, 
+                  "author", photo->user,
+                  NULL);
+    
+    /* Add the photo to the download queue */
+    g_queue_push_tail (priv->queue, (gpointer)aphoto);
+
+    /* Free the the photo struct and its data */
+    g_free (photo->id);
+    g_free (photo->title);
+    g_free (photo->user);
+    g_free (photo);
+    l->data = NULL;
+  }
+
+  g_list_free (list);
+
+  g_timeout_add (CHECK_TIMEOUT, (GSourceFunc)get_photos, (gpointer)source);
+  if (!priv->running)
+  {
+    priv->current = AAINA_PHOTO (g_queue_pop_head (priv->queue));
+    g_timeout_add (200, (GSourceFunc)get_pixbuf, (gpointer)source);
+  }
+  return FALSE;
+}
+
+static gboolean
+get_photos (AainaSourceFlickr *source)
+{
+  NFlickWorker *worker;
+  NFlickWorkerStatus *status;
+
+  worker = (NFlickWorker*)nflick_photo_search_worker_new (source->priv->tags,
+                                                          " ");
+  if (G_IS_OBJECT (source->priv->worker))
+    g_object_unref (G_OBJECT (source->priv->worker));
+
+  source->priv->worker = worker;
+  
+  nflick_worker_set_custom_data (worker, source);
+  nflick_worker_set_aborted_idle (worker, 
+                                  (NFlickWorkerIdleFunc)on_thread_abort);
+  nflick_worker_set_error_idle (worker, 
+                                (NFlickWorkerIdleFunc)on_thread_error);
+  nflick_worker_set_ok_idle (worker,
+                             (NFlickWorkerIdleFunc)on_thread_ok);
+
+  nflick_worker_start (worker);
+
+  return FALSE;
+}
+
+/* GObject stuff */
+static void
+aaina_source_flickr_class_init (AainaSourceFlickrClass *klass)
+{
+  GObjectClass    *gobject_class = G_OBJECT_CLASS (klass);
+  
+  g_type_class_add_private (gobject_class, sizeof (AainaSourceFlickrPrivate));
+
+}
+
+
+static void
+aaina_source_flickr_init (AainaSourceFlickr *source_flickr)
+{
+  AainaSourceFlickrPrivate *priv;
+
+  priv = source_flickr->priv = AAINA_SOURCE_FLICKR_GET_PRIVATE (source_flickr);
+
+  priv->table = g_hash_table_new ((GHashFunc)g_str_hash, 
+                                  (GEqualFunc)g_str_equal);
+
+  priv->queue = g_queue_new ();
+  priv->running = FALSE;
+
+  priv->add_queue = g_queue_new ();
+  priv->add_running = FALSE;
+
+  worker_quark = g_quark_from_string ("aaina.flickr.worker");
+}
+
+AainaSource*
+aaina_source_flickr_new (AainaLibrary *library, const gchar *tags)
+{
+  AainaSourceFlickr         *source_flickr;
+
+  source_flickr = g_object_new (AAINA_TYPE_SOURCE_FLICKR, 
+                                   NULL);
+
+  source_flickr->priv->tags = g_strdup (tags);
+  source_flickr->priv->library = library;
+  get_photos (source_flickr);
+
+  return AAINA_SOURCE (source_flickr);
+}
+
diff --git a/attic/aaina/sources/aaina-source-flickr.h b/attic/aaina/sources/aaina-source-flickr.h
new file mode 100644 (file)
index 0000000..0821435
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+
+#include <libaaina/aaina-library.h>
+#include <libaaina/aaina-source.h>
+
+#ifndef _HAVE_AAINA_SOURCE_FLICKR_H
+#define _HAVE_AAINA_SOURCE_FLICKR_H
+
+G_BEGIN_DECLS
+
+#define AAINA_TYPE_SOURCE_FLICKR aaina_source_flickr_get_type()
+
+#define AAINA_SOURCE_FLICKR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       AAINA_TYPE_SOURCE_FLICKR, \
+       AainaSourceFlickr))
+
+#define AAINA_SOURCE_FLICKR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_SOURCE_FLICKR, \
+       AainaSourceFlickrClass))
+
+#define AAINA_IS_SOURCE_FLICKR(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       AAINA_TYPE_SOURCE_FLICKR))
+
+#define AAINA_IS_SOURCE_FLICKR_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       AAINA_TYPE_SOURCE_FLICKR))
+
+#define AAINA_SOURCE_FLICKR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_SOURCE_FLICKR, \
+       AainaSourceFlickrClass))
+
+typedef struct _AainaSourceFlickr AainaSourceFlickr;
+typedef struct _AainaSourceFlickrClass AainaSourceFlickrClass;
+typedef struct _AainaSourceFlickrPrivate AainaSourceFlickrPrivate;
+
+struct _AainaSourceFlickr
+{
+       AainaSource         parent;
+
+  AainaSourceFlickrPrivate *priv;
+};
+
+struct _AainaSourceFlickrClass 
+{
+       
+       AainaSourceClass parent_class;
+
+  void (*_aaina_source_flickr_1) (void);
+  void (*_aaina_source_flickr_2) (void);
+  void (*_aaina_source_flickr_3) (void);
+  void (*_aaina_source_flickr_4) (void);
+}; 
+
+GType aaina_source_flickr_get_type (void) G_GNUC_CONST;
+
+AainaSource* 
+aaina_source_flickr_new (AainaLibrary *library, const gchar *tags);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/src/Makefile.am b/attic/aaina/src/Makefile.am
new file mode 100644 (file)
index 0000000..f1e696d
--- /dev/null
@@ -0,0 +1,20 @@
+bin_PROGRAMS=aaina
+
+PKGDATADIR = $(datadir)/aaina
+AM_CFLAGS = \
+       $(DEPS_CFLAGS)                          \
+       $(GCC_FLAGS)                            \
+       -I$(top_builddir)                       \
+       -I$(top_srcdir)                         \
+       -D_GNU_SOURCE                           \
+       -DPKGDATADIR=\"$(PKGDATADIR)\"
+
+aaina_LDADD  = \
+       $(DEPS_LIBS)                            \
+       $(top_builddir)/libaaina/libaaina.la    \
+       $(top_builddir)/sources/libsources.la
+
+aaina_SOURCES = \
+       aaina-slide-show.c                      \
+       aaina-slide-show.h                      \
+       main.c
diff --git a/attic/aaina/src/aaina-slide-show.c b/attic/aaina/src/aaina-slide-show.c
new file mode 100644 (file)
index 0000000..6a9f490
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libaaina/aaina-behave.h>
+
+#include "aaina-slide-show.h"
+
+G_DEFINE_TYPE (AainaSlideShow, aaina_slide_show, CLUTTER_TYPE_GROUP);
+
+#define AAINA_SLIDE_SHOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       AAINA_TYPE_SLIDE_SHOW, \
+       AainaSlideShowPrivate))
+
+#define VIEW_PHOTO_TIMEOUT 4000
+#define N_LANES 7
+
+static gint lane_frames[N_LANES] = {60, 60, 60, 60, 60, 60, 60};
+static gint lane_speed[N_LANES]  = {180, 150, 120, 90, 60, 30, 15};
+
+struct _AainaSlideShowPrivate
+{
+  AainaLibrary      *library;
+  gint               count;
+  
+  GList             *lanes[N_LANES];
+  ClutterTimeline   *timelines[N_LANES];
+  gint               lanesx[N_LANES];
+
+  /* Viewing single photo */
+  AainaPhoto        *zoomed;
+
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_LIBRARY
+};
+
+static void     on_photo_added (AainaLibrary    *library, 
+                                AainaPhoto      *photo, 
+                                AainaSlideShow  *data);
+static gboolean zoom_photo (AainaSlideShow *slide_show);
+
+static void
+on_photo_zoomed (AainaPhoto *photo, AainaSlideShow *slide_show)
+{
+  AainaSlideShowPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (slide_show));
+  priv = slide_show->priv;
+
+  priv->zoomed = NULL;
+}
+
+static gboolean
+restore_photo (AainaSlideShow *slide_show)
+{
+  AainaSlideShowPrivate *priv;
+  static GRand *rand = NULL;
+  gint i;
+
+  g_return_val_if_fail (AAINA_IS_SLIDE_SHOW (slide_show), FALSE);
+  priv = slide_show->priv;
+  
+  if (rand == NULL)
+    rand = g_rand_new ();
+
+  if (!AAINA_IS_PHOTO (priv->zoomed))
+    return FALSE;
+
+  aaina_photo_set_viewed (priv->zoomed, TRUE);
+  aaina_photo_restore (priv->zoomed);
+
+  for (i = 0; i < N_LANES; i++)
+    clutter_timeline_start (priv->timelines[i]);
+
+  g_signal_connect (G_OBJECT (priv->zoomed), "photo_restored",
+                    G_CALLBACK (on_photo_zoomed), (gpointer)slide_show);
+
+  g_timeout_add (g_rand_int_range (rand, 4000, 10000), 
+                 (GSourceFunc)zoom_photo, 
+                 (gpointer)slide_show);
+  return FALSE;
+}
+/*
+static void
+on_photo_zoomed (AainaPhoto *photo, AainaSlideShow *slide_show)
+{
+  AainaSlideShowPrivate *priv;
+  gint i;
+
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (slide_show));
+  priv = slide_show->priv;
+
+   Pause all the timelines
+  for (i = 0; i < N_LANES; i++)
+    clutter_timeline_pause (priv->timelines[i]);
+}
+*/
+static gboolean
+zoom_photo (AainaSlideShow *slide_show)
+{
+  AainaSlideShowPrivate *priv;
+  static GRand *rand = NULL;
+  GList *l, *photos = NULL;
+  gint lane, i;
+  gint stage_width = CLUTTER_STAGE_WIDTH ();
+  AainaPhoto *photo;
+  
+  g_return_val_if_fail (AAINA_IS_SLIDE_SHOW (slide_show), FALSE);
+  priv = slide_show->priv;
+
+  if (rand == NULL)
+    rand = g_rand_new ();
+  
+  /* Get a random lane to choose the picture from */
+  lane = g_rand_int_range (rand, 0, N_LANES);
+  
+  /* Create a list of possible photos to zoom (those which are 'visible' to the
+   * user)
+   */
+  for (l = priv->lanes[lane]; l != NULL; l = l->next)
+  {
+    ClutterActor *actor = CLUTTER_ACTOR (l->data);
+    gint x;
+    guint w, h;
+    
+    if (!AAINA_IS_PHOTO (actor))
+      continue;
+
+    x = clutter_actor_get_x (actor);
+    clutter_actor_get_transformed_size (actor, &w, &h);
+    x += w;
+
+    if (x > 0 && x < stage_width 
+            && !aaina_photo_get_viewed (AAINA_PHOTO (actor)))
+      photos = g_list_append (photos, actor);
+  }
+  
+  /* This should work, right? */
+  if (photos == NULL)
+  {
+    //zoom_photo (slide_show);
+    return TRUE;
+  }
+
+  /* Choose a random photo in the list */
+  i = g_rand_int_range (rand, 0, g_list_length (photos));
+  photo = AAINA_PHOTO (g_list_nth_data (photos, i));
+
+  /* Connect to 'zoomed' signal, swhen the photo has finished, we stop the
+   * timelines
+   
+  g_signal_connect (G_OBJECT (photo), "photo_zoomed", 
+                     G_CALLBACK (on_photo_zoomed), (gpointer)slide_show);
+  */
+  /* Save the photos current 'state' (x, y, and scale) */
+  aaina_photo_save (photo);
+  
+  clutter_actor_raise_top (CLUTTER_ACTOR (photo));                              
+  aaina_photo_zoom (photo);
+
+  /* Keep a pointer to the photo, and finally add a timeout for when the 
+   * slideshow should be restored.
+   */
+  priv->zoomed = photo;
+  g_timeout_add (VIEW_PHOTO_TIMEOUT, 
+
+                 (GSourceFunc)restore_photo, 
+                 (gpointer)slide_show);
+
+  return FALSE;
+
+}
+
+static void
+aaina_slide_show_move (ClutterBehaviour *behave, 
+                       guint32 alpha_value, 
+                       GList **lane)
+{
+  AainaSlideShow *slide_show = aaina_slide_show_get_default ();
+  AainaSlideShowPrivate *priv = slide_show->priv;
+  GList *l;
+  gint leftmost = 0 - (CLUTTER_STAGE_WIDTH () /4);
+
+  for (l = *lane; l != NULL; l = l->next)
+  {
+    gint x;
+    guint width;
+    gboolean viewed;
+
+    if (!AAINA_IS_PHOTO (l->data))
+      continue;
+
+    g_object_get (G_OBJECT (l->data), 
+                  "x", &x,
+                  "width", &width,
+                  "viewed", &viewed,
+                  NULL);
+    if (l->data == priv->zoomed)
+      continue;
+    else if (viewed)
+    {
+      if (x < leftmost)
+      {
+        if (aaina_library_get_pending (priv->library)
+              && aaina_library_is_full (priv->library))
+        {
+          aaina_library_remove_photo (priv->library, AAINA_PHOTO (l->data));
+          clutter_actor_destroy (CLUTTER_ACTOR (l->data));
+          l->data = NULL;
+          g_print ("Deleting\n");
+        }
+        else
+        {
+          aaina_photo_set_viewed (AAINA_PHOTO (l->data), FALSE);
+          on_photo_added (NULL, l->data, slide_show);
+          l->data = NULL;
+          g_print ("Re-adding\n");
+        }
+      }
+      else
+        g_object_set (G_OBJECT (l->data), "x", x - 1, NULL); 
+    }
+    else
+    {
+      if (x > leftmost)
+        g_object_set (G_OBJECT (l->data), "x", x - 1, NULL);
+      else
+      {
+        on_photo_added (NULL, l->data, slide_show);
+        l->data = NULL;
+      }
+    }
+  }
+}
+
+static void
+aaina_slide_show_remove_rows (AainaSlideShow *slide_show)
+{
+       clutter_group_remove_all (CLUTTER_GROUP(slide_show));
+}
+
+static void
+on_photo_added (AainaLibrary    *library, 
+                AainaPhoto      *photo, 
+                AainaSlideShow  *data)
+{
+  AainaSlideShowPrivate *priv;
+  static GRand *rand = NULL;
+  gint count;
+  gint x, y, dim;
+  gdouble scale;
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (data));
+  priv = AAINA_SLIDE_SHOW (data)->priv;
+
+  if (!rand)
+    rand = g_rand_new ();
+
+  count = priv->count;
+
+  /* We want the scale of the photos to be random 0.15, 0.35*/
+  scale = (0.35 - 0.15)/N_LANES;
+  scale = g_rand_double_range (rand,
+                               0.15 + (scale * count), 
+                               0.15 + (scale * (count+1))); 
+
+  /* We want 'random' spacing of the photos, but we don't want to overlap two
+   * photos from the same lane, hence we only randomise the gap between two
+   * photos. That also prevents photos from being too far apart
+   */
+  x = g_rand_int_range (rand, 0, CLUTTER_STAGE_WIDTH ()/4);
+  x += priv->lanesx[count];
+
+  /* Set the new x value for the lane */
+  priv->lanesx[count] = x + (CLUTTER_STAGE_WIDTH() * scale);
+
+  /* Each lane has a set 'base y value, as calculated below, in addition to 
+   * this, we add a random value between -30 and 30, which makes sure the photos
+   * look randomised.
+   */
+  y = ((CLUTTER_STAGE_HEIGHT () / (N_LANES +2)) * count) + 30;
+  y = g_rand_int_range (rand, 
+                        0, 
+                        CLUTTER_STAGE_HEIGHT ()-(CLUTTER_STAGE_HEIGHT()/5));
+         
+       /* Use AainaPhoto's scale feature as it makes sure gravity is center */
+  clutter_actor_set_scale (CLUTTER_ACTOR (photo), scale, scale);
+       clutter_actor_set_position (CLUTTER_ACTOR (photo), x, y);
+  clutter_actor_set_depth (CLUTTER_ACTOR (photo), count);
+
+  dim = 255/N_LANES;
+  dim = dim * (N_LANES - (count+1));
+  aaina_photo_set_dim (photo, dim);
+
+  if (!clutter_actor_get_parent (CLUTTER_ACTOR (photo)))
+    clutter_group_add (CLUTTER_GROUP (data), 
+                       CLUTTER_ACTOR (photo));
+  clutter_actor_show_all (CLUTTER_ACTOR (photo));
+
+  priv->lanes[count] = g_list_append (priv->lanes[count], (gpointer)photo);
+
+  priv->count++;
+  if (priv->count == N_LANES)
+    priv->count = 0;
+}
+  
+static gboolean
+aaina_slide_show_row_foreach (AainaLibrary     *library,
+                                               AainaPhoto           *photo,
+                                               gpointer          data)
+{
+  on_photo_added (library, photo, AAINA_SLIDE_SHOW (data));
+  return TRUE;
+}
+
+
+void
+aaina_slide_show_set_library (AainaSlideShow *slide_show, 
+                              AainaLibrary *library)
+{
+  AainaSlideShowPrivate *priv;
+  gint i;
+
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (slide_show));
+  if (!AAINA_IS_LIBRARY (library))
+    return;
+  priv = slide_show->priv;
+
+  if (priv->library)
+  {
+    aaina_slide_show_remove_rows (slide_show);
+    g_object_unref (priv->library);
+  }
+  priv->library = library;
+  if (!library)
+    return;
+  g_signal_connect (G_OBJECT (priv->library), "photo-added",
+                    G_CALLBACK (on_photo_added), slide_show);
+  
+  /* Sort each photo into a 'lane', and give it a 'randomised' x and y value */
+  aaina_library_foreach (priv->library, 
+                         aaina_slide_show_row_foreach,
+                         (gpointer)slide_show);
+
+  /* Now all the photos have a lane and position, we start each lanes timeline,
+   * with randomised speed
+   */
+  for (i = 0; i < N_LANES; i++)
+  {
+    
+    clutter_timeline_set_speed (priv->timelines[i], lane_speed[i]);
+    clutter_timeline_set_n_frames (priv->timelines[i], lane_frames[i]);
+    clutter_timeline_set_loop (priv->timelines[i], TRUE);
+    
+    if (!clutter_timeline_is_playing (priv->timelines[i]))
+      clutter_timeline_start (priv->timelines[i]);
+  }
+
+  /* Finally, set the timeout for zooming the pictures */
+  g_timeout_add (3000, (GSourceFunc)zoom_photo, (gpointer)slide_show);
+}
+
+
+/* GObject stuff */
+
+static void
+aaina_slide_show_set_property (GObject      *object, 
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  AainaSlideShowPrivate *priv;
+  
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (object));
+  priv = AAINA_SLIDE_SHOW (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_LIBRARY:
+      aaina_slide_show_set_library (AAINA_SLIDE_SHOW (object), 
+                                    AAINA_LIBRARY (g_value_get_object (value)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+aaina_slide_show_get_property (GObject    *object, 
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  AainaSlideShowPrivate *priv;
+  
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (object));
+  priv = AAINA_SLIDE_SHOW (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_LIBRARY:
+      g_value_set_object (value, G_OBJECT (priv->library));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+  static void
+aaina_slide_show_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (aaina_slide_show_parent_class)->dispose (object);
+}
+
+static void
+aaina_slide_show_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (aaina_slide_show_parent_class)->finalize (object);
+}
+
+static void
+aaina_slide_show_class_init (AainaSlideShowClass *klass)
+{
+  GObjectClass    *gobject_class = G_OBJECT_CLASS (klass);
+  
+  gobject_class->finalize     = aaina_slide_show_finalize;
+  gobject_class->dispose      = aaina_slide_show_dispose;
+  gobject_class->get_property = aaina_slide_show_get_property;
+  gobject_class->set_property = aaina_slide_show_set_property;
+
+  g_type_class_add_private (gobject_class, sizeof (AainaSlideShowPrivate));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_LIBRARY,
+    g_param_spec_object ("library",
+                         "The Library",
+                         "The AainaLibrary",
+                         AAINA_TYPE_LIBRARY,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+}
+
+static void
+aaina_slide_show_init (AainaSlideShow *slide_show)
+{
+  AainaSlideShowPrivate *priv;
+
+  g_return_if_fail (AAINA_IS_SLIDE_SHOW (slide_show));
+  priv = AAINA_SLIDE_SHOW_GET_PRIVATE (slide_show);
+
+  slide_show->priv = priv;
+  priv->count = 0;
+  
+  gint i;
+  for (i=0; i < N_LANES;  i++)
+  {
+    ClutterAlpha *alpha;
+    ClutterBehaviour *behave;
+
+    priv->lanes[i] = NULL;
+
+    priv->timelines[i] = clutter_timeline_new (40, 120);
+    alpha = clutter_alpha_new_full (priv->timelines[i], 
+                                    alpha_sine_inc_func,
+                                    NULL, NULL);
+    behave = aaina_behave_new (alpha, 
+                               (AainaBehaveAlphaFunc)aaina_slide_show_move, 
+                               (gpointer)&priv->lanes[i]);
+    priv->lanesx[i] = g_random_int_range (0, CLUTTER_STAGE_WIDTH () /2);
+  }
+}
+
+AainaSlideShow*
+aaina_slide_show_get_default (void)
+{
+  static AainaSlideShow *slide_show = NULL;
+
+  if (!slide_show)
+    slide_show = g_object_new (AAINA_TYPE_SLIDE_SHOW, NULL);
+  
+  return slide_show;
+}
diff --git a/attic/aaina/src/aaina-slide-show.h b/attic/aaina/src/aaina-slide-show.h
new file mode 100644 (file)
index 0000000..5fffe9f
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+* Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libaaina/aaina-library.h>
+#include <libaaina/aaina-photo.h>
+
+#ifndef _HAVE_AAINA_SLIDE_SHOW_H
+#define _HAVE_AAINA_SLIDE_SHOW_H
+
+G_BEGIN_DECLS
+
+#define AAINA_TYPE_SLIDE_SHOW aaina_slide_show_get_type()
+
+#define AAINA_SLIDE_SHOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       AAINA_TYPE_SLIDE_SHOW, \
+       AainaSlideShow))
+
+#define AAINA_SLIDE_SHOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       AAINA_TYPE_SLIDE_SHOW, \
+       AainaSlideShowClass))
+
+#define AAINA_IS_SLIDE_SHOW(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       AAINA_TYPE_SLIDE_SHOW))
+
+#define AAINA_IS_SLIDE_SHOW_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       AAINA_TYPE_SLIDE_SHOW))
+
+#define AAINA_SLIDE_SHOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       AAINA_TYPE_SLIDE_SHOW, \
+       AainaSlideShowClass))
+
+typedef struct _AainaSlideShow AainaSlideShow;
+typedef struct _AainaSlideShowClass AainaSlideShowClass;
+typedef struct _AainaSlideShowPrivate AainaSlideShowPrivate;
+
+struct _AainaSlideShow
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       AainaSlideShowPrivate   *priv;
+};
+
+struct _AainaSlideShowClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+  void (*_aaina_slide_show_1) (void);
+  void (*_aaina_slide_show_2) (void);
+  void (*_aaina_slide_show_3) (void);
+  void (*_aaina_slide_show_4) (void);
+}; 
+
+GType aaina_slide_show_get_type (void) G_GNUC_CONST;
+
+AainaSlideShow*
+aaina_slide_show_get_default (void);
+
+void
+aaina_slide_show_set_library (AainaSlideShow *slide_show, 
+                              AainaLibrary *library);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/aaina/src/main.c b/attic/aaina/src/main.c
new file mode 100644 (file)
index 0000000..32ca421
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Authored By Neil Jagdish Patel <njp@o-hand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <clutter/clutter.h>
+
+#include <libaaina/aaina-library.h>
+#include <libaaina/aaina-source.h>
+#include <libaaina/aaina-behave.h>
+
+#include <sources/aaina-source-directory.h>
+#include <sources/aaina-source-flickr.h>
+
+#include "aaina-slide-show.h"
+
+static AainaSlideShow *show = NULL;
+static ClutterTimeline *timeline = NULL;
+
+/* Command line options */
+static gboolean   fullscreen  = FALSE;
+static gchar    **directories = NULL;
+static gchar     *flickr_tags = NULL;
+
+static GOptionEntry entries[] =
+{
+  {
+    "fullscreen",
+    'f', 0,
+    G_OPTION_ARG_NONE,
+    &fullscreen,
+    "Launch Aaina in fullscreen mode",
+    NULL
+  },
+  {
+    "directory",
+    'd', 0,
+    G_OPTION_ARG_FILENAME_ARRAY,
+    &directories,
+    "The directory to load pictures from",
+    "PATH"
+  },
+  {
+    "tag",
+    't', 0,
+    G_OPTION_ARG_STRING,
+    &flickr_tags,
+    "A set of comma-separated tags to search flickr with",
+    "TAG"
+  },
+  {
+    NULL
+  }
+};
+  
+static void on_key_release_event (ClutterStage *stage, 
+                                  ClutterEvent *event,
+                                  gpointer      null);
+
+static void spin_me (ClutterBehaviour *behave, 
+                     guint32           alpha_value,
+                     gpointer          null);
+
+static gboolean
+im_spinning_around (ClutterTimeline *time)
+{
+  if (!clutter_timeline_is_playing (timeline))
+    clutter_timeline_start (timeline);
+  return TRUE;
+}
+  
+int 
+main (int argc, char **argv)
+{
+  AainaLibrary *library;
+  AainaSource *source;
+  ClutterActor *stage;
+  ClutterAlpha *alpha;
+  ClutterBehaviour *behave;
+  ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
+  GError *error = NULL;
+
+  g_thread_init (NULL);
+
+  g_set_application_name ("Aaina Image Slideshow");
+  clutter_init_with_args (&argc, &argv,
+                          " - Aaina Image Slideshow", entries,
+                          NULL,
+                          &error);
+  if (error)
+    {
+      g_print ("Unable to run Aaina: %s", error->message);
+      g_error_free (error);
+      return EXIT_FAILURE;
+    }
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_set_size (stage, 720, 480);
+  clutter_stage_hide_cursor (CLUTTER_STAGE (stage));
+  
+  if (fullscreen)
+    clutter_stage_fullscreen (CLUTTER_STAGE (stage));
+
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &black);
+
+  /* Load the test source */
+  library = aaina_library_new ();
+
+  if (directories && directories[0])
+    {
+      gint n_directories, i;
+
+      n_directories = g_strv_length (directories);
+      for (i = 0; i < n_directories; i++)
+        source = aaina_source_directory_new (library, directories[i]);
+    }
+  else if (flickr_tags)
+    source = aaina_source_flickr_new (library, flickr_tags);
+  else
+    {
+      g_print ("Usage: aaina -d <path>\n"
+               "       aaina -t <tag>[,<tag>,....]\n");
+      return EXIT_FAILURE;
+    }
+
+  show = aaina_slide_show_get_default ();
+  clutter_group_add (CLUTTER_GROUP (stage), CLUTTER_ACTOR (show));
+  clutter_actor_set_position (CLUTTER_ACTOR (show), 0, 0);
+  clutter_actor_set_size (CLUTTER_ACTOR (show), 
+                          CLUTTER_STAGE_WIDTH (),
+                          CLUTTER_STAGE_HEIGHT ()) ;
+  clutter_actor_show_all (CLUTTER_ACTOR (show));
+  g_object_set (G_OBJECT (show), "library", library, NULL);
+
+  clutter_actor_show_all (stage);
+
+  /*clutter_actor_set_scale (stage, 0.25, 0.25);*/
+
+  g_signal_connect (G_OBJECT (stage), "key-release-event",
+                    G_CALLBACK (on_key_release_event), (gpointer)stage);
+
+  
+  timeline = clutter_timeline_new (60, 30);
+  alpha = clutter_alpha_new_full (timeline,
+                                  alpha_sine_inc_func,
+                                  NULL, NULL);
+  behave = aaina_behave_new (alpha, 
+                             (AainaBehaveAlphaFunc)spin_me,
+                             (gpointer)stage);
+  
+  clutter_actor_set_rotation (stage, CLUTTER_Y_AXIS, 0,
+                              CLUTTER_STAGE_WIDTH ()/2,
+                              0,
+                              CLUTTER_STAGE_HEIGHT ());
+
+  g_timeout_add (120000, (GSourceFunc)im_spinning_around, timeline);
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}
+
+static void
+on_key_release_event (ClutterStage *stage, 
+                      ClutterEvent *event,
+                      gpointer      null)
+{
+  static gint i = 0;
+  
+  switch (clutter_key_event_symbol ((ClutterKeyEvent*)event))
+  {
+    case CLUTTER_Escape:
+      clutter_main_quit ();
+      break;
+    case CLUTTER_Left:
+       i--;
+       if (i == 0)
+         i = 359;
+       clutter_actor_set_rotation (CLUTTER_ACTOR (stage), CLUTTER_Y_AXIS, i,
+                                   CLUTTER_STAGE_WIDTH ()/2,
+                                   0,
+                                   CLUTTER_STAGE_HEIGHT ());
+       break;
+    case CLUTTER_Right:
+       i++;
+       if (i == 360)
+         i = 0;
+         clutter_actor_set_rotation (CLUTTER_ACTOR (stage), CLUTTER_Y_AXIS, i,
+                                     CLUTTER_STAGE_WIDTH ()/2,
+                                     0,
+                                     CLUTTER_STAGE_HEIGHT ());
+       break;
+    case CLUTTER_Up:
+       if (!clutter_timeline_is_playing (timeline))
+          clutter_timeline_start (timeline);
+       break;
+    default:
+      break;
+  }
+} 
+
+
+static void
+spin_me (ClutterBehaviour *behave, 
+         guint32           alpha_value,
+         gpointer          null)
+{
+ gfloat factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+ clutter_actor_set_rotation (CLUTTER_ACTOR (show), CLUTTER_Y_AXIS, factor * 360,
+                             CLUTTER_STAGE_WIDTH ()/2, 0, 0);
+}
diff --git a/attic/astro-desktop/AUTHORS b/attic/astro-desktop/AUTHORS
new file mode 100644 (file)
index 0000000..8ec34a6
--- /dev/null
@@ -0,0 +1 @@
+Neil J. Patel <njp@o-hand.com>
diff --git a/attic/astro-desktop/ChangeLog b/attic/astro-desktop/ChangeLog
new file mode 100644 (file)
index 0000000..9032ae9
--- /dev/null
@@ -0,0 +1,761 @@
+2008-02-29  Øyvind Kolås  <pippin@o-hand.com>
+
+       * src/main.c: (main): remove gdk_init() call.
+
+2008-02-29  Matthew Allum  <mallum@openedhand.com>
+
+       * applications/contacts/clutter-reflect-texture.c:
+       * applications/images/clutter-reflect-texture.c:
+       * applications/music/clutter-reflect-texture.c:
+        No need to include GL header.
+       * configure.ac:
+        No need for -Werror
+
+2008-02-29  Matthew Allum  <mallum@openedhand.com>
+
+       * applications/contacts/clutter-reflect-texture.c:
+       * applications/images/clutter-reflect-texture.c:
+       * applications/music/clutter-reflect-texture.c:
+        Quick hack to build with GLES.
+       * configure.ac:
+        Stick with 0.6, dont pull in gst
+
+2008-02-21  Neil J. Patel  <njp@o-hand.com>
+
+       * configure.ac:
+       Update to clutter 0.7 (trunk)
+
+       * src/astro-appicon.c:
+       Include the clutter-shader.h
+
+2008-02-18  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/Makefile.am:
+       * applications/contacts/astro-contacts-window.c: (ensure_layout),
+       (ensure_layout_proper), (on_event), (astro_contacts_window_init),
+       (astro_contacts_window_new):
+       * applications/contacts/init.c: (astro_application_factory_init):
+       * applications/example/init.c: (astro_application_factory_init):
+       * applications/images/Makefile.am:
+       * applications/images/astro-images-window.c:
+       (astro_images_window_class_init), (astro_images_window_init),
+       (astro_images_window_new):
+       * applications/images/astro-images-window.h:
+       * applications/images/astro-images.c: (get_title), (set_title),
+       (get_icon), (set_icon), (get_window), (close),
+       (astro_images_class_init), (astro_images_init), (astro_images_new):
+       * applications/images/astro-images.h:
+       * applications/images/clutter-reflect-texture.c:
+       (reflect_texture_render_to_gl_quad),
+       (clutter_reflect_texture_paint),
+       (clutter_reflect_texture_set_property),
+       (clutter_reflect_texture_get_property),
+       (clutter_reflect_texture_class_init),
+       (clutter_reflect_texture_init), (clutter_reflect_texture_new):
+       * applications/images/clutter-reflect-texture.h:
+       * applications/images/init.c: (astro_application_factory_init):
+       * applications/music/init.c: (astro_application_factory_init):
+       * configure.ac:
+       * data/icons/Makefile.am:
+       Added in the starting of a new images application.      
+       
+       * libastro-desktop/astro-defines.h:
+       * src/astro-panel.c: (astro_panel_init):
+       * src/astro-systray.c: (astro_systray_init):
+       Increased the default panel size, and fixed the label-sizing issues
+       that went with it.
+
+2008-02-07  Neil J. Patel  <njp@o-hand.com>
+
+       * applets/cal.json:
+       * applets/clock.json:
+       * applets/mail.json:
+       * applets/weather.json:
+       Fix the sizing so that it is a factor of the stage size.
+       
+       * applications/music/astro-songs.c: (bounds_check):
+       Remove some printfs.
+        
+       * src/astro-applet.c: (astro_applet_paint):
+       Change the bacground texture size to be the as wide as the widest 
+       child (y+width).
+
+2008-02-05  Neil J. Patel  <njp@o-hand.com>
+
+       * src/astro-appicon.c: (astro_appicon_set_application):
+       Update to new shader api.
+
+2008-02-01  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-songs.c: (astro_songs_init):
+       * src/astro-panel.c: (astro_panel_set_header):
+       * src/astro-systray.c: (astro_systray_init):
+       More fixes to sizing and display position.
+
+2008-01-31  Neil J Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c:
+       (astro_music_window_init):
+       Fix the label size. 
+
+2008-01-31  Neil J Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contact-row.c:
+       (astro_contact_row_init):
+       * applications/contacts/astro-contacts-details.c:
+       * applications/contacts/astro-contacts-window.c:
+       (astro_contacts_window_init):
+       * applications/contacts/astro-texture-group.c:
+       * applications/example/init.c: (astro_application_factory_init):
+       * libastro-desktop/astro.h:
+       Fixes to the contacts application to behave at different resolutions.
+
+2008-01-31  Neil J. Patel  <njp@o-hand.com>
+
+       * libastro-desktop/tidy-private.h:
+       Forgot to add this.     
+
+2008-01-31  Neil J Patel  <njp@o-hand.com>
+
+       * src/astro-systray.c: (set_time), (astro_systray_init):
+       Choose sizes depending on stage size, rather than magic values.
+
+2008-01-30  Neil J. Patel  <njp@o-hand.com>
+
+       * applets/cal.json:
+       * applets/clock.json:
+       * applets/weather.json:
+       * applications/contacts/astro-contact-row.c:
+       * applications/contacts/astro-contacts-window.c:
+       * applications/contacts/astro-texture-group.c:
+       * configure.ac:
+       * libastro-desktop/Makefile.am:
+       * libastro-desktop/astro-defines.h:
+       * libastro-desktop/tidy-texture-frame.c:
+       (tidy_texture_frame_paint), (tidy_texture_frame_set_property),
+       (tidy_texture_frame_get_property), (tidy_texture_frame_class_init),
+       (tidy_texture_frame_init), (tidy_texture_frame_new):
+       * libastro-desktop/tidy-texture-frame.h:
+       * src/astro-applet.c:
+       Bring the Tidy actors in-house.
+
+2008-01-30  Neil J Patel  <njp@o-hand.com>
+
+       * applets/clock.json:
+       * applications/contacts/init.c: (astro_application_factory_init):
+       * applications/music/init.c: (astro_application_factory_init):
+       * libastro-desktop/astro-defines.h:
+       * src/astro-appview.c:
+       * src/astro-desktop.c: (load_applications):
+       Misc fixes to allow astro to run at smaller resolutions.
+
+2008-01-29  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-songs.c: (bounds_check), (on_event):
+       Fixed bounds checking bug.
+
+2008-01-25  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c: (on_cover_clicked):
+       * applications/music/astro-songs.c: (on_event), (astro_songs_init):
+       Added in kinetic scrolling. Needs to be pulled out into own widget and
+       tweaked.
+
+2008-01-25  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-reflection.c:
+       (astro_reflection_set_active):
+       * applications/music/astro-songs.c: (astro_songs_set_active),
+       (on_event), (astro_songs_init):
+       * applications/music/astro-songs.h:
+       Added poor mans scrolling to the song list..now ot convert it to
+       something resembling kinetic scrolling.
+       Fixed the clips & event capture so that it works without interfering
+       with the rest of the app.
+
+2008-01-25  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contacts-window.c:
+       (astro_contacts_list_alpha):
+       * applications/music/Makefile.am:
+       * applications/music/astro-music-window.c: (on_cover_activated),
+       (astro_music_window_init):
+       * applications/music/astro-music-window.h:
+       * applications/music/astro-reflection.c:
+       (astro_reflection_set_active), (astro_reflection_set_pixbuf):
+       * applications/music/astro-songs.c: (astro_songs_class_init),
+       (astro_songs_init), (astro_songs_new):
+       * applications/music/astro-songs.h:
+       * data/albums/Makefile.am:
+       Lots more fixes, added a song list (needs scrolling support).
+       Added a few more albums.
+
+2008-01-22  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/Makefile.am:
+       * applications/contacts/astro-contact-row.h:
+       * applications/contacts/astro-contacts-details.c: (on_fade_out),
+       (astro_contact_details_set_active),
+       (astro_contact_details_class_init), (astro_contact_details_init):
+       * applications/contacts/astro-contacts-details.h:
+       * applications/contacts/astro-contacts-window.c:
+       (ensure_layout_proper), (astro_contacts_window_init):
+       * applications/contacts/astro-contacts-window.h:
+       * applications/contacts/astro-texture-group.c:
+       (astro_texture_group_set_text), (astro_texture_group_set_property),
+       (astro_texture_group_get_property),
+       (astro_texture_group_class_init), (astro_texture_group_init),
+       (astro_texture_group_new):
+       * applications/contacts/astro-texture-group.h:
+       More stuff added. More to come.
+
+2008-01-17  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contacts-window.c: (load_contacts):
+       Added more information for each contact.
+
+2008-01-17  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contact-row.c:
+       (astro_contact_row_init):
+       Fix some more stuff up.
+       
+       * data/Makefile.am:
+       Add another asset.
+
+2008-01-17  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contact-row.c:
+       (astro_contact_row_set_name), (astro_contact_row_init):
+       * applications/contacts/astro-contact-row.h:
+       Add in icon, adjust the sizes of the icons.
+
+2008-01-16  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contact-row.c:
+       (astro_contact_row_init):
+       * applications/contacts/astro-contacts-details.c:
+       (astro_contact_details_set_pixbuf),
+       (astro_contact_details_get_property), (astro_contact_details_init):
+       * applications/contacts/astro-contacts-window.c:
+       (astro_contacts_window_init):
+       * data/contact-bar.svg:
+       More and more tweaks, plus timelines now match for contact animations.
+
+2008-01-16  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contact-row.c:
+       (astro_contact_row_set_name), (astro_contact_row_init):
+       Positioning tweaks.
+
+       * data/contact-bar.svg:
+       Remove border, so it looks nicer.
+
+2008-01-15  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contacts-window.c:
+       (on_contact_activated), (astro_contacts_window_init):
+       Some more positioning tweaks.
+       Added in the face.png image for contacts application.
+
+2008-01-15  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contact-row.c: (on_active_completed),
+       (astro_contact_row_set_active), (_resize_alpha),
+       (astro_contact_row_init):
+       * applications/contacts/astro-contacts-window.c: (ensure_layout),
+       (ensure_layout_proper), (astro_contacts_list_window_advance),
+       (on_main_timeline_completed):
+       Try and get the resize of the background to appear as its pushing
+       the row beneath away.
+       Update the alpha-calculating function.
+
+       * applications/music/astro-music-window.c: (astro_music_alpha),
+       (astro_music_window_init):
+       Update the alpha-calculating function.
+
+2008-01-15  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/Makefile.am:
+       * applications/contacts/astro-contact-row.c: (on_active_completed),
+       (on_inactive_completed), (astro_contact_row_set_active),
+       (astro_contact_row_set_name), (astro_contact_row_set_icon),
+       (_resize_alpha), (astro_contact_row_set_property),
+       (astro_contact_row_get_property), (astro_contact_row_class_init),
+       (astro_contact_row_init), (astro_contact_row_new):
+       * applications/contacts/astro-contact-row.h:
+       * applications/contacts/astro-contacts-window.c: (ensure_layout),
+       (make_contact), (astro_contacts_window_init):
+       * applications/music/astro-music-window.c: (astro_music_alpha),
+       (astro_music_window_init):
+       * data/Makefile.am:
+       Changing some things around in contacts app to try and make it
+       look/work nicer.
+
+2008-01-13  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/Makefile.am:
+       Actually make the contacts application!
+
+2008-01-13  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/Makefile.am:
+       * applications/contacts/astro-contacts-details.c:
+       (astro_contact_details_set_pixbuf),
+       (astro_contact_details_set_property),
+       (astro_contact_details_get_property),
+       (astro_contact_details_class_init), (astro_contact_details_init),
+       (astro_contact_details_new):
+       * applications/contacts/astro-contacts-details.h:
+       * applications/contacts/astro-contacts-window.c:
+       (on_contact_activated), (on_contact_clicked), (load_contacts),
+       (on_key_release_event):
+       Rename astro-reflection as it was conflicting with the one in
+       music.app.
+       Starting of a contact-details widget, to show photo + actions.
+       Initally position all labels at CSH(), so they slide in.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contacts-window.c:
+       (astro_contacts_window_init):
+       * data/Makefile.am:
+       * data/contact-bar.svg:
+       Woo! Contact Bar! Does nothing usefule yet!
+       
+       * data/disc_bg.svg:
+       Added a border so you can see it clearer now.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contacts-window.c: (ensure_layout):
+       Some more spacing fixes.
+
+       * data/background.svg:
+       Changed to a darker backgrounf to get some more contrast.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+
+       * applications/contacts/astro-contacts-window.c: (make_contact),
+       (load_contacts), (astro_contacts_list_alpha),
+       (astro_contacts_window_init):
+       More tweaks to the spacing, speed and accuracy of the animation.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/astro-contacts-window.c: (ensure_layout),
+       (astro_contacts_list_window_advance),
+       (on_contact_active_completed), (on_contact_activated),
+       (on_contact_clicked), (make_contact), (load_details),
+       (load_contacts), (astro_contacts_list_alpha),
+       (on_main_timeline_completed), (on_key_release_event),
+       (astro_contacts_window_init):
+       Created the main contact list, added animations to move through it.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/contacts/Makefile.am:
+       * applications/contacts/astro-contacts-window.c: (ensure_layout),
+       (astro_contacts_window_advance), (on_cover_active_completed),
+       (on_cover_activated), (on_cover_clicked), (make_cover),
+       (load_details), (load_albums), (astro_contacts_alpha),
+       (on_main_timeline_completed), (on_key_release_event),
+       (astro_contacts_window_class_init), (astro_contacts_window_init),
+       (astro_contacts_window_new):
+       * applications/contacts/astro-contacts-window.h:
+       * applications/contacts/astro-contacts.c: (get_title), (set_title),
+       (get_icon), (set_icon), (get_window), (close),
+       (astro_contacts_class_init), (astro_contacts_init),
+       (astro_contacts_new):
+       * applications/contacts/astro-contacts.h:
+       * applications/contacts/astro-reflection.c: (fix_clip),
+       (astro_reflection_set_active), (astro_reflection_set_pixbuf),
+       (astro_reflection_set_property), (astro_reflection_get_property),
+       (astro_reflection_class_init), (astro_reflection_init),
+       (astro_reflection_new):
+       * applications/contacts/astro-reflection.h:
+       * applications/contacts/clutter-reflect-texture.c:
+       (reflect_texture_render_to_gl_quad),
+       (clutter_reflect_texture_paint),
+       (clutter_reflect_texture_set_property),
+       (clutter_reflect_texture_get_property),
+       (clutter_reflect_texture_class_init),
+       (clutter_reflect_texture_init), (clutter_reflect_texture_new):
+       * applications/contacts/clutter-reflect-texture.h:
+       * applications/contacts/init.c: (astro_application_factory_init):
+       * configure.ac:
+       * data/icons/Makefile.am:
+       Beginings of a contacts application.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/init.c: (astro_application_factory_init):
+       Set the correct name for the application.
+
+       * src/astro-desktop.c: (astro_desktop_show_application),
+       (astro_desktop_hide_application):
+       * src/astro-panel.c: (astro_panel_set_header), (astro_panel_init):
+       * src/astro-panel.h:
+       Set the title and icon for the current window.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-reflection.c: (fix_clip),
+       (astro_reflection_set_active):
+       Some clever clipping to make the reflection look proper.
+
+       * libastro-desktop/astro-utils.c: (astro_utils_set_clip):
+       Added HAVE_CLIP, which can be set to 0 to disable clipping.     
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-reflection.c:
+       (astro_reflection_set_active), (astro_reflection_set_pixbuf):
+       Added reflections for album slide out.
+       
+       * libastro-desktop/Makefile.am:
+       * libastro-desktop/astro-utils.c: (astro_utils_set_clip):
+       * libastro-desktop/astro-utils.h:
+       Beginings of a clutter_actor_set_clip wrapper which we can disable at
+       compile-time for gles chips which can handle clips.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c:
+       (on_cover_active_completed), (on_cover_activated),
+       (on_cover_clicked), (on_key_release_event),
+       (astro_music_window_init):
+       Added ability to close ablums covers again & return to original state.
+       
+       * data/disc_bg.svg:
+       Stamped the bg with hand of OH! 
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c: (ensure_layout),
+       (astro_music_window_advance), (on_cover_active_completed),
+       (on_cover_activated), (on_cover_clicked), (load_albums),
+       (astro_music_alpha), (on_main_timeline_completed),
+       (on_key_release_event), (astro_music_window_init):
+       * applications/music/astro-reflection.c:
+       (astro_reflection_set_active), (astro_reflection_set_pixbuf),
+       (astro_reflection_init):
+       * applications/music/astro-reflection.h:
+       * data/Makefile.am:
+       * data/disc_bg.svg:     
+       Added album activation, and a 'starting' songs widget (press
+       enter/click on an album).
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c: (ensure_layout),
+       (on_cover_clicked), (load_albums), (astro_music_window_init):
+       Respond to button-press-events, tweak the animation some more.
+
+2008-01-12  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c:
+       (on_main_timeline_completed), (astro_music_window_init):
+       Some fixes for the album view effect.
+
+       * applications/music/clutter-reflect-texture.c:
+       (clutter_reflect_texture_paint):
+       Swapped gl calls for cogl calls and removed glDisable calls, so
+       the ClutterReflectTexture now works perfectly.
+
+2008-01-11  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c: (load_albums):
+       Intially set the covers off the screen, so they slide in.
+
+       * libastro-desktop/astro-window.c: (astro_window_close):
+       On close, slide the window out of the RHS.
+
+2008-01-11  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c: (ensure_layout),
+       (astro_music_window_advance), (astro_music_alpha),
+       (on_key_release_event), (astro_music_window_init):
+       Hooked up the keyboard to allow moving between albums.
+       Beefed up the alpha_func + layout calculation.
+
+2008-01-11  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/astro-music-window.c: (ensure_layout),
+       (make_cover), (load_details), (load_albums), (astro_music_alpha),
+       (astro_music_window_init):
+       * libastro-desktop/Makefile.am:
+       * libastro-desktop/astro-behave.c: (astro_behave_alpha_notify),
+       (astro_behave_class_init), (astro_behave_init), (astro_behave_new):
+       * libastro-desktop/astro-behave.h:
+       Intermediate commit before laying the smackdown on the music app.
+
+2008-01-11  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/Makefile.am:
+       * applications/music/astro-music-window.c: (ensure_layout),
+       (make_cover), (load_albums), (astro_music_window_init):
+       * applications/music/astro-reflection.c:
+       (astro_reflection_set_pixbuf), (astro_reflection_set_property),
+       (astro_reflection_get_property), (astro_reflection_class_init),
+       (astro_reflection_init), (astro_reflection_new):
+       * applications/music/astro-reflection.h:
+       * applications/music/clutter-reflect-texture.c:
+       (reflect_texture_render_to_gl_quad),
+       (clutter_reflect_texture_paint),
+       (clutter_reflect_texture_set_property),
+       (clutter_reflect_texture_get_property),
+       (clutter_reflect_texture_class_init),
+       (clutter_reflect_texture_init), (clutter_reflect_texture_new):
+       * applications/music/clutter-reflect-texture.h:
+       Add a reflected texture actor which wraps ClutterReflectTexture.
+       Needs work, everything is white!
+
+2008-01-11  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/music/Makefile.am:
+       * applications/music/astro-music-window.c: (make_cover),
+       (load_albums), (astro_music_window_class_init),
+       (astro_music_window_init), (astro_music_window_new):
+       * applications/music/astro-music-window.h:
+       * applications/music/astro-music.c: (get_window):
+       Beginings of a music browser/player.
+
+       * configure.ac:
+       * data/Makefile.am:
+       * data/albums/Makefile.am:
+       Added in albums for music app.
+
+       * src/astro-desktop.c: (astro_desktop_show_application):
+       Set the window position as [0, 0], so it can decide where it wants
+       to be.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * applications/Makefile.am:
+       * applications/example/init.c: (astro_application_factory_init):
+       * applications/music/Makefile.am:
+       * applications/music/astro-music.c: (get_title), (set_title),
+       (get_icon), (set_icon), (get_window), (close),
+       (astro_music_class_init), (astro_music_init), (astro_music_new):
+       * applications/music/astro-music.h:
+       * applications/music/init.c: (astro_application_factory_init):
+       * configure.ac:
+       * data/icons/Makefile.am:
+       * libastro-desktop/astro-application.h:
+       Add the begginings of an music application.
+       Sort out the typing in the module loading function.
+       Add in the music icon.
+       Realise that I may need to learn shader programming.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * src/astro-desktop.c: (load_applications):
+       Add back the 'filler' apps, so the main list still looks good.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * Makefile.am:
+       * applications/Makefile.am:
+       * applications/example/Makefile.am:
+       * applications/example/astro-example.c: (get_title), (set_title),
+       (get_icon), (set_icon), (get_window), (close),
+       (astro_example2_class_init), (astro_example2_init),
+       (astro_example2_new):
+       * applications/example/astro-example.h:
+       * applications/example/init.c: (astro_application_factory_init):
+       * configure.ac:
+       * libastro-desktop/Makefile.am:
+       * libastro-desktop/astro-application.c:
+       * libastro-desktop/astro-application.h:
+       * libastro-desktop/astro.h:
+       * src/Makefile.am:
+       * src/astro-desktop.c: (_load_app_module), (load_applications):
+       Allow applications to be loaded as .so modules.
+       Added an simple example application.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libastro-desktop/astro-application.c:
+       * libastro-desktop/astro-application.h:
+       * src/astro-desktop.c: (astro_desktop_show_application):
+       * src/astro-example.c: (get_window), (astro_example_class_init):
+       Make AstroWindow manditory.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libastro-desktop/Makefile.am:
+       * libastro-desktop/astro-window.c: (astro_window_show),
+       (astro_window_hide), (astro_window_close),
+       (astro_window_class_init), (astro_window_init), (astro_window_new):
+       * libastro-desktop/astro-window.h:
+       A wrapper for app windows, with transitions.
+       
+       * src/astro-appview.c: (on_appicon_clicked),
+       (astro_appview_get_active_app), (astro_appview_class_init):
+       * src/astro-appview.h:
+       A function to retrieve the active application.
+       
+       * src/astro-desktop.c: (astro_desktop_show_application),
+       (astro_desktop_hide_application), (on_appview_activated),
+       (on_key_release_event), (on_panel_home_clicked),
+       (astro_desktop_init):
+       Actually show/hide application windows when icon is activated.
+       Connect to the panel signals to restore the desktop/close a window.
+       
+       * src/astro-example.c: (get_window):
+       Use the AstroWindow actor.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * configure.ac:
+       * libastro-desktop/Makefile.am:
+       * src/Makefile.am:
+       Make sure we are compiling with -Werror, cos it's fun.
+
+       * src/astro-appicon.c: (on_clicked),
+       (astro_appicon_set_application):
+       * src/astro-applet-manager.c: (_load_script):
+       * src/astro-applet.c: (astro_applet_paint):
+       * src/astro-appview.c: (ensure_layout):
+       * src/astro-desktop.c: (on_appview_activated),
+       (astro_desktop_init):
+       * src/astro-systray.c: (set_time):
+       * src/main.c: (main):
+       Consequences of compiling with -Werror.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * libastro-desktop/astro-defines.h:
+       Add ASTRO_APPICON_SPACING() #define.
+       Set the spacing to 0.9 of the icon size.
+
+       * src/astro-appview.c: (astro_appview_show), (astro_appview_hide),
+       (astro_appview_set_app_list), (astro_appview_advance):
+       Use ASTRO_APPICON_SPACING () to allow different spacing widths.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * src/astro-applet-manager.c: (astro_applet_manager_show):
+       Actually make it hide in the right direction!
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+
+       * src/astro-applet-manager.c: (astro_applet_manager_hide):
+       Move off to the left.
+
+       * src/astro-appview.c: (astro_appview_show), (astro_appview_hide):
+       Move off the left; Restore to the last active icon.
+
+       * src/astro-panel.c: (astro_panel_init):
+       Correct the home icon & title label positioning.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * src/astro-appview.c: (astro_appview_advance):
+       Correct bounds check on main list.
+
+2008-01-10  Neil J. Patel  <njp@o-hand.com>
+
+       * src/astro-applet-manager.c: (astro_applet_manager_show),
+       (on_hide_timeline_completed), (astro_applet_manager_hide),
+       (astro_applet_manager_class_init), (astro_applet_manager_init):
+       Override hide/show to make it a transition.
+
+       * src/astro-appview.c: (astro_appview_set_app_list):
+       Call _show () on actors individually, rather than the entire group.
+
+       * src/astro-desktop.c: (on_key_release_event),
+       (astro_desktop_init):
+       Also hide/show the applets in enter (for testing).
+
+       * src/astro-panel.c:
+       ?
+
+2008-01-09  Neil J. Patel  <njp@o-hand.com>
+
+       * src/astro-appview.c: (astro_appview_show),
+       (on_hide_timeline_completed), (astro_appview_hide),
+       (astro_appview_class_init), (astro_appview_init):
+       Override ClutterActor->show/hide to have an animation.
+
+       * src/astro-desktop.c: (on_key_release_event):
+       Change CLUTTER_Enter to activate show/hide for testing.
+
+2008-01-09  Neil J. Patel  <njp@o-hand.com>
+
+       * data/icons/Makefile.am:
+       Added a few more icons.
+
+       * src/Makefile.am:
+       * src/astro-appicon.c:
+       * src/astro-applet-manager.c: (astro_applet_manager_init):
+       Some spacing fixes.
+
+       * src/astro-panel.c: (astro_panel_init):
+       Added the systray.
+       
+       * src/astro-systray.c: (set_time), (astro_systray_class_init),
+       (astro_systray_init), (astro_systray_new):
+       * src/astro-systray.h:
+       Poor mans systray, with date/time and everything!
+
+2008-01-09  Neil J. Patel  <njp@o-hand.com>
+
+       * AUTHORS:
+       * Makefile.am:
+       * applets/Makefile.am:
+       * applets/cal.json:
+       * applets/clock.json:
+       * applets/mail.json:
+       * applets/weather.json:
+       * autogen.sh:
+       * configure.ac:
+       * data/Makefile.am:
+       * data/background.svg:
+       * data/icons/Makefile.am:
+       * libastro-desktop/Makefile.am:
+       * libastro-desktop/astro-application.c:
+       (astro_application_get_title), (astro_application_set_title),
+       (astro_application_get_icon), (astro_application_set_icon),
+       (astro_application_get_window), (astro_application_close),
+       (astro_application_get_property), (astro_application_set_property),
+       (astro_application_class_init), (astro_application_init):
+       * libastro-desktop/astro-application.h:
+       * libastro-desktop/astro-defines.h:
+       * libastro-desktop/astro.h:
+       * src/Makefile.am:
+       * src/astro-appicon.c: (on_clicked), (astro_appicon_get_title),
+       (astro_appicon_set_application), (astro_appicon_set_blur),
+       (astro_appicon_class_init), (astro_appicon_init),
+       (astro_appicon_new):
+       * src/astro-appicon.h:
+       * src/astro-applet-manager.c: (astro_applet_manager_class_init),
+       (_load_script), (astro_applet_manager_init),
+       (astro_applet_manager_new):
+       * src/astro-applet-manager.h:
+       * src/astro-applet.c: (astro_applet_paint),
+       (astro_applet_class_init), (astro_applet_init), (astro_applet_new):
+       * src/astro-applet.h:
+       * src/astro-appview.c: (ensure_layout),
+       (on_move_timeline_new_frame), (on_appicon_clicked),
+       (astro_appview_set_app_list), (astro_appview_advance),
+       (astro_appview_class_init), (astro_appview_init),
+       (astro_appview_new):
+       * src/astro-appview.h:
+       * src/astro-desktop.c: (on_key_release_event), (load_applications),
+       (astro_desktop_class_init), (astro_desktop_init),
+       (astro_desktop_new):
+       * src/astro-desktop.h:
+       * src/astro-example.c: (get_title), (set_title), (get_icon),
+       (set_icon), (get_window), (set_window), (close),
+       (astro_example_class_init), (astro_example_init),
+       (astro_example_new):
+       * src/astro-example.h:
+       * src/astro-panel.c: (on_home_clicked), (on_close_clicked),
+       (astro_panel_class_init), (astro_panel_init), (astro_panel_new):
+       * src/astro-panel.h:
+       * src/main.c: (main), (load_background):
+       Inital import
diff --git a/attic/astro-desktop/Makefile.am b/attic/astro-desktop/Makefile.am
new file mode 100644 (file)
index 0000000..bb184fd
--- /dev/null
@@ -0,0 +1,7 @@
+SUBDIRS = data libastro-desktop applets applications src
+
+MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub configure depcomp install-sh ltmain.sh Makefile.in missing
+
+snapshot:
+       $(MAKE) dist distdir=$(PACKAGE)-snap`date +"%Y%m%d"`
+
diff --git a/attic/astro-desktop/NEWS b/attic/astro-desktop/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/astro-desktop/README b/attic/astro-desktop/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/astro-desktop/applets/Makefile.am b/attic/astro-desktop/applets/Makefile.am
new file mode 100644 (file)
index 0000000..9294d8a
--- /dev/null
@@ -0,0 +1,11 @@
+dist_applet_DATA = \
+       cal.json \
+       cal.png \
+       clock.json \
+       clock.png \
+       clouds.png \
+       mail.json \
+       mail.png \
+       weather.json 
+
+appletdir = $(pkgdatadir)/applets
diff --git a/attic/astro-desktop/applets/cal.json b/attic/astro-desktop/applets/cal.json
new file mode 100644 (file)
index 0000000..697867f
--- /dev/null
@@ -0,0 +1,32 @@
+{
+  "id" : "applet-child",
+   "type" : "ClutterGroup",
+   "visible" : true,
+   "children": 
+     [ 
+       { "id" : "label-temp",
+         "type" : "ClutterLabel",
+         "x" : "1%",
+         "y" : "12%",
+         "width" : "9%",
+         "text" : "Tuesday",
+         "font-name" : "Sans 10px",
+         "color" : "white",
+         "alignment" : "left",
+         "wrap" : false,
+         "ellipsize" : "none",
+         "visible" : true
+       },       
+       
+       {
+         "id" : "cloud",
+         "type" : "ClutterTexture",
+         "x" : "1%",
+         "y" : 0,
+         "width" : "7%",
+         "height" : "10%",
+         "pixbuf" : "cal.png",
+         "visible" : true
+       }
+     ],
+}
diff --git a/attic/astro-desktop/applets/cal.png b/attic/astro-desktop/applets/cal.png
new file mode 100644 (file)
index 0000000..fca6460
Binary files /dev/null and b/attic/astro-desktop/applets/cal.png differ
diff --git a/attic/astro-desktop/applets/clock.json b/attic/astro-desktop/applets/clock.json
new file mode 100644 (file)
index 0000000..26c58bd
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "id" : "applet-child",
+   "type" : "ClutterGroup",
+   "visible" : true,
+   "children": 
+     [ 
+       { "id" : "label-temp",
+         "type" : "ClutterLabel",
+         "x" : "1%",
+         "y" : "12%",
+         "width" : "10%",
+         "text" : "New York",
+         "font-name" : "Sans 10px",
+         "color" : "white",
+         "alignment" : "left",
+         "wrap" : false,
+         "ellipsize" : "none",
+         "visible" : true
+       },       
+       
+       {
+         "id" : "clock",
+         "type" : "ClutterTexture",
+         "x" : "1%",
+         "y" : 0,
+         "pixbuf" : "clock.png",
+         "height" : "10%",
+         "width" : "8%",
+         "visible" : true
+       }
+      
+     ]
+}
diff --git a/attic/astro-desktop/applets/clock.png b/attic/astro-desktop/applets/clock.png
new file mode 100644 (file)
index 0000000..13bb265
Binary files /dev/null and b/attic/astro-desktop/applets/clock.png differ
diff --git a/attic/astro-desktop/applets/clouds.png b/attic/astro-desktop/applets/clouds.png
new file mode 100644 (file)
index 0000000..87e1db0
Binary files /dev/null and b/attic/astro-desktop/applets/clouds.png differ
diff --git a/attic/astro-desktop/applets/mail.json b/attic/astro-desktop/applets/mail.json
new file mode 100644 (file)
index 0000000..fb76c26
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  "id" : "applet-child",
+   "type" : "ClutterGroup",
+   "visible" : true,
+   "children": 
+     [ 
+       { "id" : "label-temp",
+         "type" : "ClutterLabel",
+         "x" : 0,
+         "y" : "12%",
+         "width" : "12%",
+         "text" : "5 Unread",
+         "font-name" : "Sans 12px",
+         "color" : "white",
+         "alignment" : "center",
+         "wrap" : false,
+         "ellipsize" : "none",
+         "visible" : true
+       },       
+       
+       {
+         "id" : "cloud",
+         "type" : "ClutterTexture",
+         "x" : "1%",
+         "y" : 0,
+         "pixbuf" : "mail.png",
+         "visible" : true
+       }
+      
+     ]
+}
diff --git a/attic/astro-desktop/applets/mail.png b/attic/astro-desktop/applets/mail.png
new file mode 100644 (file)
index 0000000..5ad6e41
Binary files /dev/null and b/attic/astro-desktop/applets/mail.png differ
diff --git a/attic/astro-desktop/applets/weather.json b/attic/astro-desktop/applets/weather.json
new file mode 100644 (file)
index 0000000..c9556b0
--- /dev/null
@@ -0,0 +1,47 @@
+{
+  "id" : "applet-child",
+   "type" : "ClutterGroup",
+   "visible" : true,
+   "children": 
+     [ 
+       { "id" : "label-temp",
+         "type" : "ClutterLabel",
+         "x" : "10%",
+         "y" : "4%",
+         "width" : "8%",
+         "text" : "14 C",
+         "font-name" : "Sans 18px",
+         "color" : "white",
+         "alignment" : "center",
+         "wrap" : false,
+         "ellipsize" : "none",
+         "visible" : true
+       },       
+     
+     { "id" : "label-tomorrow",
+         "type" : "ClutterLabel",
+         "x" : 0,
+         "y" : "12%",
+         "width" : "18%",
+         "text" : "Tomorrow: 15 C",
+         "font-name" : "Sans 10px",
+         "color" : "white",
+         "alignment" : "center",
+         "wrap" : false,
+         "ellipsize" : "none",
+         "visible" : true
+       },       
+       
+       {
+         "id" : "cloud",
+         "type" : "ClutterTexture",
+         "x" : "1%",
+         "y" : 0,
+         "width" : "10%",
+         "height" : "10%",
+         "pixbuf" : "clouds.png",
+         "visible" : true
+       }
+      
+     ]
+}
diff --git a/attic/astro-desktop/applications/Makefile.am b/attic/astro-desktop/applications/Makefile.am
new file mode 100644 (file)
index 0000000..14da3fd
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = contacts example images music
diff --git a/attic/astro-desktop/applications/contacts/Makefile.am b/attic/astro-desktop/applications/contacts/Makefile.am
new file mode 100644 (file)
index 0000000..14679e0
--- /dev/null
@@ -0,0 +1,31 @@
+INCLUDES =\
+       -I$(srcdir) \
+       $(DEPS_CFLAGS) \
+       $(GCC_CFLAGS) \
+       -DPREFIX=\"$(prefix)\" \
+       -DSYSCONFDIR=\"$(sysconfdir)\" \
+       -DPKGDATADIR=\"$(pkgdatadir)\" \
+       -DLIBDIR=\"$(libdir)\" \
+       -I$(top_builddir)/libastro-desktop
+
+APP_SOURCES = \
+       init.c \
+       astro-contact-row.c \
+       astro-contacts.c \
+       astro-contacts-details.c \
+       astro-contacts-window.c \
+       clutter-reflect-texture.c \
+       astro-texture-group.c
+
+APP_LDADD = \
+       $(DEPS_LIBS) \
+       $(top_builddir)/libastro-desktop/libastro-desktop.la            
+        
+
+contactslibdir = $(libdir)/astro-desktop/apps
+contactslib_LTLIBRARIES = contacts.la
+contacts_la_SOURCES = $(APP_SOURCES)
+contacts_la_LIBADD = $(APP_LDADD)
+contacts_la_LDFLAGS = -module -avoid-version
+contacts_la_CFLAGS =
+
diff --git a/attic/astro-desktop/applications/contacts/astro-contact-row.c b/attic/astro-desktop/applications/contacts/astro-contact-row.c
new file mode 100644 (file)
index 0000000..a1b3556
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more row.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-contact-row.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-behave.h>
+
+#include <libastro-desktop/tidy-texture-frame.h>
+
+
+G_DEFINE_TYPE (AstroContactRow, astro_contact_row, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_CONTACT_ROW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_CONTACT_ROW, AstroContactRowPrivate))
+
+#define PADDING (CSH()/200)
+#define ICON_SIZE (ROW_HEIGHT - (PADDING * 2))
+
+struct _AstroContactRowPrivate
+{
+  gchar     *name;
+  GdkPixbuf *icon;
+  gboolean   active;
+
+  /* Actors */
+  ClutterActor *bg;
+  ClutterActor *texture;
+  ClutterActor *label;
+  ClutterActor *bar;
+
+  /* Timelines */
+  ClutterEffectTemplate *active_temp;
+  ClutterTimeline       *active_time;
+  ClutterEffectTemplate *bar_temp;
+  ClutterTimeline       *bar_time;
+  ClutterAlpha          *alpha;
+  ClutterBehaviour      *behave;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_NAME,
+  PROP_ICON
+};
+
+static GdkPixbuf    *bg_pixbuf = NULL;
+static ClutterActor *bg_texture = NULL;
+
+/* Public Functions */
+static void
+on_active_completed (ClutterActor *actor, gpointer data)
+{
+  AstroContactRowPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (data));
+  priv = ASTRO_CONTACT_ROW_GET_PRIVATE (data);
+
+  if (clutter_timeline_is_playing (priv->bar_time))
+    return;
+
+   priv->bar_time = clutter_effect_fade (priv->bar_temp,
+                       priv->bar,
+                       255,
+                       NULL, NULL);
+}
+
+static void
+on_inactive_completed (ClutterActor *actor, gpointer data)
+{
+  AstroContactRowPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (data));
+  priv = ASTRO_CONTACT_ROW_GET_PRIVATE (data);
+
+  clutter_actor_set_height (priv->bg, ROW_HEIGHT);
+  clutter_actor_set_opacity (priv->bar, 0);
+}
+
+void            
+astro_contact_row_set_active (AstroContactRow *row,
+                              gboolean         active)
+{
+  AstroContactRowPrivate *priv;
+  static ClutterTimeline *active_time = NULL;
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (row));
+  priv = row->priv;
+
+  if (priv->active == active)
+    return;
+   
+  priv->active = active;
+
+  if (active)
+    {
+      active_time = clutter_effect_fade (priv->active_temp,
+                                         priv->bg,
+                                         255,
+                                         on_active_completed, row);
+      clutter_timeline_start (priv->active_time);    
+    }
+  else
+    {
+      active_time = clutter_effect_fade (priv->active_temp,
+                                         priv->bg,
+                                         0,
+                                         on_inactive_completed, row);
+      if (clutter_timeline_is_playing (priv->bar_time))
+        clutter_timeline_stop (priv->bar_time);
+
+      priv->bar_time = clutter_effect_fade (priv->active_temp,
+                                     priv->bar,
+                                     0,
+                                     NULL, NULL);
+    }
+}
+
+/* Private functions */
+static void
+astro_contact_row_set_name (AstroContactRow *row, const gchar *name)
+{
+  AstroContactRowPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (row));
+  g_return_if_fail (name);
+  priv = row->priv;
+
+  if (priv->name)
+    g_free (priv->name);
+  priv->name = g_strdup (name);
+
+  clutter_label_set_text (CLUTTER_LABEL (priv->label), name);
+
+  clutter_actor_set_position (priv->label, (PADDING*2)+ICON_SIZE, 
+                    (ROW_HEIGHT /2)-(clutter_actor_get_height (priv->label)/2));
+}
+
+static void
+astro_contact_row_set_icon (AstroContactRow *row, GdkPixbuf *icon)
+{
+  AstroContactRowPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (row));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+  priv = row->priv;
+
+  priv->icon = icon;
+
+  g_object_set (G_OBJECT (priv->texture), "pixbuf", icon, NULL);
+  clutter_actor_set_size (priv->texture, ICON_SIZE, ICON_SIZE);
+}
+
+static void
+_resize_alpha (ClutterBehaviour *behave, 
+               guint32           alpha,
+               AstroContactRow  *row)
+{
+  AstroContactRowPrivate *priv;
+  gfloat factor;
+  gint dest_height = ROW_HEIGHT;
+  gint current_height, diff_height;
+
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (row));
+  priv = row->priv;
+
+  factor = (gfloat)alpha/CLUTTER_ALPHA_MAX_ALPHA;
+
+  if (priv->active)
+    dest_height = (ROW_HEIGHT * 2) + PADDING;
+
+  current_height = clutter_actor_get_height (priv->bg);
+
+  if (current_height > dest_height)
+    diff_height = (current_height - dest_height) * -1;
+  else
+    diff_height = dest_height - current_height;
+
+  clutter_actor_set_height (priv->bg, 
+            current_height + ((diff_height * alpha)/CLUTTER_ALPHA_MAX_ALPHA));
+} 
+
+/* GObject stuff */
+static void
+astro_contact_row_set_property (GObject      *object, 
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  AstroContactRowPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (object));
+  priv = ASTRO_CONTACT_ROW (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_NAME:
+      astro_contact_row_set_name (ASTRO_CONTACT_ROW (object),
+                                  g_value_get_string (value));
+      break;
+    case PROP_ICON:
+      astro_contact_row_set_icon (ASTRO_CONTACT_ROW (object),
+                                  GDK_PIXBUF (g_value_get_object (value)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+astro_contact_row_get_property (GObject    *object, 
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  AstroContactRowPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_CONTACT_ROW (object));
+  priv = ASTRO_CONTACT_ROW (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_NAME:
+      g_value_set_string (value, priv->name);
+    case PROP_ICON:
+      g_value_set_object (value, G_OBJECT (priv->icon));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+  
+static void
+astro_contact_row_class_init (AstroContactRowClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = astro_contact_row_set_property;
+  gobject_class->get_property = astro_contact_row_get_property;
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_NAME,
+    g_param_spec_string ("contact_name",
+                         "Contact Name",
+                         "The contacts name",
+                         " ",
+                         G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_ICON,
+    g_param_spec_object ("contact_icon",
+                         "Contact Icon",
+                         "The contacts icon",
+                         GDK_TYPE_PIXBUF,
+                         G_PARAM_READWRITE));
+
+
+  g_type_class_add_private (gobject_class, sizeof (AstroContactRowPrivate));
+}
+
+static void
+astro_contact_row_init (AstroContactRow *row)
+{
+  AstroContactRowPrivate *priv;
+  ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+  gchar *font = NULL;
+  GdkPixbuf *pixbuf;
+  
+  priv = row->priv = ASTRO_CONTACT_ROW_GET_PRIVATE (row);
+
+  priv->name = NULL;
+  priv->icon = NULL;
+  priv->active = FALSE;
+
+  /* The background texture */
+  if (!GDK_IS_PIXBUF (bg_pixbuf))
+    bg_pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/applet_bg.png", NULL);
+  if (!CLUTTER_IS_ACTOR (bg_texture))
+    {
+      bg_texture = clutter_texture_new_from_pixbuf (bg_pixbuf);
+      clutter_actor_show (bg_texture);
+    }
+  
+  priv->bg = tidy_texture_frame_new (CLUTTER_TEXTURE (bg_texture), 
+                                     15, 15, 15, 15);
+  clutter_container_add_actor (CLUTTER_CONTAINER (row), priv->bg);
+  clutter_actor_set_position (priv->bg, 0, 0);
+  clutter_actor_set_size (priv->bg, CSW()*0.5, ROW_HEIGHT);
+  clutter_actor_set_opacity (priv->bg, 0);
+
+  /* The icon */
+  priv->texture = clutter_texture_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (row), priv->texture);
+  clutter_actor_set_position (priv->texture, PADDING, PADDING);
+  clutter_actor_set_size (priv->texture, ICON_SIZE, ICON_SIZE);
+
+  /* The label */
+  font = g_strdup_printf ("Sans %d", (gint)(ROW_HEIGHT * 0.3));
+  priv->label = clutter_label_new_full (font, " ", &white);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->label), FALSE);
+  clutter_actor_set_width (priv->label, CSW()/2);
+  clutter_container_add_actor (CLUTTER_CONTAINER (row), priv->label);
+  clutter_actor_set_position (priv->label, (PADDING*2) + ICON_SIZE, 
+                              ROW_HEIGHT /2);
+  g_free (font);
+
+  /* Contact bar */
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR"/contact-bar.svg", 
+                                              -1, ROW_HEIGHT-(PADDING*4), TRUE,
+                                              NULL);
+  priv->bar = clutter_texture_new_from_pixbuf (pixbuf);
+  clutter_container_add_actor (CLUTTER_CONTAINER (row), priv->bar);
+  clutter_actor_set_position (priv->bar, 
+                              (PADDING*2) + ICON_SIZE,
+                              ROW_HEIGHT + PADDING);
+  clutter_actor_set_opacity (priv->bar, 0);
+
+  /* Timelines */
+  priv->active_time = clutter_timeline_new_for_duration (200);
+  priv->active_temp = clutter_effect_template_new (priv->active_time,
+                                                   clutter_sine_inc_func);
+  priv->bar_time = clutter_timeline_new_for_duration (600);
+  priv->bar_temp = clutter_effect_template_new (priv->bar_time,
+                                                clutter_sine_inc_func);
+
+  priv->active_time = clutter_timeline_new_for_duration (800);
+  priv->alpha = clutter_alpha_new_full (priv->active_time,
+                                        clutter_sine_inc_func,
+                                        NULL, NULL);
+  priv->behave = astro_behave_new (priv->alpha,
+                                   (AstroBehaveAlphaFunc)_resize_alpha,
+                                   row);
+
+  clutter_actor_show_all (CLUTTER_ACTOR (row));
+}
+
+ClutterActor * 
+astro_contact_row_new (const gchar *name, GdkPixbuf *icon)
+{
+  ClutterActor *row =  g_object_new (ASTRO_TYPE_CONTACT_ROW,
+                                     "contact_name", name,
+                                     "contact_icon", icon,
+                                                                                    NULL);
+  return row;
+}
+
diff --git a/attic/astro-desktop/applications/contacts/astro-contact-row.h b/attic/astro-desktop/applications/contacts/astro-contact-row.h
new file mode 100644 (file)
index 0000000..e84f271
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include "astro-contacts-window.h"
+
+#ifndef _HAVE_ASTRO_CONTACT_ROW_H
+#define _HAVE_ASTRO_CONTACT_ROW_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_CONTACT_ROW astro_contact_row_get_type()
+
+#define ASTRO_CONTACT_ROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_CONTACT_ROW, \
+  AstroContactRow))
+
+#define ASTRO_CONTACT_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_CONTACT_ROW, \
+  AstroContactRowClass))
+
+#define ASTRO_IS_CONTACT_ROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_CONTACT_ROW))
+
+#define ASTRO_IS_CONTACT_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_CONTACT_ROW))
+
+#define ASTRO_CONTACT_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_CONTACT_ROW, \
+  AstroContactRowClass))
+
+#define ROW_HEIGHT (CSH()/11)
+
+typedef struct _AstroContactRow AstroContactRow;
+typedef struct _AstroContactRowClass AstroContactRowClass;
+typedef struct _AstroContactRowPrivate AstroContactRowPrivate;
+
+struct _AstroContactRow
+{
+  ClutterGroup       parent;
+       
+  /*< private >*/
+  AstroContactRowPrivate   *priv;
+};
+
+struct _AstroContactRowClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_contact_row_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_contact_row_new        (const gchar     *name,
+                                              GdkPixbuf       *icon);
+void            astro_contact_row_set_active (AstroContactRow *row,
+                                              gboolean         active);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/astro-contacts-details.c b/attic/astro-desktop/applications/contacts/astro-contacts-details.c
new file mode 100644 (file)
index 0000000..93f3490
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-contacts-details.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-utils.h>
+
+#include "astro-texture-group.h"
+
+G_DEFINE_TYPE (AstroContactDetails, astro_contact_details, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_CONTACT_DETAILS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_CONTACT_DETAILS, AstroContactDetailsPrivate))
+
+#define PADDING (CSH()/50)
+
+struct _AstroContactDetailsPrivate
+{
+  AstroContact *contact;
+  ClutterActor *address;
+  ClutterActor *tel;
+  ClutterActor *email;
+  
+  ClutterEffectTemplate *details_temp;
+  ClutterTimeline       *details_time;
+  ClutterTimeline       *timeline;
+};
+
+void 
+on_fade_out (AstroContactDetails *details)
+{
+  AstroContactDetailsPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_CONTACT_DETAILS (details));
+  priv = details->priv;
+  
+  astro_texture_group_set_text (ASTRO_TEXTURE_GROUP (priv->address),
+                                priv->contact->address);
+  astro_texture_group_set_text (ASTRO_TEXTURE_GROUP (priv->tel),
+                                priv->contact->tel);
+  astro_texture_group_set_text (ASTRO_TEXTURE_GROUP (priv->email),
+                                priv->contact->email);
+
+  clutter_actor_set_y (priv->address, 0);
+  clutter_actor_set_y (priv->tel,   
+                       clutter_actor_get_height (priv->address) + PADDING);
+  clutter_actor_set_y (priv->email,
+                       clutter_actor_get_y (priv->tel) +
+                       clutter_actor_get_height (priv->tel) + PADDING);
+
+  clutter_actor_set_y (CLUTTER_ACTOR (details), 
+                       (CSH()/2)-(clutter_actor_get_height (CLUTTER_ACTOR (details))/2));
+
+  priv->timeline = clutter_effect_fade (priv->details_temp,
+                                  CLUTTER_ACTOR (details),
+                                  255,
+                                  NULL, NULL);
+
+  g_debug ("on_fade_out\n");
+}
+
+void
+astro_contact_details_set_active (AstroContactDetails *details,
+                                  AstroContact        *contact)
+{
+  AstroContactDetailsPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_CONTACT_DETAILS (details));
+  priv = details->priv;
+
+  priv->contact = contact;
+  
+  if (CLUTTER_IS_TIMELINE (priv->timeline))
+    g_object_unref (G_OBJECT (priv->timeline));
+
+  priv->timeline = clutter_effect_fade (priv->details_temp,
+                                  CLUTTER_ACTOR (details),
+                                  0,
+                                 (ClutterEffectCompleteFunc)on_fade_out,
+                                 details);
+
+ g_debug ("set_active"); 
+}
+
+
+/* GObject stuff */
+static void
+astro_contact_details_class_init (AstroContactDetailsClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroContactDetailsPrivate));
+}
+
+static void
+astro_contact_details_init (AstroContactDetails *details)
+{
+  AstroContactDetailsPrivate *priv;
+  priv = details->priv = ASTRO_CONTACT_DETAILS_GET_PRIVATE (details);
+  
+  priv->address = astro_texture_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (details), priv->address);
+  
+  priv->tel = astro_texture_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (details), priv->tel);
+
+  priv->email = astro_texture_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (details), priv->email);
+
+  priv->details_time = clutter_timeline_new_for_duration (500);
+  priv->details_temp = clutter_effect_template_new (priv->details_time, 
+                                                    clutter_sine_inc_func);
+
+  clutter_actor_set_opacity (CLUTTER_ACTOR (details), 0);
+  clutter_actor_show_all (CLUTTER_ACTOR (details));
+}
+
+ClutterActor *
+astro_contact_details_new (void)
+{
+  ClutterActor *details =  g_object_new (ASTRO_TYPE_CONTACT_DETAILS,
+                                                 NULL);
+  return CLUTTER_ACTOR (details);
+}
+
diff --git a/attic/astro-desktop/applications/contacts/astro-contacts-details.h b/attic/astro-desktop/applications/contacts/astro-contacts-details.h
new file mode 100644 (file)
index 0000000..a475e06
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#include "astro-contacts-window.h"
+
+#ifndef _HAVE_ASTRO_CONTACT_DETAILS_H
+#define _HAVE_ASTRO_CONTACT_DETAILS_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_CONTACT_DETAILS astro_contact_details_get_type()
+
+#define ASTRO_CONTACT_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_CONTACT_DETAILS, \
+  AstroContactDetails))
+
+#define ASTRO_CONTACT_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_CONTACT_DETAILS, \
+  AstroContactDetailsClass))
+
+#define ASTRO_IS_CONTACT_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_CONTACT_DETAILS))
+
+#define ASTRO_IS_CONTACT_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_CONTACT_DETAILS))
+
+#define ASTRO_CONTACT_DETAILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_CONTACT_DETAILS, \
+  AstroContactDetailsClass))
+
+typedef struct _AstroContactDetails AstroContactDetails;
+typedef struct _AstroContactDetailsClass AstroContactDetailsClass;
+typedef struct _AstroContactDetailsPrivate AstroContactDetailsPrivate;
+
+struct _AstroContactDetails
+{
+  ClutterGroup       parent;
+       
+  /*< private >*/
+  AstroContactDetailsPrivate   *priv;
+};
+
+struct _AstroContactDetailsClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_contact_details_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_contact_details_new        (void);
+
+void            astro_contact_details_set_active (AstroContactDetails *details,
+                                                  AstroContact        *contact);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/astro-contacts-window.c b/attic/astro-desktop/applications/contacts/astro-contacts-window.c
new file mode 100644 (file)
index 0000000..aeb8b55
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-contacts-window.h"
+
+#include <math.h>
+#include <string.h>
+#include <libastro-desktop/astro.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+#include <libastro-desktop/astro-behave.h>
+#include <libastro-desktop/tidy-texture-frame.h>
+
+#include "astro-contact-row.h"
+#include "astro-contacts-details.h"
+
+G_DEFINE_TYPE (AstroContactsWindow, astro_contacts_window, ASTRO_TYPE_WINDOW);
+
+#define ASTRO_CONTACTS_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_CONTACTS_WINDOW, AstroContactsWindowPrivate))
+
+#define ALBUM_SIZE (CSW()/4)
+#define OH_ADDRESS "Unit R, Homesdale Business Centre\n216-218 Homesdale Road\nBromley, BR12QZ"
+
+#define OH_TEL "01923 820 124"
+
+struct _AstroContactsWindowPrivate
+{
+  GList *contacts_list;
+
+  ClutterActor *contacts;
+  ClutterActor *contacts_eventbox;
+  ClutterActor *label;
+
+  ClutterActor *details;
+
+  gint active;
+  gboolean activated;
+
+  ClutterTimeline  *timeline;
+  ClutterAlpha     *alpha;
+  ClutterBehaviour *behave;
+
+  gint     starty;
+  gint     endy;
+  gint     lasty;
+  guint32  start_time;
+  gboolean mousedown;
+};
+
+static AstroContact contacts[] = {
+  {"Andrew Zaborowski", OH_ADDRESS, OH_TEL, "andrew@o-hand.com"},
+  {"Chris Lord", OH_ADDRESS, OH_TEL, "chris@o-hand.com"},
+  {"Dodji Seketeli", OH_ADDRESS, OH_TEL, "dodji@o-hand.com"},
+  {"Emmanuele Bassi", OH_ADDRESS, OH_TEL, "ebassi@o-hand.com"},
+  {"Iain Holmes", OH_ADDRESS, OH_TEL, "iain@o-hand.com"},
+  {"Jorn Baayen", OH_ADDRESS, OH_TEL, "jorn@o-hand.com"},
+  {"Jussi Kukkonen", OH_ADDRESS, OH_TEL, "jku@o-hand.com"},
+  {"Marcin Juszkiewicz", OH_ADDRESS, OH_TEL, "hrw@o-hand.com"},
+  {"Matthew Allum", OH_ADDRESS, OH_TEL, "mallum@o-hand.com"},
+  {"Neil J. Patel", OH_ADDRESS, OH_TEL, "njp@o-hand.com"},
+  {"Øyvind Kolås", OH_ADDRESS, OH_TEL, "pippin@o-hand.com"},
+  {"Paul Cooper", OH_ADDRESS, OH_TEL, "pgc@o-hand.com"},
+  {"Richard Purdie", OH_ADDRESS, OH_TEL, "rp@o-hand.com"},
+  {"Robert Bradford", OH_ADDRESS, OH_TEL, "rob@o-hand.com"},
+  {"Ross Burton", OH_ADDRESS, OH_TEL, "ross@o-hand.com"},
+  {"Samuel Ortiz", OH_ADDRESS, OH_TEL, "sameo@o-hand.com"},
+  {"Sidske Allum", OH_ADDRESS, OH_TEL, "sid@o-hand.com"},
+  {"Thomas Wood", OH_ADDRESS, OH_TEL, "thomas@o-hand.com"},
+  {"Tomas Frydrych", OH_ADDRESS, OH_TEL, "tf@o-hand.com"}
+};
+
+
+
+static void on_main_timeline_completed (ClutterTimeline  *timeline,
+                                        AstroContactsWindow *window);
+
+/* Public Functions */
+
+/* Private functions */
+typedef struct
+{
+  gint y;
+  gfloat scale;
+
+} ContactTrans;
+
+static void
+ensure_layout (AstroContactsWindow *window)
+{
+#define MAX_DIST 4
+#define SPACING (ROW_HEIGHT * 1.5)
+  AstroContactsWindowPrivate *priv;
+  GList *c;
+  gint i = 0;
+
+  priv = window->priv;
+
+  c = priv->contacts_list;
+  for (c=c; c; c = c->next)
+    {
+      ClutterActor *contact = c->data;
+      ContactTrans *trans = g_object_get_data (G_OBJECT (contact), "trans");
+      gboolean active = FALSE;
+
+      if (i == priv->active)
+        {
+          trans->y = CSH ()/2;
+          trans->scale = 1.0;          
+        }
+      else if (i > priv->active)
+        {
+          gint diff;
+
+          diff = i - priv->active;
+          trans->y = (CSH()/2) + (SPACING * diff);
+          if (diff > MAX_DIST)
+            trans->scale = 0.4;
+          else
+            trans->scale = 0.4 + (0.4 * (MAX_DIST-diff)/MAX_DIST);
+
+        }
+      else
+        {
+          gint diff;
+
+          diff = priv->active - i;
+          trans->y = (CSH()/2) - (SPACING * diff);
+          if (diff > MAX_DIST)
+            trans->scale = 0.4;
+          else
+            trans->scale = 0.4 + (0.4 * (MAX_DIST-diff)/MAX_DIST);        
+        }
+
+      astro_contact_row_set_active (ASTRO_CONTACT_ROW (contact), active);
+
+      i++;
+    }
+}
+
+static void
+ensure_layout_proper (AstroContactsWindow *window)
+{
+#define MAX_DIST 4
+#define SPACING (ROW_HEIGHT * 1.5)
+  AstroContactsWindowPrivate *priv;
+  GList *c;
+  gint i = 0;
+
+  priv = window->priv;
+
+  c = priv->contacts_list;
+  for (c=c; c; c = c->next)
+    {
+      ClutterActor *contact = c->data;
+      ContactTrans *trans = g_object_get_data (G_OBJECT (contact), "trans");
+      gboolean active = FALSE;
+
+      if (i == priv->active)
+        {
+          trans->y = CSH ()/2;
+          trans->scale = 1.0;          
+          active = TRUE;
+
+          astro_contact_details_set_active (ASTRO_CONTACT_DETAILS (priv->details), 
+              &contacts[g_list_index (priv->contacts_list, contact)]);
+        }
+      else if (i > priv->active)
+        {
+          gint diff;
+
+          diff = i - priv->active;
+          trans->y = (CSH()/2) + (SPACING * diff);
+          trans->y += ROW_HEIGHT * 1;
+          if (diff > MAX_DIST)
+            trans->scale = 0.4;
+          else
+            trans->scale = 0.4 + (0.4 * (MAX_DIST-diff)/MAX_DIST);
+          }
+      else
+        {
+          gint diff;
+
+          diff = priv->active - i;
+          trans->y = (CSH()/2) - (SPACING * diff);
+          if (diff > MAX_DIST)
+            trans->scale = 0.4;
+          else
+            trans->scale = 0.4 + (0.4 * (MAX_DIST-diff)/MAX_DIST);        
+        }
+
+      astro_contact_row_set_active (ASTRO_CONTACT_ROW (contact), active);
+
+      i++;
+    }
+}
+static void
+astro_contacts_list_window_advance (AstroContactsWindow *window, gint n)
+{
+  AstroContactsWindowPrivate *priv;
+  gint new_active;
+
+  g_return_if_fail (ASTRO_IS_CONTACTS_WINDOW (window));
+  priv = window->priv;
+  
+  new_active = priv->active + n;
+  if (new_active < 0 || 
+   new_active > (clutter_group_get_n_children (CLUTTER_GROUP (priv->contacts))-1))
+    return;
+
+  priv->active += n;
+  ensure_layout (window);
+
+  g_signal_connect (priv->timeline, "completed",
+                    G_CALLBACK (on_main_timeline_completed), window);
+
+  if (clutter_timeline_is_playing (priv->timeline))
+    clutter_timeline_stop (priv->timeline);
+
+  clutter_timeline_start (priv->timeline);
+
+}
+
+static gboolean
+on_event (ClutterActor        *contacts, 
+          ClutterEvent        *event,
+          AstroContactsWindow *window)
+{
+  AstroContactsWindowPrivate *priv;
+
+  g_return_val_if_fail (ASTRO_IS_CONTACTS_WINDOW (window), FALSE);
+  priv = window->priv;
+
+  if (event->type == CLUTTER_BUTTON_PRESS)
+    {   
+      priv->mousedown = TRUE;
+      priv->starty = priv->lasty = event->button.y;
+      priv->start_time = event->button.time;
+
+      priv->active = -1;
+      clutter_timeline_start (priv->timeline);
+
+      g_debug ("button-press\n");
+    }
+  else if (event->type == CLUTTER_MOTION)
+    {
+      gint offset;
+     
+      if (!priv->mousedown)
+        return FALSE;
+
+      if (event->motion.y > priv->lasty)
+        offset = event->motion.y - priv->lasty;
+      else
+        offset = -1 * (priv->lasty - event->motion.y);
+
+      priv->lasty = event->motion.y;
+
+      clutter_actor_set_y (priv->contacts, 
+                           clutter_actor_get_y (priv->contacts) + offset);
+
+      g_debug ("button-motion\n");
+      return TRUE;
+    }
+  else if (event->type == CLUTTER_BUTTON_RELEASE)
+    {
+      gint endy;
+
+      endy = event->button.y - priv->starty;
+     
+
+      g_print ("endy = %d\n", endy);
+
+      priv->mousedown = FALSE;
+      g_debug ("button-release\n");
+    } 
+  return FALSE;
+}
+
+static void
+on_contact_activated (AstroContactsWindow *window)
+{
+#define ACTIVE_SCALE 1.5
+  AstroContactsWindowPrivate *priv;
+  ClutterActor *contact;
+  GList *children;
+  ContactTrans *trans;
+
+  g_return_if_fail (ASTRO_IS_CONTACTS_WINDOW (window));
+  priv = window->priv;
+
+  children = priv->contacts_list;
+  contact = g_list_nth_data (children, priv->active);
+
+  if (!CLUTTER_IS_ACTOR (contact))
+    return;
+
+  trans = g_object_get_data (G_OBJECT (contact), "trans");
+  if (!trans)
+    return;
+
+  priv->activated = TRUE;
+
+  trans->scale = ACTIVE_SCALE;
+  trans->y = (CSW()/2) - ((ALBUM_SIZE * ACTIVE_SCALE) * 0.5);
+
+  clutter_actor_raise_top (contact);
+
+  if (clutter_timeline_is_playing (priv->timeline))
+    clutter_timeline_rewind (priv->timeline);
+  else
+    clutter_timeline_start (priv->timeline);
+}
+
+static gboolean
+on_contact_clicked (ClutterActor      *contact, 
+                  ClutterEvent      *event,
+                  AstroContactsWindow  *window)
+{
+  AstroContactsWindowPrivate *priv;
+  GList *children;
+  gint n;
+
+  g_return_val_if_fail (ASTRO_IS_CONTACTS_WINDOW (window), FALSE);
+  priv = window->priv;
+
+  children = priv->contacts_list;
+  n = g_list_index (children, contact);
+
+  if (priv->activated)
+    {
+      priv->activated = FALSE;
+      
+      astro_contacts_list_window_advance (window, 0);
+      return FALSE;
+    }
+  if (n == priv->active)
+    on_contact_activated (window);
+  else
+    {
+      gint diff;
+      if (n > priv->active)
+        diff = (n-priv->active);
+      else
+        diff = (priv->active - n) * -1;
+      astro_contacts_list_window_advance (window, diff);
+    }
+
+  return FALSE;
+}
+
+static ClutterActor *
+make_contact (const gchar *name)
+{
+  ClutterActor *row;
+  static GdkPixbuf *face = NULL;
+
+  if (!face)
+    face = gdk_pixbuf_new_from_file (PKGDATADIR"/face.png", NULL);
+
+  row = astro_contact_row_new (name, face);
+
+  clutter_actor_set_anchor_point_from_gravity (row, CLUTTER_GRAVITY_WEST);
+
+  g_object_set_data (G_OBJECT (row), "trans", g_new0 (ContactTrans, 1));
+
+  return row;
+}
+
+static void
+load_contacts (AstroContactsWindow *window)
+{
+#define PADDING 10
+  AstroContactsWindowPrivate *priv;
+  gint i = 0;
+  
+  priv = window->priv;
+
+  for (i = 0; i < G_N_ELEMENTS (contacts); i++)
+     {
+      ClutterActor *contact;
+
+      contact = make_contact (contacts[i].name);
+      clutter_container_add_actor (CLUTTER_CONTAINER (priv->contacts), contact);
+      clutter_actor_set_position (contact, PADDING, CSH());
+      clutter_actor_show_all (contact);
+      clutter_actor_set_reactive (contact, TRUE);
+      g_signal_connect (contact, "button-release-event",
+                        G_CALLBACK (on_contact_clicked), window);
+
+      priv->contacts_list = g_list_append (priv->contacts_list, contact);
+    }
+}
+
+static void
+astro_contacts_list_alpha (ClutterBehaviour *behave,
+                   guint32           alpha_value,
+                   AstroContactsWindow *window)
+{
+  AstroContactsWindowPrivate *priv;
+  gfloat factor;
+  GList *c;
+
+  g_return_if_fail (ASTRO_IS_CONTACTS_WINDOW (window));
+  priv = window->priv;
+
+  factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+  
+  c = priv->contacts_list;
+  for (c=c; c; c = c->next)
+    {
+      ClutterActor *contact = c->data;
+      ContactTrans *trans = g_object_get_data (G_OBJECT (contact), "trans");
+      gdouble cscale, dscale;
+      gint currenty, diffy;
+      
+      currenty = clutter_actor_get_y (contact);
+      if (currenty > trans->y)
+        diffy = (currenty - trans->y) * -1;
+      else
+        diffy = trans->y - currenty;
+
+      //clutter_actor_set_y (contact, currenty + (gint)(diffy*factor));
+      clutter_actor_set_y (contact, 
+                           currenty + 
+                           (gint)((diffy*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA));
+
+      clutter_actor_get_scale (contact, &cscale, &cscale);
+      if (cscale > trans->scale)
+        dscale = (cscale - trans->scale) * -1;
+      else
+        dscale = trans->scale - cscale;
+
+      clutter_actor_set_scale (contact, 
+                              cscale + (dscale*factor),
+                              cscale + (dscale*factor));
+    }
+}
+
+static void
+on_main_timeline_completed (ClutterTimeline  *timeline,
+                            AstroContactsWindow *window)
+{
+  AstroContactsWindowPrivate *priv;
+  
+  g_return_if_fail (ASTRO_CONTACTS_WINDOW (window));
+  priv = window->priv;
+
+  g_signal_handlers_disconnect_by_func (timeline, 
+                                        on_main_timeline_completed,
+                                        window);
+  
+  ensure_layout_proper (window);
+  clutter_timeline_start (priv->timeline);
+}
+
+static gboolean
+on_key_release_event (ClutterActor     *actor, 
+                      ClutterEvent     *event,
+                      AstroContactsWindow *window)
+{
+  AstroContactsWindowPrivate *priv;
+  
+  g_return_val_if_fail (ASTRO_IS_WINDOW (window), FALSE);
+  priv = window->priv;
+
+  switch (event->key.keyval)
+    {
+      case CLUTTER_Return:
+      case CLUTTER_KP_Enter:
+      case CLUTTER_ISO_Enter:
+        on_contact_activated (window);
+        break;
+      case CLUTTER_Up:
+      case CLUTTER_KP_Up:
+        if (priv->activated)
+          {
+            priv->activated = FALSE;
+          }
+        astro_contacts_list_window_advance (window, -1);
+        break;
+      case CLUTTER_Down:
+      case CLUTTER_KP_Down:
+        if (priv->activated)
+          {
+            priv->activated = FALSE;
+          }
+          astro_contacts_list_window_advance (window, 1);
+        break;
+      default:
+        ;
+    }
+
+  return FALSE;
+}
+
+/* GObject stuff */
+static void
+astro_contacts_window_class_init (AstroContactsWindowClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroContactsWindowPrivate));
+}
+
+static void
+astro_contacts_window_init (AstroContactsWindow *window)
+{
+  AstroContactsWindowPrivate *priv;
+    
+  priv = window->priv = ASTRO_CONTACTS_WINDOW_GET_PRIVATE (window);
+
+  priv->contacts_list = NULL;
+  priv->active = 0;
+  priv->activated = FALSE;
+
+  priv->contacts = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (window), priv->contacts);
+  clutter_actor_set_size (priv->contacts, CSW(), CSH());
+  clutter_actor_set_position (priv->contacts, 0, 0);
+
+  priv->contacts_eventbox = clutter_rectangle_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (window),
+                               priv->contacts_eventbox);
+  clutter_actor_set_position (priv->contacts_eventbox, 0, 0);
+  clutter_actor_set_size (priv->contacts_eventbox, CSW()/2, CSH());
+  clutter_actor_set_opacity (priv->contacts_eventbox, 0);
+  clutter_actor_set_reactive (priv->contacts_eventbox, TRUE);
+
+  priv->details = astro_contact_details_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (window), priv->details);
+  clutter_actor_set_position (priv->details, CSW()*0.54, 0);
+
+  load_contacts (window);
+  
+  ensure_layout (window);
+
+  priv->timeline = clutter_timeline_new_for_duration (800);
+  priv->alpha = clutter_alpha_new_full (priv->timeline,
+                                        clutter_sine_inc_func,
+                                        NULL, NULL);
+  priv->behave = astro_behave_new (priv->alpha,
+                                   (AstroBehaveAlphaFunc)astro_contacts_list_alpha,
+                                   window);
+
+  g_signal_connect (priv->timeline, "completed",
+                    G_CALLBACK (on_main_timeline_completed), window);
+
+  clutter_timeline_start (priv->timeline);
+
+  g_signal_connect (window, "key-release-event",
+                    G_CALLBACK (on_key_release_event), window);
+  clutter_grab_keyboard (CLUTTER_ACTOR (window));
+
+  astro_utils_set_clip (CLUTTER_ACTOR (window), 0, ASTRO_PANEL_HEIGHT (),
+                        CSW(), CSH());
+
+  g_signal_connect (priv->contacts_eventbox, "event",
+                    G_CALLBACK (on_event), window);
+
+  clutter_actor_set_position (CLUTTER_ACTOR (window), 0, 0);
+  clutter_actor_show_all (CLUTTER_ACTOR (window));
+}
+
+AstroWindow * 
+astro_contacts_window_new (void)
+{
+  AstroWindow *contacts_window =  g_object_new (ASTRO_TYPE_CONTACTS_WINDOW,
+                                                                                              NULL);
+
+  return contacts_window;
+}
diff --git a/attic/astro-desktop/applications/contacts/astro-contacts-window.h b/attic/astro-desktop/applications/contacts/astro-contacts-window.h
new file mode 100644 (file)
index 0000000..7050392
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_CONTACTS_WINDOW_H
+#define _HAVE_ASTRO_CONTACTS_WINDOW_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_CONTACTS_WINDOW astro_contacts_window_get_type()
+
+#define ASTRO_CONTACTS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_CONTACTS_WINDOW, \
+  AstroContactsWindow))
+
+#define ASTRO_CONTACTS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_CONTACTS_WINDOW, \
+  AstroContactsWindowClass))
+
+#define ASTRO_IS_CONTACTS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_CONTACTS_WINDOW))
+
+#define ASTRO_IS_CONTACTS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_CONTACTS_WINDOW))
+
+#define ASTRO_CONTACTS_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_CONTACTS_WINDOW, \
+  AstroContactsWindowClass))
+
+typedef struct _AstroContactsWindow AstroContactsWindow;
+typedef struct _AstroContactsWindowClass AstroContactsWindowClass;
+typedef struct _AstroContactsWindowPrivate AstroContactsWindowPrivate;
+
+struct _AstroContactsWindow
+{
+  AstroWindow      parent;
+       
+  /*< private >*/
+  AstroContactsWindowPrivate   *priv;
+};
+
+struct _AstroContactsWindowClass 
+{
+  /*< private >*/
+  AstroWindowClass parent_class;
+}; 
+
+typedef struct {
+  gchar *name;
+  gchar *address;
+  gchar *tel;
+  gchar *email;
+
+} AstroContact;
+
+
+GType astro_contacts_window_get_type (void) G_GNUC_CONST;
+
+AstroWindow *  astro_contacts_window_new       (void);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/astro-contacts.c b/attic/astro-desktop/applications/contacts/astro-contacts.c
new file mode 100644 (file)
index 0000000..73d8510
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-contacts.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+
+#include "astro-contacts-window.h"
+
+G_DEFINE_TYPE (AstroContacts, astro_contacts, ASTRO_TYPE_APPLICATION);
+
+#define ASTRO_CONTACTS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_CONTACTS, AstroContactsPrivate))
+       
+struct _AstroContactsPrivate
+{
+  const gchar *title;
+  GdkPixbuf *icon;
+  ClutterActor *window;
+};
+
+/* Public Functions */
+
+/* Private functions */
+static const gchar *
+get_title (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_CONTACTS (app), NULL);
+
+  return ASTRO_CONTACTS (app)->priv->title;
+}
+
+static void
+set_title (AstroApplication *app, const gchar *title)
+{
+  g_return_if_fail (ASTRO_IS_CONTACTS (app));
+  g_return_if_fail (title);
+
+  ASTRO_CONTACTS (app)->priv->title = g_strdup (title);
+}
+
+static GdkPixbuf *
+get_icon (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_CONTACTS (app), NULL);
+
+  return ASTRO_CONTACTS (app)->priv->icon;
+}
+
+static void
+set_icon (AstroApplication *app, GdkPixbuf *icon)
+{
+  g_return_if_fail (ASTRO_IS_CONTACTS (app));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+
+  ASTRO_CONTACTS (app)->priv->icon = icon;
+}
+
+static AstroWindow *
+get_window (AstroApplication *app)
+{
+  AstroContactsPrivate *priv;
+  ClutterActor *window = NULL;
+
+  g_return_val_if_fail (ASTRO_IS_CONTACTS (app), NULL);
+  priv = ASTRO_CONTACTS (app)->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->window))
+    window = priv->window;
+  else
+    {
+      window = CLUTTER_ACTOR (astro_contacts_window_new ());
+    }
+
+  ASTRO_CONTACTS (app)->priv->window = window;
+
+  return ASTRO_WINDOW (window);
+}
+
+static void
+close (AstroApplication *app)
+{
+  AstroContactsPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_CONTACTS (app));
+  priv = ASTRO_CONTACTS (app)->priv;
+  
+  if (CLUTTER_IS_ACTOR (priv->window))
+    clutter_actor_destroy (priv->window);
+}
+
+/* GObject stuff */
+static void
+astro_contacts_class_init (AstroContactsClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  AstroApplicationClass *app_class = ASTRO_APPLICATION_CLASS (klass);
+
+  app_class->get_title = get_title;
+  app_class->set_title = set_title;
+  app_class->get_icon = get_icon;
+  app_class->set_icon = set_icon;
+  app_class->get_window = get_window;
+  app_class->close = close;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroContactsPrivate));
+}
+
+static void
+astro_contacts_init (AstroContacts *contacts)
+{
+  AstroContactsPrivate *priv;
+  priv = contacts->priv = ASTRO_CONTACTS_GET_PRIVATE (contacts);
+
+  priv->title = NULL;
+  priv->icon = NULL;
+  priv->window = NULL;
+}
+
+AstroApplication * 
+astro_contacts_new (const gchar *title, GdkPixbuf *icon)
+{
+  AstroApplication *contacts =  g_object_new (ASTRO_TYPE_CONTACTS,
+                                                                                              NULL);
+
+  astro_application_set_title (contacts, title);
+  astro_application_set_icon (contacts, icon);
+
+  return contacts;
+}
+
diff --git a/attic/astro-desktop/applications/contacts/astro-contacts.h b/attic/astro-desktop/applications/contacts/astro-contacts.h
new file mode 100644 (file)
index 0000000..a755262
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_CONTACTS_H
+#define _HAVE_ASTRO_CONTACTS_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_CONTACTS astro_contacts_get_type()
+
+#define ASTRO_CONTACTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_CONTACTS, \
+  AstroContacts))
+
+#define ASTRO_CONTACTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_CONTACTS, \
+  AstroContactsClass))
+
+#define ASTRO_IS_CONTACTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_CONTACTS))
+
+#define ASTRO_IS_CONTACTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_CONTACTS))
+
+#define ASTRO_CONTACTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_CONTACTS, \
+  AstroContactsClass))
+
+typedef struct _AstroContacts AstroContacts;
+typedef struct _AstroContactsClass AstroContactsClass;
+typedef struct _AstroContactsPrivate AstroContactsPrivate;
+
+struct _AstroContacts
+{
+  AstroApplication       parent;
+       
+  /*< private >*/
+  AstroContactsPrivate   *priv;
+};
+
+struct _AstroContactsClass 
+{
+  /*< private >*/
+  AstroApplicationClass parent_class;
+}; 
+
+GType astro_contacts_get_type (void) G_GNUC_CONST;
+
+AstroApplication *  astro_contacts_new       (const gchar  *title,
+                                             GdkPixbuf    *icon);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/astro-reflection.c b/attic/astro-desktop/applications/contacts/astro-reflection.c
new file mode 100644 (file)
index 0000000..a9feb43
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-reflection.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-utils.h>
+
+#include "clutter-reflect-texture.h"
+
+G_DEFINE_TYPE (AstroReflection, astro_reflection, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_REFLECTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_REFLECTION, AstroReflectionPrivate))
+
+static GdkPixbuf *disc_bg = NULL;
+
+struct _AstroReflectionPrivate
+{
+  ClutterActor *songs;
+  ClutterActor *songs_reflect;
+  ClutterActor *texture;
+  ClutterActor *reflect;
+  GdkPixbuf    *pixbuf;
+
+  ClutterEffectTemplate *songs_temp;
+  ClutterTimeline       *songs_time;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_PIXBUF
+};
+
+static void
+fix_clip (ClutterTimeline *timeline,
+          gint             frame_num,
+          AstroReflection *reflection)
+{
+  AstroReflectionPrivate *priv;
+  gint size;
+   
+  g_return_if_fail (ASTRO_IS_REFLECTION (reflection));
+  priv = reflection->priv;
+
+  size = clutter_actor_get_width (priv->songs);
+
+  astro_utils_set_clip (priv->songs_reflect,
+                        size - clutter_actor_get_x (priv->songs_reflect),
+                        0, size, size);
+}
+
+void
+astro_reflection_set_active (AstroReflection *reflection,
+                             gboolean         active)
+{
+  AstroReflectionPrivate *priv;
+  static ClutterTimeline *fade_time = NULL;
+  gint x = 0;
+  gint fade = 0;
+   
+  g_return_if_fail (ASTRO_IS_REFLECTION (reflection));
+  priv = reflection->priv;
+
+  if (active)
+  {
+    x = clutter_actor_get_width (priv->texture); 
+    fade = 100;
+  }
+  
+  clutter_effect_move (priv->songs_temp,
+                       priv->songs,
+                       x, clutter_actor_get_y (priv->songs),
+                       NULL, NULL);
+  clutter_effect_move (priv->songs_temp,
+                       priv->songs_reflect,
+                       x, clutter_actor_get_y (priv->songs_reflect),
+                       NULL, NULL);
+
+  fade_time = clutter_effect_fade (priv->songs_temp,
+                                   priv->songs_reflect,
+                                   fade,
+                                   NULL, NULL);
+  g_signal_connect (fade_time, "new-frame",
+                    G_CALLBACK (fix_clip), reflection);
+
+}
+
+void
+astro_reflection_set_pixbuf (AstroReflection *reflection,
+                             GdkPixbuf       *pixbuf)
+{
+  AstroReflectionPrivate *priv;
+  gint height;
+  
+  g_return_if_fail (ASTRO_IS_REFLECTION (reflection));
+  priv = reflection->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->texture))
+    clutter_actor_destroy (priv->texture);
+  
+  if (CLUTTER_IS_ACTOR (priv->reflect))
+    clutter_actor_destroy (priv->reflect);
+
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  /* Songs widget */
+  if (!disc_bg)
+    {
+      disc_bg = gdk_pixbuf_new_from_file_at_size (PKGDATADIR"/disc_bg.svg",
+                                                  height, height, NULL);
+    }
+  priv->songs = clutter_texture_new_from_pixbuf (disc_bg);
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), priv->songs);
+  clutter_actor_set_size (priv->songs, height, height);
+  clutter_actor_set_position (priv->songs, 0, 0);
+
+  priv->songs_reflect = clutter_reflect_texture_new (CLUTTER_TEXTURE (priv->songs),
+                                               height * 0.7);
+  clutter_actor_set_opacity (priv->songs_reflect, 0);
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), 
+                               priv->songs_reflect);
+  clutter_actor_set_position (priv->songs_reflect, 0, height+1);
+     
+  /* Album cover */
+  priv->texture = g_object_new (CLUTTER_TYPE_TEXTURE,
+                                "pixbuf", pixbuf,
+                                "tiled", FALSE,
+                                NULL);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection),
+                               priv->texture);
+  clutter_actor_set_position (priv->texture, 0, 0);
+  
+  priv->reflect = clutter_reflect_texture_new (CLUTTER_TEXTURE (priv->texture),
+                                               height * 0.7);
+  clutter_actor_set_opacity (priv->reflect, 100);
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), 
+                               priv->reflect);
+  clutter_actor_set_position (priv->reflect, 0, height+1);
+  
+  clutter_actor_set_anchor_point (CLUTTER_ACTOR (reflection),
+                                  clutter_actor_get_width (priv->texture)/2,
+                                  height/2);
+
+  clutter_actor_show_all (CLUTTER_ACTOR (reflection));
+}
+
+/* GObject stuff */
+static void
+astro_reflection_set_property (GObject      *object, 
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  AstroReflectionPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_REFLECTION (object));
+  priv = ASTRO_REFLECTION (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_PIXBUF:
+      astro_reflection_set_pixbuf (ASTRO_REFLECTION (object),
+                                   GDK_PIXBUF (g_value_get_object (value)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+astro_reflection_get_property (GObject    *object, 
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  AstroReflectionPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_REFLECTION (object));
+  priv = ASTRO_REFLECTION (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_PIXBUF:
+      g_value_set_object (value, G_OBJECT (priv->pixbuf));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+astro_reflection_class_init (AstroReflectionClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = astro_reflection_set_property;
+  gobject_class->get_property = astro_reflection_get_property;
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_PIXBUF,
+    g_param_spec_object ("pixbuf",
+                         "Pixbuf",
+                         "A pixbuf",
+                         GDK_TYPE_PIXBUF,
+                         G_PARAM_READWRITE));
+
+  g_type_class_add_private (gobject_class, sizeof (AstroReflectionPrivate));
+}
+
+static void
+astro_reflection_init (AstroReflection *reflection)
+{
+  AstroReflectionPrivate *priv;
+  priv = reflection->priv = ASTRO_REFLECTION_GET_PRIVATE (reflection);
+
+  priv->texture = NULL;
+  priv->reflect = NULL;
+
+  priv->songs_time = clutter_timeline_new_for_duration (600);
+  priv->songs_temp = clutter_effect_template_new (priv->songs_time, 
+                                                  clutter_sine_inc_func);
+}
+
+ClutterActor *
+astro_reflection_new (GdkPixbuf *pixbuf)
+{
+  ClutterActor *reflection =  g_object_new (ASTRO_TYPE_REFLECTION,
+                                            "pixbuf", pixbuf,
+                                            NULL);
+  return CLUTTER_ACTOR (reflection);
+}
+
diff --git a/attic/astro-desktop/applications/contacts/astro-reflection.h b/attic/astro-desktop/applications/contacts/astro-reflection.h
new file mode 100644 (file)
index 0000000..1d71ea9
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_REFLECTION_H
+#define _HAVE_ASTRO_REFLECTION_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_REFLECTION astro_reflection_get_type()
+
+#define ASTRO_REFLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_REFLECTION, \
+  AstroReflection))
+
+#define ASTRO_REFLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_REFLECTION, \
+  AstroReflectionClass))
+
+#define ASTRO_IS_REFLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_REFLECTION))
+
+#define ASTRO_IS_REFLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_REFLECTION))
+
+#define ASTRO_REFLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_REFLECTION, \
+  AstroReflectionClass))
+
+typedef struct _AstroReflection AstroReflection;
+typedef struct _AstroReflectionClass AstroReflectionClass;
+typedef struct _AstroReflectionPrivate AstroReflectionPrivate;
+
+struct _AstroReflection
+{
+  ClutterGroup       parent;
+       
+  /*< private >*/
+  AstroReflectionPrivate   *priv;
+};
+
+struct _AstroReflectionClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_reflection_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_reflection_new        (GdkPixbuf    *pixbuf);
+
+void            astro_reflection_set_active (AstroReflection *reflection,
+                                             gboolean         active);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/astro-texture-group.c b/attic/astro-desktop/applications/contacts/astro-texture-group.c
new file mode 100644 (file)
index 0000000..fa1d616
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more group.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-texture-group.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-behave.h>
+
+#include <libastro-desktop/tidy-texture-frame.h>
+
+
+G_DEFINE_TYPE (AstroTextureGroup, astro_texture_group, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_TEXTURE_GROUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_TEXTURE_GROUP, AstroTextureGroupPrivate))
+
+#define PADDING (CSH()/30)
+#define GROUP_WIDTH (CSW()*0.45)
+#define GROUP_HEIGHT (CSH()/10) 
+
+static GdkPixbuf    *bg_pixbuf = NULL;
+static ClutterActor *bg_texture = NULL;
+
+struct _AstroTextureGroupPrivate
+{
+  ClutterActor *bg;
+  ClutterActor *label;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_TEXT,
+};
+
+
+/* Public Functions */
+void
+astro_texture_group_set_text (AstroTextureGroup *group, const gchar *text)
+{
+  AstroTextureGroupPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_TEXTURE_GROUP (group));
+  g_return_if_fail (text);
+  priv = group->priv;
+
+  clutter_label_set_text (CLUTTER_LABEL (priv->label), text);
+
+  clutter_actor_set_position (priv->label, PADDING, PADDING);
+  
+  clutter_actor_set_size (priv->bg, 
+                          GROUP_WIDTH,
+                          clutter_actor_get_height (priv->label) + (2*PADDING));
+  clutter_actor_set_position (priv->bg, 0, 0);
+}
+
+/* GObject stuff */
+static void
+astro_texture_group_set_property (GObject      *object, 
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  AstroTextureGroupPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_TEXTURE_GROUP (object));
+  priv = ASTRO_TEXTURE_GROUP (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_TEXT:
+      astro_texture_group_set_text (ASTRO_TEXTURE_GROUP (object),
+                                  g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+astro_texture_group_get_property (GObject    *object, 
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  AstroTextureGroupPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_TEXTURE_GROUP (object));
+  priv = ASTRO_TEXTURE_GROUP (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_TEXT:
+      g_value_set_string (value, 
+                          clutter_label_get_text (CLUTTER_LABEL (priv->label)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+  
+static void
+astro_texture_group_class_init (AstroTextureGroupClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = astro_texture_group_set_property;
+  gobject_class->get_property = astro_texture_group_get_property;
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_TEXT,
+    g_param_spec_string ("text",
+                         "Text",
+                         "The text to display",
+                         " ",
+                         G_PARAM_READWRITE));
+
+  g_type_class_add_private (gobject_class, sizeof (AstroTextureGroupPrivate));
+}
+
+static void
+astro_texture_group_init (AstroTextureGroup *group)
+{
+  AstroTextureGroupPrivate *priv;
+  ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+  gchar *font = NULL;
+
+  
+  priv = group->priv = ASTRO_TEXTURE_GROUP_GET_PRIVATE (group);
+
+  /* The background texture */
+  if (!GDK_IS_PIXBUF (bg_pixbuf))
+    bg_pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/info_bg.png", NULL);
+  if (!CLUTTER_IS_ACTOR (bg_texture))
+    {
+      bg_texture = clutter_texture_new_from_pixbuf (bg_pixbuf);
+      clutter_actor_show (bg_texture);
+    }
+  
+  priv->bg = tidy_texture_frame_new (CLUTTER_TEXTURE (bg_texture), 
+                                     15, 15, 15, 15);
+  clutter_container_add_actor (CLUTTER_CONTAINER (group), priv->bg);
+  clutter_actor_set_position (priv->bg, 0, 0);
+  clutter_actor_set_size (priv->bg, GROUP_WIDTH, GROUP_HEIGHT);
+
+
+  /* The label */
+  font = g_strdup_printf ("Sans %d", (gint)(GROUP_HEIGHT * 0.3));
+  priv->label = clutter_label_new_full (font, " ", &white);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->label), TRUE);
+  clutter_actor_set_width (priv->label, GROUP_WIDTH);
+  clutter_container_add_actor (CLUTTER_CONTAINER (group), priv->label);
+  clutter_actor_set_position (priv->label, PADDING, GROUP_HEIGHT /2);
+  g_free (font);
+
+  clutter_actor_show_all (CLUTTER_ACTOR (group));
+}
+
+ClutterActor * 
+astro_texture_group_new ()
+{
+  ClutterActor *group =  g_object_new (ASTRO_TYPE_TEXTURE_GROUP,
+                                                                    NULL);
+  return group;
+}
+
diff --git a/attic/astro-desktop/applications/contacts/astro-texture-group.h b/attic/astro-desktop/applications/contacts/astro-texture-group.h
new file mode 100644 (file)
index 0000000..1efb939
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include "astro-contacts-window.h"
+
+#ifndef _HAVE_ASTRO_TEXTURE_GROUP_H
+#define _HAVE_ASTRO_TEXTURE_GROUP_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_TEXTURE_GROUP astro_texture_group_get_type()
+
+#define ASTRO_TEXTURE_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_TEXTURE_GROUP, \
+  AstroTextureGroup))
+
+#define ASTRO_TEXTURE_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_TEXTURE_GROUP, \
+  AstroTextureGroupClass))
+
+#define ASTRO_IS_TEXTURE_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_TEXTURE_GROUP))
+
+#define ASTRO_IS_TEXTURE_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_TEXTURE_GROUP))
+
+#define ASTRO_TEXTURE_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_TEXTURE_GROUP, \
+  AstroTextureGroupClass))
+
+#define ROW_HEIGHT (CSH()/11)
+
+typedef struct _AstroTextureGroup AstroTextureGroup;
+typedef struct _AstroTextureGroupClass AstroTextureGroupClass;
+typedef struct _AstroTextureGroupPrivate AstroTextureGroupPrivate;
+
+struct _AstroTextureGroup
+{
+  ClutterGroup       parent;
+       
+  /*< private >*/
+  AstroTextureGroupPrivate   *priv;
+};
+
+struct _AstroTextureGroupClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_texture_group_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_texture_group_new       ();
+void            astro_texture_group_set_text (AstroTextureGroup *group,
+                                              const gchar       *text);
+
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/clutter-reflect-texture.c b/attic/astro-desktop/applications/contacts/clutter-reflect-texture.c
new file mode 100644 (file)
index 0000000..5689d49
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define CLUTTER_PARAM_READWRITE \
+        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+
+
+/**
+ * SECTION:clutter-reflect-texture
+ * @short_description: Actor for cloning existing textures in an 
+ * efficient way.
+ *
+ * #ClutterReflectTexture allows the cloning of existing #ClutterTexture with 
+ * a refelction like effect.
+ */
+
+#include <clutter/cogl.h>
+
+#include "clutter-reflect-texture.h"
+
+enum
+{
+  PROP_0,
+  PROP_REFLECTION_HEIGHT
+};
+
+G_DEFINE_TYPE (ClutterReflectTexture,
+              clutter_reflect_texture,
+              CLUTTER_TYPE_CLONE_TEXTURE);
+
+#define CLUTTER_REFLECT_TEXTURE_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexturePrivate))
+
+struct _ClutterReflectTexturePrivate
+{
+  gint                 reflection_height;
+};
+
+static void
+reflect_texture_render_to_gl_quad (ClutterReflectTexture *ctexture, 
+                                int             x1, 
+                                int             y1, 
+                                int             x2, 
+                                int             y2)
+{
+  gint   qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0;
+  gint   qwidth = 0, qheight = 0;
+  gint   x, y, i =0, lastx = 0, lasty = 0;
+  gint   n_x_tiles, n_y_tiles; 
+  gint   pwidth, pheight, rheight;
+  float tx, ty, ty2 = 0.0;
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+  ClutterReflectTexturePrivate *priv = ctexture->priv;
+  ClutterActor *parent_texture = CLUTTER_ACTOR(clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(ctexture)));
+
+  priv = ctexture->priv;
+
+  qwidth  = x2 - x1;
+  qheight = y2 - y1;
+
+  rheight = priv->reflection_height;
+
+  if (rheight > qheight)
+    rheight = qheight;
+
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+      clutter_actor_realize (parent_texture);
+
+  /* Only paint if parent is in a state to do so */
+  if (!clutter_texture_has_generated_tiles (CLUTTER_TEXTURE(parent_texture)))
+    return;
+  
+  clutter_texture_get_base_size (CLUTTER_TEXTURE(parent_texture), 
+                                &pwidth, &pheight); 
+
+  if (!clutter_texture_is_tiled (CLUTTER_TEXTURE(parent_texture)))
+    {
+      clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), 0);
+
+      /* NPOTS textures *always* used if extension available
+       */
+      if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+       {
+         tx = (float) pwidth;
+         ty = (float) pheight;
+         ty2 = (float)(clutter_actor_get_height (CLUTTER_ACTOR(ctexture)) * rheight) 
+                                             / pheight;
+         ty2 = pheight - ty2;
+
+       }
+      else
+       {
+         tx = (float) pwidth / clutter_util_next_p2 (pwidth);  
+         ty = (float) pheight / clutter_util_next_p2 (pheight);
+       }
+
+      qx1 = x1; qx2 = x2;
+      qy1 = y1; qy2 = y1 + rheight;
+
+      glBegin (GL_QUADS);
+
+      glColor4ub (255, 255, 255, 
+                 clutter_actor_get_opacity (CLUTTER_ACTOR(ctexture)));
+
+      glTexCoord2f (0, ty);   
+      glVertex2i   (qx1, qy1);
+
+      glTexCoord2f (tx,  ty);   
+      glVertex2i   (qx2, qy1);
+
+      glColor4ub (255, 255, 255, 0);
+
+      glTexCoord2f (tx,  ty2);    
+      glVertex2i   (qx2, qy2);
+      
+      glTexCoord2f (0, ty2);    
+      glVertex2i   (qx1, qy2);
+
+      glEnd ();        
+      
+      return;
+    }
+
+  clutter_texture_get_n_tiles (CLUTTER_TEXTURE(parent_texture), 
+                              &n_x_tiles, &n_y_tiles); 
+
+  for (x = 0; x < n_x_tiles; x++)
+    {
+      lasty = 0;
+
+      for (y = 0; y < n_y_tiles; y++)
+       {
+         gint actual_w, actual_h;
+         gint xpos, ypos, xsize, ysize, ywaste, xwaste;
+         
+         clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), i);
+        
+         clutter_texture_get_x_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            x, &xpos, &xsize, &xwaste);
+
+         clutter_texture_get_y_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            y, &ypos, &ysize, &ywaste);
+
+         actual_w = xsize - xwaste;
+         actual_h = ysize - ywaste;
+
+         tx = (float) actual_w / xsize;
+         ty = (float) actual_h / ysize;
+
+         qx1 = x1 + lastx;
+         qx2 = qx1 + ((qwidth * actual_w ) / pwidth );
+         
+         qy1 = y1 + lasty;
+         qy2 = qy1 + ((qheight * actual_h) / pheight );
+
+         glBegin (GL_QUADS);
+         glTexCoord2f (tx, ty);   glVertex2i   (qx2, qy2);
+         glTexCoord2f (0,  ty);   glVertex2i   (qx1, qy2);
+         glTexCoord2f (0,  0);    glVertex2i   (qx1, qy1);
+         glTexCoord2f (tx, 0);    glVertex2i   (qx2, qy1);
+         glEnd ();     
+
+         lasty += qy2 - qy1;     
+
+         i++;
+       }
+      lastx += qx2 - qx1;
+    }
+#endif
+
+}
+
+static void
+clutter_reflect_texture_paint (ClutterActor *self)
+{
+  ClutterReflectTexturePrivate  *priv;
+  ClutterActor                *parent_texture;
+  gint                         x1, y1, x2, y2;
+  GLenum                       target_type;
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+  priv = CLUTTER_REFLECT_TEXTURE (self)->priv;
+
+  /* no need to paint stuff if we don't have a texture to reflect */
+  if (!clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)))
+    return;
+
+  /* parent texture may have been hidden, there for need to make sure its 
+   * realised with resources available.  
+  */
+  parent_texture = CLUTTER_ACTOR (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)));
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+    clutter_actor_realize (parent_texture);
+
+  /* FIXME: figure out nicer way of getting at this info...  
+   */  
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE) &&
+      clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture)) == FALSE)
+    {
+      target_type = CGL_TEXTURE_RECTANGLE_ARB;
+      cogl_enable (CGL_ENABLE_TEXTURE_RECT | CGL_ENABLE_BLEND);
+    }
+  else
+    {
+      target_type = CGL_TEXTURE_2D;
+      cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
+    }
+  
+  cogl_push_matrix ();
+
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glColor4ub (255, 255, 255, clutter_actor_get_opacity (self));
+
+  clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
+
+  /* Parent paint translated us into position */
+  reflect_texture_render_to_gl_quad (CLUTTER_REFLECT_TEXTURE (self), 
+                                  0, 0, x2 - x1, y2 - y1);
+
+  cogl_pop_matrix ();
+#endif
+}
+
+
+
+static void
+clutter_reflect_texture_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterReflectTexture         *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      priv->reflection_height = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  ClutterReflectTexture *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      g_value_set_int (value, priv->reflection_height);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_class_init (ClutterReflectTextureClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->paint = clutter_reflect_texture_paint;
+
+  gobject_class->set_property = clutter_reflect_texture_set_property;
+  gobject_class->get_property = clutter_reflect_texture_get_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_REFLECTION_HEIGHT,
+                                   g_param_spec_int ("reflection-height",
+                                                     "Reflection Height",
+                                                     "",
+                                                     0, G_MAXINT,
+                                                     0,
+                                                     (G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)));
+
+  g_type_class_add_private (gobject_class, sizeof (ClutterReflectTexturePrivate));
+}
+
+static void
+clutter_reflect_texture_init (ClutterReflectTexture *self)
+{
+  ClutterReflectTexturePrivate *priv;
+
+  self->priv = priv = CLUTTER_REFLECT_TEXTURE_GET_PRIVATE (self);
+  priv->reflection_height = 100; 
+}
+
+/**
+ * clutter_reflect_texture_new:
+ * @texture: a #ClutterTexture or %NULL
+ *
+ * Creates an efficient 'reflect' of a pre-existing texture if which it 
+ * shares the underlying pixbuf data.
+ *
+ * You can use clutter_reflect_texture_set_parent_texture() to change the
+ * parent texture to be reflectd.
+ *
+ * Return value: the newly created #ClutterReflectTexture
+ */
+ClutterActor *
+clutter_reflect_texture_new (ClutterTexture *texture, gint reflection_height)
+{
+  g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
+
+  return g_object_new (CLUTTER_TYPE_REFLECT_TEXTURE,
+                      "parent-texture", texture,
+                      "reflection-height", reflection_height,
+                      NULL);
+}
+
diff --git a/attic/astro-desktop/applications/contacts/clutter-reflect-texture.h b/attic/astro-desktop/applications/contacts/clutter-reflect-texture.h
new file mode 100644 (file)
index 0000000..9ba7353
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_REFLECT_TEXTURE_H
+#define _HAVE_CLUTTER_REFLECT_TEXTURE_H
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_REFLECT_TEXTURE (clutter_reflect_texture_get_type ())
+
+#define CLUTTER_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexture))
+
+#define CLUTTER_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+#define CLUTTER_IS_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_IS_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_REFLECT_TEXTURE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+typedef struct _ClutterReflectTexture        ClutterReflectTexture;
+typedef struct _ClutterReflectTexturePrivate ClutterReflectTexturePrivate;
+typedef struct _ClutterReflectTextureClass   ClutterReflectTextureClass;
+
+struct _ClutterReflectTexture
+{
+  ClutterCloneTexture              parent;
+  
+  /*< priv >*/
+  ClutterReflectTexturePrivate    *priv;
+};
+
+struct _ClutterReflectTextureClass 
+{
+  ClutterCloneTextureClass parent_class;
+
+  /* padding for future expansion */
+  void (*_clutter_reflect_1) (void);
+  void (*_clutter_reflect_2) (void);
+  void (*_clutter_reflect_3) (void);
+  void (*_clutter_reflect_4) (void);
+}; 
+
+GType           clutter_reflect_texture_get_type           (void) G_GNUC_CONST;
+
+ClutterActor *  clutter_reflect_texture_new                (ClutterTexture      *texture, gint reflection_height);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/contacts/init.c b/attic/astro-desktop/applications/contacts/init.c
new file mode 100644 (file)
index 0000000..d693877
--- /dev/null
@@ -0,0 +1,26 @@
+
+#include <glib.h>
+#include <libastro-desktop/astro.h>
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+
+#include "astro-contacts.h"
+
+
+AstroApplication *
+astro_application_factory_init ()
+{
+  AstroApplication *app;
+  GdkPixbuf *pixbuf;
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR "/icons/contacts.png", 
+                                     ASTRO_APPICON_SIZE(), ASTRO_APPICON_SIZE(),
+                                     TRUE,
+                                     NULL);
+
+  app = astro_contacts_new ("Contacts", pixbuf);
+
+  g_debug ("Contacts application loaded\n");
+
+  return app;
+}
diff --git a/attic/astro-desktop/applications/example/Makefile.am b/attic/astro-desktop/applications/example/Makefile.am
new file mode 100644 (file)
index 0000000..5e008b9
--- /dev/null
@@ -0,0 +1,26 @@
+INCLUDES =\
+       -I$(srcdir) \
+       $(DEPS_CFLAGS) \
+       $(GCC_CFLAGS) \
+       -DPREFIX=\"$(prefix)\" \
+       -DSYSCONFDIR=\"$(sysconfdir)\" \
+       -DPKGDATADIR=\"$(pkgdatadir)\" \
+       -DLIBDIR=\"$(libdir)\" \
+       -I$(top_builddir)/libastro-desktop
+
+APP_SOURCES = \
+       init.c \
+       astro-example.c
+
+APP_LDADD = \
+       $(DEPS_LIBS) \
+       $(top_builddir)/libastro-desktop/libastro-desktop.la            
+        
+
+examplelibdir = $(libdir)/astro-desktop/apps
+examplelib_LTLIBRARIES = example.la
+example_la_SOURCES = $(APP_SOURCES)
+example_la_LIBADD = $(APP_LDADD)
+example_la_LDFLAGS = -module -avoid-version
+example_la_CFLAGS =
+
diff --git a/attic/astro-desktop/applications/example/astro-example.c b/attic/astro-desktop/applications/example/astro-example.c
new file mode 100644 (file)
index 0000000..fadb7c6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-example.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+
+G_DEFINE_TYPE (AstroExample2, astro_example2, ASTRO_TYPE_APPLICATION);
+
+#define ASTRO_EXAMPLE2_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_EXAMPLE2, AstroExample2Private))
+       
+struct _AstroExample2Private
+{
+  const gchar *title;
+  GdkPixbuf *icon;
+  ClutterActor *window;
+};
+
+/* Public Functions */
+
+/* Private functions */
+static const gchar *
+get_title (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_EXAMPLE2 (app), NULL);
+
+  return ASTRO_EXAMPLE2 (app)->priv->title;
+}
+
+static void
+set_title (AstroApplication *app, const gchar *title)
+{
+  g_return_if_fail (ASTRO_IS_EXAMPLE2 (app));
+  g_return_if_fail (title);
+
+  ASTRO_EXAMPLE2 (app)->priv->title = g_strdup (title);
+}
+
+static GdkPixbuf *
+get_icon (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_EXAMPLE2 (app), NULL);
+
+  return ASTRO_EXAMPLE2 (app)->priv->icon;
+}
+
+static void
+set_icon (AstroApplication *app, GdkPixbuf *icon)
+{
+  g_return_if_fail (ASTRO_IS_EXAMPLE2 (app));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+
+  ASTRO_EXAMPLE2 (app)->priv->icon = icon;
+}
+
+static AstroWindow *
+get_window (AstroApplication *app)
+{
+  AstroExample2Private *priv;
+  ClutterColor color = { 0xff, 0xff, 0x22, 0x22 };
+  ClutterActor *window = NULL, *rect;
+
+  g_return_val_if_fail (ASTRO_IS_EXAMPLE2 (app), NULL);
+  priv = ASTRO_EXAMPLE2 (app)->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->window))
+    window = priv->window;
+  else
+    {
+      window = astro_window_new ();
+      
+      rect = clutter_rectangle_new_with_color (&color);
+      clutter_container_add_actor (CLUTTER_CONTAINER (window), rect);
+      clutter_actor_set_size (rect, CSW (), CSH()-ASTRO_PANEL_HEIGHT());
+      clutter_actor_show (rect);
+    }
+
+  ASTRO_EXAMPLE2 (app)->priv->window = window;
+
+  return ASTRO_WINDOW (window);
+}
+
+static void
+close (AstroApplication *app)
+{
+  AstroExample2Private *priv;
+  
+  g_return_if_fail (ASTRO_IS_EXAMPLE2 (app));
+  priv = ASTRO_EXAMPLE2 (app)->priv;
+  
+  if (CLUTTER_IS_ACTOR (priv->window))
+    clutter_actor_destroy (priv->window);
+}
+
+/* GObject stuff */
+static void
+astro_example2_class_init (AstroExample2Class *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  AstroApplicationClass *app_class = ASTRO_APPLICATION_CLASS (klass);
+
+  app_class->get_title = get_title;
+  app_class->set_title = set_title;
+  app_class->get_icon = get_icon;
+  app_class->set_icon = set_icon;
+  app_class->get_window = get_window;
+  app_class->close = close;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroExample2Private));
+}
+
+static void
+astro_example2_init (AstroExample2 *example2)
+{
+  AstroExample2Private *priv;
+  priv = example2->priv = ASTRO_EXAMPLE2_GET_PRIVATE (example2);
+
+  priv->title = NULL;
+  priv->icon = NULL;
+  priv->window = NULL;
+}
+
+AstroApplication * 
+astro_example2_new (const gchar *title, GdkPixbuf *icon)
+{
+  AstroApplication *example2 =  g_object_new (ASTRO_TYPE_EXAMPLE2,
+                                                                                              NULL);
+
+  astro_application_set_title (example2, title);
+  astro_application_set_icon (example2, icon);
+
+  return example2;
+}
+
diff --git a/attic/astro-desktop/applications/example/astro-example.h b/attic/astro-desktop/applications/example/astro-example.h
new file mode 100644 (file)
index 0000000..a452ecb
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_EXAMPLE2_H
+#define _HAVE_ASTRO_EXAMPLE2_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_EXAMPLE2 astro_example2_get_type()
+
+#define ASTRO_EXAMPLE2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_EXAMPLE2, \
+  AstroExample2))
+
+#define ASTRO_EXAMPLE2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_EXAMPLE2, \
+  AstroExample2Class))
+
+#define ASTRO_IS_EXAMPLE2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_EXAMPLE2))
+
+#define ASTRO_IS_EXAMPLE2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_EXAMPLE2))
+
+#define ASTRO_EXAMPLE2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_EXAMPLE2, \
+  AstroExample2Class))
+
+typedef struct _AstroExample2 AstroExample2;
+typedef struct _AstroExample2Class AstroExample2Class;
+typedef struct _AstroExample2Private AstroExample2Private;
+
+struct _AstroExample2
+{
+  AstroApplication       parent;
+       
+  /*< private >*/
+  AstroExample2Private   *priv;
+};
+
+struct _AstroExample2Class 
+{
+  /*< private >*/
+  AstroApplicationClass parent_class;
+}; 
+
+GType astro_example2_get_type (void) G_GNUC_CONST;
+
+AstroApplication *  astro_example2_new       (const gchar  *title,
+                                             GdkPixbuf    *icon);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/example/init.c b/attic/astro-desktop/applications/example/init.c
new file mode 100644 (file)
index 0000000..4d54fdd
--- /dev/null
@@ -0,0 +1,25 @@
+
+#include <glib.h>
+#include <libastro-desktop/astro.h>
+#include <libastro-desktop/astro-application.h>
+
+#include "astro-example.h"
+
+
+AstroApplication *
+astro_application_factory_init ()
+{
+  AstroApplication *app;
+  GdkPixbuf *pixbuf;
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR "/icons/exec.png", 
+                                     ASTRO_APPICON_SIZE(), ASTRO_APPICON_SIZE(),
+                                     TRUE,
+                                     NULL);
+
+  app = astro_example2_new ("Example Application", pixbuf);
+
+  g_debug ("Example application loaded\n");
+
+  return app;
+}
diff --git a/attic/astro-desktop/applications/images/Makefile.am b/attic/astro-desktop/applications/images/Makefile.am
new file mode 100644 (file)
index 0000000..1eee4a5
--- /dev/null
@@ -0,0 +1,28 @@
+INCLUDES =\
+       -I$(srcdir) \
+       $(DEPS_CFLAGS) \
+       $(GCC_CFLAGS) \
+       -DPREFIX=\"$(prefix)\" \
+       -DSYSCONFDIR=\"$(sysconfdir)\" \
+       -DPKGDATADIR=\"$(pkgdatadir)\" \
+       -DLIBDIR=\"$(libdir)\" \
+       -I$(top_builddir)/libastro-desktop
+
+APP_SOURCES = \
+       init.c \
+       astro-images.c \
+       astro-images-window.c \
+       clutter-reflect-texture.c 
+
+APP_LDADD = \
+       $(DEPS_LIBS) \
+       $(top_builddir)/libastro-desktop/libastro-desktop.la            
+        
+
+imageslibdir = $(libdir)/astro-desktop/apps
+imageslib_LTLIBRARIES = images.la
+images_la_SOURCES = $(APP_SOURCES)
+images_la_LIBADD = $(APP_LDADD)
+images_la_LDFLAGS = -module -avoid-version
+images_la_CFLAGS =
+
diff --git a/attic/astro-desktop/applications/images/astro-images-window.c b/attic/astro-desktop/applications/images/astro-images-window.c
new file mode 100644 (file)
index 0000000..7919147
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-images-window.h"
+
+#include <math.h>
+#include <string.h>
+#include <libastro-desktop/astro.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+#include <libastro-desktop/astro-behave.h>
+#include <libastro-desktop/tidy-texture-frame.h>
+
+G_DEFINE_TYPE (AstroImagesWindow, astro_images_window, ASTRO_TYPE_WINDOW);
+
+#define ASTRO_IMAGES_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ASTRO_TYPE_IMAGES_WINDOW, AstroImagesWindowPrivate))
+
+struct _AstroImagesWindowPrivate
+{
+  gint i;
+};
+
+
+
+/* GObject stuff */
+static void
+astro_images_window_class_init (AstroImagesWindowClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroImagesWindowPrivate));
+}
+
+static void
+astro_images_window_init (AstroImagesWindow *window)
+{
+  AstroImagesWindowPrivate *priv;
+    
+  priv = window->priv = ASTRO_IMAGES_WINDOW_GET_PRIVATE (window);
+
+  clutter_actor_set_position (CLUTTER_ACTOR (window), 0, 0);
+  clutter_actor_show_all (CLUTTER_ACTOR (window));
+}
+
+AstroWindow * 
+astro_images_window_new (void)
+{
+  AstroWindow *images_window =  g_object_new (ASTRO_TYPE_IMAGES_WINDOW,
+                                                                                              NULL);
+
+  return images_window;
+}
diff --git a/attic/astro-desktop/applications/images/astro-images-window.h b/attic/astro-desktop/applications/images/astro-images-window.h
new file mode 100644 (file)
index 0000000..f3995ea
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_IMAGES_WINDOW_H
+#define _HAVE_ASTRO_IMAGES_WINDOW_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_IMAGES_WINDOW astro_images_window_get_type()
+
+#define ASTRO_IMAGES_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_IMAGES_WINDOW, \
+  AstroImagesWindow))
+
+#define ASTRO_IMAGES_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_IMAGES_WINDOW, \
+  AstroImagesWindowClass))
+
+#define ASTRO_IS_IMAGES_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_IMAGES_WINDOW))
+
+#define ASTRO_IS_IMAGES_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_IMAGES_WINDOW))
+
+#define ASTRO_IMAGES_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_IMAGES_WINDOW, \
+  AstroImagesWindowClass))
+
+typedef struct _AstroImagesWindow AstroImagesWindow;
+typedef struct _AstroImagesWindowClass AstroImagesWindowClass;
+typedef struct _AstroImagesWindowPrivate AstroImagesWindowPrivate;
+
+struct _AstroImagesWindow
+{
+  AstroWindow      parent;
+       
+  /*< private >*/
+  AstroImagesWindowPrivate   *priv;
+};
+
+struct _AstroImagesWindowClass 
+{
+  /*< private >*/
+  AstroWindowClass parent_class;
+}; 
+
+GType astro_images_window_get_type (void) G_GNUC_CONST;
+
+AstroWindow *  astro_images_window_new       (void);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/images/astro-images.c b/attic/astro-desktop/applications/images/astro-images.c
new file mode 100644 (file)
index 0000000..e4e8d47
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-images.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+
+#include "astro-images-window.h"
+
+G_DEFINE_TYPE (AstroImages, astro_images, ASTRO_TYPE_APPLICATION);
+
+#define ASTRO_IMAGES_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_IMAGES, AstroImagesPrivate))
+       
+struct _AstroImagesPrivate
+{
+  const gchar *title;
+  GdkPixbuf *icon;
+  ClutterActor *window;
+};
+
+/* Public Functions */
+
+/* Private functions */
+static const gchar *
+get_title (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_IMAGES (app), NULL);
+
+  return ASTRO_IMAGES (app)->priv->title;
+}
+
+static void
+set_title (AstroApplication *app, const gchar *title)
+{
+  g_return_if_fail (ASTRO_IS_IMAGES (app));
+  g_return_if_fail (title);
+
+  ASTRO_IMAGES (app)->priv->title = g_strdup (title);
+}
+
+static GdkPixbuf *
+get_icon (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_IMAGES (app), NULL);
+
+  return ASTRO_IMAGES (app)->priv->icon;
+}
+
+static void
+set_icon (AstroApplication *app, GdkPixbuf *icon)
+{
+  g_return_if_fail (ASTRO_IS_IMAGES (app));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+
+  ASTRO_IMAGES (app)->priv->icon = icon;
+}
+
+static AstroWindow *
+get_window (AstroApplication *app)
+{
+  AstroImagesPrivate *priv;
+  ClutterActor *window = NULL;
+
+  g_return_val_if_fail (ASTRO_IS_IMAGES (app), NULL);
+  priv = ASTRO_IMAGES (app)->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->window))
+    window = priv->window;
+  else
+    {
+      window = CLUTTER_ACTOR (astro_images_window_new ());
+    }
+
+  ASTRO_IMAGES (app)->priv->window = window;
+
+  return ASTRO_WINDOW (window);
+}
+
+static void
+close (AstroApplication *app)
+{
+  AstroImagesPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_IMAGES (app));
+  priv = ASTRO_IMAGES (app)->priv;
+  
+  if (CLUTTER_IS_ACTOR (priv->window))
+    clutter_actor_destroy (priv->window);
+}
+
+/* GObject stuff */
+static void
+astro_images_class_init (AstroImagesClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  AstroApplicationClass *app_class = ASTRO_APPLICATION_CLASS (klass);
+
+  app_class->get_title = get_title;
+  app_class->set_title = set_title;
+  app_class->get_icon = get_icon;
+  app_class->set_icon = set_icon;
+  app_class->get_window = get_window;
+  app_class->close = close;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroImagesPrivate));
+}
+
+static void
+astro_images_init (AstroImages *images)
+{
+  AstroImagesPrivate *priv;
+  priv = images->priv = ASTRO_IMAGES_GET_PRIVATE (images);
+
+  priv->title = NULL;
+  priv->icon = NULL;
+  priv->window = NULL;
+}
+
+AstroApplication * 
+astro_images_new (const gchar *title, GdkPixbuf *icon)
+{
+  AstroApplication *images =  g_object_new (ASTRO_TYPE_IMAGES,
+                                                                                              NULL);
+
+  astro_application_set_title (images, title);
+  astro_application_set_icon (images, icon);
+
+  return images;
+}
+
diff --git a/attic/astro-desktop/applications/images/astro-images.h b/attic/astro-desktop/applications/images/astro-images.h
new file mode 100644 (file)
index 0000000..012d58b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_IMAGES_H
+#define _HAVE_ASTRO_IMAGES_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_IMAGES astro_images_get_type()
+
+#define ASTRO_IMAGES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_IMAGES, \
+  AstroImages))
+
+#define ASTRO_IMAGES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_IMAGES, \
+  AstroImagesClass))
+
+#define ASTRO_IS_IMAGES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_IMAGES))
+
+#define ASTRO_IS_IMAGES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_IMAGES))
+
+#define ASTRO_IMAGES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_IMAGES, \
+  AstroImagesClass))
+
+typedef struct _AstroImages AstroImages;
+typedef struct _AstroImagesClass AstroImagesClass;
+typedef struct _AstroImagesPrivate AstroImagesPrivate;
+
+struct _AstroImages
+{
+  AstroApplication       parent;
+       
+  /*< private >*/
+  AstroImagesPrivate   *priv;
+};
+
+struct _AstroImagesClass 
+{
+  /*< private >*/
+  AstroApplicationClass parent_class;
+}; 
+
+GType astro_images_get_type (void) G_GNUC_CONST;
+
+AstroApplication *  astro_images_new       (const gchar  *title,
+                                             GdkPixbuf    *icon);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/images/clutter-reflect-texture.c b/attic/astro-desktop/applications/images/clutter-reflect-texture.c
new file mode 100644 (file)
index 0000000..5689d49
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define CLUTTER_PARAM_READWRITE \
+        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+
+
+/**
+ * SECTION:clutter-reflect-texture
+ * @short_description: Actor for cloning existing textures in an 
+ * efficient way.
+ *
+ * #ClutterReflectTexture allows the cloning of existing #ClutterTexture with 
+ * a refelction like effect.
+ */
+
+#include <clutter/cogl.h>
+
+#include "clutter-reflect-texture.h"
+
+enum
+{
+  PROP_0,
+  PROP_REFLECTION_HEIGHT
+};
+
+G_DEFINE_TYPE (ClutterReflectTexture,
+              clutter_reflect_texture,
+              CLUTTER_TYPE_CLONE_TEXTURE);
+
+#define CLUTTER_REFLECT_TEXTURE_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexturePrivate))
+
+struct _ClutterReflectTexturePrivate
+{
+  gint                 reflection_height;
+};
+
+static void
+reflect_texture_render_to_gl_quad (ClutterReflectTexture *ctexture, 
+                                int             x1, 
+                                int             y1, 
+                                int             x2, 
+                                int             y2)
+{
+  gint   qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0;
+  gint   qwidth = 0, qheight = 0;
+  gint   x, y, i =0, lastx = 0, lasty = 0;
+  gint   n_x_tiles, n_y_tiles; 
+  gint   pwidth, pheight, rheight;
+  float tx, ty, ty2 = 0.0;
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+  ClutterReflectTexturePrivate *priv = ctexture->priv;
+  ClutterActor *parent_texture = CLUTTER_ACTOR(clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(ctexture)));
+
+  priv = ctexture->priv;
+
+  qwidth  = x2 - x1;
+  qheight = y2 - y1;
+
+  rheight = priv->reflection_height;
+
+  if (rheight > qheight)
+    rheight = qheight;
+
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+      clutter_actor_realize (parent_texture);
+
+  /* Only paint if parent is in a state to do so */
+  if (!clutter_texture_has_generated_tiles (CLUTTER_TEXTURE(parent_texture)))
+    return;
+  
+  clutter_texture_get_base_size (CLUTTER_TEXTURE(parent_texture), 
+                                &pwidth, &pheight); 
+
+  if (!clutter_texture_is_tiled (CLUTTER_TEXTURE(parent_texture)))
+    {
+      clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), 0);
+
+      /* NPOTS textures *always* used if extension available
+       */
+      if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+       {
+         tx = (float) pwidth;
+         ty = (float) pheight;
+         ty2 = (float)(clutter_actor_get_height (CLUTTER_ACTOR(ctexture)) * rheight) 
+                                             / pheight;
+         ty2 = pheight - ty2;
+
+       }
+      else
+       {
+         tx = (float) pwidth / clutter_util_next_p2 (pwidth);  
+         ty = (float) pheight / clutter_util_next_p2 (pheight);
+       }
+
+      qx1 = x1; qx2 = x2;
+      qy1 = y1; qy2 = y1 + rheight;
+
+      glBegin (GL_QUADS);
+
+      glColor4ub (255, 255, 255, 
+                 clutter_actor_get_opacity (CLUTTER_ACTOR(ctexture)));
+
+      glTexCoord2f (0, ty);   
+      glVertex2i   (qx1, qy1);
+
+      glTexCoord2f (tx,  ty);   
+      glVertex2i   (qx2, qy1);
+
+      glColor4ub (255, 255, 255, 0);
+
+      glTexCoord2f (tx,  ty2);    
+      glVertex2i   (qx2, qy2);
+      
+      glTexCoord2f (0, ty2);    
+      glVertex2i   (qx1, qy2);
+
+      glEnd ();        
+      
+      return;
+    }
+
+  clutter_texture_get_n_tiles (CLUTTER_TEXTURE(parent_texture), 
+                              &n_x_tiles, &n_y_tiles); 
+
+  for (x = 0; x < n_x_tiles; x++)
+    {
+      lasty = 0;
+
+      for (y = 0; y < n_y_tiles; y++)
+       {
+         gint actual_w, actual_h;
+         gint xpos, ypos, xsize, ysize, ywaste, xwaste;
+         
+         clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), i);
+        
+         clutter_texture_get_x_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            x, &xpos, &xsize, &xwaste);
+
+         clutter_texture_get_y_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            y, &ypos, &ysize, &ywaste);
+
+         actual_w = xsize - xwaste;
+         actual_h = ysize - ywaste;
+
+         tx = (float) actual_w / xsize;
+         ty = (float) actual_h / ysize;
+
+         qx1 = x1 + lastx;
+         qx2 = qx1 + ((qwidth * actual_w ) / pwidth );
+         
+         qy1 = y1 + lasty;
+         qy2 = qy1 + ((qheight * actual_h) / pheight );
+
+         glBegin (GL_QUADS);
+         glTexCoord2f (tx, ty);   glVertex2i   (qx2, qy2);
+         glTexCoord2f (0,  ty);   glVertex2i   (qx1, qy2);
+         glTexCoord2f (0,  0);    glVertex2i   (qx1, qy1);
+         glTexCoord2f (tx, 0);    glVertex2i   (qx2, qy1);
+         glEnd ();     
+
+         lasty += qy2 - qy1;     
+
+         i++;
+       }
+      lastx += qx2 - qx1;
+    }
+#endif
+
+}
+
+static void
+clutter_reflect_texture_paint (ClutterActor *self)
+{
+  ClutterReflectTexturePrivate  *priv;
+  ClutterActor                *parent_texture;
+  gint                         x1, y1, x2, y2;
+  GLenum                       target_type;
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+  priv = CLUTTER_REFLECT_TEXTURE (self)->priv;
+
+  /* no need to paint stuff if we don't have a texture to reflect */
+  if (!clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)))
+    return;
+
+  /* parent texture may have been hidden, there for need to make sure its 
+   * realised with resources available.  
+  */
+  parent_texture = CLUTTER_ACTOR (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)));
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+    clutter_actor_realize (parent_texture);
+
+  /* FIXME: figure out nicer way of getting at this info...  
+   */  
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE) &&
+      clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture)) == FALSE)
+    {
+      target_type = CGL_TEXTURE_RECTANGLE_ARB;
+      cogl_enable (CGL_ENABLE_TEXTURE_RECT | CGL_ENABLE_BLEND);
+    }
+  else
+    {
+      target_type = CGL_TEXTURE_2D;
+      cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
+    }
+  
+  cogl_push_matrix ();
+
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glColor4ub (255, 255, 255, clutter_actor_get_opacity (self));
+
+  clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
+
+  /* Parent paint translated us into position */
+  reflect_texture_render_to_gl_quad (CLUTTER_REFLECT_TEXTURE (self), 
+                                  0, 0, x2 - x1, y2 - y1);
+
+  cogl_pop_matrix ();
+#endif
+}
+
+
+
+static void
+clutter_reflect_texture_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterReflectTexture         *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      priv->reflection_height = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  ClutterReflectTexture *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      g_value_set_int (value, priv->reflection_height);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_class_init (ClutterReflectTextureClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->paint = clutter_reflect_texture_paint;
+
+  gobject_class->set_property = clutter_reflect_texture_set_property;
+  gobject_class->get_property = clutter_reflect_texture_get_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_REFLECTION_HEIGHT,
+                                   g_param_spec_int ("reflection-height",
+                                                     "Reflection Height",
+                                                     "",
+                                                     0, G_MAXINT,
+                                                     0,
+                                                     (G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)));
+
+  g_type_class_add_private (gobject_class, sizeof (ClutterReflectTexturePrivate));
+}
+
+static void
+clutter_reflect_texture_init (ClutterReflectTexture *self)
+{
+  ClutterReflectTexturePrivate *priv;
+
+  self->priv = priv = CLUTTER_REFLECT_TEXTURE_GET_PRIVATE (self);
+  priv->reflection_height = 100; 
+}
+
+/**
+ * clutter_reflect_texture_new:
+ * @texture: a #ClutterTexture or %NULL
+ *
+ * Creates an efficient 'reflect' of a pre-existing texture if which it 
+ * shares the underlying pixbuf data.
+ *
+ * You can use clutter_reflect_texture_set_parent_texture() to change the
+ * parent texture to be reflectd.
+ *
+ * Return value: the newly created #ClutterReflectTexture
+ */
+ClutterActor *
+clutter_reflect_texture_new (ClutterTexture *texture, gint reflection_height)
+{
+  g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
+
+  return g_object_new (CLUTTER_TYPE_REFLECT_TEXTURE,
+                      "parent-texture", texture,
+                      "reflection-height", reflection_height,
+                      NULL);
+}
+
diff --git a/attic/astro-desktop/applications/images/clutter-reflect-texture.h b/attic/astro-desktop/applications/images/clutter-reflect-texture.h
new file mode 100644 (file)
index 0000000..9ba7353
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_REFLECT_TEXTURE_H
+#define _HAVE_CLUTTER_REFLECT_TEXTURE_H
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_REFLECT_TEXTURE (clutter_reflect_texture_get_type ())
+
+#define CLUTTER_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexture))
+
+#define CLUTTER_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+#define CLUTTER_IS_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_IS_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_REFLECT_TEXTURE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+typedef struct _ClutterReflectTexture        ClutterReflectTexture;
+typedef struct _ClutterReflectTexturePrivate ClutterReflectTexturePrivate;
+typedef struct _ClutterReflectTextureClass   ClutterReflectTextureClass;
+
+struct _ClutterReflectTexture
+{
+  ClutterCloneTexture              parent;
+  
+  /*< priv >*/
+  ClutterReflectTexturePrivate    *priv;
+};
+
+struct _ClutterReflectTextureClass 
+{
+  ClutterCloneTextureClass parent_class;
+
+  /* padding for future expansion */
+  void (*_clutter_reflect_1) (void);
+  void (*_clutter_reflect_2) (void);
+  void (*_clutter_reflect_3) (void);
+  void (*_clutter_reflect_4) (void);
+}; 
+
+GType           clutter_reflect_texture_get_type           (void) G_GNUC_CONST;
+
+ClutterActor *  clutter_reflect_texture_new                (ClutterTexture      *texture, gint reflection_height);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/images/init.c b/attic/astro-desktop/applications/images/init.c
new file mode 100644 (file)
index 0000000..4fab13f
--- /dev/null
@@ -0,0 +1,26 @@
+
+#include <glib.h>
+#include <libastro-desktop/astro.h>
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+
+#include "astro-images.h"
+
+
+AstroApplication *
+astro_application_factory_init ()
+{
+  AstroApplication *app;
+  GdkPixbuf *pixbuf;
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR "/icons/images.png", 
+                                     ASTRO_APPICON_SIZE(), ASTRO_APPICON_SIZE(),
+                                     TRUE,
+                                     NULL);
+
+  app = astro_images_new ("Images", pixbuf);
+
+  g_debug ("Images application loaded\n");
+
+  return app;
+}
diff --git a/attic/astro-desktop/applications/music/Makefile.am b/attic/astro-desktop/applications/music/Makefile.am
new file mode 100644 (file)
index 0000000..98b669f
--- /dev/null
@@ -0,0 +1,30 @@
+INCLUDES =\
+       -I$(srcdir) \
+       $(DEPS_CFLAGS) \
+       $(GCC_CFLAGS) \
+       -DPREFIX=\"$(prefix)\" \
+       -DSYSCONFDIR=\"$(sysconfdir)\" \
+       -DPKGDATADIR=\"$(pkgdatadir)\" \
+       -DLIBDIR=\"$(libdir)\" \
+       -I$(top_builddir)/libastro-desktop
+
+APP_SOURCES = \
+       init.c \
+       astro-music.c \
+       astro-music-window.c \
+       astro-reflection.c \
+       astro-songs.c \
+       clutter-reflect-texture.c
+
+APP_LDADD = \
+       $(DEPS_LIBS) \
+       $(top_builddir)/libastro-desktop/libastro-desktop.la            
+        
+
+musiclibdir = $(libdir)/astro-desktop/apps
+musiclib_LTLIBRARIES = music.la
+music_la_SOURCES = $(APP_SOURCES)
+music_la_LIBADD = $(APP_LDADD)
+music_la_LDFLAGS = -module -avoid-version
+music_la_CFLAGS =
+
diff --git a/attic/astro-desktop/applications/music/astro-music-window.c b/attic/astro-desktop/applications/music/astro-music-window.c
new file mode 100644 (file)
index 0000000..8a25165
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-music-window.h"
+
+#include <math.h>
+#include <string.h>
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+#include <libastro-desktop/astro-behave.h>
+#include <libastro-desktop/astro-utils.h>
+
+#include "astro-reflection.h"
+
+G_DEFINE_TYPE (AstroMusicWindow, astro_music_window, ASTRO_TYPE_WINDOW);
+
+#define ASTRO_MUSIC_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_MUSIC_WINDOW, AstroMusicWindowPrivate))
+
+#define ALBUM_DIR PKGDATADIR"/albums"
+
+struct _AstroMusicWindowPrivate
+{
+  GList *covers;
+
+  ClutterActor *albums;
+  ClutterActor *label;
+
+  ClutterActor *player;
+
+  gint active;
+  gboolean activated;
+
+  ClutterTimeline  *timeline;
+  ClutterAlpha     *alpha;
+  ClutterBehaviour *behave;
+};
+
+/* Public Functions */
+
+/* Private functions */
+typedef struct
+{
+  gint x;
+  gfloat scale;
+
+} CoverTrans;
+
+static void
+ensure_layout (AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  GList *c;
+  gint i = 0;
+
+  priv = window->priv;
+
+  c = priv->covers;
+  for (c=c; c; c = c->next)
+    {
+      ClutterActor *cover = c->data;
+      CoverTrans *trans = g_object_get_data (G_OBJECT (cover), "trans");
+
+      if (i == priv->active)
+        {
+          trans->x = CSW ()/2;
+          trans->scale = 1.0;
+        }
+      else if (i > priv->active)
+        {
+          gint diff;
+
+          diff = i - priv->active;
+          trans->x = (CSW()/2) + ((CSW()/4)*diff);
+          if (diff > 3)
+            trans->scale = 0.4;
+          else
+            trans->scale = 0.4 + (0.4 * (3-diff)/3);
+        }
+      else
+        {
+          gint diff;
+
+          diff = priv->active - i;
+          trans->x = (CSW()/2) - ((CSW()/4)*diff);
+          if (diff > 3)
+            trans->scale = 0.4;
+          else
+            trans->scale = 0.4 + (0.4 * (3-diff)/3);        
+        }
+
+      i++;
+    }
+}
+
+static void
+astro_music_window_advance (AstroMusicWindow *window, gint n)
+{
+  AstroMusicWindowPrivate *priv;
+  gint new_active;
+
+  g_return_if_fail (ASTRO_IS_MUSIC_WINDOW (window));
+  priv = window->priv;
+  
+  new_active = priv->active + n;
+  if (new_active < 0 || 
+   new_active > (clutter_group_get_n_children (CLUTTER_GROUP (priv->albums))-1))
+    return;
+
+  priv->active += n;
+  ensure_layout (window);
+
+  if (clutter_timeline_is_playing (priv->timeline))
+    clutter_timeline_rewind (priv->timeline);
+  else
+    clutter_timeline_start (priv->timeline);
+
+}
+
+static void
+on_cover_active_completed (ClutterTimeline *timeline,
+                           AstroReflection *reflection)
+{
+  astro_reflection_set_active (reflection, TRUE);
+
+  g_signal_handlers_disconnect_by_func (timeline, 
+                                        on_cover_active_completed,
+                                        reflection);
+}
+
+static void
+on_cover_activated (AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  ClutterActor *cover;
+  GList *children;
+  CoverTrans *trans;
+
+  g_return_if_fail (ASTRO_IS_MUSIC_WINDOW (window));
+  priv = window->priv;
+
+  children = priv->covers;
+  cover = g_list_nth_data (children, priv->active);
+
+  if (!CLUTTER_IS_ACTOR (cover))
+    return;
+
+  trans = g_object_get_data (G_OBJECT (cover), "trans");
+  if (!trans)
+    return;
+
+  priv->activated = TRUE;
+
+  trans->scale = ALBUM_SCALE;
+  trans->x = (CSW()/2) - ((ALBUM_SIZE * ALBUM_SCALE) * 0.5);
+
+  clutter_actor_raise_top (cover);
+
+  if (clutter_timeline_is_playing (priv->timeline))
+    clutter_timeline_rewind (priv->timeline);
+  else
+    clutter_timeline_start (priv->timeline);
+
+  g_signal_connect (priv->timeline, "completed",
+                    G_CALLBACK (on_cover_active_completed), cover);
+}
+
+static gboolean
+on_cover_clicked (ClutterActor      *cover, 
+                  ClutterEvent      *event,
+                  AstroMusicWindow  *window)
+{
+  AstroMusicWindowPrivate *priv;
+  GList *children;
+  gint n;
+
+  g_return_val_if_fail (ASTRO_IS_MUSIC_WINDOW (window), FALSE);
+  priv = window->priv;
+
+  children = priv->covers;
+  n = g_list_index (children, cover);
+
+  if (priv->activated)
+    {
+      if (event->button.x > CSW()/2)
+        return FALSE;
+      astro_reflection_set_active (g_list_nth_data (priv->covers,
+                                   priv->active), FALSE);
+      priv->activated = FALSE;
+      
+      astro_music_window_advance (window, 0);
+      return FALSE;
+    }
+
+  if (n == priv->active)
+    on_cover_activated (window);
+  else
+    {
+      gint diff;
+      if (n > priv->active)
+        diff = (n-priv->active);
+      else
+        diff = (priv->active - n) * -1;
+      astro_music_window_advance (window, diff);
+    }
+
+  return FALSE;
+}
+
+static ClutterActor *
+make_cover (const gchar *filename)
+{
+  GdkPixbuf *pixbuf;
+  ClutterActor *texture;
+
+  pixbuf = gdk_pixbuf_new_from_file_at_size (filename,
+                                             ALBUM_SIZE, ALBUM_SIZE,
+                                             NULL);
+  if (!pixbuf)
+    return NULL;
+
+  texture = astro_reflection_new (pixbuf);
+
+  g_object_set_data (G_OBJECT (texture), "trans", g_new0 (CoverTrans, 1));
+  return texture;
+}
+
+static void
+load_details (ClutterActor *cover, const gchar *leaf)
+{
+  gchar *details;
+  gint i;
+
+  details = g_strndup (leaf, strlen (leaf)-4);
+
+  for (i = 0; i < strlen (details); i++)
+    if (details[i] == '_') details[i] = ' ';
+
+  clutter_actor_set_name (cover, details);
+  g_free (details);
+}
+
+static void
+load_albums (AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  GDir *dir;
+  const gchar *leaf;
+  GError *error = NULL;
+  gint offset = CSW()*2;
+
+  priv = window->priv;
+
+  dir = g_dir_open (ALBUM_DIR, 0, &error);
+  if (error)
+    {
+      g_warning ("Cannot load albums: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+  
+  while ((leaf = g_dir_read_name (dir)))
+    {
+      ClutterActor *cover;
+      gchar *filename;
+
+      if (!g_str_has_suffix (leaf, ".jpg"))
+        continue;
+
+      filename = g_build_filename (ALBUM_DIR, leaf, NULL);
+      cover = make_cover (filename);
+
+      if (!CLUTTER_IS_ACTOR (cover))
+        {
+          g_free (filename);
+          continue;
+        }
+      load_details (cover, leaf);
+      clutter_container_add_actor (CLUTTER_CONTAINER (priv->albums), cover);
+      clutter_actor_set_position (cover, offset, 0);
+      clutter_actor_show_all (cover);
+      clutter_actor_set_reactive (cover, TRUE);
+      g_signal_connect (cover, "button-release-event",
+                        G_CALLBACK (on_cover_clicked), window);
+
+      priv->covers = g_list_append (priv->covers, cover);
+
+      g_free (filename);
+
+      offset += ALBUM_SIZE * 0.9;
+    }
+}
+
+static void
+astro_music_alpha (ClutterBehaviour *behave,
+                   guint32           alpha_value,
+                   AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  GList *c;
+
+  g_return_if_fail (ASTRO_IS_MUSIC_WINDOW (window));
+  priv = window->priv;
+
+  c = priv->covers;
+  for (c=c; c; c = c->next)
+    {
+      ClutterActor *cover = c->data;
+      CoverTrans *trans = g_object_get_data (G_OBJECT (cover), "trans");
+      gdouble cscale, dscale;
+      gint currentx, diffx;
+      
+      currentx = clutter_actor_get_x (cover);
+      if (currentx > trans->x)
+        diffx = (currentx - trans->x) * -1;
+      else
+        diffx = trans->x - currentx;
+
+      clutter_actor_set_x (cover, currentx 
+        + (gint)((diffx*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA));
+
+      clutter_actor_get_scale (cover, &cscale, &cscale);
+      if (cscale > trans->scale)
+        dscale = (cscale - trans->scale) * -1;
+      else
+        dscale = trans->scale - cscale;
+
+      clutter_actor_set_scale (cover, 
+        cscale + ((dscale*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA),
+        cscale + ((dscale*alpha_value)/CLUTTER_ALPHA_MAX_ALPHA));
+    }
+}
+
+static void
+on_main_timeline_completed (ClutterTimeline  *timeline,
+                            AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  const gchar *details;
+  GList *children;
+
+  g_return_if_fail (ASTRO_MUSIC_WINDOW (window));
+  priv = window->priv;
+
+  children = priv->covers;
+  details = clutter_actor_get_name (g_list_nth_data (children, priv->active));
+
+  clutter_label_set_text (CLUTTER_LABEL (priv->label), details);
+}
+
+static gboolean
+on_key_release_event (ClutterActor     *actor, 
+                      ClutterEvent     *event,
+                      AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  
+  g_return_val_if_fail (ASTRO_IS_WINDOW (window), FALSE);
+  priv = window->priv;
+
+  switch (event->key.keyval)
+    {
+      case CLUTTER_Return:
+      case CLUTTER_KP_Enter:
+      case CLUTTER_ISO_Enter:
+        on_cover_activated (window);
+        break;
+      case CLUTTER_Left:
+      case CLUTTER_KP_Left:
+        if (priv->activated)
+          {
+            astro_reflection_set_active (g_list_nth_data (priv->covers,
+                                                          priv->active), FALSE);  
+            priv->activated = FALSE;
+          }
+        astro_music_window_advance (window, -1);
+        break;
+      case CLUTTER_Right:
+      case CLUTTER_KP_Right:
+        if (priv->activated)
+          {
+            astro_reflection_set_active (g_list_nth_data (priv->covers,
+                                                        priv->active), FALSE);
+            priv->activated = FALSE;
+          }
+          astro_music_window_advance (window, 1);
+        break;
+      default:
+        ;
+    }
+
+  return FALSE;
+}
+
+/* GObject stuff */
+static void
+astro_music_window_class_init (AstroMusicWindowClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroMusicWindowPrivate));
+}
+
+static void
+astro_music_window_init (AstroMusicWindow *window)
+{
+  AstroMusicWindowPrivate *priv;
+  ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+  gchar *font = NULL;
+
+  priv = window->priv = ASTRO_MUSIC_WINDOW_GET_PRIVATE (window);
+
+  priv->covers = NULL;
+  priv->active = 0;
+  priv->activated = FALSE;
+
+  priv->albums = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (window), priv->albums);
+  clutter_actor_set_anchor_point_from_gravity (priv->albums, 
+                                               CLUTTER_GRAVITY_WEST);
+  clutter_actor_set_position (priv->albums, 0, CSH() * 0.5);
+
+  load_albums (window);
+  
+  font = g_strdup_printf ("Sans %d", CSH()/30);
+  priv->label = clutter_label_new_full (font, 
+                                        "Jay Z - American Gangster",
+                                        &white);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->label), FALSE);
+  clutter_label_set_alignment (CLUTTER_LABEL (priv->label),
+                               PANGO_ALIGN_CENTER);
+  clutter_container_add_actor (CLUTTER_CONTAINER (window), priv->label);
+  clutter_actor_set_size (priv->label, CSW(), CSH()/10);
+  clutter_actor_set_anchor_point_from_gravity (priv->label, 
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (priv->label, CSW()/2, CSH()*0.95);
+  g_free (font);
+
+  ensure_layout (window);
+
+  priv->timeline = clutter_timeline_new_for_duration (1200);
+  priv->alpha = clutter_alpha_new_full (priv->timeline,
+                                        clutter_sine_inc_func,
+                                        NULL, NULL);
+  priv->behave = astro_behave_new (priv->alpha,
+                                   (AstroBehaveAlphaFunc)astro_music_alpha,
+                                   window);
+
+  g_signal_connect (priv->timeline, "completed",
+                    G_CALLBACK (on_main_timeline_completed), window);
+
+  clutter_timeline_start (priv->timeline);
+
+  g_signal_connect (window, "key-release-event",
+                    G_CALLBACK (on_key_release_event), window);
+  clutter_grab_keyboard (CLUTTER_ACTOR (window));
+
+
+  clutter_actor_set_position (CLUTTER_ACTOR (window), 0, 0);
+  clutter_actor_show_all (CLUTTER_ACTOR (window));
+}
+
+AstroWindow * 
+astro_music_window_new (void)
+{
+  AstroWindow *music_window =  g_object_new (ASTRO_TYPE_MUSIC_WINDOW,
+                                                                                              NULL);
+
+  return music_window;
+}
+
diff --git a/attic/astro-desktop/applications/music/astro-music-window.h b/attic/astro-desktop/applications/music/astro-music-window.h
new file mode 100644 (file)
index 0000000..fc590e9
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_MUSIC_WINDOW_H
+#define _HAVE_ASTRO_MUSIC_WINDOW_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_MUSIC_WINDOW astro_music_window_get_type()
+
+#define ASTRO_MUSIC_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_MUSIC_WINDOW, \
+  AstroMusicWindow))
+
+#define ASTRO_MUSIC_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_MUSIC_WINDOW, \
+  AstroMusicWindowClass))
+
+#define ASTRO_IS_MUSIC_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_MUSIC_WINDOW))
+
+#define ASTRO_IS_MUSIC_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_MUSIC_WINDOW))
+
+#define ASTRO_MUSIC_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_MUSIC_WINDOW, \
+  AstroMusicWindowClass))
+
+#define ALBUM_SIZE (CSW()/4)
+#define ALBUM_SCALE 1.9
+
+typedef struct _AstroMusicWindow AstroMusicWindow;
+typedef struct _AstroMusicWindowClass AstroMusicWindowClass;
+typedef struct _AstroMusicWindowPrivate AstroMusicWindowPrivate;
+
+struct _AstroMusicWindow
+{
+  AstroWindow      parent;
+       
+  /*< private >*/
+  AstroMusicWindowPrivate   *priv;
+};
+
+struct _AstroMusicWindowClass 
+{
+  /*< private >*/
+  AstroWindowClass parent_class;
+}; 
+
+GType astro_music_window_get_type (void) G_GNUC_CONST;
+
+AstroWindow *  astro_music_window_new       (void);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/music/astro-music.c b/attic/astro-desktop/applications/music/astro-music.c
new file mode 100644 (file)
index 0000000..4f1594b
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-music.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+
+#include "astro-music-window.h"
+
+G_DEFINE_TYPE (AstroMusic, astro_music, ASTRO_TYPE_APPLICATION);
+
+#define ASTRO_MUSIC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_MUSIC, AstroMusicPrivate))
+       
+struct _AstroMusicPrivate
+{
+  const gchar *title;
+  GdkPixbuf *icon;
+  ClutterActor *window;
+};
+
+/* Public Functions */
+
+/* Private functions */
+static const gchar *
+get_title (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_MUSIC (app), NULL);
+
+  return ASTRO_MUSIC (app)->priv->title;
+}
+
+static void
+set_title (AstroApplication *app, const gchar *title)
+{
+  g_return_if_fail (ASTRO_IS_MUSIC (app));
+  g_return_if_fail (title);
+
+  ASTRO_MUSIC (app)->priv->title = g_strdup (title);
+}
+
+static GdkPixbuf *
+get_icon (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_MUSIC (app), NULL);
+
+  return ASTRO_MUSIC (app)->priv->icon;
+}
+
+static void
+set_icon (AstroApplication *app, GdkPixbuf *icon)
+{
+  g_return_if_fail (ASTRO_IS_MUSIC (app));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+
+  ASTRO_MUSIC (app)->priv->icon = icon;
+}
+
+static AstroWindow *
+get_window (AstroApplication *app)
+{
+  AstroMusicPrivate *priv;
+  ClutterActor *window = NULL;
+
+  g_return_val_if_fail (ASTRO_IS_MUSIC (app), NULL);
+  priv = ASTRO_MUSIC (app)->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->window))
+    window = priv->window;
+  else
+    {
+      window = CLUTTER_ACTOR (astro_music_window_new ());
+    }
+
+  ASTRO_MUSIC (app)->priv->window = window;
+
+  return ASTRO_WINDOW (window);
+}
+
+static void
+close (AstroApplication *app)
+{
+  AstroMusicPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_MUSIC (app));
+  priv = ASTRO_MUSIC (app)->priv;
+  
+  if (CLUTTER_IS_ACTOR (priv->window))
+    clutter_actor_destroy (priv->window);
+}
+
+/* GObject stuff */
+static void
+astro_music_class_init (AstroMusicClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  AstroApplicationClass *app_class = ASTRO_APPLICATION_CLASS (klass);
+
+  app_class->get_title = get_title;
+  app_class->set_title = set_title;
+  app_class->get_icon = get_icon;
+  app_class->set_icon = set_icon;
+  app_class->get_window = get_window;
+  app_class->close = close;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroMusicPrivate));
+}
+
+static void
+astro_music_init (AstroMusic *music)
+{
+  AstroMusicPrivate *priv;
+  priv = music->priv = ASTRO_MUSIC_GET_PRIVATE (music);
+
+  priv->title = NULL;
+  priv->icon = NULL;
+  priv->window = NULL;
+}
+
+AstroApplication * 
+astro_music_new (const gchar *title, GdkPixbuf *icon)
+{
+  AstroApplication *music =  g_object_new (ASTRO_TYPE_MUSIC,
+                                                                                              NULL);
+
+  astro_application_set_title (music, title);
+  astro_application_set_icon (music, icon);
+
+  return music;
+}
+
diff --git a/attic/astro-desktop/applications/music/astro-music.h b/attic/astro-desktop/applications/music/astro-music.h
new file mode 100644 (file)
index 0000000..05c5d5a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_MUSIC_H
+#define _HAVE_ASTRO_MUSIC_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_MUSIC astro_music_get_type()
+
+#define ASTRO_MUSIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_MUSIC, \
+  AstroMusic))
+
+#define ASTRO_MUSIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_MUSIC, \
+  AstroMusicClass))
+
+#define ASTRO_IS_MUSIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_MUSIC))
+
+#define ASTRO_IS_MUSIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_MUSIC))
+
+#define ASTRO_MUSIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_MUSIC, \
+  AstroMusicClass))
+
+typedef struct _AstroMusic AstroMusic;
+typedef struct _AstroMusicClass AstroMusicClass;
+typedef struct _AstroMusicPrivate AstroMusicPrivate;
+
+struct _AstroMusic
+{
+  AstroApplication       parent;
+       
+  /*< private >*/
+  AstroMusicPrivate   *priv;
+};
+
+struct _AstroMusicClass 
+{
+  /*< private >*/
+  AstroApplicationClass parent_class;
+}; 
+
+GType astro_music_get_type (void) G_GNUC_CONST;
+
+AstroApplication *  astro_music_new       (const gchar  *title,
+                                             GdkPixbuf    *icon);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/music/astro-reflection.c b/attic/astro-desktop/applications/music/astro-reflection.c
new file mode 100644 (file)
index 0000000..87e9cc5
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-reflection.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-utils.h>
+
+#include "clutter-reflect-texture.h"
+#include "astro-songs.h"
+
+G_DEFINE_TYPE (AstroReflection, astro_reflection, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_REFLECTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_REFLECTION, AstroReflectionPrivate))
+
+static GdkPixbuf *disc_bg = NULL;
+
+struct _AstroReflectionPrivate
+{
+  ClutterActor *songs;
+  ClutterActor *songs_reflect;
+  ClutterActor *song_list;
+  ClutterActor *texture;
+  ClutterActor *reflect;
+  GdkPixbuf    *pixbuf;
+
+  ClutterEffectTemplate *songs_temp;
+  ClutterTimeline       *songs_time;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_PIXBUF
+};
+
+static void
+fix_clip (ClutterTimeline *timeline,
+          gint             frame_num,
+          AstroReflection *reflection)
+{
+  AstroReflectionPrivate *priv;
+  gint size;
+   
+  g_return_if_fail (ASTRO_IS_REFLECTION (reflection));
+  priv = reflection->priv;
+
+  size = clutter_actor_get_width (priv->songs);
+
+  astro_utils_set_clip (priv->songs_reflect,
+                        size - clutter_actor_get_x (priv->songs_reflect),
+                        0, size, size);
+}
+
+void
+astro_reflection_set_active (AstroReflection *reflection,
+                             gboolean         active)
+{
+  AstroReflectionPrivate *priv;
+  static ClutterTimeline *fade_time = NULL;
+  gint x = 0;
+  gint fade = 0;
+   
+  g_return_if_fail (ASTRO_IS_REFLECTION (reflection));
+  priv = reflection->priv;
+
+  if (active)
+  {
+    x = clutter_actor_get_width (priv->texture); 
+    fade = 100;
+  }
+  
+  clutter_effect_move (priv->songs_temp,
+                       priv->songs,
+                       x, clutter_actor_get_y (priv->songs),
+                       NULL, NULL);
+  clutter_effect_move (priv->songs_temp,
+                       priv->song_list,
+                       x, clutter_actor_get_y (priv->song_list),
+                       NULL, NULL);
+  clutter_effect_move (priv->songs_temp,
+                       priv->songs_reflect,
+                       x, clutter_actor_get_y (priv->songs_reflect),
+                       NULL, NULL);
+
+  fade_time = clutter_effect_fade (priv->songs_temp,
+                                   priv->songs_reflect,
+                                   fade,
+                                   NULL, NULL);
+  g_signal_connect (fade_time, "new-frame",
+                    G_CALLBACK (fix_clip), reflection);
+
+  astro_songs_set_active (ASTRO_SONGS (priv->song_list), active);
+}
+
+void
+astro_reflection_set_pixbuf (AstroReflection *reflection,
+                             GdkPixbuf       *pixbuf)
+{
+  AstroReflectionPrivate *priv;
+  gint height;
+  
+  g_return_if_fail (ASTRO_IS_REFLECTION (reflection));
+  priv = reflection->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->texture))
+    clutter_actor_destroy (priv->texture);
+  
+  if (CLUTTER_IS_ACTOR (priv->reflect))
+    clutter_actor_destroy (priv->reflect);
+
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  /* Songs widget */
+  if (!disc_bg)
+    {
+      disc_bg = gdk_pixbuf_new_from_file_at_size (PKGDATADIR"/disc_bg.svg",
+                                                  height, height, NULL);
+    }
+  priv->songs = clutter_texture_new_from_pixbuf (disc_bg);
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), priv->songs);
+  clutter_actor_set_size (priv->songs, height, height);
+  clutter_actor_set_position (priv->songs, 0, 0);
+
+  priv->songs_reflect = clutter_reflect_texture_new (CLUTTER_TEXTURE (priv->songs),
+                                               height * 0.7);
+  clutter_actor_set_opacity (priv->songs_reflect, 0);
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), 
+                               priv->songs_reflect);
+  clutter_actor_set_position (priv->songs_reflect, 0, height+1);
+
+  /* Song list */
+  priv->song_list = astro_songs_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), priv->song_list);
+  clutter_actor_set_size (priv->song_list, height, height);
+  clutter_actor_set_position (priv->song_list, 0, 0);
+
+     
+  /* Album cover */
+  priv->texture = g_object_new (CLUTTER_TYPE_TEXTURE,
+                                "pixbuf", pixbuf,
+                                "tiled", FALSE,
+                                NULL);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection),
+                               priv->texture);
+  clutter_actor_set_position (priv->texture, 0, 0);
+  
+  priv->reflect = clutter_reflect_texture_new (CLUTTER_TEXTURE (priv->texture),
+                                               height * 0.7);
+  clutter_actor_set_opacity (priv->reflect, 100);
+  clutter_container_add_actor (CLUTTER_CONTAINER (reflection), 
+                               priv->reflect);
+  clutter_actor_set_position (priv->reflect, 0, height+1);
+  
+  clutter_actor_set_anchor_point (CLUTTER_ACTOR (reflection),
+                                  clutter_actor_get_width (priv->texture)/2,
+                                  height/2);
+
+  clutter_actor_show_all (CLUTTER_ACTOR (reflection));
+}
+
+/* GObject stuff */
+static void
+astro_reflection_set_property (GObject      *object, 
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  AstroReflectionPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_REFLECTION (object));
+  priv = ASTRO_REFLECTION (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_PIXBUF:
+      astro_reflection_set_pixbuf (ASTRO_REFLECTION (object),
+                                   GDK_PIXBUF (g_value_get_object (value)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+astro_reflection_get_property (GObject    *object, 
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  AstroReflectionPrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_REFLECTION (object));
+  priv = ASTRO_REFLECTION (object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_PIXBUF:
+      g_value_set_object (value, G_OBJECT (priv->pixbuf));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+astro_reflection_class_init (AstroReflectionClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = astro_reflection_set_property;
+  gobject_class->get_property = astro_reflection_get_property;
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_PIXBUF,
+    g_param_spec_object ("pixbuf",
+                         "Pixbuf",
+                         "A pixbuf",
+                         GDK_TYPE_PIXBUF,
+                         G_PARAM_READWRITE));
+
+  g_type_class_add_private (gobject_class, sizeof (AstroReflectionPrivate));
+}
+
+static void
+astro_reflection_init (AstroReflection *reflection)
+{
+  AstroReflectionPrivate *priv;
+  priv = reflection->priv = ASTRO_REFLECTION_GET_PRIVATE (reflection);
+
+  priv->texture = NULL;
+  priv->reflect = NULL;
+
+  priv->songs_time = clutter_timeline_new_for_duration (600);
+  priv->songs_temp = clutter_effect_template_new (priv->songs_time, 
+                                                  clutter_sine_inc_func);
+}
+
+ClutterActor *
+astro_reflection_new (GdkPixbuf *pixbuf)
+{
+  ClutterActor *reflection =  g_object_new (ASTRO_TYPE_REFLECTION,
+                                            "pixbuf", pixbuf,
+                                            NULL);
+  return CLUTTER_ACTOR (reflection);
+}
+
diff --git a/attic/astro-desktop/applications/music/astro-reflection.h b/attic/astro-desktop/applications/music/astro-reflection.h
new file mode 100644 (file)
index 0000000..1d71ea9
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_REFLECTION_H
+#define _HAVE_ASTRO_REFLECTION_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_REFLECTION astro_reflection_get_type()
+
+#define ASTRO_REFLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_REFLECTION, \
+  AstroReflection))
+
+#define ASTRO_REFLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_REFLECTION, \
+  AstroReflectionClass))
+
+#define ASTRO_IS_REFLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_REFLECTION))
+
+#define ASTRO_IS_REFLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_REFLECTION))
+
+#define ASTRO_REFLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_REFLECTION, \
+  AstroReflectionClass))
+
+typedef struct _AstroReflection AstroReflection;
+typedef struct _AstroReflectionClass AstroReflectionClass;
+typedef struct _AstroReflectionPrivate AstroReflectionPrivate;
+
+struct _AstroReflection
+{
+  ClutterGroup       parent;
+       
+  /*< private >*/
+  AstroReflectionPrivate   *priv;
+};
+
+struct _AstroReflectionClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_reflection_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_reflection_new        (GdkPixbuf    *pixbuf);
+
+void            astro_reflection_set_active (AstroReflection *reflection,
+                                             gboolean         active);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/music/astro-songs.c b/attic/astro-desktop/applications/music/astro-songs.c
new file mode 100644 (file)
index 0000000..dcdd774
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-songs.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+
+#include "astro-music-window.h"
+
+G_DEFINE_TYPE (AstroSongs, astro_songs, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_SONGS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_SONGS, AstroSongsPrivate))
+       
+struct _AstroSongsPrivate
+{
+  ClutterActor *group;
+  ClutterActor *events;
+
+  gboolean mousedown;
+  gint     lasty;
+  gint     starty;
+  guint32  start_time;
+  gint     endy;
+  
+  ClutterEffectTemplate *temp;
+  ClutterTimeline       *timeline;
+};
+
+static gchar *song_names[] = {
+  "Oh Timbaland",
+  "Give It To Me",
+  "Release",
+  "The Way I Are",
+  "Bounce",
+  "Come And Get Me",
+  "Kill Yourself",
+  "Boardmeeting",
+  "Fantasy",
+  "Screem",
+  "Miscommunication",
+  "Bombay",
+  "Throw It On Me",
+  "Time",
+  "One And Only",
+  "Apologize",
+  "2 Man Show",
+  "Hello"
+};
+
+static gboolean on_event (AstroSongs *songs, ClutterEvent *event);
+
+/* Public Functions */
+void 
+astro_songs_set_active (AstroSongs *songs, gboolean active)
+{
+  AstroSongsPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_SONGS (songs));
+  priv = songs->priv;
+
+  if (active)
+    {
+      g_signal_connect (songs, "event", G_CALLBACK (on_event), NULL);
+    }
+  else
+    {
+      g_signal_handlers_disconnect_by_func (songs, on_event, NULL);
+      priv->mousedown = FALSE;
+    }
+}
+
+
+/* Private functions */
+static void
+bounds_check (ClutterActor *group, AstroSongs *songs)
+{
+  AstroSongsPrivate *priv;
+  gint y, height;
+
+  g_return_if_fail (ASTRO_IS_SONGS (songs));
+  priv = songs->priv;
+
+  height = clutter_actor_get_height (group);
+  y = clutter_actor_get_y (group);
+   
+  if (y < 0 && y < (-1*height+(ALBUM_SIZE/2)))
+  {
+    y = (-1*height) + ALBUM_SIZE/2;
+  }
+  
+  if ( y > 0 && y > (ALBUM_SIZE/2))
+    {
+      y = ALBUM_SIZE/2;
+    }
+      
+  priv->timeline = clutter_effect_move (priv->temp, priv->group,
+                                        clutter_actor_get_x (priv->group),
+                                        y, 
+                                        NULL, NULL);
+}
+
+static gboolean 
+on_event (AstroSongs *songs, ClutterEvent *event)
+{
+#define TIMEOUT 400
+#define SPEED_FACTOR 1.5
+  AstroSongsPrivate *priv = songs->priv;
+    
+  if (event->type == CLUTTER_BUTTON_PRESS)
+    {
+      priv->starty = priv->lasty = event->button.y;
+      
+      priv->start_time = event->button.time;
+    
+      if (clutter_timeline_is_playing (priv->timeline))
+        clutter_timeline_stop (priv->timeline);
+    
+    }
+  else if (event->type == CLUTTER_BUTTON_RELEASE)
+    {
+      gint endy = clutter_actor_get_y (priv->group);
+      guint32 time = event->button.time - priv->start_time;
+      gfloat factor;
+      
+      factor = 2.0 - (time/event->button.time);
+    
+      if (time > TIMEOUT)
+        {
+          priv->endy = endy;
+        }
+      else if (event->button.y > priv->starty)
+        {
+          /* 
+          * The mouse from left to right, so we have to *add* pixels to the
+          * current group position to make it move to the right
+          */
+          endy += (event->motion.y - priv->starty) * SPEED_FACTOR * factor;
+          priv->endy = endy;
+        }
+      else if (event->button.y < priv->starty)
+        {
+          /* 
+          * The mouse from right to left, so we have to *minus* p.yels to the
+          * current group position to make it move to the left
+          */
+          endy -= (priv->starty - event->button.y) * SPEED_FACTOR * factor;
+          priv->endy = endy;
+        }
+      else
+        {
+          /* If the click was fast, treat it as a standard 'clicked' event */
+          if (time < TIMEOUT)
+            g_debug ("Song clicked\n");
+          priv->starty = priv->lasty = 0;
+          return FALSE;
+        }
+  
+     priv->timeline = clutter_effect_move (priv->temp, priv->group,
+                                          clutter_actor_get_x (priv->group),
+                                          priv->endy, 
+                                      (ClutterEffectCompleteFunc)bounds_check, 
+                                          songs);
+
+      priv->starty =  priv->lasty = 0;
+    }
+  else if (event->type == CLUTTER_MOTION)
+    {
+      gint offset;
+
+      if (!priv->starty)
+        return FALSE;
+      if (event->motion.y > priv->lasty)
+        {
+          offset = event->motion.y - priv->lasty;
+        }
+      else
+        {
+          offset = priv->lasty - event->motion.y;
+          offset *= -1;
+        }
+      priv->lasty = event->motion.y;
+      clutter_actor_set_position (priv->group,
+                                  clutter_actor_get_x (priv->group),
+                                  clutter_actor_get_y (priv->group)+ offset);
+    }  
+  
+  return FALSE;
+}
+
+/* GObject stuff */
+static void
+astro_songs_class_init (AstroSongsClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  
+  g_type_class_add_private (gobject_class, sizeof (AstroSongsPrivate));
+}
+
+static void
+astro_songs_init (AstroSongs *songs)
+{
+#define FONT_SIZE (ALBUM_SIZE/8)
+#define ROW_SPACING (FONT_SIZE*1.3)
+#define PAD 2
+  AstroSongsPrivate *priv;
+  ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+  gchar *font = NULL;
+  gint i, offset = ROW_SPACING/2;
+
+  priv = songs->priv = ASTRO_SONGS_GET_PRIVATE (songs);
+
+  priv->mousedown = FALSE;
+
+  priv->group = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (songs), priv->group);
+  clutter_actor_set_position (priv->group, 0, 0);
+
+  font = g_strdup_printf ("Sans %d", FONT_SIZE);
+
+  for (i = 0; i < 10; i++)
+    {
+      ClutterActor *row;
+           
+      row = clutter_label_new_full (font, song_names[i], &white);
+      
+      clutter_container_add_actor (CLUTTER_CONTAINER (priv->group), row);
+      clutter_actor_set_anchor_point_from_gravity (row, 
+                                                   CLUTTER_GRAVITY_WEST);
+      clutter_actor_set_position (row, 10, offset);
+      clutter_actor_set_scale (row, 1/ALBUM_SCALE, 1/ALBUM_SCALE);
+      clutter_actor_set_opacity (row, i%2 ? 200: 255);
+
+      offset += ROW_SPACING;
+    }
+
+  priv->timeline = clutter_timeline_new_for_duration (1000);
+  priv->temp = clutter_effect_template_new (priv->timeline,
+                                            clutter_sine_inc_func);
+
+  clutter_actor_set_reactive (CLUTTER_ACTOR (songs), TRUE);
+  
+  clutter_actor_set_clip (CLUTTER_ACTOR (songs), 
+                          PAD, PAD, ALBUM_SIZE-(2*PAD), ALBUM_SIZE-(2*PAD));
+  clutter_actor_show_all (CLUTTER_ACTOR (priv->group));
+  clutter_actor_show_all (CLUTTER_ACTOR (songs));
+  g_free (font);
+}
+
+ClutterActor * 
+astro_songs_new (void)
+{
+  ClutterActor *songs =  g_object_new (ASTRO_TYPE_SONGS,
+                                            NULL);
+
+  return songs;
+}
+
diff --git a/attic/astro-desktop/applications/music/astro-songs.h b/attic/astro-desktop/applications/music/astro-songs.h
new file mode 100644 (file)
index 0000000..21fa78c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_SONGS_H
+#define _HAVE_ASTRO_SONGS_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_SONGS astro_songs_get_type()
+
+#define ASTRO_SONGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_SONGS, \
+  AstroSongs))
+
+#define ASTRO_SONGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_SONGS, \
+  AstroSongsClass))
+
+#define ASTRO_IS_SONGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_SONGS))
+
+#define ASTRO_IS_SONGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_SONGS))
+
+#define ASTRO_SONGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_SONGS, \
+  AstroSongsClass))
+
+typedef struct _AstroSongs AstroSongs;
+typedef struct _AstroSongsClass AstroSongsClass;
+typedef struct _AstroSongsPrivate AstroSongsPrivate;
+
+struct _AstroSongs
+{
+  ClutterGroup       parent;
+       
+  /*< private >*/
+  AstroSongsPrivate   *priv;
+};
+
+struct _AstroSongsClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_songs_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_songs_new       (void);
+
+void astro_songs_set_active (AstroSongs *songs, gboolean active);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/music/clutter-reflect-texture.c b/attic/astro-desktop/applications/music/clutter-reflect-texture.c
new file mode 100644 (file)
index 0000000..5689d49
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define CLUTTER_PARAM_READWRITE \
+        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+
+
+/**
+ * SECTION:clutter-reflect-texture
+ * @short_description: Actor for cloning existing textures in an 
+ * efficient way.
+ *
+ * #ClutterReflectTexture allows the cloning of existing #ClutterTexture with 
+ * a refelction like effect.
+ */
+
+#include <clutter/cogl.h>
+
+#include "clutter-reflect-texture.h"
+
+enum
+{
+  PROP_0,
+  PROP_REFLECTION_HEIGHT
+};
+
+G_DEFINE_TYPE (ClutterReflectTexture,
+              clutter_reflect_texture,
+              CLUTTER_TYPE_CLONE_TEXTURE);
+
+#define CLUTTER_REFLECT_TEXTURE_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexturePrivate))
+
+struct _ClutterReflectTexturePrivate
+{
+  gint                 reflection_height;
+};
+
+static void
+reflect_texture_render_to_gl_quad (ClutterReflectTexture *ctexture, 
+                                int             x1, 
+                                int             y1, 
+                                int             x2, 
+                                int             y2)
+{
+  gint   qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0;
+  gint   qwidth = 0, qheight = 0;
+  gint   x, y, i =0, lastx = 0, lasty = 0;
+  gint   n_x_tiles, n_y_tiles; 
+  gint   pwidth, pheight, rheight;
+  float tx, ty, ty2 = 0.0;
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+  ClutterReflectTexturePrivate *priv = ctexture->priv;
+  ClutterActor *parent_texture = CLUTTER_ACTOR(clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(ctexture)));
+
+  priv = ctexture->priv;
+
+  qwidth  = x2 - x1;
+  qheight = y2 - y1;
+
+  rheight = priv->reflection_height;
+
+  if (rheight > qheight)
+    rheight = qheight;
+
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+      clutter_actor_realize (parent_texture);
+
+  /* Only paint if parent is in a state to do so */
+  if (!clutter_texture_has_generated_tiles (CLUTTER_TEXTURE(parent_texture)))
+    return;
+  
+  clutter_texture_get_base_size (CLUTTER_TEXTURE(parent_texture), 
+                                &pwidth, &pheight); 
+
+  if (!clutter_texture_is_tiled (CLUTTER_TEXTURE(parent_texture)))
+    {
+      clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), 0);
+
+      /* NPOTS textures *always* used if extension available
+       */
+      if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+       {
+         tx = (float) pwidth;
+         ty = (float) pheight;
+         ty2 = (float)(clutter_actor_get_height (CLUTTER_ACTOR(ctexture)) * rheight) 
+                                             / pheight;
+         ty2 = pheight - ty2;
+
+       }
+      else
+       {
+         tx = (float) pwidth / clutter_util_next_p2 (pwidth);  
+         ty = (float) pheight / clutter_util_next_p2 (pheight);
+       }
+
+      qx1 = x1; qx2 = x2;
+      qy1 = y1; qy2 = y1 + rheight;
+
+      glBegin (GL_QUADS);
+
+      glColor4ub (255, 255, 255, 
+                 clutter_actor_get_opacity (CLUTTER_ACTOR(ctexture)));
+
+      glTexCoord2f (0, ty);   
+      glVertex2i   (qx1, qy1);
+
+      glTexCoord2f (tx,  ty);   
+      glVertex2i   (qx2, qy1);
+
+      glColor4ub (255, 255, 255, 0);
+
+      glTexCoord2f (tx,  ty2);    
+      glVertex2i   (qx2, qy2);
+      
+      glTexCoord2f (0, ty2);    
+      glVertex2i   (qx1, qy2);
+
+      glEnd ();        
+      
+      return;
+    }
+
+  clutter_texture_get_n_tiles (CLUTTER_TEXTURE(parent_texture), 
+                              &n_x_tiles, &n_y_tiles); 
+
+  for (x = 0; x < n_x_tiles; x++)
+    {
+      lasty = 0;
+
+      for (y = 0; y < n_y_tiles; y++)
+       {
+         gint actual_w, actual_h;
+         gint xpos, ypos, xsize, ysize, ywaste, xwaste;
+         
+         clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), i);
+        
+         clutter_texture_get_x_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            x, &xpos, &xsize, &xwaste);
+
+         clutter_texture_get_y_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            y, &ypos, &ysize, &ywaste);
+
+         actual_w = xsize - xwaste;
+         actual_h = ysize - ywaste;
+
+         tx = (float) actual_w / xsize;
+         ty = (float) actual_h / ysize;
+
+         qx1 = x1 + lastx;
+         qx2 = qx1 + ((qwidth * actual_w ) / pwidth );
+         
+         qy1 = y1 + lasty;
+         qy2 = qy1 + ((qheight * actual_h) / pheight );
+
+         glBegin (GL_QUADS);
+         glTexCoord2f (tx, ty);   glVertex2i   (qx2, qy2);
+         glTexCoord2f (0,  ty);   glVertex2i   (qx1, qy2);
+         glTexCoord2f (0,  0);    glVertex2i   (qx1, qy1);
+         glTexCoord2f (tx, 0);    glVertex2i   (qx2, qy1);
+         glEnd ();     
+
+         lasty += qy2 - qy1;     
+
+         i++;
+       }
+      lastx += qx2 - qx1;
+    }
+#endif
+
+}
+
+static void
+clutter_reflect_texture_paint (ClutterActor *self)
+{
+  ClutterReflectTexturePrivate  *priv;
+  ClutterActor                *parent_texture;
+  gint                         x1, y1, x2, y2;
+  GLenum                       target_type;
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+  priv = CLUTTER_REFLECT_TEXTURE (self)->priv;
+
+  /* no need to paint stuff if we don't have a texture to reflect */
+  if (!clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)))
+    return;
+
+  /* parent texture may have been hidden, there for need to make sure its 
+   * realised with resources available.  
+  */
+  parent_texture = CLUTTER_ACTOR (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)));
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+    clutter_actor_realize (parent_texture);
+
+  /* FIXME: figure out nicer way of getting at this info...  
+   */  
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE) &&
+      clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture)) == FALSE)
+    {
+      target_type = CGL_TEXTURE_RECTANGLE_ARB;
+      cogl_enable (CGL_ENABLE_TEXTURE_RECT | CGL_ENABLE_BLEND);
+    }
+  else
+    {
+      target_type = CGL_TEXTURE_2D;
+      cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
+    }
+  
+  cogl_push_matrix ();
+
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glColor4ub (255, 255, 255, clutter_actor_get_opacity (self));
+
+  clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
+
+  /* Parent paint translated us into position */
+  reflect_texture_render_to_gl_quad (CLUTTER_REFLECT_TEXTURE (self), 
+                                  0, 0, x2 - x1, y2 - y1);
+
+  cogl_pop_matrix ();
+#endif
+}
+
+
+
+static void
+clutter_reflect_texture_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterReflectTexture         *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      priv->reflection_height = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  ClutterReflectTexture *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      g_value_set_int (value, priv->reflection_height);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_class_init (ClutterReflectTextureClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->paint = clutter_reflect_texture_paint;
+
+  gobject_class->set_property = clutter_reflect_texture_set_property;
+  gobject_class->get_property = clutter_reflect_texture_get_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_REFLECTION_HEIGHT,
+                                   g_param_spec_int ("reflection-height",
+                                                     "Reflection Height",
+                                                     "",
+                                                     0, G_MAXINT,
+                                                     0,
+                                                     (G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)));
+
+  g_type_class_add_private (gobject_class, sizeof (ClutterReflectTexturePrivate));
+}
+
+static void
+clutter_reflect_texture_init (ClutterReflectTexture *self)
+{
+  ClutterReflectTexturePrivate *priv;
+
+  self->priv = priv = CLUTTER_REFLECT_TEXTURE_GET_PRIVATE (self);
+  priv->reflection_height = 100; 
+}
+
+/**
+ * clutter_reflect_texture_new:
+ * @texture: a #ClutterTexture or %NULL
+ *
+ * Creates an efficient 'reflect' of a pre-existing texture if which it 
+ * shares the underlying pixbuf data.
+ *
+ * You can use clutter_reflect_texture_set_parent_texture() to change the
+ * parent texture to be reflectd.
+ *
+ * Return value: the newly created #ClutterReflectTexture
+ */
+ClutterActor *
+clutter_reflect_texture_new (ClutterTexture *texture, gint reflection_height)
+{
+  g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
+
+  return g_object_new (CLUTTER_TYPE_REFLECT_TEXTURE,
+                      "parent-texture", texture,
+                      "reflection-height", reflection_height,
+                      NULL);
+}
+
diff --git a/attic/astro-desktop/applications/music/clutter-reflect-texture.h b/attic/astro-desktop/applications/music/clutter-reflect-texture.h
new file mode 100644 (file)
index 0000000..9ba7353
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_REFLECT_TEXTURE_H
+#define _HAVE_CLUTTER_REFLECT_TEXTURE_H
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_REFLECT_TEXTURE (clutter_reflect_texture_get_type ())
+
+#define CLUTTER_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexture))
+
+#define CLUTTER_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+#define CLUTTER_IS_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_IS_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_REFLECT_TEXTURE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+typedef struct _ClutterReflectTexture        ClutterReflectTexture;
+typedef struct _ClutterReflectTexturePrivate ClutterReflectTexturePrivate;
+typedef struct _ClutterReflectTextureClass   ClutterReflectTextureClass;
+
+struct _ClutterReflectTexture
+{
+  ClutterCloneTexture              parent;
+  
+  /*< priv >*/
+  ClutterReflectTexturePrivate    *priv;
+};
+
+struct _ClutterReflectTextureClass 
+{
+  ClutterCloneTextureClass parent_class;
+
+  /* padding for future expansion */
+  void (*_clutter_reflect_1) (void);
+  void (*_clutter_reflect_2) (void);
+  void (*_clutter_reflect_3) (void);
+  void (*_clutter_reflect_4) (void);
+}; 
+
+GType           clutter_reflect_texture_get_type           (void) G_GNUC_CONST;
+
+ClutterActor *  clutter_reflect_texture_new                (ClutterTexture      *texture, gint reflection_height);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/applications/music/init.c b/attic/astro-desktop/applications/music/init.c
new file mode 100644 (file)
index 0000000..7d17570
--- /dev/null
@@ -0,0 +1,25 @@
+
+#include <glib.h>
+#include <libastro-desktop/astro.h>
+#include <libastro-desktop/astro-application.h>
+
+#include "astro-music.h"
+
+
+AstroApplication *
+astro_application_factory_init ()
+{
+  AstroApplication *app;
+  GdkPixbuf *pixbuf;
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR "/icons/music.png",
+                                     ASTRO_APPICON_SIZE(), ASTRO_APPICON_SIZE(),
+                                     TRUE,
+                                     NULL);
+
+  app = astro_music_new ("Music Player", pixbuf);
+
+  g_debug ("Music application loaded\n");
+
+  return app;
+}
diff --git a/attic/astro-desktop/autogen.sh b/attic/astro-desktop/autogen.sh
new file mode 100755 (executable)
index 0000000..b1376df
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/attic/astro-desktop/configure.ac b/attic/astro-desktop/configure.ac
new file mode 100644 (file)
index 0000000..10f06a0
--- /dev/null
@@ -0,0 +1,37 @@
+AC_PREREQ(2.53)
+AC_INIT(astro-desktop, 0.1, [])
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/main.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES(DEPS, 
+                  clutter-0.6 
+                  gdk-2.0)
+AC_SUBST(DEPS_CFLAGS)
+AC_SUBST(DEPS_LIBS)
+
+if test "x$GCC" = "xyes"; then
+        GCC_CFLAGS="-g -Wall"
+fi
+AC_SUBST(GCC_CFLAGS)
+
+AC_OUTPUT([
+Makefile
+data/Makefile
+data/albums/Makefile
+data/icons/Makefile
+libastro-desktop/Makefile
+applets/Makefile
+applications/Makefile
+applications/contacts/Makefile
+applications/example/Makefile
+applications/images/Makefile
+applications/music/Makefile
+src/Makefile
+])
diff --git a/attic/astro-desktop/data/Makefile.am b/attic/astro-desktop/data/Makefile.am
new file mode 100644 (file)
index 0000000..7a73690
--- /dev/null
@@ -0,0 +1,12 @@
+SUBDIRS = albums icons
+
+dist_default_DATA = \
+  applet_bg.png \
+       background.svg \
+       contact.png \
+       contact-bar.svg \
+       disc_bg.svg \
+       face.png \
+       info_bg.png
+
+defaultdir = $(pkgdatadir)
diff --git a/attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpg b/attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpg
new file mode 100644 (file)
index 0000000..36e2745
Binary files /dev/null and b/attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpg differ
diff --git a/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg b/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg
new file mode 100644 (file)
index 0000000..7dab931
Binary files /dev/null and b/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg differ
diff --git a/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg b/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg
new file mode 100644 (file)
index 0000000..133687e
Binary files /dev/null and b/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg differ
diff --git a/attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpg b/attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpg
new file mode 100644 (file)
index 0000000..5ce60bd
Binary files /dev/null and b/attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpg differ
diff --git a/attic/astro-desktop/data/albums/Makefile.am b/attic/astro-desktop/data/albums/Makefile.am
new file mode 100644 (file)
index 0000000..a804798
--- /dev/null
@@ -0,0 +1,10 @@
+dist_album_DATA = \
+       Amy_Winehouse_-_Back_To_Black.jpg \
+       Jay_Z_-_American_Gangster.jpg \
+       Kanye_West_-_Graduation.jpg \
+       Lupe_Fiasco_-_Food_and_Liquor.jpg \
+       Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg \
+       Santana_-_Ultimate_Santana.jpg \
+       Timbaland_-_Shock_Value.jpg
+
+albumdir = $(pkgdatadir)/albums
diff --git a/attic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg b/attic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg
new file mode 100755 (executable)
index 0000000..04de882
Binary files /dev/null and b/attic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg differ
diff --git a/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg b/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg
new file mode 100644 (file)
index 0000000..ad75622
Binary files /dev/null and b/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg differ
diff --git a/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg b/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg
new file mode 100755 (executable)
index 0000000..216fbcc
Binary files /dev/null and b/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg differ
diff --git a/attic/astro-desktop/data/applet_bg.png b/attic/astro-desktop/data/applet_bg.png
new file mode 100644 (file)
index 0000000..9d25c90
Binary files /dev/null and b/attic/astro-desktop/data/applet_bg.png differ
diff --git a/attic/astro-desktop/data/background.svg b/attic/astro-desktop/data/background.svg
new file mode 100644 (file)
index 0000000..03d9b16
Binary files /dev/null and b/attic/astro-desktop/data/background.svg differ
diff --git a/attic/astro-desktop/data/contact-bar.svg b/attic/astro-desktop/data/contact-bar.svg
new file mode 100644 (file)
index 0000000..a3f549e
--- /dev/null
@@ -0,0 +1,447 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="180.47015"
+   height="24.242943"
+   id="svg3428"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   version="1.0"
+   sodipodi:docbase="/home/njp/Projects/clutter/trunk/toys/astro-desktop/data"
+   sodipodi:docname="contact-bar.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs3430">
+    <linearGradient
+       id="linearGradient2274">
+      <stop
+         id="stop2276"
+         offset="0.0000000"
+         style="stop-color:#000000;stop-opacity:0.12871288;" />
+      <stop
+         id="stop7499"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2274"
+       id="linearGradient3332"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.3239721,0,0,0.4317921,136.91003,341.14399)"
+       x1="8.7803764"
+       y1="37.784683"
+       x2="9.7619219"
+       y2="32.203163" />
+    <linearGradient
+       id="linearGradient9749">
+      <stop
+         id="stop9751"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop9753"
+         offset="1.0000000"
+         style="stop-color:#ededed;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient9749"
+       id="linearGradient3330"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.7578899,0,0,0.7981524,136.66215,340.87654)"
+       x1="11.233107"
+       y1="13.686079"
+       x2="21.111549"
+       y2="24.132717" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2152"
+       id="linearGradient3328"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.3570761,0,0,0.4212585,136.91003,341.14399)"
+       x1="8.9156475"
+       y1="37.197018"
+       x2="9.8855038"
+       y2="52.090679" />
+    <linearGradient
+       id="linearGradient2152">
+      <stop
+         style="stop-color:#9aa29a;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2154" />
+      <stop
+         style="stop-color:#b5beb5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2156" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2152"
+       id="linearGradient3326"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.3570761,0,0,0.4212585,136.91003,341.14399)"
+       x1="8.9156475"
+       y1="37.197018"
+       x2="9.8855038"
+       y2="52.090679" />
+    <linearGradient
+       id="linearGradient18913">
+      <stop
+         id="stop18915"
+         offset="0.0000000"
+         style="stop-color:#ededed;stop-opacity:1.0000000;" />
+      <stop
+         id="stop18917"
+         offset="1.0000000"
+         style="stop-color:#c8c8c8;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient18913"
+       id="linearGradient3324"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.8682784,0,0,0.658407,136.91003,341.14399)"
+       x1="5.8266134"
+       y1="7.2310905"
+       x2="13.467486"
+       y2="17.876846" />
+    <linearGradient
+       id="linearGradient2136">
+      <stop
+         id="stop2138"
+         offset="0.0000000"
+         style="stop-color:#989690;stop-opacity:1.0000000;" />
+      <stop
+         id="stop2140"
+         offset="1.0000000"
+         style="stop-color:#656460;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2136"
+       id="linearGradient3322"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.742713,0,0,0.7838319,136.91003,341.12829)"
+       x1="2.0618775"
+       y1="15.257116"
+       x2="30.599684"
+       y2="15.257116" />
+    <linearGradient
+       id="linearGradient15107">
+      <stop
+         id="stop15109"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop15111"
+         offset="1.0000000"
+         style="stop-color:#e2e2e2;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient15107"
+       id="linearGradient3320"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.742713,0,0,0.7838319,136.91003,341.12829)"
+       x1="11.572842"
+       y1="4.7461624"
+       x2="18.475286"
+       y2="26.022909" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient3318"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-3.5474511e-2,0,0,1.6178436e-2,161.81453,355.68479)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       id="linearGradient5060"
+       inkscape:collect="always">
+      <stop
+         id="stop5062"
+         offset="0"
+         style="stop-color:black;stop-opacity:1;" />
+      <stop
+         id="stop5064"
+         offset="1"
+         style="stop-color:black;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient3316"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.5474511e-2,0,0,1.6178436e-2,136.18548,355.68479)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       id="linearGradient5048">
+      <stop
+         id="stop5050"
+         offset="0"
+         style="stop-color:black;stop-opacity:0;" />
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0.5"
+         id="stop5056" />
+      <stop
+         id="stop5052"
+         offset="1"
+         style="stop-color:black;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5048"
+       id="linearGradient3314"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.5474511e-2,0,0,1.6178436e-2,136.1785,355.68479)"
+       x1="302.85715"
+       y1="366.64789"
+       x2="302.85715"
+       y2="609.50507" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5392"
+       id="linearGradient3336"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5811813,0,0,0.5811813,69.757731,147.45416)"
+       x1="57.627918"
+       y1="314.09448"
+       x2="24.935883"
+       y2="388.94205" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5392">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5394" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5396" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5392"
+       id="linearGradient3334"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5811813,0,0,0.5811813,69.757731,147.45416)"
+       x1="57.627918"
+       y1="314.09448"
+       x2="24.935883"
+       y2="388.94205" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5023"
+       id="linearGradient3382"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5132646,0,0,0.5132646,109.28118,-57.203569)"
+       x1="106"
+       y1="333.5625"
+       x2="82.305023"
+       y2="373.7756" />
+    <linearGradient
+       id="linearGradient5023">
+      <stop
+         id="stop5025"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop5027"
+         offset="1.0000000"
+         style="stop-color:#ededed;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5023"
+       id="linearGradient3379"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.7457361,0,0,0.7457361,124.18979,-139.54519)"
+       x1="260.56619"
+       y1="344.9021"
+       x2="260.56619"
+       y2="359.40948" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.35"
+     inkscape:cx="375"
+     inkscape:cy="520"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="872"
+     inkscape:window-height="627"
+     inkscape:window-x="388"
+     inkscape:window-y="47" />
+  <metadata
+     id="metadata3433">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-149.76493,-111.6693)">
+    <g
+       style="display:inline"
+       id="g5423"
+       transform="matrix(0.9148739,0,0,0.9148739,70.26323,-200.61078)">
+      <rect
+         y="361.61658"
+         x="140.43544"
+         height="3.929049"
+         width="17.129122"
+         id="rect4173"
+         style="opacity:0.40206185;color:#000000;fill:url(#linearGradient3314);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path5058"
+         d="M 157.56456,361.61672 C 157.56456,361.61672 157.56456,365.54555 157.56456,365.54555 C 159.39141,365.55295 161.98099,364.6653 161.98099,363.58088 C 161.98099,362.49646 159.94237,361.61672 157.56456,361.61672 z "
+         style="opacity:0.40206185;color:#000000;fill:url(#radialGradient3316);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <path
+         style="opacity:0.40206185;color:#000000;fill:url(#radialGradient3318);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         d="M 140.43544,361.61672 C 140.43544,361.61672 140.43544,365.54555 140.43544,365.54555 C 138.60859,365.55295 136.01901,364.6653 136.01901,363.58088 C 136.01901,362.49646 138.05763,361.61672 140.43544,361.61672 z "
+         id="path5018"
+         sodipodi:nodetypes="cccc" />
+      <path
+         sodipodi:nodetypes="ccczzzz"
+         id="path12723"
+         d="M 138.81946,350.33714 L 138.81946,363.88674 L 159.25875,363.88674 L 159.225,350.40215 C 159.22309,349.64058 152.67479,342.28786 151.46679,342.28786 L 146.73928,342.28786 C 145.46925,342.28786 138.81946,349.6194 138.81946,350.33714 z "
+         style="fill:url(#linearGradient3320);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3322);stroke-width:0.47355643;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="czzzccz"
+         id="path18153"
+         d="M 139.14542,350.23478 C 138.92538,349.99699 145.71686,342.66457 146.7436,342.66457 L 151.37397,342.66457 C 152.34003,342.66457 159.13382,349.92216 158.79688,350.34084 L 152.79247,357.80194 L 145.98521,357.62597 L 139.14542,350.23478 z "
+         style="fill:url(#linearGradient3324);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccccc"
+         id="path14245"
+         d="M 146.64477,357.022 L 139.23908,363.08764 L 146.9283,357.77809 L 151.91381,357.77809 L 158.77943,363.02013 L 152.22097,357.022 L 146.64477,357.022 z "
+         style="fill:url(#linearGradient3326);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path14339"
+         d="M 139.16777,350.28898 L 145.53425,358.2034 L 146.12495,357.73084 L 139.16777,350.28898 z "
+         style="color:#000000;fill:url(#linearGradient3328);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <path
+         sodipodi:nodetypes="ccczzzz"
+         id="path15103"
+         d="M 139.35807,350.42513 L 139.37529,363.25686 L 158.69382,363.25686 L 158.65937,350.49484 C 158.65825,350.08071 152.45866,342.86671 151.26023,342.86671 L 146.89528,342.86671 C 145.65016,342.86671 139.35749,349.99373 139.35807,350.42513 z "
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:url(#linearGradient3330);stroke-width:0.47355637;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cccccc"
+         id="path17393"
+         d="M 146.90395,357.78955 L 140.30234,362.36192 L 141.52931,362.3653 L 147.05657,358.56794 L 151.93358,357.78136 L 146.90395,357.78955 z "
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccccc"
+         id="path2272"
+         d="M 142.67526,354.02124 L 146.00681,357.58907 L 146.66839,357.022 L 152.2446,357.04563 L 152.69353,357.4473 L 154.89093,354.82459 C 154.25298,354.04487 142.67526,354.02124 142.67526,354.02124 z "
+         style="fill:url(#linearGradient3332);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         style="color:#000000;fill:#b1b1b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         d="M 158.43359,350.82125 L 152.93203,357.8042 L 152.34133,357.33164 L 158.43359,350.82125 z "
+         id="path27492"
+         sodipodi:nodetypes="cccc" />
+    </g>
+    <g
+       style="display:inline"
+       id="g5525"
+       transform="matrix(0.9589904,0,0,0.9589904,69.26002,-215.48727)">
+      <path
+         sodipodi:nodetypes="cscccsc"
+         id="path2079"
+         d="M 201.54698,342.2888 C 194.96948,342.2888 189.57578,346.71889 189.63276,352.16889 C 189.71579,360.19298 199.84658,363.07897 204.30759,361.74022 C 207.0682,362.64572 207.74935,363.78936 211.79686,363.78157 C 209.45138,362.23781 209.49854,361.29624 209.47952,359.62794 C 211.8776,357.82137 213.46119,355.06398 213.46119,352.16889 C 213.46119,346.7186 208.12447,342.2888 201.54698,342.2888 z "
+         style="fill:url(#linearGradient3334);fill-opacity:1;stroke:#888a85;stroke-width:0.55563754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cscccsc"
+         id="path2095"
+         d="M 201.54387,342.8437 C 195.27485,342.8437 190.1341,347.05829 190.18841,352.24317 C 190.26754,359.87694 200.09935,362.44643 204.35114,361.17279 C 206.76703,362.0805 206.973,362.43674 209.95287,363.01529 C 208.93156,361.82249 208.87461,360.78567 208.86681,359.40666 C 211.15243,357.68798 212.89934,354.99744 212.89934,352.24317 C 212.89934,347.05801 207.8129,342.8437 201.54387,342.8437 z "
+         style="fill:url(#linearGradient3336);fill-opacity:1;stroke:#ffffff;stroke-width:0.5557546;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    </g>
+    <path
+       sodipodi:nodetypes="csccsccc"
+       id="path5390"
+       d="M 162.0512,112.04547 C 160.1919,112.04547 158.6829,113.58317 158.6829,115.47787 C 158.6829,116.85417 159.47536,118.04247 160.62368,118.58957 C 166.7038,117.68547 159.07412,135.96537 153.35778,128.91897 C 151.48077,128.91897 149.9574,130.44237 149.9574,132.31937 C 149.9574,134.19637 151.48077,135.71977 153.35778,135.71977 C 160.92673,134.41337 166.31954,124.64997 165.41949,115.97507 C 164.53958,112.97267 163.42441,112.32077 162.0512,112.04547 z "
+       style="fill:url(#linearGradient3382);fill-opacity:1;fill-rule:nonzero;stroke:#686868;stroke-width:0.38494846;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+    <path
+       style="color:#000000;fill:url(#linearGradient3379);fill-opacity:1;fill-rule:evenodd;stroke:#a9a3a3;stroke-width:0.74573612;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 307.14457,117.40877 L 307.14457,128.58327 L 316.82822,128.58327 L 316.82822,134.09807 L 329.86221,123.06437 L 316.81632,112.04217 L 316.81632,117.41247 L 307.14457,117.40877 z "
+       id="path5486"
+       sodipodi:nodetypes="cccccccc" />
+    <rect
+       style="opacity:0.15555558;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.82913888;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;display:inline"
+       id="rect5553"
+       width="0.82608694"
+       height="19"
+       x="178.50333"
+       y="114.07005" />
+    <rect
+       y="114.07005"
+       x="179.32944"
+       height="19"
+       width="0.82608694"
+       id="rect5555"
+       style="opacity:0.15555558;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.82913888;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+    <rect
+       y="114.07005"
+       x="232.50336"
+       height="19"
+       width="0.82608694"
+       id="rect3420"
+       style="opacity:0.15555558;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.82913888;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+    <rect
+       style="opacity:0.15555558;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.82913888;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;display:inline"
+       id="rect3422"
+       width="0.82608694"
+       height="19"
+       x="233.32941"
+       y="114.07005" />
+    <rect
+       style="opacity:0.15555558;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.82913888;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;display:inline"
+       id="rect3424"
+       width="0.82608694"
+       height="19"
+       x="290.50336"
+       y="114.07005" />
+    <rect
+       y="114.07005"
+       x="291.32941"
+       height="19"
+       width="0.82608694"
+       id="rect3426"
+       style="opacity:0.15555558;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.82913888;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+  </g>
+</svg>
diff --git a/attic/astro-desktop/data/contact.png b/attic/astro-desktop/data/contact.png
new file mode 100644 (file)
index 0000000..9749d8b
Binary files /dev/null and b/attic/astro-desktop/data/contact.png differ
diff --git a/attic/astro-desktop/data/disc_bg.svg b/attic/astro-desktop/data/disc_bg.svg
new file mode 100644 (file)
index 0000000..eb0731c
--- /dev/null
@@ -0,0 +1,1028 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="200"
+   height="200"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   version="1.0"
+   sodipodi:docbase="/home/njp/Projects/clutter/toys/astro-desktop/data"
+   sodipodi:docname="disc_bg.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="-15.69549"
+     inkscape:cy="136.41305"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="200px"
+     height="200px"
+     inkscape:window-width="951"
+     inkscape:window-height="704"
+     inkscape:window-x="62"
+     inkscape:window-y="93"
+     showguides="true"
+     inkscape:guide-bbox="true" />
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient7986">
+      <stop
+         id="stop7988"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop7990"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7968">
+      <stop
+         id="stop7970"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1" />
+      <stop
+         id="stop7972"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0.39795917;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7956">
+      <stop
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0"
+         id="stop7958" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop7960" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23425"
+       gradientTransform="matrix(1,0,0,0.25,0,31.22703)"
+       r="22.627417"
+       cy="41.63604"
+       fx="23.334524"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient23419"
+       fy="41.63604"
+       cx="23.334524" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23400"
+       x1="14.9966"
+       x2="32.511"
+       gradientTransform="matrix(1.190476,0,0,1.190476,-4.224424,-2.5)"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1"
+       y2="34.3075" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23397"
+       x1="12.2744"
+       x2="35.3912"
+       gradientTransform="matrix(1.190476,0,0,1.190476,-4.224424,-2.500001)"
+       y1="32.4165"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd2"
+       y2="14.2033" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23393"
+       x1="21.125000"
+       x2="29.000000"
+       gradientTransform="matrix(1.25,0,0,1.25,-5.652995,-2.604165)"
+       y1="14.625000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23390"
+       x1="21.125000"
+       x2="29.000000"
+       gradientTransform="matrix(1.25,0,0,1.25,-5.652995,-2.604165)"
+       y1="14.625000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23387"
+       x1="10.501720"
+       x2="48.798885"
+       y1="3.6100161"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient6036"
+       y2="54.698483" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23383"
+       r="21.333334"
+       gradientTransform="matrix(0.848684,0.95802,-0.782119,0.692834,18.69147,-20.52578)"
+       cx="37.751469"
+       cy="27.569166"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3394"
+       fy="27.569166"
+       fx="37.751469" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23380"
+       r="21.333334"
+       gradientTransform="matrix(0.769501,-1.2425,0.6703,0.415141,-21.77857,41.36563)"
+       cx="26.137741"
+       cy="38.807304"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3406"
+       fy="38.807304"
+       fx="26.137741" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23377"
+       r="21.333334"
+       gradientTransform="matrix(0.15845,-0.158988,0.432907,0.431441,-2.723645,15.00107)"
+       cx="53.556889"
+       cy="48.238270"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3421"
+       fy="48.238270"
+       fx="53.556889" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23374"
+       r="21.333334"
+       gradientTransform="matrix(5.184267e-3,-0.12286,0.544548,2.297824e-2,0.957234,26.30756)"
+       cx="16.885271"
+       cy="33.377594"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="33.377594"
+       fx="16.885271" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23371"
+       r="21.333334"
+       gradientTransform="matrix(0.105916,-1.91424e-2,0.104789,0.579807,17.13693,7.115158)"
+       cx="35.511295"
+       cy="21.618015"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="21.618015"
+       fx="35.511295" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23368"
+       r="21.333334"
+       gradientTransform="matrix(-5.04822e-2,1.387847e-2,-0.12844,-0.467196,35.41257,39.44172)"
+       cx="133.84108"
+       cy="23.914305"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="23.914305"
+       fx="133.84108" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23365"
+       r="21.333334"
+       gradientTransform="matrix(-5.04822e-2,1.387847e-2,-0.12844,-0.467196,35.41257,39.44172)"
+       cx="133.84108"
+       cy="23.914305"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="23.914305"
+       fx="133.84108" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23363"
+       r="21.333334"
+       gradientTransform="matrix(0.105916,-1.91424e-2,0.104789,0.579807,17.13693,7.115158)"
+       cx="35.511295"
+       cy="21.618015"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="21.618015"
+       fx="35.511295" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23361"
+       r="21.333334"
+       gradientTransform="matrix(5.184267e-3,-0.12286,0.544548,2.297824e-2,0.957234,26.30756)"
+       cx="16.885271"
+       cy="33.377594"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="33.377594"
+       fx="16.885271" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23359"
+       r="21.333334"
+       gradientTransform="matrix(0.15845,-0.158988,0.432907,0.431441,-2.723645,15.00107)"
+       cx="53.556889"
+       cy="48.238270"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3421"
+       fy="48.238270"
+       fx="53.556889" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23357"
+       r="21.333334"
+       gradientTransform="matrix(0.769501,-1.2425,0.6703,0.415141,-21.77857,41.36563)"
+       cx="26.137741"
+       cy="38.807304"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3406"
+       fy="38.807304"
+       fx="26.137741" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient23355"
+       r="21.333334"
+       gradientTransform="matrix(0.848684,0.95802,-0.782119,0.692834,18.69147,-20.52578)"
+       cx="37.751469"
+       cy="27.569166"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3394"
+       fy="27.569166"
+       fx="37.751469" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23351"
+       x1="10.501720"
+       x2="48.798885"
+       y1="3.6100161"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient6036"
+       y2="54.698483" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23349"
+       x1="21.125000"
+       x2="29.000000"
+       gradientTransform="matrix(1.25,0,0,1.25,-5.652995,-2.604165)"
+       y1="14.625000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23347"
+       x1="21.125000"
+       x2="29.000000"
+       gradientTransform="matrix(1.25,0,0,1.25,-5.652995,-2.604165)"
+       y1="14.625000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23345"
+       x1="12.2744"
+       x2="35.3912"
+       gradientTransform="matrix(1.190476,0,0,1.190476,-4.224424,-2.500001)"
+       y1="32.4165"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd2"
+       y2="14.2033" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23343"
+       x1="14.9966"
+       x2="32.511"
+       gradientTransform="matrix(1.190476,0,0,1.190476,-4.224424,-2.5)"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1"
+       y2="34.3075" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3449"
+       r="21.333334"
+       gradientTransform="matrix(0.769501,-1.242500,0.670300,0.415141,-21.77857,41.36563)"
+       cx="26.137741"
+       cy="38.807304"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3406"
+       fy="38.807304"
+       fx="26.137741" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3447"
+       r="21.333334"
+       gradientTransform="matrix(-5.048220e-2,1.387847e-2,-0.128440,-0.467196,35.41257,39.44172)"
+       cx="133.84108"
+       cy="23.914305"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="23.914305"
+       fx="133.84108" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3443"
+       r="21.333334"
+       gradientTransform="matrix(0.105916,-1.914240e-2,0.104789,0.579807,17.13693,7.115158)"
+       cx="35.511295"
+       cy="21.618015"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="21.618015"
+       fx="35.511295" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3433"
+       r="21.333334"
+       gradientTransform="matrix(5.184267e-3,-0.122860,0.544548,2.297824e-2,0.957234,26.30756)"
+       cx="16.885271"
+       cy="33.377594"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="33.377594"
+       fx="16.885271" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3429"
+       r="21.333334"
+       gradientTransform="matrix(0.158450,-0.158988,0.432907,0.431441,-2.723645,15.00107)"
+       cx="53.556889"
+       cy="48.238270"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3421"
+       fy="48.238270"
+       fx="53.556889" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3392"
+       r="21.333334"
+       gradientTransform="matrix(0.848684,0.958020,-0.782119,0.692834,18.69147,-20.52578)"
+       cx="37.751469"
+       cy="27.569166"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3394"
+       fy="27.569166"
+       fx="37.751469" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient6042"
+       x1="10.501720"
+       x2="48.798885"
+       y1="3.6100161"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient6036"
+       y2="54.698483" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient6034"
+       x1="28.702885"
+       x2="17.742729"
+       y1="31.494707"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient6028"
+       y2="18.366575" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4242"
+       x1="12.2744"
+       x2="35.3912"
+       gradientTransform="matrix(1.190476,0.000000,0.000000,1.190476,-4.224424,-2.500001)"
+       y1="32.4165"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd2"
+       y2="14.2033" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4224"
+       x1="21.125000"
+       x2="29.000000"
+       gradientTransform="matrix(1.250000,0.000000,0.000000,1.250000,-5.652995,-2.604165)"
+       y1="14.625000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4222"
+       x1="21.125000"
+       x2="29.000000"
+       gradientTransform="matrix(1.250000,0.000000,0.000000,1.250000,-5.652995,-2.604165)"
+       y1="14.625000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3912"
+       x1="14.9966"
+       x2="32.511"
+       gradientTransform="matrix(1.190476,0.000000,0.000000,1.190476,-4.224424,-2.500000)"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1"
+       y2="34.3075" />
+    <linearGradient
+       id="aigrd1"
+       y2="34.3075"
+       x2="32.511"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       x1="14.9966">
+      <stop
+         offset="0"
+         id="stop3034"
+         style="stop-color:#EBEBEB" />
+      <stop
+         offset="0.5"
+         id="stop3036"
+         style="stop-color:#FFFFFF" />
+      <stop
+         offset="1"
+         id="stop3038"
+         style="stop-color:#EBEBEB" />
+    </linearGradient>
+    <linearGradient
+       id="aigrd2"
+       y2="14.2033"
+       x2="35.3912"
+       y1="32.4165"
+       gradientUnits="userSpaceOnUse"
+       x1="12.2744">
+      <stop
+         offset="0"
+         id="stop3043"
+         style="stop-color:#FBFBFB" />
+      <stop
+         offset="0.5"
+         id="stop3045"
+         style="stop-color:#B6B6B6" />
+      <stop
+         offset="1"
+         id="stop3047"
+         style="stop-color:#E4E4E4" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4236">
+      <stop
+         offset="0.0000000"
+         id="stop4238"
+         style="stop-color:#ffffff;stop-opacity:0.32673267;" />
+      <stop
+         offset="1.0000000"
+         id="stop4240"
+         style="stop-color:#ffffff;stop-opacity:0.60396039;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient6028">
+      <stop
+         offset="0"
+         id="stop6030"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         offset="1"
+         id="stop6032"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient6036">
+      <stop
+         offset="0"
+         id="stop6038"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         offset="1"
+         id="stop6040"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3394"
+       y2="14.2033"
+       y1="32.4165"
+       x2="35.3912"
+       gradientUnits="userSpaceOnUse"
+       x1="12.2744">
+      <stop
+         offset="0.0000000"
+         id="stop3396"
+         style="stop-color:#fff307;stop-opacity:1.0000000;" />
+      <stop
+         offset="0.50000000"
+         id="stop3398"
+         style="stop-color:#166eff;stop-opacity:1.0000000;" />
+      <stop
+         offset="1.0000000"
+         id="stop3400"
+         style="stop-color:#ffffff;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3406"
+       y2="14.2033"
+       x2="35.3912"
+       y1="32.4165"
+       gradientUnits="userSpaceOnUse"
+       x1="12.2744">
+      <stop
+         offset="0.0000000"
+         id="stop3408"
+         style="stop-color:#b307ff;stop-opacity:0.82178217;" />
+      <stop
+         offset="1.0000000"
+         id="stop3410"
+         style="stop-color:#f0ff8b;stop-opacity:0.64356434;" />
+      <stop
+         offset="1.0000000"
+         id="stop3412"
+         style="stop-color:#ffffff;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3421"
+       y2="14.2033"
+       y1="32.4165"
+       x2="35.3912"
+       gradientUnits="userSpaceOnUse"
+       x1="12.2744">
+      <stop
+         offset="0.0000000"
+         id="stop3423"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         offset="1.0000000"
+         id="stop3427"
+         style="stop-color:#b8c04c;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3435"
+       y2="14.2033"
+       x2="35.3912"
+       y1="32.4165"
+       gradientUnits="userSpaceOnUse"
+       x1="12.2744">
+      <stop
+         offset="0.0000000"
+         id="stop3437"
+         style="stop-color:#ffffc8;stop-opacity:1.0000000;" />
+      <stop
+         offset="1.0000000"
+         id="stop3439"
+         style="stop-color:#9a91ef;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient23419">
+      <stop
+         offset="0"
+         id="stop23421"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         offset="1"
+         id="stop23423"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3320"
+       r="21.333334"
+       gradientTransform="matrix(-0.2060808,5.6655348e-2,-0.5243239,-1.9072097,153.22332,156.48584)"
+       cx="133.84108"
+       cy="23.914305"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="23.914305"
+       fx="133.84108" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3323"
+       r="21.333334"
+       gradientTransform="matrix(0.4323753,-7.8144013e-2,0.4277746,2.3669156,78.61764,24.520813)"
+       cx="35.511295"
+       cy="21.618015"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="21.618015"
+       fx="35.511295" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3326"
+       r="21.333334"
+       gradientTransform="matrix(2.116346e-2,-0.5015449,2.2229797,9.380286e-2,12.568118,102.86895)"
+       cx="16.885271"
+       cy="33.377594"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3435"
+       fy="33.377594"
+       fx="16.885271" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3329"
+       r="21.333334"
+       gradientTransform="matrix(0.6468321,-0.6490283,1.7672335,1.7612489,-2.4581411,56.713056)"
+       cx="53.556889"
+       cy="48.238270"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3421"
+       fy="48.238270"
+       fx="53.556889" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3332"
+       r="21.333334"
+       gradientTransform="matrix(3.1412935,-5.0721924,2.7363304,1.6947083,-80.245059,164.33971)"
+       cx="26.137741"
+       cy="38.807304"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3406"
+       fy="38.807304"
+       fx="26.137741" />
+    <radialGradient
+       inkscape:collect="always"
+       id="radialGradient3335"
+       r="21.333334"
+       gradientTransform="matrix(3.4645381,3.9108747,-3.1928033,2.8283198,84.963656,-88.316335)"
+       cx="37.751469"
+       cy="27.569166"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient3394"
+       fy="27.569166"
+       fx="37.751469" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3339"
+       x1="10.501720"
+       y1="3.6100161"
+       gradientTransform="matrix(4.0822474,0,0,4.0822474,8.6604516,-4.5250226)"
+       x2="48.798885"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient6036"
+       y2="54.698483" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3342"
+       x1="21.125000"
+       y1="14.625000"
+       gradientTransform="matrix(5.1028092,0,0,5.1028092,-14.416473,-15.155868)"
+       x2="29.000000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3345"
+       x1="21.125000"
+       y1="14.625000"
+       gradientTransform="matrix(5.1028092,0,0,5.1028092,-14.416473,-15.155868)"
+       x2="29.000000"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient4236"
+       y2="28.000000" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3349"
+       x1="12.2744"
+       y1="32.4165"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730645)"
+       x2="35.3912"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd2"
+       y2="14.2033" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352"
+       x1="14.9966"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1"
+       y2="34.3075" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749"
+       y2="34.3075"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163"
+       x1="14.9966" />
+    <linearGradient
+       id="aigrd1-163"
+       y2="34.3075"
+       y1="11.1885"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       x1="14.9966">
+      <stop
+         offset="0"
+         id="stop6145"
+         style="stop-color:#dedede" />
+      <stop
+         offset="0.5"
+         id="stop6147"
+         style="stop-color:#f2f2f2" />
+      <stop
+         offset="1"
+         id="stop6149"
+         style="stop-color:#dedede" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749-687"
+       x1="14.9966"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163-250"
+       y2="34.3075" />
+    <linearGradient
+       id="aigrd1-163-250"
+       x1="14.9966"
+       x2="32.511"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       y2="34.3075">
+      <stop
+         offset="0"
+         id="stop6350"
+         style="stop-color:#d1d1d1" />
+      <stop
+         offset="0.5"
+         id="stop6352"
+         style="stop-color:#e5e5e5" />
+      <stop
+         offset="1"
+         id="stop6354"
+         style="stop-color:#d1d1d1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749-687-155"
+       y2="34.3075"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163-250-506"
+       x1="14.9966" />
+    <linearGradient
+       id="aigrd1-163-250-506"
+       y2="34.3075"
+       y1="11.1885"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       x1="14.9966">
+      <stop
+         offset="0"
+         id="stop6564"
+         style="stop-color:#c4c4c4" />
+      <stop
+         offset="0.5"
+         id="stop6566"
+         style="stop-color:#d8d8d8" />
+      <stop
+         offset="1"
+         id="stop6568"
+         style="stop-color:#c4c4c4" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749-687-155-267"
+       x1="14.9966"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163-250-506-618"
+       y2="34.3075" />
+    <linearGradient
+       id="aigrd1-163-250-506-618"
+       x1="14.9966"
+       x2="32.511"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       y2="34.3075">
+      <stop
+         offset="0"
+         id="stop6788"
+         style="stop-color:#b7b7b7" />
+      <stop
+         offset="0.5"
+         id="stop6790"
+         style="stop-color:#cbcbcb" />
+      <stop
+         offset="1"
+         id="stop6792"
+         style="stop-color:#b7b7b7" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749-687-155-267-96"
+       y2="34.3075"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163-250-506-618-158"
+       x1="14.9966" />
+    <linearGradient
+       id="aigrd1-163-250-506-618-158"
+       y2="34.3075"
+       y1="11.1885"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       x1="14.9966">
+      <stop
+         offset="0"
+         id="stop7022"
+         style="stop-color:#aaaaaa" />
+      <stop
+         offset="0.5"
+         id="stop7024"
+         style="stop-color:#bebebe" />
+      <stop
+         offset="1"
+         id="stop7026"
+         style="stop-color:#aaaaaa" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749-687-155-267-96-885"
+       x1="14.9966"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163-250-506-618-158-462"
+       y2="34.3075" />
+    <linearGradient
+       id="aigrd1-163-250-506-618-158-462"
+       x1="14.9966"
+       x2="32.511"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       y2="34.3075">
+      <stop
+         offset="0"
+         id="stop7266"
+         style="stop-color:#9d9d9d" />
+      <stop
+         offset="0.5"
+         id="stop7268"
+         style="stop-color:#b1b1b1" />
+      <stop
+         offset="1"
+         id="stop7270"
+         style="stop-color:#9d9d9d" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3352-749-687-155-267-96-885-691"
+       y2="34.3075"
+       y1="11.1885"
+       gradientTransform="matrix(4.8598176,0,0,4.8598176,-8.5846923,-14.730641)"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#aigrd1-163-250-506-618-158-462-795"
+       x1="14.9966" />
+    <linearGradient
+       id="aigrd1-163-250-506-618-158-462-795"
+       y2="34.3075"
+       y1="11.1885"
+       x2="32.511"
+       gradientUnits="userSpaceOnUse"
+       x1="14.9966">
+      <stop
+         offset="0"
+         id="stop7520"
+         style="stop-color:#909090" />
+      <stop
+         offset="0.5"
+         id="stop7522"
+         style="stop-color:#a4a4a4" />
+      <stop
+         offset="1"
+         id="stop7524"
+         style="stop-color:#909090" />
+    </linearGradient>
+    <linearGradient
+       id="aigrd1-163-250-506-618-158-462-795-346"
+       x1="14.9966"
+       x2="32.511"
+       y1="11.1885"
+       gradientUnits="userSpaceOnUse"
+       y2="34.3075">
+      <stop
+         offset="0"
+         id="stop7784"
+         style="stop-color:#838383" />
+      <stop
+         offset="0.5"
+         id="stop7786"
+         style="stop-color:#979797" />
+      <stop
+         offset="1"
+         id="stop7788"
+         style="stop-color:#838383" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7968"
+       id="linearGradient7995"
+       gradientUnits="userSpaceOnUse"
+       x1="48.526371"
+       y1="39.995167"
+       x2="247.29153"
+       y2="238.76033"
+       gradientTransform="translate(-8.046875,0.484375)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7986"
+       id="linearGradient8000"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.2196699,1)"
+       x1="0"
+       y1="100"
+       x2="5.0178518"
+       y2="100" />
+  </defs>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer1"
+     inkscape:label="Layer 1">
+    <rect
+       id="rect2160"
+       x="0"
+       y="1.0817736e-14"
+       width="200"
+       height="200"
+       style="opacity:1;fill:#2a2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.25523013"
+       ry="0" />
+    <path
+       style="opacity:0.6935484;fill:url(#linearGradient8000);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 0,0 L 0.412981,0 C 6.4738963,50.507628 6.9789725,150.50253 0.412981,200 L 0,200 L 0,0 z "
+       id="rect3136"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       id="path7964"
+       d="M 100.01562,14.953125 C 52.875388,14.953125 14.953125,52.87539 14.953125,100.01562 C 14.953126,147.15587 52.875387,185.04688 100.01562,185.04688 C 147.15588,185.04688 185.04688,147.15587 185.04688,100.01562 C 185.04688,52.875392 147.15588,14.953125 100.01562,14.953125 z M 100.01562,79.609375 C 111.19321,79.609374 120.42188,88.838046 120.42188,100.01562 C 120.42188,111.19321 111.19321,120.42188 100.01562,120.42188 C 88.838048,120.42188 79.578125,111.19321 79.578125,100.01562 C 79.578125,88.838048 88.838047,79.609375 100.01562,79.609375 z M 98.953125,80.015625 C 88.26259,80.56011 79.984375,89.460464 79.984375,100.04688 C 79.984377,111.23498 89.087719,120.07812 100.01562,120.07812 C 111.20373,120.07812 120.04688,110.9748 120.04688,100.04688 C 120.04688,88.858778 110.94355,80.015625 100.01562,80.015625 C 99.665995,80.015625 99.297985,79.998061 98.953125,80.015625 z M 100.01562,89.109375 C 105.99997,89.109371 110.92188,94.062544 110.92188,100.04688 C 110.92188,106.03122 105.99997,110.95312 100.01562,110.95312 C 94.031295,110.95312 89.078125,106.03122 89.078125,100.04688 C 89.078122,94.062546 94.031295,89.109375 100.01562,89.109375 z "
+       style="opacity:0.30241939;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient7995);stroke-miterlimit:4" />
+    <g
+       id="g2126"
+       transform="matrix(0.5196104,0,0,0.5196104,129.86864,173.15423)"
+       inkscape:export-xdpi="312.71841"
+       inkscape:export-ydpi="312.71841"
+       style="opacity:0.0685484;fill:#ffffff;fill-opacity:1">
+      <g
+         transform="translate(86.33975,4.23985e-2)"
+         style="fill:#ffffff;fill-opacity:1"
+         id="g2114">
+        <g
+           style="fill:#ffffff;fill-opacity:1"
+           id="g2116">
+          <path
+             id="path2118"
+             transform="translate(-86.33975,-4.239934e-2)"
+             d="M 89.96875,0.03125 C 87.962748,0.031250001 86.34375,1.6815001 86.34375,3.6875 L 86.34375,17.71875 L 86.34375,19.6875 L 86.34375,28.90625 C 86.343752,39.06825 94.61925,47.34375 104.78125,47.34375 L 113.375,47.34375 L 123.1875,47.34375 L 127.15625,47.34375 C 129.16325,47.343749 130.8125,45.72475 130.8125,43.71875 C 130.8125,41.71275 129.16325,40.09375 127.15625,40.09375 L 123.1875,40.09375 L 123.1875,19.6875 L 123.1875,14.65625 L 123.1875,3.6875 C 123.1875,1.6815 121.5675,0.03125 119.5625,0.03125 C 117.5555,0.031250001 115.9375,1.6815001 115.9375,3.6875 L 115.9375,14.28125 C 115.1185,13.65425 114.26275,13.109 113.34375,12.625 L 113.34375,3.6875 C 113.34475,1.6815 111.6925,0.03125 109.6875,0.03125 C 107.6825,0.031250001 106.0625,1.6815001 106.0625,3.6875 L 106.0625,10.5625 C 105.6305,10.5325 105.22025,10.5 104.78125,10.5 C 104.34125,10.5 103.90075,10.5325 103.46875,10.5625 L 103.46875,3.6875 C 103.46975,1.6815 101.84975,0.03125 99.84375,0.03125 C 97.837749,0.031250001 96.21875,1.6815001 96.21875,3.6875 L 96.21875,12.625 C 95.299754,13.109 94.41375,13.65425 93.59375,14.28125 L 93.59375,3.6875 C 93.59475,1.6815 91.97475,0.03125 89.96875,0.03125 z M 104.78125,14.34375 C 112.80825,14.34375 119.3125,20.87925 119.3125,28.90625 C 119.3125,36.93325 112.80825,43.46875 104.78125,43.46875 C 96.754254,43.46875 90.21875,36.93425 90.21875,28.90625 C 90.218752,20.87825 96.753253,14.34375 104.78125,14.34375 z "
+             style="fill:#ffffff;fill-opacity:1" />
+        </g>
+      </g>
+      <path
+         style="fill:#ffffff;fill-opacity:1"
+         id="path2122"
+         d="M 112.04875,28.913399 C 112.04875,24.899399 108.78275,21.634399 104.76975,21.634399 C 100.75675,21.634399 97.490753,24.900399 97.490753,28.913399 C 97.490753,32.926399 100.75675,36.192399 104.76975,36.192399 C 108.78275,36.192399 112.04875,32.927399 112.04875,28.913399 z " />
+    </g>
+  </g>
+</svg>
diff --git a/attic/astro-desktop/data/face.png b/attic/astro-desktop/data/face.png
new file mode 100644 (file)
index 0000000..5fca186
Binary files /dev/null and b/attic/astro-desktop/data/face.png differ
diff --git a/attic/astro-desktop/data/icons/Makefile.am b/attic/astro-desktop/data/icons/Makefile.am
new file mode 100644 (file)
index 0000000..afaa4d1
--- /dev/null
@@ -0,0 +1,11 @@
+dist_default_DATA = \
+       bt.png \
+       close.png \
+       contacts.png \
+       exec.png \
+       home.png \
+       images.png \
+       music.png \
+       nm.png
+
+defaultdir = $(pkgdatadir)/icons
diff --git a/attic/astro-desktop/data/icons/bt.png b/attic/astro-desktop/data/icons/bt.png
new file mode 100644 (file)
index 0000000..2b29dc5
Binary files /dev/null and b/attic/astro-desktop/data/icons/bt.png differ
diff --git a/attic/astro-desktop/data/icons/close.png b/attic/astro-desktop/data/icons/close.png
new file mode 100644 (file)
index 0000000..f17b36c
Binary files /dev/null and b/attic/astro-desktop/data/icons/close.png differ
diff --git a/attic/astro-desktop/data/icons/contacts.png b/attic/astro-desktop/data/icons/contacts.png
new file mode 100644 (file)
index 0000000..d37e990
Binary files /dev/null and b/attic/astro-desktop/data/icons/contacts.png differ
diff --git a/attic/astro-desktop/data/icons/exec.png b/attic/astro-desktop/data/icons/exec.png
new file mode 100644 (file)
index 0000000..7c4abdb
Binary files /dev/null and b/attic/astro-desktop/data/icons/exec.png differ
diff --git a/attic/astro-desktop/data/icons/home.png b/attic/astro-desktop/data/icons/home.png
new file mode 100644 (file)
index 0000000..f165f03
Binary files /dev/null and b/attic/astro-desktop/data/icons/home.png differ
diff --git a/attic/astro-desktop/data/icons/images.png b/attic/astro-desktop/data/icons/images.png
new file mode 100644 (file)
index 0000000..0432e78
Binary files /dev/null and b/attic/astro-desktop/data/icons/images.png differ
diff --git a/attic/astro-desktop/data/icons/music.png b/attic/astro-desktop/data/icons/music.png
new file mode 100644 (file)
index 0000000..637be83
Binary files /dev/null and b/attic/astro-desktop/data/icons/music.png differ
diff --git a/attic/astro-desktop/data/icons/nm.png b/attic/astro-desktop/data/icons/nm.png
new file mode 100644 (file)
index 0000000..a3d973e
Binary files /dev/null and b/attic/astro-desktop/data/icons/nm.png differ
diff --git a/attic/astro-desktop/data/info_bg.png b/attic/astro-desktop/data/info_bg.png
new file mode 100644 (file)
index 0000000..b9f5fcc
Binary files /dev/null and b/attic/astro-desktop/data/info_bg.png differ
diff --git a/attic/astro-desktop/libastro-desktop/Makefile.am b/attic/astro-desktop/libastro-desktop/Makefile.am
new file mode 100644 (file)
index 0000000..354f018
--- /dev/null
@@ -0,0 +1,20 @@
+INCLUDES = \
+       -I$(srcdir)                             \
+       -I$(top_srcdir)                         \
+       -DPREFIX=\""$(prefix)"\"                \
+       -DLIBDIR=\""$(libdir)"\"                \
+       -DDATADIR=\""$(datadir)"\"              \
+       $(GCC_CFLAGS)                           \
+       $(DEPS_CFLAGS)  
+
+lib_LTLIBRARIES = libastro-desktop.la
+
+libastro_desktop_la_SOURCES = \
+       astro-application.c \
+       astro-behave.c \
+       astro-utils.c \
+       astro-window.c \
+       tidy-texture-frame.c
+
+libastro_desktop_la_LIBADD = $(DEPS_LIBS)
+libastro_desktop_la_LDFLAGS = $(DEPS_LT_LDFLAGS) -version-info 0:1:0
diff --git a/attic/astro-desktop/libastro-desktop/astro-application.c b/attic/astro-desktop/libastro-desktop/astro-application.c
new file mode 100644 (file)
index 0000000..cf907e6
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-application.h"
+
+#include "astro-defines.h"
+
+G_DEFINE_TYPE (AstroApplication, astro_application, G_TYPE_OBJECT);
+       
+enum
+{
+  PROP_0,
+  PROP_TITLE,
+  PROP_ICON
+};
+
+/* Public Functions */
+const gchar *   
+astro_application_get_title (AstroApplication *application)
+{
+  AstroApplicationClass *klass;
+
+  g_return_val_if_fail (ASTRO_IS_APPLICATION (application), NULL);
+  
+  klass = ASTRO_APPLICATION_GET_CLASS (application);
+  g_return_val_if_fail (klass->get_title != NULL, NULL);
+
+  return klass->get_title (application);
+}
+
+void            
+astro_application_set_title (AstroApplication *application, const gchar *title)
+{
+  AstroApplicationClass *klass;
+
+  g_return_if_fail (ASTRO_IS_APPLICATION (application));
+  g_return_if_fail (title);
+  
+  klass = ASTRO_APPLICATION_GET_CLASS (application);
+  g_return_if_fail (klass->set_title != NULL);
+
+  klass->set_title (application, title);
+  /* FIXME: emit signal */
+}
+
+GdkPixbuf *     
+astro_application_get_icon  (AstroApplication *application)
+{
+  AstroApplicationClass *klass;
+
+  g_return_val_if_fail (ASTRO_IS_APPLICATION (application), NULL);
+  
+  klass = ASTRO_APPLICATION_GET_CLASS (application);
+  g_return_val_if_fail (klass->get_icon != NULL, NULL);
+
+  return klass->get_icon (application);
+}
+
+void            
+astro_application_set_icon  (AstroApplication *application, 
+                             GdkPixbuf        *icon)
+{
+  AstroApplicationClass *klass;
+
+  g_return_if_fail (ASTRO_IS_APPLICATION (application));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+  
+  klass = ASTRO_APPLICATION_GET_CLASS (application);
+  g_return_if_fail (klass->set_icon != NULL);
+
+  klass->set_icon (application, icon);
+  /* FIXME: emit signal */
+}
+
+AstroWindow *     
+astro_application_get_window (AstroApplication *application)
+{
+  AstroApplicationClass *klass;
+
+  g_return_val_if_fail (ASTRO_IS_APPLICATION (application), NULL);
+  
+  klass = ASTRO_APPLICATION_GET_CLASS (application);
+  g_return_val_if_fail (klass->get_window != NULL, NULL);
+
+  return klass->get_window (application);
+}
+
+void 
+astro_application_close (AstroApplication *application)
+{
+  AstroApplicationClass *klass;
+
+  g_return_if_fail (ASTRO_IS_APPLICATION (application));
+    
+  klass = ASTRO_APPLICATION_GET_CLASS (application);
+  g_return_if_fail (klass->close != NULL);
+
+  klass->close (application);
+}
+/* GObject stuff */
+static void
+astro_application_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  AstroApplication *app = ASTRO_APPLICATION (object);
+
+  g_return_if_fail (ASTRO_IS_APPLICATION (object));
+
+  switch (prop_id)
+  {
+   case PROP_TITLE:
+      g_value_set_string (value, astro_application_get_title (app));
+      break;
+    case PROP_ICON:
+      g_value_set_object (value, astro_application_get_icon (app));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+astro_application_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  AstroApplication *app = ASTRO_APPLICATION (object);
+
+  g_return_if_fail (ASTRO_IS_APPLICATION (object));
+  
+  switch (prop_id)
+  {
+   case PROP_TITLE:
+      astro_application_set_title (app, g_value_get_string (value));
+      break;
+    case PROP_ICON:
+      astro_application_set_icon (app, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+astro_application_class_init (AstroApplicationClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = astro_application_set_property;
+  gobject_class->get_property = astro_application_get_property;
+
+  /* Class properties */
+  g_object_class_install_property (gobject_class,
+    PROP_TITLE,
+    g_param_spec_string ("title",
+                         "Title",
+                         "The title of the application",
+                         "Untitled",
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+  
+  g_object_class_install_property (gobject_class,
+    PROP_ICON,
+    g_param_spec_object ("icon",
+                         "Icon",
+                         "The icon of the application",
+                         CLUTTER_TYPE_ACTOR,
+                         G_PARAM_READWRITE));
+}
+
+static void
+astro_application_init (AstroApplication *application)
+{
+  ;
+}
+
diff --git a/attic/astro-desktop/libastro-desktop/astro-application.h b/attic/astro-desktop/libastro-desktop/astro-application.h
new file mode 100644 (file)
index 0000000..4ae43df
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include "astro-window.h"
+
+#ifndef _HAVE_ASTRO_APPLICATION_H
+#define _HAVE_ASTRO_APPLICATION_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_APPLICATION astro_application_get_type()
+
+#define ASTRO_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_APPLICATION, \
+  AstroApplication))
+
+#define ASTRO_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_APPLICATION, \
+  AstroApplicationClass))
+
+#define ASTRO_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_APPLICATION))
+
+#define ASTRO_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_APPLICATION))
+
+#define ASTRO_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_APPLICATION, \
+  AstroApplicationClass))
+
+typedef struct _AstroApplication AstroApplication;
+typedef struct _AstroApplicationClass AstroApplicationClass;
+
+struct _AstroApplication
+{
+  GObject         parent;
+};
+
+struct _AstroApplicationClass 
+{
+  /*< private >*/
+  GObjectClass parent_class;
+
+  /*< VTable, not signals >*/
+  const gchar  * (*get_title)  (AstroApplication *application);
+  void           (*set_title)  (AstroApplication *application, 
+                                const gchar      *title);
+  GdkPixbuf    * (*get_icon)   (AstroApplication *application);
+  void           (*set_icon)   (AstroApplication *application,
+                                GdkPixbuf        *icon);
+  AstroWindow  * (*get_window) (AstroApplication *application);
+
+  void           (*close)      (AstroApplication *application);
+  
+};
+
+typedef AstroApplication * (*AstroApplicationInitFunc) ();
+
+GType astro_application_get_type (void) G_GNUC_CONST;
+
+const gchar *      astro_application_get_title  (AstroApplication *application);
+void               astro_application_set_title  (AstroApplication *application,
+                                                 const gchar      *title);
+GdkPixbuf   *      astro_application_get_icon   (AstroApplication *application);
+void               astro_application_set_icon   (AstroApplication *application,
+                                                 GdkPixbuf        *pixbuf);
+AstroWindow *      astro_application_get_window (AstroApplication *application);
+void               astro_application_close      (AstroApplication *application);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/libastro-desktop/astro-behave.c b/attic/astro-desktop/libastro-desktop/astro-behave.c
new file mode 100644 (file)
index 0000000..00b7c56
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 Intel
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authored by Neil Jagdish Patel <njp@o-hand.com>
+ *
+ */
+
+#include "astro-behave.h"
+
+G_DEFINE_TYPE (AstroBehave, astro_behave, CLUTTER_TYPE_BEHAVIOUR);
+
+#define ASTRO_BEHAVE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+  ASTRO_TYPE_BEHAVE, \
+  AstroBehavePrivate))
+
+struct _AstroBehavePrivate
+{
+  AstroBehaveAlphaFunc     func;
+  gpointer             data;
+};
+
+static void
+astro_behave_alpha_notify (ClutterBehaviour *behave, guint32 alpha_value)
+{
+  AstroBehave *astro_behave = ASTRO_BEHAVE(behave);
+  AstroBehavePrivate *priv;
+       
+  priv = ASTRO_BEHAVE_GET_PRIVATE (astro_behave);
+       
+  if (priv->func != NULL) 
+    priv->func (behave, alpha_value, priv->data);
+}
+
+static void
+astro_behave_class_init (AstroBehaveClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
+
+  behave_class->alpha_notify = astro_behave_alpha_notify;
+       
+  g_type_class_add_private (gobject_class, sizeof (AstroBehavePrivate));
+}
+
+static void
+astro_behave_init (AstroBehave *self)
+{
+  AstroBehavePrivate *priv;
+       
+  priv = ASTRO_BEHAVE_GET_PRIVATE (self);
+       
+  priv->func = NULL;
+  priv->data = NULL;
+}
+
+ClutterBehaviour*
+astro_behave_new (ClutterAlpha                        *alpha,
+                     AstroBehaveAlphaFunc      func,
+                     gpointer                        data)
+{
+  AstroBehave *behave;
+  AstroBehavePrivate *priv;
+       
+  behave = g_object_new (ASTRO_TYPE_BEHAVE, 
+                         "alpha", alpha,
+                         NULL);
+
+  priv = ASTRO_BEHAVE_GET_PRIVATE (behave);  
+       
+  priv->func = func;
+  priv->data = data;
+               
+  return CLUTTER_BEHAVIOUR(behave);
+}
diff --git a/attic/astro-desktop/libastro-desktop/astro-behave.h b/attic/astro-desktop/libastro-desktop/astro-behave.h
new file mode 100644 (file)
index 0000000..164495d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 Intel
+ *
+ * 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 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
+ * Lesser 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authored by Neil Jagdish Patel <njp@o-hand.com>
+ *
+ */
+
+/* This is a utility ClutterBehaviour-derived class, in which you can set the
+   alphanotify function. It is useful for situations where you do not need the
+   full capabilities of the ClutterBehvaiour class, you just want a function to
+   be called for each iteration along the timeline
+*/
+
+#ifndef _ASTRO_BEHAVE_H_
+#define _ASTRO_BEHAVE_H_
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+#define ASTRO_TYPE_BEHAVE (astro_behave_get_type ())
+
+#define ASTRO_BEHAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+       ASTRO_TYPE_BEHAVE, AstroBehave))
+
+#define ASTRO_BEHAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       ASTRO_TYPE_BEHAVE, AstroBehaveClass))
+
+#define CLUTTER_IS_BEHAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+       ASTRO_TYPE_BEHAVE))
+
+#define CLUTTER_IS_BEHAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+       ASTRO_TYPE_BEHAVE))
+
+#define ASTRO_BEHAVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       ASTRO_TYPE_BEHAVE, AstroBehaveClass))
+
+typedef struct _AstroBehave        AstroBehave;
+typedef struct _AstroBehaveClass   AstroBehaveClass;
+typedef struct _AstroBehavePrivate AstroBehavePrivate;
+struct _AstroBehave
+{
+  ClutterBehaviour        parent;      
+};
+
+struct _AstroBehaveClass
+{
+  ClutterBehaviourClass   parent_class;
+};
+
+typedef void (*AstroBehaveAlphaFunc) (ClutterBehaviour *behave, 
+                                      guint32                alpha_value,
+                                      gpointer               data);
+
+GType astro_behave_get_type (void) G_GNUC_CONST;
+
+ClutterBehaviour* 
+astro_behave_new (ClutterAlpha         *alpha, 
+                  AstroBehaveAlphaFunc  func,
+                  gpointer                       data);
+
+
+#endif /* _ASTRO_BEHAVE_H_ */
+
diff --git a/attic/astro-desktop/libastro-desktop/astro-defines.h b/attic/astro-desktop/libastro-desktop/astro-defines.h
new file mode 100644 (file)
index 0000000..705a1f4
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#ifndef _HAVE_ASTRO_DEFINES_H
+#define _HAVE_ASTRO_DEFINES_H
+
+#define CSW() (CLUTTER_STAGE_WIDTH())
+#define CSH() (CLUTTER_STAGE_HEIGHT())
+
+#define ASTRO_PANEL_HEIGHT() (CSH() * 0.15)
+
+#define ASTRO_WINDOW_WIDTH() (CSW())
+#define ASTRO_WINDOW_HEIGHT() (CSW()-ASTRO_PANEL_HEIGHT())
+
+#define ASTRO_APPICON_SIZE() (CSH()*0.3)
+#define ASTRO_APPICON_SPACING() (ASTRO_APPICON_SIZE()*0.9)
+
+#define ASTRO_APPLET_HEIGHT() (CSH()*0.15)
+#define ASTRO_APPLET_PADDING 4
+
+#endif
diff --git a/attic/astro-desktop/libastro-desktop/astro-utils.c b/attic/astro-desktop/libastro-desktop/astro-utils.c
new file mode 100644 (file)
index 0000000..26c872a
--- /dev/null
@@ -0,0 +1,14 @@
+#include "astro-utils.h"
+
+
+void 
+astro_utils_set_clip (ClutterActor *actor,
+                      gint          xoff, 
+                      gint          yoff,
+                      gint          width,
+                      gint          height)
+{
+#if 1
+  clutter_actor_set_clip (actor, xoff, yoff, width, height);
+#endif
+}
diff --git a/attic/astro-desktop/libastro-desktop/astro-utils.h b/attic/astro-desktop/libastro-desktop/astro-utils.h
new file mode 100644 (file)
index 0000000..f8528fc
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_ASTRO_UTILS_H
+#define _HAVE_ASTRO_UTILS_H
+
+
+void astro_utils_set_clip (ClutterActor *actor,
+                           gint          xoff, 
+                           gint          yoff,
+                           gint          width,
+                           gint          height);
+
+#endif
diff --git a/attic/astro-desktop/libastro-desktop/astro-window.c b/attic/astro-desktop/libastro-desktop/astro-window.c
new file mode 100644 (file)
index 0000000..54bc88c
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-window.h"
+
+#include "astro-defines.h"
+
+G_DEFINE_TYPE (AstroWindow, astro_window, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_WINDOW, AstroWindowPrivate))
+
+struct _AstroWindowPrivate
+{
+  ClutterEffectTemplate *show_temp;
+  ClutterTimeline       *show_time;
+
+  ClutterEffectTemplate *hide_temp;
+  ClutterTimeline       *hide_time;
+};
+
+
+static void
+astro_window_show (ClutterActor *view)
+{
+  AstroWindowPrivate *priv;
+  static ClutterTimeline *show_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_WINDOW (view));
+  priv = ASTRO_WINDOW (view)->priv;
+
+  if (CLUTTER_IS_TIMELINE (show_time) &&clutter_timeline_is_playing (show_time))
+    {
+      clutter_timeline_stop (show_time);
+      g_object_unref (show_time);
+    }
+
+  CLUTTER_ACTOR_CLASS (astro_window_parent_class)->show (view);
+
+  show_time = clutter_effect_fade (priv->show_temp,
+                                   CLUTTER_ACTOR (view),
+                                   255,
+                                   NULL, NULL);
+}
+
+static void
+astro_window_hide (ClutterActor *view)
+{
+  AstroWindowPrivate *priv;
+  static ClutterTimeline *hide_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_WINDOW (view));
+  priv = ASTRO_WINDOW (view)->priv;
+
+  if (CLUTTER_IS_TIMELINE (hide_time) &&clutter_timeline_is_playing (hide_time))
+    {
+      clutter_timeline_stop (hide_time);
+      g_object_unref (hide_time);
+    }
+  
+  hide_time = clutter_effect_fade (priv->hide_temp,
+                                   CLUTTER_ACTOR (view),
+                                   0,
+     (ClutterEffectCompleteFunc)
+        CLUTTER_ACTOR_CLASS (astro_window_parent_class)->hide,
+                                   NULL);
+}
+
+
+
+void               
+astro_window_close      (AstroWindow *window)
+{
+  AstroWindowPrivate *priv;
+  static ClutterTimeline *hide_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_WINDOW (window));
+  priv = ASTRO_WINDOW (window)->priv;
+
+  if (CLUTTER_IS_TIMELINE (hide_time) &&clutter_timeline_is_playing (hide_time))
+    {
+      clutter_timeline_stop (hide_time);
+      g_object_unref (hide_time);
+    }
+
+  hide_time = clutter_effect_move (priv->hide_temp,
+                                   CLUTTER_ACTOR (window),
+                                   CSW(),
+                                   clutter_actor_get_y (CLUTTER_ACTOR (window)),
+                                   NULL, NULL);
+  
+  hide_time = clutter_effect_fade (priv->hide_temp,
+                                   CLUTTER_ACTOR (window),
+                                   0,
+                            (ClutterEffectCompleteFunc)clutter_actor_destroy,
+                            NULL);
+}
+
+/* GObject stuff */
+static void
+astro_window_class_init (AstroWindowClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->show = astro_window_show;
+  actor_class->hide = astro_window_hide;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroWindowPrivate));
+}
+
+
+static void
+astro_window_init (AstroWindow *window)
+{
+  AstroWindowPrivate *priv;
+
+  priv = window->priv = ASTRO_WINDOW_GET_PRIVATE (window);
+
+  clutter_actor_set_opacity (CLUTTER_ACTOR (window), 0);
+
+  priv->show_time = clutter_timeline_new_for_duration (300);
+  priv->show_temp = clutter_effect_template_new (priv->show_time, 
+                                                 clutter_sine_inc_func);
+  priv->hide_time = clutter_timeline_new_for_duration (300);
+  priv->hide_temp = clutter_effect_template_new (priv->hide_time, 
+                                                 clutter_sine_inc_func);;
+}
+
+ClutterActor *
+astro_window_new ()
+{
+  return g_object_new (ASTRO_TYPE_WINDOW, NULL);
+}
+
diff --git a/attic/astro-desktop/libastro-desktop/astro-window.h b/attic/astro-desktop/libastro-desktop/astro-window.h
new file mode 100644 (file)
index 0000000..73c3ab6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_ASTRO_WINDOW_H
+#define _HAVE_ASTRO_WINDOW_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_WINDOW astro_window_get_type()
+
+#define ASTRO_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_WINDOW, \
+  AstroWindow))
+
+#define ASTRO_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_WINDOW, \
+  AstroWindowClass))
+
+#define ASTRO_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_WINDOW))
+
+#define ASTRO_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_WINDOW))
+
+#define ASTRO_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_WINDOW, \
+  AstroWindowClass))
+
+typedef struct _AstroWindow AstroWindow;
+typedef struct _AstroWindowClass AstroWindowClass;
+typedef struct _AstroWindowPrivate AstroWindowPrivate;
+
+struct _AstroWindow
+{
+  ClutterGroup         parent;
+
+  /*< private >*/
+  AstroWindowPrivate *priv;
+};
+
+struct _AstroWindowClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /*< signals >*/
+  void           (*close)      (AstroWindow *window);  
+}; 
+
+GType astro_window_get_type (void) G_GNUC_CONST;
+
+ClutterActor *     astro_window_new        (void);
+void               astro_window_close      (AstroWindow *window);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/libastro-desktop/astro.h b/attic/astro-desktop/libastro-desktop/astro.h
new file mode 100644 (file)
index 0000000..2fa048c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#ifndef _HAVE_ASTRO_H
+#define _HAVE_ASTRO_H
+
+#include "astro-application.h"
+#include "astro-defines.h"
+#include "astro-utils.h"
+#include "astro-window.h"
+#endif
diff --git a/attic/astro-desktop/libastro-desktop/tidy-private.h b/attic/astro-desktop/libastro-desktop/tidy-private.h
new file mode 100644 (file)
index 0000000..5f17d93
--- /dev/null
@@ -0,0 +1,40 @@
+/* tidy-private.h: Private declarations
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TIDY_PRIVATE_H__
+#define __TIDY_PRIVATE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define I_(str)         (g_intern_static_string ((str)))
+
+#define TIDY_PARAM_READABLE     \
+        (G_PARAM_READABLE |     \
+         G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+#define TIDY_PARAM_READWRITE    \
+        (G_PARAM_READABLE | G_PARAM_WRITABLE | \
+         G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+G_END_DECLS
+
+#endif /* __TIDY_PRIVATE_H__ */
diff --git a/attic/astro-desktop/libastro-desktop/tidy-texture-frame.c b/attic/astro-desktop/libastro-desktop/tidy-texture-frame.c
new file mode 100644 (file)
index 0000000..8bc91c0
--- /dev/null
@@ -0,0 +1,378 @@
+/* tidy-texture-frame.h: Expandible texture actor
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:tidy-texture-frame
+ * @short_description: Actor for cloning existing textures in an 
+ * efficient way.
+ *
+ * #TidyTextureFrame
+ *
+ */
+
+#include <clutter/cogl.h>
+
+#include "tidy-texture-frame.h"
+#include "tidy-private.h"
+
+enum
+{
+  PROP_0,
+  PROP_LEFT,
+  PROP_TOP,
+  PROP_RIGHT,
+  PROP_BOTTOM
+};
+
+G_DEFINE_TYPE (TidyTextureFrame,
+              tidy_texture_frame,
+              CLUTTER_TYPE_CLONE_TEXTURE);
+
+#define TIDY_TEXTURE_FRAME_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFramePrivate))
+
+struct _TidyTextureFramePrivate
+{
+  gint left, top, right, bottom;
+};
+
+static void
+tidy_texture_frame_paint (ClutterActor *self)
+{
+  TidyTextureFramePrivate    *priv;
+  ClutterActor                *parent_texture;
+  guint                        width, height;
+  gint                         pwidth, pheight, ex, ey;
+  ClutterFixed                 tx1, ty1, tx2, ty2, tw, th;
+  GLenum                       target_type;
+  ClutterColor                 col = { 0xff, 0xff, 0xff, 0xff };
+
+  priv = TIDY_TEXTURE_FRAME (self)->priv;
+
+  /* no need to paint stuff if we don't have a texture to reflect */
+  if (!clutter_clone_texture_get_parent_texture (CLUTTER_CLONE_TEXTURE(self)))
+    return;
+
+  /* parent texture may have been hidden, there for need to make sure its 
+   * realised with resources available.  
+  */
+  parent_texture 
+    = CLUTTER_ACTOR 
+       (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)));
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+    clutter_actor_realize (parent_texture);
+
+  if (clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture)))
+    {
+      g_warning("tiled textures not yet supported...");
+      return;
+    }
+
+  cogl_push_matrix ();
+
+#define FX(x) CLUTTER_INT_TO_FIXED(x)
+
+  clutter_texture_get_base_size (CLUTTER_TEXTURE(parent_texture), 
+                                &pwidth, &pheight); 
+  clutter_actor_get_size (self, &width, &height); 
+
+  tx1 = FX (priv->left);
+  tx2 = FX (pwidth - priv->right);
+  ty1 = FX (priv->top);
+  ty2 = FX (pheight - priv->bottom);
+  tw = FX (pwidth);
+  th = FX (pheight);
+
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+    {
+      target_type = CGL_TEXTURE_RECTANGLE_ARB;
+      cogl_enable (CGL_ENABLE_TEXTURE_RECT|CGL_ENABLE_BLEND);
+    }
+  else
+    {
+      target_type = CGL_TEXTURE_2D;
+      cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
+
+      tw = clutter_util_next_p2 (pwidth);
+      th = clutter_util_next_p2 (pheight);
+
+      tx1 = tx1/tw;
+      tx2 = tx2/tw;
+      ty1 = ty1/th;
+      ty2 = ty2/th;
+      tw = FX(pwidth)/tw;
+      th = FX(pheight)/th;
+    }
+
+  col.alpha = clutter_actor_get_opacity (self);
+  cogl_color (&col);
+
+  clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), 0);
+
+  ex = width - priv->right;
+  if (ex < 0) 
+    ex = priv->right;          /* FIXME */
+
+  ey = height - priv->bottom;
+  if (ey < 0) 
+    ey = priv->bottom;                 /* FIXME */
+
+  /* top left corner */
+  cogl_texture_quad (0, 
+                    priv->left, /* FIXME: clip if smaller */
+                    0,
+                    priv->top,
+                    0,
+                    0,
+                    tx1,
+                    ty1);
+
+  /* top middle */
+  cogl_texture_quad (priv->left,
+                    ex,
+                    0,
+                    priv->top,
+                    tx1,
+                    0,
+                    tx2,
+                    ty1);
+
+  /* top right */
+  cogl_texture_quad (ex,
+                    width,
+                    0,
+                    priv->top,
+                    tx2,
+                    0,
+                    tw,
+                    ty1);
+
+  /* mid left */
+  cogl_texture_quad (0, 
+                    priv->left,
+                    priv->top,
+                    ey,
+                    0,
+                    ty1,
+                    tx1,
+                    ty2);
+
+  /* center */
+  cogl_texture_quad (priv->left,
+                    ex,
+                    priv->top,
+                    ey,
+                    tx1,
+                    ty1,
+                    tx2,
+                    ty2);
+
+  /* mid right */
+  cogl_texture_quad (ex,
+                    width,
+                    priv->top,
+                    ey,
+                    tx2,
+                    ty1,
+                    tw,
+                    ty2);
+
+  /* bottom left */
+  cogl_texture_quad (0, 
+                    priv->left,
+                    ey,
+                    height,
+                    0,
+                    ty2,
+                    tx1,
+                    th);
+
+  /* bottom center */
+  cogl_texture_quad (priv->left,
+                    ex,
+                    ey,
+                    height,
+                    tx1,
+                    ty2,
+                    tx2,
+                    th);
+
+  /* bottom right */
+  cogl_texture_quad (ex,
+                    width,
+                    ey,
+                    height,
+                    tx2,
+                    ty2,
+                    tw,
+                    th);
+
+  cogl_pop_matrix ();
+
+#undef FX
+}
+
+
+static void
+tidy_texture_frame_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  TidyTextureFrame         *ctexture = TIDY_TEXTURE_FRAME (object);
+  TidyTextureFramePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_LEFT:
+      priv->left = g_value_get_int (value);
+      break;
+    case PROP_TOP:
+      priv->top = g_value_get_int (value);
+      break;
+    case PROP_RIGHT:
+      priv->right = g_value_get_int (value);
+      break;
+    case PROP_BOTTOM:
+      priv->bottom = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tidy_texture_frame_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  TidyTextureFrame *ctexture = TIDY_TEXTURE_FRAME (object);
+  TidyTextureFramePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_LEFT:
+      g_value_set_int (value, priv->left);
+      break;
+    case PROP_TOP:
+      g_value_set_int (value, priv->top);
+      break;
+    case PROP_RIGHT:
+      g_value_set_int (value, priv->right);
+      break;
+    case PROP_BOTTOM:
+      g_value_set_int (value, priv->bottom);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tidy_texture_frame_class_init (TidyTextureFrameClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->paint = tidy_texture_frame_paint;
+
+  gobject_class->set_property = tidy_texture_frame_set_property;
+  gobject_class->get_property = tidy_texture_frame_get_property;
+
+  g_object_class_install_property 
+            (gobject_class,
+            PROP_LEFT,
+            g_param_spec_int ("left",
+                              "left",
+                              "",
+                              0, G_MAXINT,
+                              0,
+                              TIDY_PARAM_READWRITE));
+
+  g_object_class_install_property 
+            (gobject_class,
+            PROP_TOP,
+            g_param_spec_int ("top",
+                              "top",
+                              "",
+                              0, G_MAXINT,
+                              0,
+                              TIDY_PARAM_READWRITE));
+
+  g_object_class_install_property 
+            (gobject_class,
+            PROP_BOTTOM,
+            g_param_spec_int ("bottom",
+                              "bottom",
+                              "",
+                              0, G_MAXINT,
+                              0,
+                              TIDY_PARAM_READWRITE));
+  
+  g_object_class_install_property 
+            (gobject_class,
+            PROP_RIGHT,
+            g_param_spec_int ("right",
+                              "right",
+                              "",
+                              0, G_MAXINT,
+                              0,
+                              TIDY_PARAM_READWRITE));
+  
+  g_type_class_add_private (gobject_class, sizeof (TidyTextureFramePrivate));
+}
+
+static void
+tidy_texture_frame_init (TidyTextureFrame *self)
+{
+  TidyTextureFramePrivate *priv;
+
+  self->priv = priv = TIDY_TEXTURE_FRAME_GET_PRIVATE (self);
+}
+
+/**
+ * tidy_texture_frame_new:
+ * @texture: a #ClutterTexture or %NULL
+ *
+ * FIXME
+ *
+ * Return value: the newly created #TidyTextureFrame
+ */
+ClutterActor*
+tidy_texture_frame_new (ClutterTexture *texture, 
+                       gint            left,
+                       gint            top,
+                       gint            right,
+                       gint            bottom)
+{
+  g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
+
+  return g_object_new (TIDY_TYPE_TEXTURE_FRAME,
+                      "parent-texture", texture,
+                      "left", left,
+                      "top", top,
+                      "right", right,
+                      "bottom", bottom,
+                      NULL);
+}
+
diff --git a/attic/astro-desktop/libastro-desktop/tidy-texture-frame.h b/attic/astro-desktop/libastro-desktop/tidy-texture-frame.h
new file mode 100644 (file)
index 0000000..87d2d04
--- /dev/null
@@ -0,0 +1,82 @@
+/* tidy-texture-frame.h: Expandible texture actor
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_TIDY_TEXTURE_FRAME_H
+#define _HAVE_TIDY_TEXTURE_FRAME_H
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_TEXTURE_FRAME (tidy_texture_frame_get_type ())
+
+#define TIDY_TEXTURE_FRAME(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrame))
+
+#define TIDY_TEXTURE_FRAME_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass))
+
+#define TIDY_IS_TEXTURE_FRAME(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  TIDY_TYPE_TEXTURE_FRAME))
+
+#define TIDY_IS_TEXTURE_FRAME_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  TIDY_TYPE_TEXTURE_FRAME))
+
+#define TIDY_TEXTURE_FRAME_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass))
+
+typedef struct _TidyTextureFrame        TidyTextureFrame;
+typedef struct _TidyTextureFramePrivate TidyTextureFramePrivate;
+typedef struct _TidyTextureFrameClass   TidyTextureFrameClass;
+
+struct _TidyTextureFrame
+{
+  ClutterCloneTexture              parent;
+  
+  /*< priv >*/
+  TidyTextureFramePrivate    *priv;
+};
+
+struct _TidyTextureFrameClass 
+{
+  ClutterCloneTextureClass parent_class;
+
+  /* padding for future expansion */
+  void (*_clutter_box_1) (void);
+  void (*_clutter_box_2) (void);
+  void (*_clutter_box_3) (void);
+  void (*_clutter_box_4) (void);
+}; 
+
+GType         tidy_texture_frame_get_type (void) G_GNUC_CONST;
+ClutterActor *tidy_texture_frame_new      (ClutterTexture *texture,
+                                           gint            left,
+                                           gint            top,
+                                           gint            right,
+                                           gint            bottom);
+
+G_END_DECLS
+
+#endif /* _HAVE_TIDY_TEXTURE_FRAME_H */
diff --git a/attic/astro-desktop/src/Makefile.am b/attic/astro-desktop/src/Makefile.am
new file mode 100644 (file)
index 0000000..2228260
--- /dev/null
@@ -0,0 +1,35 @@
+bin_PROGRAMS = astro-desktop
+
+AM_CFLAGS = \
+       $(DEPS_CFLAGS) \
+       $(GCC_CFLAGS) \
+       -DDATADIR=\""$(datadir)"\" \
+       -DLIBDIR=\""$(libdir)"\" \
+       -DPKGDATADIR=\""$(pkgdatadir)"\" \
+       -DPKGLIBDIR=\""$(libdir)/astro-desktop"\" \
+       -I$(top_builddir)/libastro-desktop
+
+astro_desktop_LDADD  = \
+       $(DEPS_LIBS) \
+       $(top_builddir)/libastro-desktop/libastro-desktop.la 
+
+astro_desktop_SOURCES = \
+       astro-appicon.c \
+       astro-appicon.h \
+       astro-applet.c \
+       astro-applet.h \
+       astro-applet-manager.c \
+       astro-applet-manager.h \
+       astro-appview.c \
+       astro-appview.h \
+       astro-desktop.c \
+       astro-desktop.h \
+       astro-example.c \
+       astro-example.h \
+       astro-panel.c \
+       astro-panel.h \
+       astro-systray.c \
+       astro-systray.h \
+       main.c
+
+       
diff --git a/attic/astro-desktop/src/astro-appicon.c b/attic/astro-desktop/src/astro-appicon.c
new file mode 100644 (file)
index 0000000..9ce40ff
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-appicon.h"
+
+#include <clutter/clutter-shader.h>
+#include <libastro-desktop/astro-defines.h>
+
+G_DEFINE_TYPE (AstroAppicon, astro_appicon, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_APPICON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_APPICON, AstroAppiconPrivate))
+       
+struct _AstroAppiconPrivate
+{
+  AstroApplication *application;
+  ClutterActor     *texture;
+  ClutterShader     *shader;
+};
+
+enum
+{
+  CLICKED,
+
+  LAST_SIGNAL
+};
+static guint _appicon_signals[LAST_SIGNAL] = { 0 };
+
+static gchar *source = "uniform float radius ;"
+        "uniform sampler2DRect rectTexture;"
+        ""
+        "void main()"
+        "{"
+        "    vec4 color = texture2DRect(rectTexture, gl_TexCoord[0].st);"
+        "    float u;"
+        "    float v;"
+        "    int count = 1;"
+        "    for (u=-radius;u<radius;u++)"
+        "      for (v=-radius;v<radius;v++)"
+        "        {"
+        "          color += texture2DRect(rectTexture, vec2(gl_TexCoord[0].s + u * 2, gl_TexCoord[0].t +v * 2));"
+        "          count ++;"
+        "        }"
+        ""
+        "    gl_FragColor = color / count;"
+        "}" ;
+
+
+/* Callbacks */
+static gboolean
+on_clicked (ClutterActor *home, ClutterEvent *event, AstroAppicon *appicon)
+{
+  g_return_val_if_fail (ASTRO_APPICON (appicon), FALSE);
+  g_debug ("app button clicked");
+
+  g_signal_emit (appicon, _appicon_signals[CLICKED], 
+                 0, appicon->priv->application);
+  return FALSE;
+}
+
+
+/* Public Functions */
+const gchar  *
+astro_appicon_get_title (AstroAppicon     *icon)
+{
+  g_return_val_if_fail (ASTRO_IS_APPICON (icon), NULL);
+
+  return astro_application_get_title (icon->priv->application);
+}
+  
+static void
+astro_appicon_set_application (AstroAppicon *appicon, AstroApplication *app)
+{
+  AstroAppiconPrivate *priv;
+  ClutterShader *shader;
+  ClutterActor *texture;
+  GdkPixbuf *pixbuf;
+  GError *error = NULL;
+
+  g_return_if_fail (ASTRO_IS_APPICON (appicon));
+  priv = appicon->priv;
+
+  priv->application = app;
+
+  pixbuf = astro_application_get_icon (app);
+  if (pixbuf)
+    {
+      priv->texture = texture = clutter_texture_new_from_pixbuf (pixbuf);
+      clutter_container_add_actor (CLUTTER_CONTAINER (appicon), texture);
+      
+      clutter_actor_set_position (texture, 0, 0);
+      clutter_actor_set_reactive (texture, TRUE);
+
+      g_signal_connect (texture, "button-release-event",
+                        G_CALLBACK (on_clicked), appicon);
+
+    }
+  else
+    return;
+  /* Set up shader */
+  priv->shader = shader = clutter_shader_new ();
+  clutter_shader_set_fragment_source (shader, source, -1);
+   
+  /* We try and bind the source, we'll catch and error if there are issues */
+  clutter_shader_bind (shader, &error);
+  if (error)
+    {
+      g_warning ("Unable to init shader: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    {
+      clutter_actor_set_shader (texture, shader);
+      clutter_actor_set_shader_param (texture, "radius", 5.0);
+    }
+
+  clutter_actor_show_all (CLUTTER_ACTOR (appicon));
+}
+
+void            
+astro_appicon_set_blur  (AstroAppicon     *appicon,
+                         gfloat            blur)
+{
+  AstroAppiconPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_APPICON (appicon));
+  priv = appicon->priv;
+
+  clutter_actor_set_shader_param (priv->texture, "radius", blur);
+}  
+
+/* GObject stuff */
+static void
+astro_appicon_class_init (AstroAppiconClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  _appicon_signals[CLICKED] = 
+    g_signal_new ("clicked",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (AstroAppiconClass, clicked),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, ASTRO_TYPE_APPLICATION);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroAppiconPrivate));
+}
+
+static void
+astro_appicon_init (AstroAppicon *appicon)
+{
+  AstroAppiconPrivate *priv;
+
+  priv = appicon->priv = ASTRO_APPICON_GET_PRIVATE (appicon);
+
+  priv->application = NULL;
+  priv->texture = NULL;
+  priv->shader = NULL;
+}
+
+ClutterActor * 
+astro_appicon_new (AstroApplication *app)
+{
+  AstroAppicon *appicon =  g_object_new (ASTRO_TYPE_APPICON,
+                                                                                              NULL);
+  astro_appicon_set_application (appicon, app);
+
+  return CLUTTER_ACTOR (appicon);
+}
+
diff --git a/attic/astro-desktop/src/astro-appicon.h b/attic/astro-desktop/src/astro-appicon.h
new file mode 100644 (file)
index 0000000..a33b938
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_APPICON_H
+#define _HAVE_ASTRO_APPICON_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_APPICON astro_appicon_get_type()
+
+#define ASTRO_APPICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_APPICON, \
+  AstroAppicon))
+
+#define ASTRO_APPICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_APPICON, \
+  AstroAppiconClass))
+
+#define ASTRO_IS_APPICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_APPICON))
+
+#define ASTRO_IS_APPICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_APPICON))
+
+#define ASTRO_APPICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_APPICON, \
+  AstroAppiconClass))
+
+typedef struct _AstroAppicon AstroAppicon;
+typedef struct _AstroAppiconClass AstroAppiconClass;
+typedef struct _AstroAppiconPrivate AstroAppiconPrivate;
+
+struct _AstroAppicon
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroAppiconPrivate   *priv;
+};
+
+struct _AstroAppiconClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /*< signals >*/
+  void (*clicked)    (AstroAppicon *appicon, AstroApplication *application);
+}; 
+
+GType astro_appicon_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_appicon_new       (AstroApplication *application);
+const gchar  *  astro_appicon_get_title (AstroAppicon     *icon);
+void            astro_appicon_set_blur  (AstroAppicon     *icon,
+                                         gfloat            blur);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-applet-manager.c b/attic/astro-desktop/src/astro-applet-manager.c
new file mode 100644 (file)
index 0000000..380d782
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-applet-manager.h"
+
+#include <libastro-desktop/astro-defines.h>
+
+#include "astro-applet.h"
+
+G_DEFINE_TYPE (AstroAppletManager, astro_applet_manager, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_APPLET_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ASTRO_TYPE_APPLET_MANAGER, AstroAppletManagerPrivate))
+
+struct _AstroAppletManagerPrivate
+{
+  GList *applets;
+
+  ClutterEffectTemplate *show_temp;
+  ClutterTimeline       *show_time;
+
+  ClutterEffectTemplate *hide_temp;
+  ClutterTimeline       *hide_time;
+};
+
+
+/* GObject stuff */
+static void
+astro_applet_manager_show (ClutterActor *appman)
+{
+  AstroAppletManagerPrivate *priv;
+  static ClutterTimeline *show_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_APPLET_MANAGER (appman));
+  priv = ASTRO_APPLET_MANAGER (appman)->priv;
+
+  if (CLUTTER_IS_TIMELINE (show_time) &&clutter_timeline_is_playing (show_time))
+    {
+      clutter_timeline_stop (show_time);
+      g_object_unref (show_time);
+    }
+
+  clutter_actor_set_x (appman, clutter_actor_get_width (appman) * -1);
+  CLUTTER_ACTOR_CLASS (astro_applet_manager_parent_class)->show (appman);
+
+  show_time = clutter_effect_move (priv->show_temp,
+                                   CLUTTER_ACTOR (appman),
+                                   ASTRO_APPLET_PADDING,
+                                   clutter_actor_get_y (CLUTTER_ACTOR (appman)),
+                                   NULL, NULL);
+}
+
+static void
+on_hide_timeline_completed (ClutterTimeline *timeline, ClutterActor *appman)
+{
+  CLUTTER_ACTOR_CLASS (astro_applet_manager_parent_class)->hide (appman);
+}
+
+static void
+astro_applet_manager_hide (ClutterActor *appman)
+{
+  AstroAppletManagerPrivate *priv;
+  static ClutterTimeline *hide_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_APPLET_MANAGER (appman));
+  priv = ASTRO_APPLET_MANAGER (appman)->priv;
+
+  if (CLUTTER_IS_TIMELINE (hide_time) &&clutter_timeline_is_playing (hide_time))
+    {
+      clutter_timeline_stop (hide_time);
+      g_object_unref (hide_time);
+    }
+  
+  hide_time = clutter_effect_move (priv->hide_temp,
+                                   CLUTTER_ACTOR (appman),
+                                   -1*clutter_actor_get_width (appman),
+                                   clutter_actor_get_y (CLUTTER_ACTOR (appman)),
+                                   NULL, NULL);
+
+  g_signal_connect (hide_time, "completed",
+                    G_CALLBACK (on_hide_timeline_completed), appman);
+}
+
+static void
+astro_applet_manager_class_init (AstroAppletManagerClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->show = astro_applet_manager_show;
+  actor_class->hide = astro_applet_manager_hide;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroAppletManagerPrivate));
+}
+
+static ClutterActor *
+_load_script (const gchar *name)
+{
+  ClutterScript *script;
+  ClutterActor *applet;
+  ClutterActor *child = NULL;
+  GError *error = NULL;
+  gint res;
+  
+  script = clutter_script_new ();
+
+  clutter_script_load_from_file (script, name, &error);
+  if (error)
+    {
+      g_warning ("Unable to load applet: %s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+  
+  res = clutter_script_get_objects (script, "applet-child", &child, NULL);
+   if (res == 3)
+    {
+      g_warning ("Unable to load script: %s", name);
+      return NULL;  
+    }
+
+   if (!CLUTTER_IS_ACTOR (child))
+    {
+      g_warning ("Did not get child\n");
+      return NULL;
+    }
+
+  applet = astro_applet_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (applet), child);
+  clutter_actor_set_position (child, 
+                              ASTRO_APPLET_PADDING, ASTRO_APPLET_PADDING);
+
+  return applet;
+}
+
+static void
+astro_applet_manager_init (AstroAppletManager *applet_manager)
+{
+  AstroAppletManagerPrivate *priv;
+  GDir *dir;
+  GError *error = NULL;
+  const gchar *name;
+  gint offset = 0;
+
+  applet_manager->priv = ASTRO_APPLET_MANAGER_GET_PRIVATE (applet_manager);
+  priv = applet_manager->priv;
+
+  /* Load applets */
+  dir = g_dir_open (PKGDATADIR "/applets", 0, &error);
+  if (error)
+    {
+      g_warning ("Can't open applet directory: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+  
+  while ((name = g_dir_read_name (dir)))
+    {
+      if (g_str_has_suffix (name, ".json"))
+        {
+          ClutterActor *applet = NULL;
+          gchar *filename = g_strdup_printf ("%s%s",
+                                             PKGDATADIR"/applets/", 
+                                             name);
+
+          applet = _load_script (filename);
+
+          if (!CLUTTER_IS_ACTOR (applet))
+            { 
+              g_free (filename);
+              continue;
+            }
+          clutter_container_add_actor (CLUTTER_CONTAINER (applet_manager),
+                                       applet);
+          clutter_actor_set_position (applet, offset, 0);
+          
+          offset+= clutter_actor_get_width (applet) + ASTRO_APPLET_PADDING;
+          g_free (filename);
+        }
+    }
+  g_dir_close (dir);
+
+  priv->show_time = clutter_timeline_new_for_duration (600);
+  priv->show_temp = clutter_effect_template_new (priv->show_time, 
+                                                 clutter_sine_inc_func);
+  priv->hide_time = clutter_timeline_new_for_duration (300);
+  priv->hide_temp = clutter_effect_template_new (priv->hide_time, 
+                                                 clutter_sine_inc_func);
+}
+
+ClutterActor * 
+astro_applet_manager_new (void)
+{
+  AstroAppletManager *applet_manager =  g_object_new (ASTRO_TYPE_APPLET_MANAGER,
+                                                                                              NULL);
+  return CLUTTER_ACTOR (applet_manager);
+}
+
diff --git a/attic/astro-desktop/src/astro-applet-manager.h b/attic/astro-desktop/src/astro-applet-manager.h
new file mode 100644 (file)
index 0000000..dd07ce2
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_ASTRO_APPLET_MANAGER_H
+#define _HAVE_ASTRO_APPLET_MANAGER_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_APPLET_MANAGER astro_applet_manager_get_type()
+
+#define ASTRO_APPLET_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_APPLET_MANAGER, \
+  AstroAppletManager))
+
+#define ASTRO_APPLET_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_APPLET_MANAGER, \
+  AstroAppletManagerClass))
+
+#define ASTRO_IS_APPLET_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_APPLET_MANAGER))
+
+#define ASTRO_IS_APPLET_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_APPLET_MANAGER))
+
+#define ASTRO_APPLET_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_APPLET_MANAGER, \
+  AstroAppletManagerClass))
+
+typedef struct _AstroAppletManager AstroAppletManager;
+typedef struct _AstroAppletManagerClass AstroAppletManagerClass;
+typedef struct _AstroAppletManagerPrivate AstroAppletManagerPrivate;
+
+struct _AstroAppletManager
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroAppletManagerPrivate   *priv;
+};
+
+struct _AstroAppletManagerClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_applet_manager_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_applet_manager_new       (void);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-applet.c b/attic/astro-desktop/src/astro-applet.c
new file mode 100644 (file)
index 0000000..d897758
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-applet.h"
+
+#include <libastro-desktop/tidy-texture-frame.h>
+
+#include <libastro-desktop/astro-defines.h>
+
+G_DEFINE_TYPE (AstroApplet, astro_applet, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_APPLET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_APPLET, AstroAppletPrivate))
+
+static GdkPixbuf    *applet_bg = NULL;
+static ClutterActor *texture = NULL;
+       
+struct _AstroAppletPrivate
+{
+  ClutterActor *texture;
+};
+
+/* GObject stuff */
+static void
+astro_applet_paint (ClutterActor *applet)
+{
+  AstroAppletPrivate *priv;
+  GList *c;
+  gint width = 0;
+
+  g_return_if_fail (ASTRO_IS_APPLET (applet));
+  priv = ASTRO_APPLET (applet)->priv;
+  
+  c = clutter_container_get_children (CLUTTER_CONTAINER (applet));
+  
+  for (c = c; c; c = c->next)
+    {
+      gint total = clutter_actor_get_y (c->data) + 
+                   clutter_actor_get_width (c->data);
+      if (total > width && c->data != priv->texture)
+        width = total;
+    }
+  
+  clutter_actor_set_size (priv->texture,
+                          width,
+                          clutter_actor_get_height (applet));
+
+   c = clutter_container_get_children (CLUTTER_CONTAINER (applet));
+   for (c = c; c; c = c->next)
+    clutter_actor_paint (c->data);
+    
+}
+
+static void
+astro_applet_class_init (AstroAppletClass *klass)
+{ 
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->paint = astro_applet_paint;
+  
+  g_type_class_add_private (gobject_class, sizeof (AstroAppletPrivate));
+}
+
+static void
+astro_applet_init (AstroApplet *applet)
+{
+  AstroAppletPrivate *priv;
+  
+  priv = applet->priv = ASTRO_APPLET_GET_PRIVATE (applet);
+
+  if (!CLUTTER_IS_TEXTURE (texture))
+    {
+      applet_bg = gdk_pixbuf_new_from_file (PKGDATADIR "/applet_bg.png", NULL);
+      texture = g_object_new (CLUTTER_TYPE_TEXTURE,
+                              "pixbuf", applet_bg,
+                              "tiled", FALSE,
+                              NULL);
+
+    }
+  
+  priv->texture = tidy_texture_frame_new (CLUTTER_TEXTURE (texture), 
+                                          15, 15, 15, 15);
+  clutter_container_add_actor (CLUTTER_CONTAINER (applet), priv->texture);
+  
+  clutter_actor_show_all (CLUTTER_ACTOR (applet));
+}
+
+ClutterActor * 
+astro_applet_new (void)
+{
+  AstroApplet *applet =  g_object_new (ASTRO_TYPE_APPLET,
+                                                                                            NULL);
+
+  return CLUTTER_ACTOR (applet);
+}
+
diff --git a/attic/astro-desktop/src/astro-applet.h b/attic/astro-desktop/src/astro-applet.h
new file mode 100644 (file)
index 0000000..2ad9705
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_APPLET_H
+#define _HAVE_ASTRO_APPLET_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_APPLET astro_applet_get_type()
+
+#define ASTRO_APPLET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_APPLET, \
+  AstroApplet))
+
+#define ASTRO_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_APPLET, \
+  AstroAppletClass))
+
+#define ASTRO_IS_APPLET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_APPLET))
+
+#define ASTRO_IS_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_APPLET))
+
+#define ASTRO_APPLET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_APPLET, \
+  AstroAppletClass))
+
+typedef struct _AstroApplet AstroApplet;
+typedef struct _AstroAppletClass AstroAppletClass;
+typedef struct _AstroAppletPrivate AstroAppletPrivate;
+
+struct _AstroApplet
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroAppletPrivate   *priv;
+};
+
+struct _AstroAppletClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /*< signals >*/
+  void (*clicked)    (AstroApplet *applet, AstroApplication *application);
+}; 
+
+GType astro_applet_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_applet_new       (void);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-appview.c b/attic/astro-desktop/src/astro-appview.c
new file mode 100644 (file)
index 0000000..b65f27d
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-appview.h"
+
+#include <math.h>
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+
+#include "astro-panel.h"
+#include "astro-example.h"
+#include "astro-appicon.h"
+
+G_DEFINE_TYPE (AstroAppview, astro_appview, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_APPVIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_APPVIEW, AstroAppviewPrivate))
+#define VARIANCE (CSH()*-0.2)
+#define MAX_BLUR 10.0
+
+struct _AstroAppviewPrivate
+{
+  GList                 *apps;
+  gint                   active;
+
+  /* Timeline stuff */
+  ClutterEffectTemplate *move_temp;
+  ClutterTimeline       *move_time;
+
+  ClutterEffectTemplate *show_temp;
+  ClutterTimeline       *show_time;
+
+  ClutterEffectTemplate *hide_temp;
+  ClutterTimeline       *hide_time;
+};
+
+enum
+{
+  LAUNCH_APP,
+
+  LAST_SIGNAL
+};
+static guint _appview_signals[LAST_SIGNAL] = { 0 };
+
+/* Private functions */
+static void
+ensure_layout (AstroAppview *view)
+{
+  AstroAppviewPrivate *priv;
+  GList *l;
+  gint groupx = 0;
+  gint center = 0;
+  gint i = 0;
+  
+  priv = view->priv;
+
+  groupx = clutter_actor_get_x (CLUTTER_ACTOR (view));
+  center = CSW()/2;
+
+  l = clutter_container_get_children (CLUTTER_CONTAINER (view));
+  for (l = l; l; l = l->next)
+    {
+      ClutterActor *icon = l->data;
+      gint realx, diff, y_diff;;
+      gfloat scale;
+
+      realx = clutter_actor_get_x (icon) + groupx;
+      
+      if (realx > center && realx < CSW ())
+        {
+          diff = center - (realx - center);
+        }
+      else if (realx > 0 && realx <= center)
+        {
+          diff = realx;
+        }
+      else
+        {
+          diff = 0;
+        }
+  
+      scale = (gfloat)diff/center;
+      scale = 0.2 + (0.8 * scale);
+      clutter_actor_set_scale (icon, scale, scale);
+
+      if (realx < center)
+        {
+          gfloat angle, sine;
+
+          angle = scale * (3.14*2);
+          sine = sin (0.5 *angle);
+          
+          y_diff = (CSH()/2) + (VARIANCE * sine);
+        }
+      else
+        {
+          gfloat angle, sine;
+
+          angle = scale * (3.14*2);
+          sine = sin (0.5*angle);
+          
+          y_diff = (CSH()/2) - (VARIANCE * sine);
+
+        }
+      clutter_actor_set_y (icon, y_diff);
+      
+      astro_appicon_set_blur (ASTRO_APPICON (icon), (1.0 - scale) * MAX_BLUR);
+
+      i++;
+    }
+}
+
+static void
+on_move_timeline_new_frame (ClutterTimeline *timeline, 
+                            gint             frame,
+                            AstroAppview    *view)
+{
+  g_return_if_fail (ASTRO_IS_APPVIEW (view));
+  
+  ensure_layout (view);
+}
+
+static void
+on_appicon_clicked (AstroAppicon     *icon, 
+                    AstroApplication *app, 
+                    AstroAppview     *view)
+{
+  AstroAppviewPrivate *priv;
+  AstroApplication *active_app;
+
+  g_return_if_fail (ASTRO_IS_APPVIEW (view));
+  priv = view->priv;
+
+  active_app = g_list_nth_data (priv->apps, priv->active);
+
+  if (active_app == app)
+    {
+      g_signal_emit (view, _appview_signals[LAUNCH_APP], 
+                     0, g_list_nth_data (priv->apps, priv->active));
+    }
+  else
+    {
+      gint new_active = g_list_index (priv->apps, app);
+      astro_appview_advance (view, new_active - priv->active);
+    }
+}
+
+static void
+astro_appview_show (ClutterActor *view)
+{
+  AstroAppviewPrivate *priv;
+  static ClutterTimeline *show_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_APPVIEW (view));
+  priv = ASTRO_APPVIEW (view)->priv;
+
+  if (CLUTTER_IS_TIMELINE (show_time) &&clutter_timeline_is_playing (show_time))
+    {
+      clutter_timeline_stop (show_time);
+      g_object_unref (show_time);
+    }
+
+  clutter_actor_set_x (view, -1* clutter_actor_get_width (view));
+  CLUTTER_ACTOR_CLASS (astro_appview_parent_class)->show (view);
+
+  show_time = clutter_effect_move (priv->show_temp,
+                                   CLUTTER_ACTOR (view),
+                            (CSW()/2)- (priv->active * ASTRO_APPICON_SPACING()),
+                             clutter_actor_get_y (CLUTTER_ACTOR (view)),
+                                   NULL, NULL);
+
+  g_signal_connect (show_time, "new-frame",
+                    G_CALLBACK (on_move_timeline_new_frame), view); 
+}
+
+static void
+on_hide_timeline_completed (ClutterTimeline *timeline, ClutterActor *view)
+{
+  CLUTTER_ACTOR_CLASS (astro_appview_parent_class)->hide (view);
+}
+
+static void
+astro_appview_hide (ClutterActor *view)
+{
+  AstroAppviewPrivate *priv;
+  static ClutterTimeline *hide_time = NULL;
+  
+  g_return_if_fail (ASTRO_IS_APPVIEW (view));
+  priv = ASTRO_APPVIEW (view)->priv;
+
+  if (CLUTTER_IS_TIMELINE (hide_time) &&clutter_timeline_is_playing (hide_time))
+    {
+      clutter_timeline_stop (hide_time);
+      g_object_unref (hide_time);
+    }
+  
+  hide_time = clutter_effect_move (priv->hide_temp,
+                                   CLUTTER_ACTOR (view),
+                                   -1 * clutter_actor_get_width (view),
+                                   clutter_actor_get_y (CLUTTER_ACTOR (view)),
+                                   NULL, NULL);
+
+  g_signal_connect (hide_time, "new-frame",
+                    G_CALLBACK (on_move_timeline_new_frame), view); 
+  g_signal_connect (hide_time, "completed",
+                    G_CALLBACK (on_hide_timeline_completed), view);
+}
+
+
+/* Public Functions */
+void
+astro_appview_set_app_list (AstroAppview *view, 
+                            GList        *apps)
+{
+  AstroAppviewPrivate *priv;
+  GList *l;
+  gint offset = 0;
+
+  g_return_if_fail (ASTRO_IS_APPVIEW (view));
+  priv = view->priv;
+
+  priv->apps = apps;
+  priv->active = 0;
+
+  /* Add all the icons */
+  for (l = apps; l; l = l->next)
+    {
+      AstroApplication *app = l->data;
+      ClutterActor *icon = astro_appicon_new (app);
+
+      clutter_container_add_actor (CLUTTER_CONTAINER (view), icon);
+      clutter_actor_set_size (icon, ASTRO_APPICON_SIZE (),ASTRO_APPICON_SIZE());
+      clutter_actor_set_anchor_point_from_gravity (icon,CLUTTER_GRAVITY_CENTER);
+
+      clutter_actor_set_position (icon, offset, CSH ()/2);
+      clutter_actor_show (icon);
+      g_signal_connect (icon, "clicked",
+                        G_CALLBACK (on_appicon_clicked), view);
+
+      offset += ASTRO_APPICON_SPACING ();
+    }
+  astro_appview_advance (view, 0);
+}
+
+void
+astro_appview_advance (AstroAppview *view,
+                       gint          n)
+{
+  AstroAppviewPrivate *priv;
+  static ClutterTimeline *move_time = NULL;
+  gint new_active;
+
+  g_return_if_fail (ASTRO_IS_APPVIEW (view));
+  priv = view->priv;
+
+  new_active = priv->active + n;
+  if (new_active < 0 || new_active >= g_list_length (priv->apps))
+    return;
+  priv->active = new_active;
+
+  if (CLUTTER_IS_TIMELINE (move_time) &&clutter_timeline_is_playing (move_time))
+    {
+      clutter_timeline_stop (move_time);
+      g_object_unref (move_time);
+    }
+  move_time = clutter_effect_move (priv->move_temp,
+                                   CLUTTER_ACTOR (view),
+                          (CSW()/2)- (priv->active * ASTRO_APPICON_SPACING ()),
+                                    clutter_actor_get_y (CLUTTER_ACTOR (view)),
+                                    NULL, NULL);
+
+  g_signal_connect (move_time, "new-frame",
+                    G_CALLBACK (on_move_timeline_new_frame), view);
+}
+
+AstroApplication * 
+astro_appview_get_active_app (AstroAppview *view)
+{
+  g_return_val_if_fail (ASTRO_IS_APPVIEW (view), NULL);
+
+  return g_list_nth_data (view->priv->apps, view->priv->active);
+}
+
+/* GObject stuff */
+static void
+astro_appview_class_init (AstroAppviewClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->show = astro_appview_show;
+  actor_class->hide = astro_appview_hide;
+
+  _appview_signals[LAUNCH_APP] = 
+    g_signal_new ("launch-app",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (AstroAppviewClass, launch_app),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  ASTRO_TYPE_APPLICATION);
+
+
+  g_type_class_add_private (gobject_class, sizeof (AstroAppviewPrivate));
+}
+
+static void
+astro_appview_init (AstroAppview *appview)
+{
+  AstroAppviewPrivate *priv;
+  priv = appview->priv = ASTRO_APPVIEW_GET_PRIVATE (appview);
+
+  priv->active = 0;
+  priv->apps = NULL;
+
+  priv->move_time = clutter_timeline_new_for_duration (300);
+  priv->move_temp = clutter_effect_template_new (priv->move_time, 
+                                                 clutter_sine_inc_func);
+
+  priv->show_time = clutter_timeline_new_for_duration (600);
+  priv->show_temp = clutter_effect_template_new (priv->show_time, 
+                                                 clutter_sine_inc_func);
+  priv->hide_time = clutter_timeline_new_for_duration (300);
+  priv->hide_temp = clutter_effect_template_new (priv->hide_time, 
+                                                 clutter_sine_inc_func);
+ }
+
+ClutterActor * 
+astro_appview_new (void)
+{
+  AstroAppview *appview =  g_object_new (ASTRO_TYPE_APPVIEW,
+                                                                                              NULL);
+
+  return CLUTTER_ACTOR (appview);
+}
+
diff --git a/attic/astro-desktop/src/astro-appview.h b/attic/astro-desktop/src/astro-appview.h
new file mode 100644 (file)
index 0000000..2e5c7b5
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_APPVIEW_H
+#define _HAVE_ASTRO_APPVIEW_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_APPVIEW astro_appview_get_type()
+
+#define ASTRO_APPVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_APPVIEW, \
+  AstroAppview))
+
+#define ASTRO_APPVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_APPVIEW, \
+  AstroAppviewClass))
+
+#define ASTRO_IS_APPVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_APPVIEW))
+
+#define ASTRO_IS_APPVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_APPVIEW))
+
+#define ASTRO_APPVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_APPVIEW, \
+  AstroAppviewClass))
+
+typedef struct _AstroAppview AstroAppview;
+typedef struct _AstroAppviewClass AstroAppviewClass;
+typedef struct _AstroAppviewPrivate AstroAppviewPrivate;
+
+struct _AstroAppview
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroAppviewPrivate   *priv;
+};
+
+struct _AstroAppviewClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /*< signals >*/
+  void (*launch_app) (AstroAppview *view, AstroApplication *application);
+}; 
+
+GType              astro_appview_get_type       (void) G_GNUC_CONST;
+
+ClutterActor *     astro_appview_new            (void);
+void               astro_appview_set_app_list   (AstroAppview *view,
+                                                 GList        *apps);
+void               astro_appview_advance        (AstroAppview *view,
+                                                 gint          n);
+AstroApplication * astro_appview_get_active_app (AstroAppview *view);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-desktop.c b/attic/astro-desktop/src/astro-desktop.c
new file mode 100644 (file)
index 0000000..4129743
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-desktop.h"
+
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-window.h>
+
+#include "astro-applet-manager.h"
+#include "astro-appview.h"
+#include "astro-example.h"
+#include "astro-panel.h"
+
+G_DEFINE_TYPE (AstroDesktop, astro_desktop, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_DESKTOP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_DESKTOP, AstroDesktopPrivate))
+       
+struct _AstroDesktopPrivate
+{
+  ClutterActor                  *panel;
+  ClutterActor     *appview;
+  ClutterActor     *applets;
+
+  GList            *apps;
+  GList            *apps_modules;
+       
+  AstroApplication *active_app;
+  ClutterActor     *active_window;
+};
+
+/* Public Functions */
+
+/* Private functions */
+static void
+astro_desktop_show_application (AstroDesktop     *desktop,
+                                AstroApplication *application)
+{
+  AstroDesktopPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_DESKTOP (desktop));
+  priv = desktop->priv;
+  if (ASTRO_IS_WINDOW (priv->active_window))
+    {
+      astro_window_close (ASTRO_WINDOW (priv->active_window));
+    }
+
+  clutter_ungrab_keyboard ();  
+  clutter_actor_hide (priv->appview);
+  clutter_actor_hide (priv->applets);
+
+  astro_panel_set_header (ASTRO_PANEL (priv->panel),
+                          astro_application_get_title (application),
+                          astro_application_get_icon (application));
+
+  priv->active_window = (ClutterActor*)astro_application_get_window 
+                                                                 (application);
+  clutter_container_add_actor (CLUTTER_CONTAINER (desktop), 
+                               priv->active_window);
+  clutter_actor_set_position (priv->active_window, 
+                              0, 
+                              0);
+  clutter_actor_show (priv->active_window);
+}
+
+static void
+astro_desktop_hide_application (AstroDesktop     *desktop)
+{
+  AstroDesktopPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_DESKTOP (desktop));
+  priv = desktop->priv;
+  if (!ASTRO_IS_WINDOW (priv->active_window))
+    return; 
+  astro_window_close (ASTRO_WINDOW (priv->active_window));
+  
+  astro_panel_set_header (ASTRO_PANEL (priv->panel),
+                          "Home",
+                          NULL);
+
+  clutter_actor_show (priv->applets);
+  clutter_actor_show (priv->appview);
+
+  clutter_grab_keyboard (CLUTTER_ACTOR (desktop));
+}
+
+
+static void
+on_appview_activated (AstroAppview     *appview, 
+                      AstroApplication *application,
+                      AstroDesktop     *desktop)
+{
+  AstroDesktopPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_DESKTOP (desktop));
+  priv = desktop->priv;
+
+  astro_desktop_show_application (desktop, application);
+}
+
+static gboolean
+on_key_release_event (ClutterActor *actor, 
+                      ClutterEvent *event,
+                      AstroDesktop *desktop)
+{
+  AstroDesktopPrivate *priv;
+  AstroApplication *application;
+
+  g_return_val_if_fail (ASTRO_IS_DESKTOP (desktop), FALSE);
+  priv = desktop->priv;
+
+  switch (event->key.keyval)
+    {
+      case CLUTTER_Return:
+      case CLUTTER_KP_Enter:
+      case CLUTTER_ISO_Enter:
+        application = astro_appview_get_active_app 
+                                               (ASTRO_APPVIEW (priv->appview));
+        astro_desktop_show_application (desktop, application);
+        break;
+      case CLUTTER_Left:
+      case CLUTTER_KP_Left:
+        astro_appview_advance (ASTRO_APPVIEW (priv->appview), -1);
+        break;
+      case CLUTTER_Right:
+      case CLUTTER_KP_Right:
+        astro_appview_advance (ASTRO_APPVIEW (priv->appview), 1);
+        break;
+      default:
+        ;
+    }
+
+  return FALSE;
+}
+
+static void
+on_panel_home_clicked (AstroPanel *panel, AstroDesktop *desktop)
+{
+  g_return_if_fail (ASTRO_IS_DESKTOP (desktop));
+
+  astro_desktop_hide_application (desktop);
+}
+
+static AstroApplication *
+_load_app_module (const gchar *filename)
+{
+  GModule *module;
+  AstroApplication *app;
+  AstroApplicationInitFunc init_func;
+
+  module = g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+  if (module == NULL)
+    {
+      g_warning ("Unable to load module %s : %s\n",filename, g_module_error ());
+      return NULL;
+    }
+
+  /* Try and load the init symbol */
+  if (g_module_symbol (module, "astro_application_factory_init",
+                       (void*)&init_func)) 
+    {
+      app = (AstroApplication*)init_func ();
+      if (ASTRO_IS_APPLICATION (app))
+        {
+          g_object_set_data (G_OBJECT (app), "module", module);
+          return app;
+        }
+    } 
+  
+  g_warning ("Cannot init module %s: %s", filename, g_module_error ());
+
+  g_module_close (module);
+
+  return NULL;
+}
+
+static void
+load_applications (AstroDesktop *desktop)
+{
+  AstroDesktopPrivate *priv;
+  GdkPixbuf *pixbuf;
+  GDir *dir;
+  const gchar *leaf;
+  gint i;
+
+  g_return_if_fail (ASTRO_IS_DESKTOP (desktop));
+  priv = desktop->priv;
+
+  /* Load .so applications */
+  dir = g_dir_open (PKGLIBDIR"/apps", 0, NULL);
+  if (!dir)
+    { 
+      g_warning ("%s doesn't exist", PKGLIBDIR"/apps");
+      return;
+    }
+  while ((leaf = g_dir_read_name (dir)))
+    {
+      AstroApplication *app;
+      gchar *filename;
+
+      if (!g_str_has_suffix (leaf, ".so"))
+        continue;
+
+      filename = g_build_filename (PKGLIBDIR"/apps", leaf, NULL);
+      app = _load_app_module (filename);
+
+      if (ASTRO_IS_APPLICATION (app))
+        priv->apps = g_list_append (priv->apps, app);
+      else
+        g_debug ("load failed\n");
+
+      g_free (filename);
+    }
+  g_dir_close (dir);
+  
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR "/icons/exec.png", 
+                                              ASTRO_APPICON_SIZE(), 
+                                              ASTRO_APPICON_SIZE(),
+                                              TRUE, NULL);
+  for (i = 0; i < 5; i++)
+    {
+      AstroApplication *app;
+      gchar *title;
+      
+      title = g_strdup_printf ("Example %d", i+1);
+      app = astro_example_new (title,
+                               pixbuf);
+      g_free (title);
+
+      priv->apps = g_list_append (priv->apps, app);
+    }
+}
+
+/* GObject stuff */
+static void
+astro_desktop_class_init (AstroDesktopClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroDesktopPrivate));
+}
+
+static void
+astro_desktop_init (AstroDesktop *desktop)
+{
+  AstroDesktopPrivate *priv;
+  priv = desktop->priv = ASTRO_DESKTOP_GET_PRIVATE (desktop);
+
+  /* Load the panel */
+  priv->panel = astro_panel_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (desktop), priv->panel);
+  clutter_actor_set_position (priv->panel, 0, 0);
+  g_signal_connect (priv->panel, "show-home",
+                    G_CALLBACK (on_panel_home_clicked), desktop);
+  g_signal_connect (priv->panel, "close-window",
+                    G_CALLBACK (on_panel_home_clicked), desktop);
+
+  /* Load the applications */
+  load_applications (desktop);
+  priv->appview = astro_appview_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (desktop), priv->appview);
+  clutter_actor_set_size (priv->appview, 
+                          ASTRO_WINDOW_WIDTH (), 
+                          ASTRO_WINDOW_HEIGHT ());
+  clutter_actor_set_position (priv->appview, CSW(), 0);
+  astro_appview_set_app_list (ASTRO_APPVIEW (priv->appview), priv->apps);
+
+  g_signal_connect (priv->appview, "launch-app",
+                    G_CALLBACK (on_appview_activated), desktop);
+
+  /* Load the applets */
+  priv->applets = astro_applet_manager_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (desktop), priv->applets);
+  clutter_actor_set_position (priv->applets, 
+                              CSW(), 
+                       CSH() - ASTRO_APPLET_HEIGHT() -(ASTRO_APPLET_PADDING*3));
+
+  g_signal_connect (desktop, "key-release-event",
+                    G_CALLBACK (on_key_release_event), desktop);
+
+  clutter_grab_keyboard (CLUTTER_ACTOR (desktop));
+  clutter_actor_show_all (CLUTTER_ACTOR (desktop));
+}
+
+ClutterActor * 
+astro_desktop_new (void)
+{
+  AstroDesktop *desktop =  g_object_new (ASTRO_TYPE_DESKTOP,
+                                                                                              NULL);
+
+  return CLUTTER_ACTOR (desktop);
+}
+
diff --git a/attic/astro-desktop/src/astro-desktop.h b/attic/astro-desktop/src/astro-desktop.h
new file mode 100644 (file)
index 0000000..ea6d539
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_ASTRO_DESKTOP_H
+#define _HAVE_ASTRO_DESKTOP_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_DESKTOP astro_desktop_get_type()
+
+#define ASTRO_DESKTOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_DESKTOP, \
+  AstroDesktop))
+
+#define ASTRO_DESKTOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_DESKTOP, \
+  AstroDesktopClass))
+
+#define ASTRO_IS_DESKTOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_DESKTOP))
+
+#define ASTRO_IS_DESKTOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_DESKTOP))
+
+#define ASTRO_DESKTOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_DESKTOP, \
+  AstroDesktopClass))
+
+typedef struct _AstroDesktop AstroDesktop;
+typedef struct _AstroDesktopClass AstroDesktopClass;
+typedef struct _AstroDesktopPrivate AstroDesktopPrivate;
+
+struct _AstroDesktop
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroDesktopPrivate   *priv;
+};
+
+struct _AstroDesktopClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+}; 
+
+GType astro_desktop_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_desktop_new       (void);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-example.c b/attic/astro-desktop/src/astro-example.c
new file mode 100644 (file)
index 0000000..ff73340
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-example.h"
+
+#include <libastro-desktop/astro-defines.h>
+#include <libastro-desktop/astro-application.h>
+#include <libastro-desktop/astro-window.h>
+
+G_DEFINE_TYPE (AstroExample, astro_example, ASTRO_TYPE_APPLICATION);
+
+#define ASTRO_EXAMPLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_EXAMPLE, AstroExamplePrivate))
+       
+struct _AstroExamplePrivate
+{
+  const gchar *title;
+  GdkPixbuf *icon;
+  ClutterActor *window;
+};
+
+/* Public Functions */
+
+/* Private functions */
+static const gchar *
+get_title (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_EXAMPLE (app), NULL);
+
+  return ASTRO_EXAMPLE (app)->priv->title;
+}
+
+static void
+set_title (AstroApplication *app, const gchar *title)
+{
+  g_return_if_fail (ASTRO_IS_EXAMPLE (app));
+  g_return_if_fail (title);
+
+  ASTRO_EXAMPLE (app)->priv->title = g_strdup (title);
+}
+
+static GdkPixbuf *
+get_icon (AstroApplication *app)
+{
+  g_return_val_if_fail (ASTRO_IS_EXAMPLE (app), NULL);
+
+  return ASTRO_EXAMPLE (app)->priv->icon;
+}
+
+static void
+set_icon (AstroApplication *app, GdkPixbuf *icon)
+{
+  g_return_if_fail (ASTRO_IS_EXAMPLE (app));
+  g_return_if_fail (GDK_IS_PIXBUF (icon));
+
+  ASTRO_EXAMPLE (app)->priv->icon = icon;
+}
+
+static AstroWindow *
+get_window (AstroApplication *app)
+{
+  AstroExamplePrivate *priv;
+  ClutterColor color = { 0xff, 0xff, 0x22, 0x22 };
+  ClutterActor *window = NULL, *rect;
+
+  g_return_val_if_fail (ASTRO_IS_EXAMPLE (app), NULL);
+  priv = ASTRO_EXAMPLE (app)->priv;
+
+  if (CLUTTER_IS_ACTOR (priv->window))
+    window = priv->window;
+  else
+    {
+      window = astro_window_new ();
+      
+      rect = clutter_rectangle_new_with_color (&color);
+      clutter_container_add_actor (CLUTTER_CONTAINER (window), rect);
+      clutter_actor_set_size (rect, CSW (), CSH()-ASTRO_PANEL_HEIGHT());
+      clutter_actor_show (rect);
+    }
+
+  ASTRO_EXAMPLE (app)->priv->window = window;
+
+  return ASTRO_WINDOW (window);
+}
+
+static void
+close (AstroApplication *app)
+{
+  AstroExamplePrivate *priv;
+  
+  g_return_if_fail (ASTRO_IS_EXAMPLE (app));
+  priv = ASTRO_EXAMPLE (app)->priv;
+  
+  if (CLUTTER_IS_ACTOR (priv->window))
+    clutter_actor_destroy (priv->window);
+}
+
+/* GObject stuff */
+static void
+astro_example_class_init (AstroExampleClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  AstroApplicationClass *app_class = ASTRO_APPLICATION_CLASS (klass);
+
+  app_class->get_title = get_title;
+  app_class->set_title = set_title;
+  app_class->get_icon = get_icon;
+  app_class->set_icon = set_icon;
+  app_class->get_window = get_window;
+  app_class->close = close;
+
+  g_type_class_add_private (gobject_class, sizeof (AstroExamplePrivate));
+}
+
+static void
+astro_example_init (AstroExample *example)
+{
+  AstroExamplePrivate *priv;
+  priv = example->priv = ASTRO_EXAMPLE_GET_PRIVATE (example);
+
+  priv->title = NULL;
+  priv->icon = NULL;
+  priv->window = NULL;
+}
+
+AstroApplication * 
+astro_example_new (const gchar *title, GdkPixbuf *icon)
+{
+  AstroApplication *example =  g_object_new (ASTRO_TYPE_EXAMPLE,
+                                                                                              NULL);
+
+  astro_application_set_title (example, title);
+  astro_application_set_icon (example, icon);
+
+  return example;
+}
+
diff --git a/attic/astro-desktop/src/astro-example.h b/attic/astro-desktop/src/astro-example.h
new file mode 100644 (file)
index 0000000..87c06a5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <libastro-desktop/astro-application.h>
+
+#ifndef _HAVE_ASTRO_EXAMPLE_H
+#define _HAVE_ASTRO_EXAMPLE_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_EXAMPLE astro_example_get_type()
+
+#define ASTRO_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_EXAMPLE, \
+  AstroExample))
+
+#define ASTRO_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_EXAMPLE, \
+  AstroExampleClass))
+
+#define ASTRO_IS_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_EXAMPLE))
+
+#define ASTRO_IS_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_EXAMPLE))
+
+#define ASTRO_EXAMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_EXAMPLE, \
+  AstroExampleClass))
+
+typedef struct _AstroExample AstroExample;
+typedef struct _AstroExampleClass AstroExampleClass;
+typedef struct _AstroExamplePrivate AstroExamplePrivate;
+
+struct _AstroExample
+{
+  AstroApplication       parent;
+       
+  /*< private >*/
+  AstroExamplePrivate   *priv;
+};
+
+struct _AstroExampleClass 
+{
+  /*< private >*/
+  AstroApplicationClass parent_class;
+}; 
+
+GType astro_example_get_type (void) G_GNUC_CONST;
+
+AstroApplication *  astro_example_new       (const gchar  *title,
+                                             GdkPixbuf    *icon);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-panel.c b/attic/astro-desktop/src/astro-panel.c
new file mode 100644 (file)
index 0000000..df600ce
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-panel.h"
+
+#include <libastro-desktop/astro-defines.h>
+
+#include "astro-systray.h"
+
+G_DEFINE_TYPE (AstroPanel, astro_panel, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_PANEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_PANEL, AstroPanelPrivate))
+
+#define PADDING 4
+       
+struct _AstroPanelPrivate
+{
+  ClutterActor *panel_bg;
+  ClutterActor *home;
+  ClutterActor *title;
+  ClutterActor *systray;
+  ClutterActor *close;
+
+  GdkPixbuf *home_pixbuf;
+};
+
+enum
+{
+  SHOW_HOME,
+  CLOSE_WINDOW,
+
+  LAST_SIGNAL
+};
+static guint _panel_signals[LAST_SIGNAL] = { 0 };
+
+
+/* Public Functions */
+void
+astro_panel_set_header (AstroPanel  *panel,
+                        const gchar *title,
+                        GdkPixbuf   *icon)
+{
+  AstroPanelPrivate *priv;
+
+  g_return_if_fail (ASTRO_IS_PANEL (panel));
+  priv = panel->priv;
+  
+  clutter_label_set_text (CLUTTER_LABEL (priv->title), title);
+  clutter_actor_set_position (priv->title, 
+                              clutter_actor_get_width (priv->home)+(PADDING*3),
+                              (ASTRO_PANEL_HEIGHT ()/2));
+
+  if (!icon)
+    icon = priv->home_pixbuf;
+
+  clutter_texture_set_pixbuf (CLUTTER_TEXTURE (priv->home), icon, NULL);
+  clutter_actor_set_position (priv->home, PADDING/2,
+                                  ASTRO_PANEL_HEIGHT ()/2);
+}
+
+/* Callbacks */
+static gboolean
+on_home_clicked (ClutterActor *home, ClutterEvent *event, AstroPanel *panel)
+{
+  g_debug ("home button clicked");
+
+  g_signal_emit (panel, _panel_signals[SHOW_HOME], 0);
+  return FALSE;
+}
+
+static gboolean
+on_close_clicked (ClutterActor *home, ClutterEvent *event, AstroPanel *panel)
+{
+  g_debug ("close button clicked");
+
+  g_signal_emit (panel, _panel_signals[CLOSE_WINDOW], 0);
+  return FALSE;
+}
+
+
+
+/* GObject stuff */
+static void
+astro_panel_class_init (AstroPanelClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  _panel_signals[SHOW_HOME] = 
+    g_signal_new ("show-home",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (AstroPanelClass, show_home),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  _panel_signals[CLOSE_WINDOW] = 
+    g_signal_new ("close-window",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (AstroPanelClass, close_window),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroPanelPrivate));
+}
+
+static void
+astro_panel_init (AstroPanel *panel)
+{
+  AstroPanelPrivate *priv;
+  ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+  GdkPixbuf *pixbuf;
+  gchar *font;
+
+  priv = panel->priv = ASTRO_PANEL_GET_PRIVATE (panel);
+
+  clutter_actor_set_size (CLUTTER_ACTOR (panel),
+                          CSW (), ASTRO_PANEL_HEIGHT ());
+
+  /* Background rect */
+  priv->panel_bg = clutter_rectangle_new_with_color (&white);
+  clutter_container_add_actor (CLUTTER_CONTAINER (panel), priv->panel_bg);
+  clutter_actor_set_size (priv->panel_bg, CSW(), ASTRO_PANEL_HEIGHT ());
+  clutter_actor_set_position (priv->panel_bg, 0, 0);
+  clutter_actor_set_opacity (priv->panel_bg, 0);
+
+  /* Home button */
+  pixbuf = gdk_pixbuf_new_from_file_at_size (PKGDATADIR "/icons/home.png",
+                                             ASTRO_PANEL_HEIGHT () - PADDING,
+                                             ASTRO_PANEL_HEIGHT () - PADDING,
+                                             NULL);
+  if (pixbuf)
+    {
+      priv->home_pixbuf = pixbuf;
+      priv->home = clutter_texture_new_from_pixbuf (pixbuf);
+      clutter_container_add_actor (CLUTTER_CONTAINER (panel), priv->home);
+      clutter_actor_set_anchor_point_from_gravity (priv->home,
+                                                   CLUTTER_GRAVITY_WEST);
+      clutter_actor_set_position (priv->home, PADDING/2,
+                                  ASTRO_PANEL_HEIGHT ()/2);
+      clutter_actor_set_reactive (priv->home, TRUE);
+
+      g_signal_connect (priv->home, "button-release-event",
+                        G_CALLBACK (on_home_clicked), panel);
+    }
+
+  /* Title label */
+  font = g_strdup_printf ("Sans %d", (int)(ASTRO_PANEL_HEIGHT () * 0.3));
+  priv->title = clutter_label_new_full (font, "Home", &white);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->title), FALSE);
+  clutter_container_add_actor (CLUTTER_CONTAINER (panel), priv->title);
+  clutter_actor_set_anchor_point_from_gravity (priv->title, 
+                                               CLUTTER_GRAVITY_WEST);
+  clutter_actor_set_position (priv->title, 
+                              clutter_actor_get_width (priv->home)+(PADDING*3),
+                              (ASTRO_PANEL_HEIGHT ()/2) + PADDING);
+  g_free (font);
+
+  /* Close button */
+  pixbuf = gdk_pixbuf_new_from_file_at_size (PKGDATADIR "/icons/close.png",
+                                           ASTRO_PANEL_HEIGHT () - PADDING,
+                                           ASTRO_PANEL_HEIGHT () - PADDING,
+                                           NULL);
+  if (pixbuf)
+    {
+      priv->close = clutter_texture_new_from_pixbuf (pixbuf);
+      clutter_container_add_actor (CLUTTER_CONTAINER (panel), priv->close);
+      clutter_actor_set_anchor_point_from_gravity (priv->close,
+                                                   CLUTTER_GRAVITY_WEST);
+      clutter_actor_set_position (priv->close, 
+                   CSW () - clutter_actor_get_width (priv->close) - (PADDING/2),
+                                  ASTRO_PANEL_HEIGHT () /2);
+      clutter_actor_set_reactive (priv->close, TRUE);
+
+      g_signal_connect (priv->close, "button-release-event",
+                        G_CALLBACK (on_close_clicked), panel);
+    }
+
+  /* Systray */
+  priv->systray = astro_systray_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (panel), priv->systray);
+  clutter_actor_set_position (priv->systray,
+                              CSW () 
+                                - clutter_actor_get_width (priv->close)
+                                - clutter_actor_get_width (priv->systray)
+                                - PADDING*2,
+                              PADDING/2);
+
+  clutter_actor_show_all (CLUTTER_ACTOR (panel));
+}
+
+ClutterActor * 
+astro_panel_new (void)
+{
+  AstroPanel *panel =  g_object_new (ASTRO_TYPE_PANEL,
+                                                                                              NULL);
+
+  return CLUTTER_ACTOR (panel);
+}
+
diff --git a/attic/astro-desktop/src/astro-panel.h b/attic/astro-desktop/src/astro-panel.h
new file mode 100644 (file)
index 0000000..ec81149
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_ASTRO_PANEL_H
+#define _HAVE_ASTRO_PANEL_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_PANEL astro_panel_get_type()
+
+#define ASTRO_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_PANEL, \
+  AstroPanel))
+
+#define ASTRO_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_PANEL, \
+  AstroPanelClass))
+
+#define ASTRO_IS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_PANEL))
+
+#define ASTRO_IS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_PANEL))
+
+#define ASTRO_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_PANEL, \
+  AstroPanelClass))
+
+typedef struct _AstroPanel AstroPanel;
+typedef struct _AstroPanelClass AstroPanelClass;
+typedef struct _AstroPanelPrivate AstroPanelPrivate;
+
+struct _AstroPanel
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroPanelPrivate   *priv;
+};
+
+struct _AstroPanelClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /*< signals >*/
+  void (*show_home)    (AstroPanel *panel);
+  void (*close_window) (AstroPanel *panel);
+}; 
+
+GType astro_panel_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_panel_new       (void);
+
+void            astro_panel_set_header (AstroPanel  *panel,
+                                        const gchar *title,
+                                        GdkPixbuf   *icon);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/astro-systray.c b/attic/astro-desktop/src/astro-systray.c
new file mode 100644 (file)
index 0000000..449cb4c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include "astro-systray.h"
+
+#include <time.h>
+#include <libastro-desktop/astro-defines.h>
+
+G_DEFINE_TYPE (AstroSystray, astro_systray, CLUTTER_TYPE_GROUP);
+
+#define ASTRO_SYSTRAY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+        ASTRO_TYPE_SYSTRAY, AstroSystrayPrivate))
+
+#define PADDING 10
+
+struct _AstroSystrayPrivate
+{
+  ClutterActor *bt;
+  ClutterActor *nm;
+  ClutterActor *time;
+};
+
+static gboolean 
+set_time (AstroSystray *systray)
+{
+  AstroSystrayPrivate *priv;
+  time_t rawtime;
+  struct tm *timeinfo;
+  char buffer [100];
+
+  g_return_val_if_fail (ASTRO_IS_SYSTRAY (systray), FALSE);
+  priv = systray->priv;
+
+  time (&rawtime);
+  timeinfo = localtime (&rawtime);
+
+  strftime (buffer, 100, "%a %d %b,%H:%M   ", timeinfo);
+  
+  clutter_label_set_text (CLUTTER_LABEL (priv->time), buffer);
+  
+  return TRUE;
+}
+
+/* GObject stuff */
+static void
+astro_systray_class_init (AstroSystrayClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (gobject_class, sizeof (AstroSystrayPrivate));
+}
+
+static void
+astro_systray_init (AstroSystray *systray)
+{
+  AstroSystrayPrivate *priv;
+  GdkPixbuf *pixbuf;
+  ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+  gint width;
+  gchar *font;
+  
+  priv = systray->priv = ASTRO_SYSTRAY_GET_PRIVATE (systray);
+
+  pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/icons/bt.png", NULL);
+  if (pixbuf)
+    {
+      priv->bt = clutter_texture_new_from_pixbuf (pixbuf);
+      clutter_container_add_actor (CLUTTER_CONTAINER (systray), priv->bt);
+      clutter_actor_set_anchor_point_from_gravity (priv->bt,
+                                                   CLUTTER_GRAVITY_CENTER);
+      clutter_actor_set_position (priv->bt, 0, ASTRO_PANEL_HEIGHT ()/2);
+    }
+  
+  pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/icons/nm.png", NULL);
+  if (pixbuf)
+    {
+      priv->nm = clutter_texture_new_from_pixbuf (pixbuf);
+      clutter_container_add_actor (CLUTTER_CONTAINER (systray), priv->nm);
+      clutter_actor_set_anchor_point_from_gravity (priv->nm,
+                                                   CLUTTER_GRAVITY_WEST);
+      clutter_actor_set_position (priv->nm, 
+                                  clutter_actor_get_width (priv->bt) + PADDING,
+                                  ASTRO_PANEL_HEIGHT () /2);
+    }
+
+  width = clutter_actor_get_width (CLUTTER_ACTOR (systray));
+
+  /* Time date */
+  font = g_strdup_printf ("Sans %d", (int)(ASTRO_PANEL_HEIGHT () * 0.2));
+  priv->time = clutter_label_new_full (font, "   ", &white);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->time), FALSE);
+  clutter_container_add_actor (CLUTTER_CONTAINER (systray), priv->time);
+  clutter_actor_set_anchor_point_from_gravity (priv->time,CLUTTER_GRAVITY_WEST);
+  set_time (systray);
+  clutter_actor_set_position (priv->time, width + PADDING,
+                              ASTRO_PANEL_HEIGHT ()/2);
+
+  g_timeout_add (1000, (GSourceFunc)set_time, systray);
+  g_free (font);
+
+  clutter_actor_show_all (CLUTTER_ACTOR (systray));
+}
+
+ClutterActor * 
+astro_systray_new (void)
+{
+  AstroSystray *systray =  g_object_new (ASTRO_TYPE_SYSTRAY,
+                                                                                              NULL);
+
+  return CLUTTER_ACTOR (systray);
+}
+
diff --git a/attic/astro-desktop/src/astro-systray.h b/attic/astro-desktop/src/astro-systray.h
new file mode 100644 (file)
index 0000000..5042636
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 OpenedHand Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Neil Jagdish Patel <njp@o-hand.com>
+ */
+
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_ASTRO_SYSTRAY_H
+#define _HAVE_ASTRO_SYSTRAY_H
+
+G_BEGIN_DECLS
+
+#define ASTRO_TYPE_SYSTRAY astro_systray_get_type()
+
+#define ASTRO_SYSTRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ASTRO_TYPE_SYSTRAY, \
+  AstroSystray))
+
+#define ASTRO_SYSTRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+  ASTRO_TYPE_SYSTRAY, \
+  AstroSystrayClass))
+
+#define ASTRO_IS_SYSTRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ASTRO_TYPE_SYSTRAY))
+
+#define ASTRO_IS_SYSTRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ASTRO_TYPE_SYSTRAY))
+
+#define ASTRO_SYSTRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+  ASTRO_TYPE_SYSTRAY, \
+  AstroSystrayClass))
+
+typedef struct _AstroSystray AstroSystray;
+typedef struct _AstroSystrayClass AstroSystrayClass;
+typedef struct _AstroSystrayPrivate AstroSystrayPrivate;
+
+struct _AstroSystray
+{
+  ClutterGroup         parent;
+       
+  /*< private >*/
+  AstroSystrayPrivate   *priv;
+};
+
+struct _AstroSystrayClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+}; 
+
+GType astro_systray_get_type (void) G_GNUC_CONST;
+
+ClutterActor *  astro_systray_new       (void);
+  
+G_END_DECLS
+
+#endif
diff --git a/attic/astro-desktop/src/main.c b/attic/astro-desktop/src/main.c
new file mode 100644 (file)
index 0000000..a7f3fec
--- /dev/null
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <gdk/gdk.h>
+
+#include <libastro-desktop/astro.h>
+
+#include "astro-desktop.h"
+
+/* forwards */
+static ClutterActor * load_background (void);
+
+/* Command line options */
+static gint     width      = 640;
+static gint     height     = 480;
+static gboolean fullscreen = FALSE;
+
+static GOptionEntry entries[] =
+{
+  {
+    "width",
+    'w', 0,
+    G_OPTION_ARG_INT,
+    &width,
+    "Width of application window. Default: 640",
+    NULL
+  },
+  {
+    "height",
+    'h', 0,
+    G_OPTION_ARG_INT,
+    &height,
+    "Height of application window. Default: 480",
+    NULL
+  },
+  {
+    "fullscreen",
+    'f', 0,
+    G_OPTION_ARG_NONE,
+    &fullscreen,
+    "Whether the application window should be fullscreen.",
+    NULL
+  },  
+  {
+    NULL
+  }
+};
+
+gint
+main (gint argc, gchar *argv[])
+{
+  ClutterActor *stage, *bg, *desktop;
+  GError *error = NULL;
+
+  g_thread_init (NULL);
+
+  clutter_init_with_args (&argc, &argv,
+                          " - Astro Desktop", entries,
+                          NULL, &error);
+  if (error)
+    {
+      g_error ("Unable to run Astro Desktop: %s", error->message);
+      g_error_free (error);
+      return EXIT_FAILURE;
+    }
+
+  /* Set up the stage */
+  stage = clutter_stage_get_default ();
+  clutter_actor_set_size (stage, width, height);
+    
+  if (fullscreen)
+    clutter_stage_fullscreen (CLUTTER_STAGE (stage));
+
+  /* Draw the background */
+  bg = load_background ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), bg);
+  clutter_actor_set_position (bg, 0, 0);
+
+  /* Load the desktop */
+  desktop = astro_desktop_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), desktop);
+  clutter_actor_set_size (desktop, CSW (), CSH ());
+  clutter_actor_set_position (desktop, 0, 0);
+  
+  clutter_actor_show_all (stage);
+  
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}
+
+static ClutterActor * 
+load_background (void)
+{
+  ClutterActor *texture;
+  GdkPixbuf *pixbuf;
+
+  texture = clutter_texture_new ();
+  pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR "/background.svg",
+                                              CSW (),
+                                              CSH (),
+                                              FALSE,
+                                              NULL);
+  if (pixbuf)
+    clutter_texture_set_pixbuf (CLUTTER_TEXTURE (texture), pixbuf, NULL);
+
+  return texture;
+}
diff --git a/attic/fluttr/AUTHORS b/attic/fluttr/AUTHORS
new file mode 100644 (file)
index 0000000..8ec34a6
--- /dev/null
@@ -0,0 +1 @@
+Neil J. Patel <njp@o-hand.com>
diff --git a/attic/fluttr/COPYING b/attic/fluttr/COPYING
new file mode 100644 (file)
index 0000000..623b625
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/attic/fluttr/ChangeLog b/attic/fluttr/ChangeLog
new file mode 100644 (file)
index 0000000..7c71cb1
--- /dev/null
@@ -0,0 +1,740 @@
+2008-02-18  Chris Lord  <chris@openedhand.com>
+
+       * configure.ac:
+       Bump clutter version to 0.6
+
+2008-02-08  Chris Lord  <chris@openedhand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_init):
+       * src/fluttr-set.c: (fluttr_set_init):
+       * src/fluttr-spinner.c: (fluttr_spinner_alpha_func):
+       Update to new 0.5 rotation API
+
+2007-09-07  Neil J. Patel  <njp@o-hand.com>
+
+       Patch by: Andre Magalhaes <andrunko@gmail.com>
+
+       * configure.ac:
+       Bump to 0.5
+
+       * src/fluttr-list-view.c: (fluttr_list_view_advance):
+       Make sure the active_actor is raised to the top.
+
+       * src/main.c: (main), (photo_input_cb), (list_input_cb),
+       (sets_input_cb):
+       Add a list_view into the app struct, as two objects were sharing the same
+       reference :-/.
+
+2007-08-07  Neil J. Patel  <njp@o-hand.com>
+
+       * configure.ac:
+       Bump to 0.4. Remove check and warning for 0.2.
+
+2007-08-01  Neil J. Patel  <njp@o-hand.com>
+
+       * prepare-ChangeLog.pl:
+       Should not be here.
+
+2007-08-01  Neil J. Patel  <njp@o-hand.com>
+
+       * AUTHORS:
+       Include email address.
+
+2007-07-12  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_opt_alpha_func):
+       Remove the spinning of the photos.
+
+2007-06-28  Neil J. Patel  <njp@o-hand.com>
+
+       * README:
+       * configure.ac:
+       Added instructions on where to download Fluttr for clutter-0.2
+
+       * src/fluttr-auth.c:
+       * src/fluttr-list-view.c: (fluttr_list_view_set_property):
+       * src/fluttr-list.c: (fluttr_list_init):
+       * src/fluttr-photo.c: (fluttr_photo_set_visible),
+       (fluttr_photo_swap_alpha_func), (fluttr_photo_init):
+       * src/fluttr-set-view.c:
+       * src/fluttr-spinner.c: (fluttr_spinner_new):
+       * src/fluttr-viewer.c: (fluttr_viewer_swap_alpha_func):
+       * src/main.c: (main), (create_background):
+       Port to clutter-0.3.
+       Call clutter_actor_show_all () on groups where parent == ClutterGroup.
+       Update clutter_texture_set_pixbuf to new api.
+
+2007-06-19  Ross Burton  <ross@openedhand.com>
+
+       * libnflick/Makefile.am:
+       Don't install the library.
+
+2007-06-19  Rob Bradford  <rob@openedhand.com>
+
+       * libnflick/Makefile.am:
+       * src/Makefile.am:
+       Make distcheck pass.
+
+2007-06-19  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-viewer.c: (fluttr_viewer_go),
+       (fluttr_viewer_swap_alpha_func), (fluttr_viewer_init):
+       Added a spinner while we are fecthing the main pixbuf.
+
+2007-06-19  Neil J. Patel  <njp@o-hand.com>
+
+       * README:
+       Added options info.
+
+2007-06-19  Neil J. Patel  <njp@o-hand.com>
+
+       * README:
+       Added some more info.
+
+2007-06-19  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_opt_alpha_func),
+       (on_thread_ok_idle), (fluttr_photo_init):
+       Added black background.
+       Stopped printing known warnings/errors.
+
+2007-05-29  Tomas Frydrych <tf@o-hand.com>
+
+       * configure.ac:
+       Check that neon is at least 0.26.0
+       
+2007-05-22  Neil J Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_advance):
+       Added some more code to 'shrink' the stage, so there's less work for
+       clutter to do. Definitely a visible improvement on large lists.
+
+2007-05-21  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_set_visible),
+       (fluttr_photo_swap_alpha_func):
+       Fixed Clutter-CRITICAL warnings in the texture-destroying code.
+
+2007-05-21  Neil J. Patel  <njp@o-hand.com>
+
+       * data/picture.svg:
+       Made it fit the ratio of the thumbnails so it doesn't appear
+       stretched.
+
+       * src/fluttr-photo.c: (fluttr_photo_get_default_size):
+       Made the default size a little larger.
+
+2007-05-21  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (on_thread_ok_idle), (_check_cache):
+       * src/main.c: (main):
+       Thumbnails will be created according to stage size, and will be saved
+       in .fluttr-thumbs/<SIZE>/<PHOTO_ID>.png. Therefore photos will always
+       be at the proper size for the current stage size.
+
+       * src/main.c: (main):
+       Added fulscreen (-f), width (-w) and height (-h) options.
+
+2007-05-21  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_advance),
+       (fluttr_list_view_activate), (fluttr_list_view_advance_row),
+       (fluttr_list_view_set_property), (fluttr_list_view_get_property),
+       (fluttr_list_view_class_init):
+       * src/main.c: (main):
+       You can now set the number of columns in the list view via the -c
+       switch (default=3).
+
+2007-05-20  Neil J. Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-photo-set.c: (nflick_photo_set_give_list):
+       * libnflick/nflick-pixbuf-fetch.c: (nflick_pixbuf_fetch):
+       Removed unnecassary warnings.
+
+       * src/fluttr-list-view.c: (fluttr_list_view_paint):
+       * src/fluttr-photo.c: (fluttr_photo_set_visible),
+       (fluttr_photo_swap_alpha_func), (on_thread_ok_idle),
+       (fluttr_photo_finalize), (fluttr_photo_init):
+       * src/fluttr-photo.h:
+       When a FLuttrPhoto is not painted, it will destroy its private texture
+       which holds the photo, recreating it before it is painted.
+
+2007-05-18  Neil J Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_empty),
+       (fluttr_list_view_paint):
+       Stopped painting textures which cannot be seen.
+
+2007-05-10  Neil J. Patel  <njp@o-hand.com>
+
+       * src/main.c: (_swap_alpha_func), (browse_input_cb):
+       Removed unnecessary variables.
+
+2007-05-10  Neil J. Patel  <njp@o-hand.com>
+
+       * README:
+       * src/fluttr-set-view.c:
+       * src/main.c: (main):
+       Restored default column settings.
+       Added some more info to README.
+
+2007-05-10  Neil J Patel  <njp@o-hand.com>
+
+       * README:
+       Added authorisation instructions.
+       
+       * src/main.c: (main):
+       Removed 'forced' full screen.
+
+2007-05-10  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c:
+       * src/fluttr-photo.c:
+       * src/fluttr-set-view.c:
+       * src/main.c: (main):
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_opt_alpha_func),
+       (_fluttr_photo_fetch_pixbuf):
+       Fixed transition.
+       
+       * src/fluttr-viewer.c: (fluttr_viewer_show),
+       (fluttr_viewer_swap_alpha_func), (fluttr_viewer_init):
+       Tweaked effect.
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (on_thread_ok_idle), (_check_cache),
+       (_fluttr_photo_fetch_pixbuf):
+       Implemented caching for thumbnails.
+       
+       * src/fluttr-set-view.c: (fluttr_set_view_advance),
+       (fluttr_set_view_init):
+       * src/fluttr-set.c: (fluttr_set_set_active),
+       (fluttr_set_act_alpha_func):
+       Made the activated set have a different text colour.
+       
+       * src/main.c: (main):
+       Made sure the thumbnail directory is created.
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-set-view.c: (fluttr_set_view_add_set):
+       All sets start from the middle of the stage.
+
+       * src/main.c: (main), (_swap_alpha_func), (list_input_cb),
+       (sets_input_cb):
+       Smooth fading transition from sets<->list.      
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_opt_alpha_func),
+       (fluttr_photo_class_init), (fluttr_photo_init):
+       * src/fluttr-photo.h:
+       Emits signal when the activation effect is complete.
+       
+       * src/fluttr-viewer.c: (fluttr_viewer_show),
+       (close_message_window), (on_thread_ok_idle), (fluttr_viewer_go),
+       (fluttr_viewer_alpha_func), (fluttr_viewer_swap_alpha_func),
+       (fluttr_viewer_set_property), (fluttr_viewer_get_property),
+       (fluttr_viewer_class_init), (fluttr_viewer_init):       
+       * src/main.c: (photo_input_cb), (_show_viewer), (list_input_cb):
+       Fixed bug where the viewer was not hiding properly, and blockign the 
+       current view.
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-viewer.c: (on_thread_abort_idle), (on_thread_ok_idle),
+       (on_thread_error_idle), (fluttr_viewer_go),
+       (fluttr_viewer_swap_alpha_func), (fluttr_viewer_init):
+       Fixed bug which was stopping the active photo (and subsequent threads) 
+       from doing their work because of a timeline.
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * src/Makefile.am:
+       * src/fluttr-photo.c: 
+       * src/fluttr-photo.h:
+       * src/fluttr-viewer.c:
+       * src/fluttr-viewer.h:
+       * src/main.c:
+       Added basic fullscreen photo viewing capability.
+
+2007-05-09  Neil J.Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-set-list-worker.c: (thread_func):
+       Removed useless status messages.
+       
+       * src/Makefile.am:
+       Added the new set-view files.
+       
+       * src/fluttr-list-view.c: (fluttr_list_view_advance), (_peg),
+       (fluttr_list_view_activate), (fluttr_list_view_empty),
+       (fluttr_list_view_populate), (fluttr_list_view_set_property),
+       (fluttr_list_view_get_property), (fluttr_list_view_class_init),
+       (fluttr_list_view_init), (fluttr_list_view_new):
+       * src/fluttr-list-view.h:
+       Amended code to use a FluttrSet as the underlying data-type rather than
+       a FluttrLibrary class.
+       
+       * src/fluttr-list.c: (on_thread_msg_change_idle):
+       Added a '\n' at the end of each message.
+       
+       * src/fluttr-set-view.c: (fluttr_set_view_get_active),
+       (fluttr_set_view_advance), (fluttr_set_view_activate),
+       (fluttr_set_view_advance_row), (fluttr_set_view_advance_col),
+       (fluttr_set_view_add_set), (fluttr_set_view_set_property),
+       (fluttr_set_view_get_property), (fluttr_set_view_paint),
+       (fluttr_set_view_dispose), (fluttr_set_view_finalize),
+       (fluttr_set_view_class_init), (fluttr_set_view_init),
+       (fluttr_set_view_new):
+       * src/fluttr-set-view.h:
+       A new view whihc is based on the list view, but handles FLuttrSets.
+       
+       * src/fluttr-set.c: (fluttr_set_get_default_size),
+       (fluttr_set_get_default_width), (fluttr_set_get_default_height),
+       (fluttr_set_set_active), (fluttr_set_update_position),
+       (fluttr_set_trans_alpha_func), (fluttr_set_act_alpha_func),
+       (_refresh_thumbs), (fluttr_set_append_photo),
+       (fluttr_set_get_photos), (_update_text), (fluttr_set_set_property),
+       (fluttr_set_get_property), (fluttr_set_dispose),
+       (fluttr_set_finalize), (fluttr_set_class_init), (fluttr_set_init),
+       (fluttr_set_new):
+       * src/fluttr-set.h:
+       A CluttrActor which is the representation of a Flickr set. It also
+       contains the list of photos belonging to that set.
+       
+       * src/main.c: (main), (list_get_successful), (list_input_cb),
+       (sets_input_cb), (browse_input_cb):
+       Added ability to browse sets and then photos belonging to the activated
+       set.
+
+2007-05-08  Neil J.Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-set-list-worker.c: (thread_func): Changed to download
+       photo information for every set rather than just the first set.
+       
+       * src/main.c: (list_get_successful): Chhanged data output.
+
+2007-05-08  Neil J.Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_set_active),
+       (_fluttr_photo_fetch_pixbuf): Fixed problem where the photo fetching
+       worker was being called repeatedly affecting performance.
+
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_advance),
+       (fluttr_list_view_activate):
+       All visible rows will 'fall' when a photo is activated.
+
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_advance):
+       * src/fluttr-photo.c: (fluttr_photo_get_default_width),
+       (fluttr_photo_get_default_height), (fluttr_photo_swap_alpha_func),
+       (fluttr_photo_paint), (fluttr_photo_init):
+       * src/fluttr-photo.h:
+       Photos are w>h again, instead of squares. Looks nicer.
+       
+       
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       reviewed by: <delete if not using a buddy>
+
+       * src/fluttr-list-view.c:
+       Changed the 'falling photos' code so it moves up first, then down.
+       
+       * src/fluttr-photo.c:
+       Fixed some silly resize errors, removed the 'flipping' code when
+       activated.
+       
+       * src/main.c:
+       Stopped activation from calling the fluttr_photo_set_options.
+       
+
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_get_active),
+       (fluttr_list_view_advance), (fluttr_list_view_activate):
+       * src/fluttr-list-view.h:
+       Added a call to 'activate' the current photo. Activation consists of
+       letting the other photos 'fall' away, and the centering the main photo.
+       
+       * src/fluttr-photo.c: (fluttr_photo_opt_alpha_func),
+       (on_thread_ok_idle), (fluttr_photo_init):
+       Cleaned up some over-the-top printing.
+       
+       * src/main.c: (_set_options), (browse_input_cb):
+       Changed to 'activate the list view when enter is pressed.
+
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       reviewed by: <delete if not using a buddy>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_get_active),
+       (fluttr_list_view_advance), (fluttr_list_view_activate):
+       * src/fluttr-list-view.h:
+       * src/fluttr-photo.c: (fluttr_photo_opt_alpha_func),
+       (on_thread_ok_idle), (fluttr_photo_init):
+       * src/main.c: (_set_options), (browse_input_cb):
+
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       reviewed by: <delete if not using a buddy>
+
+       * src/fluttr-list-view.c: (fluttr_list_view_get_active),
+       (fluttr_list_view_advance):
+       * src/fluttr-photo.c: (fluttr_photo_get_default_size),
+       (fluttr_photo_set_options), (fluttr_photo_set_active),
+       (fluttr_photo_act_alpha_func), (fluttr_photo_opt_alpha_func),
+       (fluttr_photo_fetch_pixbuf), (fluttr_photo_set_property),
+       (fluttr_photo_paint), (fluttr_photo_init):
+       * src/fluttr-photo.h:
+       * src/main.c: (_set_options):
+
+2007-05-04  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-photo.c: (fluttr_photo_act_alpha_func),
+       (fluttr_photo_set_options), (fluttr_photo_paint),
+       (fluttr_photo_init):
+       * src/fluttr-photo.h:
+       Adjusted to use glScale over a timeline, rather than
+       clutter_actor_set_scale.
+       After settings the options, FluttrPhoto will automatically start the
+       'active' timeline.
+       
+       * src/main.c: (_set_options):
+       Sets a test 'options' widget upon pressing enter.
+
+2007-05-03  Neil J. Patel  <njp@o-hand.com>
+
+       * libnflick/nflick-show-worker.c:
+       Stop spitting out annoying messages.
+       
+       * src/fluttr-auth.h:
+       * src/fluttr-library-row.c:
+       Added a GdkPixbuf property.
+       
+       * src/fluttr-list-view.c:
+       * src/fluttr-list-view.h:
+       Ability to control table size.
+       Added calls to allow you to move n numbr os rows or columns.
+       Ability to get the currently selected FluttrPhoto.
+       
+       * src/fluttr-photo.c:
+       * src/fluttr-photo.h:
+       Added the 'options' widget at the correct rotation.
+       Function to set the options widget.
+       
+       * src/main.c:
+       Responds to keystrokes.
+       
+
+2007-05-03  Neil J. Patel  <njp@o-hand.com>
+
+       * Makefile.am:
+       * config.guess:
+       * config.sub:
+       * configure.ac:
+       * libnflick/Makefile.am:
+       * libnflick/nflick-api-request-private.h:
+       * libnflick/nflick-api-request.c:
+       * libnflick/nflick-api-request.h:
+       * libnflick/nflick-api-response-private.h:
+       * libnflick/nflick-api-response.c:
+       * libnflick/nflick-auth-worker.h:
+       * libnflick/nflick-flickr.h:
+       * libnflick/nflick-get-sizes-response-private.h:
+       * libnflick/nflick-get-sizes-response.c:
+       * libnflick/nflick-get-sizes-response.h:
+       * libnflick/nflick-gft-response-private.h:
+       * libnflick/nflick-gft-response.c:
+       * libnflick/nflick-gft-response.h:
+       * libnflick/nflick-no-set-response-private.h:
+       * libnflick/nflick-no-set-response.c:
+       * libnflick/nflick-no-set-response.h:
+       * libnflick/nflick-photo-data.c:
+       * libnflick/nflick-photo-data.h:
+       * libnflick/nflick-photo-list-response-private.h:
+       * libnflick/nflick-photo-list-response.c:
+       * libnflick/nflick-photo-list-response.h:
+       * libnflick/nflick-photo-list-worker-private.h:
+       * libnflick/nflick-photo-list-worker.c:
+       * libnflick/nflick-photo-list-worker.h:
+       * libnflick/nflick-photo-set-private.h:
+       * libnflick/nflick-photo-set.c:
+       * libnflick/nflick-photo-set.h:
+       * libnflick/nflick-pixbuf-fetch-private.h:
+       * libnflick/nflick-pixbuf-fetch.c:
+       * libnflick/nflick-pixbuf-fetch.h:
+       * libnflick/nflick-set-list-response-private.h:
+       * libnflick/nflick-set-list-response.c:
+       * libnflick/nflick-set-list-response.h:
+       * libnflick/nflick-set-list-worker-private.h:
+       * libnflick/nflick-set-list-worker.c:
+       * libnflick/nflick-set-list-worker.h:
+       * libnflick/nflick-show-worker-private.h:
+       * libnflick/nflick-show-worker.c:
+       * libnflick/nflick-show-worker.h:
+       * libnflick/nflick-types.h:
+       * libnflick/nflick-worker-private.h:
+       * libnflick/nflick-worker.c:
+       * libnflick/nflick-worker.h:
+       * libnflick/nflick.h:
+       * ltmain.sh:
+       * src/Makefile.am:
+       * src/fluttr-auth.c:
+       * src/fluttr-library-row.c:
+       * src/fluttr-library-row.h:
+       * src/fluttr-list-view.h:
+       * src/fluttr-list.c:
+       * src/fluttr-list.h:
+       * src/fluttr-photo.c:
+       * src/fluttr-photo.h:
+       * src/main.c:
+       * src/nflick-api-request-private.h:
+       * src/nflick-api-request.c:
+       * src/nflick-api-request.h:
+       * src/nflick-api-response-private.h:
+       * src/nflick-api-response.c:
+       * src/nflick-api-response.h:
+       * src/nflick-auth-worker-private.h:
+       * src/nflick-auth-worker.c:
+       * src/nflick-auth-worker.h:
+       * src/nflick-flickr.h:
+       * src/nflick-get-sizes-response-private.h:
+       * src/nflick-get-sizes-response.c:
+       * src/nflick-get-sizes-response.h:
+       * src/nflick-gft-response-private.h:
+       * src/nflick-gft-response.c:
+       * src/nflick-gft-response.h:
+       * src/nflick-no-set-response-private.h:
+       * src/nflick-no-set-response.c:
+       * src/nflick-no-set-response.h:
+       * src/nflick-photo-data.c:
+       * src/nflick-photo-data.h:
+       * src/nflick-photo-list-response-private.h:
+       * src/nflick-photo-list-response.c:
+       * src/nflick-photo-list-response.h:
+       * src/nflick-photo-list-worker-private.h:
+       * src/nflick-photo-list-worker.c:
+       * src/nflick-photo-list-worker.h:
+       * src/nflick-photo-set-private.h:
+       * src/nflick-photo-set.c:
+       * src/nflick-photo-set.h:
+       * src/nflick-pixbuf-fetch-private.h:
+       * src/nflick-pixbuf-fetch.c:
+       * src/nflick-pixbuf-fetch.h:
+       * src/nflick-set-list-response-private.h:
+       * src/nflick-set-list-response.c:
+       * src/nflick-set-list-response.h:
+       * src/nflick-set-list-worker-private.h:
+       * src/nflick-set-list-worker.c:
+       * src/nflick-set-list-worker.h:
+       * src/nflick-show-worker-private.h:
+       * src/nflick-show-worker.c:
+       * src/nflick-show-worker.h:
+       * src/nflick-types.h:
+       * src/nflick-worker-private.h:
+       * src/nflick-worker.c:
+       * src/nflick-worker.h:
+       Pulled all nflick files into its own directory.
+       Updated sources to reflect change.
+
+2007-05-03  Neil J. Patel  <njp@o-hand.com>
+
+       * data/picture.svg:
+       Changed to lighter colour, and added clock picture (from Tango icon).
+       
+       * src/fluttr-list-view.c: (fluttr_list_view_advance):
+       Changed to make a grid of 4x3 icons.
+       
+       * src/fluttr-photo.c: (fluttr_photo_swap_alpha_func),
+       (on_thread_ok_idle), (fluttr_photo_fetch_pixbuf),
+       (fluttr_photo_get_default_size), (fluttr_photo_init):
+       Changed the sizing to be a square with a set size, rather than a
+       resizable rectangle. The downloaded picture is now set in the middle
+       of a clip region.
+       
+       * src/fluttr-photo.h:
+       Added a utility function to get the default size of the photo square for
+       the current stage width & height.
+       
+
+2007-05-02  Neil J. Patel  <njp@o-hand.com>
+
+       * src/Makefile.am:
+       * src/fluttr-library-row.c:
+       Fixed pixbuf swapping effect. Lowered fps.
+       
+       * src/fluttr-library.c:
+       * src/fluttr-library.h:
+       Changed function names.
+       
+       * src/fluttr-list-view.c: 
+       * src/fluttr-list-view.h:
+       A table widget to show photos. Handles positioning.
+       
+       * src/fluttr-photo.c:
+       Changed fps to be faster. Send signal when finished.
+       
+       * src/main.c:
+       Commented out the test code.
+
+2007-05-02  Neil J. Patel  <njp@o-hand.com>
+
+       * src/fluttr-list.c: (fluttr_list_text_alpha_func):
+       Correctted factor calulation for text fade out.
+
+       * src/fluttr-photo.c: (fluttr_photo_trans_alpha_func),
+       (fluttr_photo_swap_alpha_func), (on_thread_ok_idle),
+       (fluttr_photo_fetch_pixbuf), (fluttr_photo_init):
+       Added a effect for swapping the default pixbuf with the downloaded
+       photo pixbuf.
+
+2007-05-02  Neil J. Patel  <njp@o-hand.com>
+
+       * data/Makefile.am:
+       * src/Makefile.am:
+       * src/fluttr-library-row.c:
+       * src/fluttr-library-row.h:
+       * src/fluttr-library.c:
+       Added library interface, with a FluttrLibraryRow class which is created
+       or every photo.
+       
+       * src/fluttr-list.c:
+       Adjusted timeline fps to allow other threads to work properly.
+       
+       * src/fluttr-photo.c:
+       * src/fluttr-photo.h:
+       A class representing a photo *on* the stage, it is created & destroyed
+       as needed.
+       
+       * src/fluttr-settings.c:
+       * src/fluttr-settings.h:
+       A singleton containing the current sessions auth properties.
+       
+       * src/main.c:
+       Added a test case for downloading a picture.
+       
+       * src/nflick-show-worker-private.h:
+       * src/nflick-show-worker.c:
+       * src/nflick-show-worker.h:
+       Added missing files from NFlick to allow downloading of photos.
+
+2007-05-01  Neil J. Patel  <njp@o-hand.com>
+
+       * data/Makefile.am:
+       * data/background.svg:
+       * data/message.svg:
+       * data/spinner.svg:
+       Added some nice pictures.
+       
+       * src/Makefile.am:
+       * src/fluttr-auth.c:
+       Removed unneeded header.
+
+       * src/fluttr-behave.c: (alpha_sine_inc_func),
+       (alpha_linear_inc_func), (fluttr_behave_alpha_notify),
+       (fluttr_behave_class_init), (fluttr_behave_init),
+       (fluttr_behave_new):
+       * src/fluttr-behave.h:
+       A utility behaviour class witch will call a custom function on each
+       iteration of the timeline.
+
+       * src/fluttr-library-row.h:
+       Removed unused headers.
+
+       * src/fluttr-list.c: (close_message_window),
+       (on_thread_abort_idle), (on_thread_ok_idle),
+       (on_thread_error_idle), (on_thread_msg_change_idle),
+       (fluttr_list_go), (fluttr_list_alpha_func),
+       (fluttr_list_text_alpha_func), (fluttr_list_init),
+       (fluttr_list_new):
+       Added a startup spinning effect while the photo data is being
+       downloaded from flickr.
+
+       * src/fluttr-spinner.c: (fluttr_spinner_spin),
+       (fluttr_spinner_alpha_func), (fluttr_spinner_dispose),
+       (fluttr_spinner_finalize), (fluttr_spinner_class_init),
+       (fluttr_spinner_init), (fluttr_spinner_new):
+       * src/fluttr-spinner.h:
+       A basic spinner widget.
+
+       * src/main.c: (main), (create_background):
+       Added a background.
+
+       * src/nflick-worker.c: (thread_start):
+       Changed the thread for OkIdle to be called with a higher priority.
+
+
+2007-04-30  Neil J. Patel  <njp@o-hand.com>
+
+       * src/Makefile.am
+       Imported missing files from NFlick.
+
+       * src/fluttr-auth.h:
+       Fixed typo from copy.
+
+       * src/fluttr-list.c: 
+       * src/fluttr-list.h:
+       An actor which wraps nflick_set_list_worker, sends signals on
+       completion.
+       
+       * src/main.c: (main), (auth_successful), (auth_error),
+       (list_get_successful), (list_get_error):
+       Added the ability to get a list of photos and print them out.
+
+2007-04-30  Neil J. Patel  <njp@o-hand.com>
+
+       * README:
+       Added explaination of where the Flickr code came from.
+
+       * src/Makefile.am:
+       * src/fluttr-auth.c:
+       * src/fluttr-auth.h:
+       Added a FluttrAuth class which handles Flickr authorisations and uses
+       signals to provide feedback.
+       
+       * src/main.c: (_auth_timeout):Starts the FluttrAuth class.
+       (main):Added checks for authorisation.
+       (check_credentials): Loads up a .fluttr keyfile which contains the
+       username, fullname, token and usernsid of the previous session.
+       (auth_successful): Will save the new details in the .fluttr keyfile
+       (auth_error): FluttrAuth error handler.
+       
+       * src/nflick-flickr.h:
+       Changed the values to authorise for fluttr and not nflic.
+
+2007-04-30  Neil J. Patel  <njp@o-hand.com>
+
+       * configure.ac:
+       * prepare-ChangeLog.pl:
+       * src/Makefile.am:
+       * src/main.c: (main):
+       * src/nflick-api-request-private.h:
+       * src/nflick-api-request.c:
+       * src/nflick-api-request.h:
+       * src/nflick-api-response-private.h:
+       * src/nflick-api-response.c:
+       * src/nflick-api-response.h:
+       * src/nflick-auth-worker-private.h:
+       * src/nflick-auth-worker.c:
+       * src/nflick-auth-worker.h:
+       * src/nflick-flickr.h:
+       * src/nflick-gft-response-private.h:
+       * src/nflick-gft-response.c:
+       * src/nflick-gft-response.h:
+       * src/nflick-types.h:
+       * src/nflick-worker-private.h:
+       * src/nflick-worker.c:
+       * src/nflick-worker.h:
+       Import of nflick's Flickr code, made it compile.
+
+2007-04-27  Neil J. Patel  <njp@o-hand.com>
+
+       * Inital Import:
+       Initial Import
+
diff --git a/attic/fluttr/INSTALL b/attic/fluttr/INSTALL
new file mode 100644 (file)
index 0000000..23e5f25
--- /dev/null
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/attic/fluttr/Makefile.am b/attic/fluttr/Makefile.am
new file mode 100644 (file)
index 0000000..7dba0bf
--- /dev/null
@@ -0,0 +1,7 @@
+SUBDIRS = data libnflick src
+
+#MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub configure depcomp install-sh ltmain.sh Makefile.in missing
+
+snapshot:
+       $(MAKE) dist distdir=$(PACKAGE)-snap`date +"%Y%m%d"`
+
diff --git a/attic/fluttr/NEWS b/attic/fluttr/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/fluttr/README b/attic/fluttr/README
new file mode 100644 (file)
index 0000000..b21d2e7
--- /dev/null
@@ -0,0 +1,69 @@
+A clutter-based flickr viewer.
+
+NOTE
+====
+
+Fluttr is now tracking clutter svn (clutter-0.3 upwards), so you can either 
+install clutter svn on your system, or you can grab a copy of Fluttr which will
+compile against clutter-0.2 from:
+http://folks.o-hand.com/njp/fluttr/fluttr-0.1-svn846.tar.gz
+
+
+Authorising yourself with Flickr
+================================
+
+Type this url into your web-browser of choice:
+
+http://www.flickr.com/auth-72157600141007022
+
+You will then be asked to log into flickr (or not if you are already 
+logged in). The next screen will ask you if you want to let Fluttr access 
+your Flickr pictures, click "OK, I'll allow it", and Flickr will take you to 
+a page which has a auth code in the middle like this:
+
+123-456-789
+
+Now, start fluttr with that code:
+
+$ fluttr 123-456-789
+
+Fluttr will then contact Flickr and save its settings. From now on, you can 
+just run fluttr without any options.
+
+NB: You may need to restart fluttr after the initial authorisation.
+
+Using Fluttr
+===========
+
+Fluttr is pretty simple in that it can view sets, view photos within a set, 
+and finally view a photo. Certain things, like moving between photos when 
+maximised, still need to be added.
+
+The main keys for using Fluttr are the Up/Down/Left/Right keys to navigate, 
+and Enter to select. Esc will bring you back to the previous menu. If you are
+already at 'root level' ie. you can see all the different photo sets, then 
+pressing Esc will quit Fluttr. Pressing q at any time will also cause Fluttr 
+to quit.
+
+Options
+=======
+-c, --columns=3      Number of picture columns in the view
+-f, --fullscreen     Launch Fluttr in fullscreen mode
+-w, --width=800      Width of the Fluttr window
+-h, --height=440     Height of the Fluttr window
+
+Know Issues
+===========
+
+On some machines, Fluttr does not quit properly (due to a thread problem in 
+either libneon or the nflick code), so you may have to kill it. You will 
+know that this has happened because your cpu usage will be raised. I am
+trying to find the reason for this, or how to prevent it. If you have any 
+ideas, you know what to do :).
+
+
+Credits
+=======
+All of the 'flickr' code (anything starting with nflick-*), has been taken 
+from the excellent NFlick Flickr browser for the n800 by MDK
+(https://garage.maemo.org/projects/nflick).
diff --git a/attic/fluttr/TODO b/attic/fluttr/TODO
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/attic/fluttr/autogen.sh b/attic/fluttr/autogen.sh
new file mode 100755 (executable)
index 0000000..b1376df
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/attic/fluttr/config.guess b/attic/fluttr/config.guess
new file mode 120000 (symlink)
index 0000000..d0bb19b
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/libtool/config.guess
\ No newline at end of file
diff --git a/attic/fluttr/config.sub b/attic/fluttr/config.sub
new file mode 120000 (symlink)
index 0000000..31a57ca
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/libtool/config.sub
\ No newline at end of file
diff --git a/attic/fluttr/configure.ac b/attic/fluttr/configure.ac
new file mode 100644 (file)
index 0000000..02fcd08
--- /dev/null
@@ -0,0 +1,28 @@
+AC_PREREQ(2.53)
+AC_INIT(fluttr, 0.1.1, [])
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/main.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES(DEPS, clutter-0.6 gdk-2.0 gtk+-2.0 neon >= 0.26.0 libxml-2.0)
+AC_SUBST(DEPS_CFLAGS)
+AC_SUBST(DEPS_LIBS)
+
+if test "x$GCC" = "xyes"; then
+        GCC_FLAGS="-g -Wall"
+fi
+
+AC_SUBST(GCC_FLAGS)
+
+AC_OUTPUT([
+Makefile
+data/Makefile
+libnflick/Makefile
+src/Makefile
+])
diff --git a/attic/fluttr/data/Makefile.am b/attic/fluttr/data/Makefile.am
new file mode 100644 (file)
index 0000000..4754dd6
--- /dev/null
@@ -0,0 +1,12 @@
+imagedir = $(datadir)/fluttr
+image_DATA = \
+       background.svg          \
+       message.svg             \
+       spinner.svg             \
+       picture.svg     
+
+EXTRA_DIST = \
+       background.svg          \
+       message.svg             \
+       spinner.svg             \
+       picture.svg             
diff --git a/attic/fluttr/data/background.svg b/attic/fluttr/data/background.svg
new file mode 100644 (file)
index 0000000..b3e1b2a
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="800"
+   height="440"
+   id="svg2263"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   sodipodi:modified="true"
+   version="1.0">
+  <defs
+     id="defs2265">
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#1f2221;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient3139"
+       x1="462.85715"
+       y1="0"
+       x2="462.85715"
+       y2="600.20575"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1,0.7333333)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="426.08353"
+     inkscape:cy="180.94201"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="800px"
+     height="440px"
+     inkscape:window-width="910"
+     inkscape:window-height="624"
+     inkscape:window-x="4"
+     inkscape:window-y="47" />
+  <metadata
+     id="metadata2268">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;fill:url(#linearGradient3139);fill-opacity:1;stroke:none;stroke-width:20;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+       id="rect2160"
+       width="800"
+       height="440"
+       x="0"
+       y="0"
+       ry="0" />
+  </g>
+</svg>
diff --git a/attic/fluttr/data/message.svg b/attic/fluttr/data/message.svg
new file mode 100644 (file)
index 0000000..64daef9
--- /dev/null
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="400"
+   height="250"
+   id="svg2263"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/home/njp/o-hand/svn/clutter/trunk/toys/fluttr/data"
+   sodipodi:docname="message.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs2265">
+    <linearGradient
+       id="linearGradient3289">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3291" />
+      <stop
+         style="stop-color:#474747;stop-opacity:1;"
+         offset="1"
+         id="stop3293" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3275">
+      <stop
+         id="stop3277"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop3279"
+         offset="1"
+         style="stop-color:#cfcfcf;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#1f2221;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient3139"
+       x1="462.85715"
+       y1="0"
+       x2="462.85715"
+       y2="600.20575"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1,0.7333333)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3275"
+       id="linearGradient3273"
+       x1="478.57144"
+       y1="91.428574"
+       x2="478.57144"
+       y2="345.06439"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient3283"
+       gradientUnits="userSpaceOnUse"
+       x1="478.57144"
+       y1="91.428574"
+       x2="478.57144"
+       y2="345.06439"
+       gradientTransform="matrix(0.9328572,0,0,0.8971429,26.857143,22.628568)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3289"
+       id="linearGradient3287"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.9328572,0,0,0.3085715,26.857139,78.54285)"
+       x1="478.57144"
+       y1="91.428574"
+       x2="478.57144"
+       y2="345.06439" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="426.08353"
+     inkscape:cy="180.94201"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer2"
+     width="800px"
+     height="440px"
+     inkscape:window-width="910"
+     inkscape:window-height="624"
+     inkscape:window-x="4"
+     inkscape:window-y="47" />
+  <metadata
+     id="metadata2268">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     transform="translate(-200,-95)">
+    <rect
+       style="opacity:1;fill:url(#linearGradient3273);fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect2294"
+       width="400"
+       height="250"
+       x="200"
+       y="95"
+       ry="12.857142" />
+    <rect
+       style="opacity:1;fill:url(#linearGradient3283);fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3281"
+       width="373.14285"
+       height="224.28572"
+       x="213.42857"
+       y="107.85714"
+       ry="0" />
+    <rect
+       style="opacity:0.09473685;fill:url(#linearGradient3287);fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3285"
+       width="373.14285"
+       height="77.14286"
+       x="213.42857"
+       y="107.85714"
+       ry="0" />
+  </g>
+</svg>
diff --git a/attic/fluttr/data/picture.svg b/attic/fluttr/data/picture.svg
new file mode 100644 (file)
index 0000000..7d17d9f
--- /dev/null
@@ -0,0 +1,950 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="200"
+   height="160"
+   id="svg3341"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/home/njp/o-hand/svn/clutter/trunk/toys/fluttr/data"
+   sodipodi:docname="picture.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs3343">
+    <linearGradient
+       id="linearGradient3389">
+      <stop
+         style="stop-color:#ff0084;stop-opacity:1;"
+         offset="0"
+         id="stop3391" />
+      <stop
+         style="stop-color:#9a004f;stop-opacity:1;"
+         offset="1"
+         id="stop3393" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3379">
+      <stop
+         id="stop3381"
+         offset="0"
+         style="stop-color:#036def;stop-opacity:1;" />
+      <stop
+         id="stop3383"
+         offset="1"
+         style="stop-color:#00306c;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3363">
+      <stop
+         id="stop3365"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop3367"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0.11560693;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3351">
+      <stop
+         style="stop-color:#ececec;stop-opacity:1;"
+         offset="0"
+         id="stop3353" />
+      <stop
+         style="stop-color:#d8d8d8;stop-opacity:1;"
+         offset="1"
+         id="stop3355" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3351"
+       id="linearGradient3357"
+       x1="111.42857"
+       y1="0"
+       x2="111.42857"
+       y2="200.15428"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3363"
+       id="linearGradient3361"
+       gradientUnits="userSpaceOnUse"
+       x1="150.71429"
+       y1="203.92157"
+       x2="111.42857"
+       y2="200.15428"
+       gradientTransform="matrix(1,0,0,0.3642857,-0.7142857,126.42857)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3379"
+       id="linearGradient3377"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3389"
+       id="linearGradient3387"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3379"
+       id="linearGradient3399"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3389"
+       id="linearGradient3401"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3389"
+       id="linearGradient3405"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3379"
+       id="linearGradient3407"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3379"
+       id="linearGradient3413"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3389"
+       id="linearGradient3415"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3363"
+       id="linearGradient3425"
+       x1="129.28572"
+       y1="-14.711914"
+       x2="129.28572"
+       y2="44.428345"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,16)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3363"
+       id="linearGradient2197"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.8708506,0,0,1,12.440723,19.214286)"
+       x1="129.28572"
+       y1="-14.711914"
+       x2="129.28572"
+       y2="44.428345" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3351"
+       id="linearGradient2206"
+       gradientUnits="userSpaceOnUse"
+       x1="111.42857"
+       y1="0"
+       x2="111.42857"
+       y2="200.15428" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3379"
+       id="linearGradient2208"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3389"
+       id="linearGradient2210"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3363"
+       id="linearGradient2212"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.8708506,0,0,1,12.440723,19.214286)"
+       x1="129.28572"
+       y1="-14.711914"
+       x2="129.28572"
+       y2="44.428345" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3363"
+       id="linearGradient2215"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5809128,0,0,1,8.2987586,19.250001)"
+       x1="129.28572"
+       y1="-14.711914"
+       x2="129.28572"
+       y2="44.428345" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3351"
+       id="linearGradient2221"
+       gradientUnits="userSpaceOnUse"
+       x1="111.42857"
+       y1="0"
+       x2="111.42857"
+       y2="200.15428"
+       gradientTransform="scale(0.6666667,0.8035714)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3379"
+       id="linearGradient2223"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3389"
+       id="linearGradient2225"
+       gradientUnits="userSpaceOnUse"
+       x1="111.5051"
+       y1="77.135796"
+       x2="111.5051"
+       y2="121.43551" />
+    <radialGradient
+       r="11.5"
+       fy="31"
+       fx="23.75"
+       cy="31"
+       cx="23.75"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2313"
+       xlink:href="#linearGradient4642"
+       inkscape:collect="always" />
+    <radialGradient
+       r="11.5"
+       fy="31"
+       fx="23.75"
+       cy="31"
+       cx="23.75"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient2280"
+       xlink:href="#linearGradient4642"
+       inkscape:collect="always" />
+    <radialGradient
+       r="38.158695"
+       fy="7.2678967"
+       fx="8.1435566"
+       cy="7.2678967"
+       cx="8.1435566"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4056"
+       xlink:href="#linearGradient15662"
+       inkscape:collect="always" />
+    <radialGradient
+       r="37.751713"
+       fy="3.7561285"
+       fx="8.824419"
+       cy="3.7561285"
+       cx="8.824419"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4054"
+       xlink:href="#linearGradient269"
+       inkscape:collect="always" />
+    <radialGradient
+       r="86.70845"
+       fy="35.736916"
+       fx="33.966679"
+       cy="35.736916"
+       cx="33.966679"
+       gradientTransform="scale(0.960493,1.041132)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4052"
+       xlink:href="#linearGradient259"
+       inkscape:collect="always" />
+    <radialGradient
+       r="11.5"
+       fy="31"
+       fx="23.75"
+       cy="31"
+       cx="23.75"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4029"
+       xlink:href="#linearGradient4642"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="37.964115"
+       x2="29.940228"
+       y1="1.3897572"
+       x1="6.5263553"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4025"
+       xlink:href="#linearGradient4650"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12.372997"
+       x2="14.409305"
+       y1="3.3621745"
+       x1="8.0876923"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4023"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12.372997"
+       x2="24.308804"
+       y1="3.3621745"
+       x1="17.987192"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4021"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="7.423245"
+       x2="19.359053"
+       y1="-1.5875777"
+       x1="13.037439"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4019"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="17.322744"
+       x2="19.359053"
+       y1="8.3119221"
+       x1="13.037439"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4017"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="25.884274"
+       x2="22.218424"
+       y1="7.7893324"
+       x1="6.342216"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4015"
+       xlink:href="#linearGradient42174"
+       inkscape:collect="always" />
+    <radialGradient
+       r="29.292715"
+       fy="10.045444"
+       fx="11.901996"
+       cy="10.045444"
+       cx="11.901996"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4013"
+       xlink:href="#linearGradient2145"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="52.090679"
+       x2="9.8855038"
+       y1="37.197018"
+       x1="8.9156475"
+       gradientTransform="matrix(1.909643,0,0,0.592783,-10.06194,-1.765898)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4011"
+       xlink:href="#linearGradient2152"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="37.964115"
+       x2="29.940228"
+       y1="1.3897572"
+       x1="6.5263553"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4809"
+       xlink:href="#linearGradient4650"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12.372997"
+       x2="14.409305"
+       y1="3.3621745"
+       x1="8.0876923"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4807"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12.372997"
+       x2="24.308804"
+       y1="3.3621745"
+       x1="17.987192"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4805"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="7.423245"
+       x2="19.359053"
+       y1="-1.5875777"
+       x1="13.037439"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4803"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="17.322744"
+       x2="19.359053"
+       y1="8.3119221"
+       x1="13.037439"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4801"
+       xlink:href="#linearGradient2111"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="25.884274"
+       x2="22.218424"
+       y1="7.7893324"
+       x1="6.342216"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4799"
+       xlink:href="#linearGradient42174"
+       inkscape:collect="always" />
+    <radialGradient
+       r="29.292715"
+       fy="10.045444"
+       fx="11.901996"
+       cy="10.045444"
+       cx="11.901996"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4797"
+       xlink:href="#linearGradient2145"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="52.090679"
+       x2="9.8855038"
+       y1="37.197018"
+       x1="8.9156475"
+       gradientTransform="matrix(1.909643,0,0,0.592783,-10.06194,-1.765898)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient4795"
+       xlink:href="#linearGradient2152"
+       inkscape:collect="always" />
+    <radialGradient
+       r="11.5"
+       fy="31"
+       fx="23.75"
+       cy="31"
+       cx="23.75"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient4793"
+       xlink:href="#linearGradient4642"
+       inkscape:collect="always" />
+    <radialGradient
+       r="38.158695"
+       fy="7.2678967"
+       fx="8.1435566"
+       cy="7.2678967"
+       cx="8.1435566"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient15668"
+       xlink:href="#linearGradient15662"
+       inkscape:collect="always" />
+    <radialGradient
+       r="86.70845"
+       fy="35.736916"
+       fx="33.966679"
+       cy="35.736916"
+       cx="33.966679"
+       gradientTransform="scale(0.960493,1.041132)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient15658"
+       xlink:href="#linearGradient259"
+       inkscape:collect="always" />
+    <radialGradient
+       r="37.751713"
+       fy="3.7561285"
+       fx="8.824419"
+       cy="3.7561285"
+       cx="8.824419"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient15656"
+       xlink:href="#linearGradient269"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient259">
+      <stop
+         style="stop-color:#fafafa;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop260" />
+      <stop
+         style="stop-color:#bbbbbb;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop261" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient269">
+      <stop
+         style="stop-color:#a3a3a3;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop270" />
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop271" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient15662">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop15664" />
+      <stop
+         style="stop-color:#f8f8f8;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop15666" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2152">
+      <stop
+         style="stop-color:#9aa29a;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2154" />
+      <stop
+         style="stop-color:#b5beb5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2156" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2145">
+      <stop
+         id="stop2147"
+         offset="0.0000000"
+         style="stop-color:#fffffd;stop-opacity:1.0000000;" />
+      <stop
+         id="stop2149"
+         offset="1.0000000"
+         style="stop-color:#cbcbc9;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient42174">
+      <stop
+         id="stop42176"
+         offset="0.0000000"
+         style="stop-color:#a0a0a0;stop-opacity:1.0000000;" />
+      <stop
+         id="stop42178"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2111">
+      <stop
+         id="stop2113"
+         offset="0.0000000"
+         style="stop-color:#838383;stop-opacity:1.0000000;" />
+      <stop
+         id="stop2115"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4642"
+       inkscape:collect="always">
+      <stop
+         id="stop4644"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop4646"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4650"
+       inkscape:collect="always">
+      <stop
+         id="stop4652"
+         offset="0"
+         style="stop-color:#c6c6c6;stop-opacity:1;" />
+      <stop
+         id="stop4654"
+         offset="1"
+         style="stop-color:#c6c6c6;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       y2="609.50507"
+       x2="302.85715"
+       y1="366.64789"
+       x1="302.85715"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient6715"
+       xlink:href="#linearGradient5048"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient5048">
+      <stop
+         id="stop5050"
+         offset="0"
+         style="stop-color:black;stop-opacity:0;" />
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0.5"
+         id="stop5056" />
+      <stop
+         id="stop5052"
+         offset="1"
+         style="stop-color:black;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       r="117.14286"
+       fy="486.64789"
+       fx="605.71429"
+       cy="486.64789"
+       cx="605.71429"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient6717"
+       xlink:href="#linearGradient5060"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient5060"
+       inkscape:collect="always">
+      <stop
+         id="stop5062"
+         offset="0"
+         style="stop-color:black;stop-opacity:1;" />
+      <stop
+         id="stop5064"
+         offset="1"
+         style="stop-color:black;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       r="117.14286"
+       fy="486.64789"
+       fx="605.71429"
+       cy="486.64789"
+       cx="605.71429"
+       gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient6719"
+       xlink:href="#linearGradient5060"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2145"
+       id="radialGradient3638"
+       gradientUnits="userSpaceOnUse"
+       cx="11.901996"
+       cy="10.045444"
+       fx="11.901996"
+       fy="10.045444"
+       r="29.292715" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient42174"
+       id="linearGradient3640"
+       gradientUnits="userSpaceOnUse"
+       x1="6.342216"
+       y1="7.7893324"
+       x2="22.218424"
+       y2="25.884274" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4650"
+       id="linearGradient3650"
+       gradientUnits="userSpaceOnUse"
+       x1="6.5263553"
+       y1="1.3897572"
+       x2="29.940228"
+       y2="37.964115" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2152"
+       id="linearGradient3665"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(11.002524,0,0,3.4153551,-96.249847,-48.451698)"
+       x1="8.9156475"
+       y1="37.197018"
+       x2="9.8855038"
+       y2="52.090679" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2152"
+       id="linearGradient3682"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(11.002524,0,0,3.4153551,-96.249847,-48.451698)"
+       x1="8.9156475"
+       y1="37.197018"
+       x2="9.8855038"
+       y2="52.090679" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2145"
+       id="radialGradient3684"
+       gradientUnits="userSpaceOnUse"
+       cx="11.901996"
+       cy="10.045444"
+       fx="11.901996"
+       fy="10.045444"
+       r="29.292715" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient42174"
+       id="linearGradient3686"
+       gradientUnits="userSpaceOnUse"
+       x1="6.342216"
+       y1="7.7893324"
+       x2="22.218424"
+       y2="25.884274" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4650"
+       id="linearGradient3688"
+       gradientUnits="userSpaceOnUse"
+       x1="6.5263553"
+       y1="1.3897572"
+       x2="29.940228"
+       y2="37.964115" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="227.52108"
+     inkscape:cy="106.59314"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer2"
+     width="200px"
+     height="160px"
+     inkscape:window-width="983"
+     inkscape:window-height="680"
+     inkscape:window-x="147"
+     inkscape:window-y="81" />
+  <metadata
+     id="metadata3346">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     sodipodi:insensitive="true">
+    <rect
+       style="fill:url(#linearGradient2221);fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3349"
+       width="200"
+       height="160.71428"
+       x="7.6161299e-14"
+       y="0" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2">
+    <g
+       id="layer6"
+       inkscape:label="Shadow"
+       transform="matrix(6.7143879,0,0,6.7143879,-67.858297,-67.858257)" />
+    <g
+       style="display:inline"
+       inkscape:label="Base"
+       id="g3518"
+       transform="matrix(6.7143879,0,0,6.7143879,-67.858297,-67.858257)" />
+    <g
+       id="g3667"
+       transform="matrix(0.574467,0,0,0.574467,42.553305,24.553305)">
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         sodipodi:nodetypes="cccc"
+         id="path14341"
+         d="M 81.529405,25.507939 L 30.948919,84.302347 L 35.382261,88.680961 L 81.529405,25.507939 z "
+         style="color:#000000;fill:url(#linearGradient3682);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         sodipodi:nodetypes="cccc"
+         id="path18921"
+         d="M 81.105285,25.191214 L 35.998979,87.739746 L 42.442777,93.429022 L 81.105285,25.191214 z "
+         style="fill:#fefefe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(5.130017,0,0,5.130017,16.637224,13.247745)"
+         d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1  1.3392859,16.910715 A 14.910714 14.910714 0 1 1  31.160714 16.910715 z"
+         sodipodi:ry="14.910714"
+         sodipodi:rx="14.910714"
+         sodipodi:cy="16.910715"
+         sodipodi:cx="16.25"
+         id="path27786"
+         style="opacity:1;fill:#7d7d7d;fill-opacity:1;fill-rule:evenodd;stroke:#c1b5b5;stroke-width:1.59024715;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(3.7329504,0,0,3.7329504,39.006331,36.539763)"
+         d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1  1.3392859,16.910715 A 14.910714 14.910714 0 1 1  31.160714 16.910715 z"
+         sodipodi:ry="14.910714"
+         sodipodi:rx="14.910714"
+         sodipodi:cy="16.910715"
+         sodipodi:cx="16.25"
+         id="path35549"
+         style="fill:url(#radialGradient3684);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3686);stroke-width:1.48921716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <g
+         style="opacity:1"
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         id="g4606"
+         transform="matrix(-1.0620839,-6.8167458,6.8167458,-1.0620839,-36.984559,300.87459)">
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:type="arc"
+           style="fill:#f3f3f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.87022346;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+           id="path34778"
+           sodipodi:cx="15.1875"
+           sodipodi:cy="17.28125"
+           sodipodi:rx="1.21875"
+           sodipodi:ry="1.21875"
+           d="M 16.40625 17.28125 A 1.21875 1.21875 0 1 1  13.96875,17.28125 A 1.21875 1.21875 0 1 1  16.40625 17.28125 z"
+           transform="matrix(0.925965,0,0,0.925965,11.99631,8.116076)" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.80579656;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+           d="M 25.559726,22.971323 L 23.41133,18.168206"
+           id="path35559" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:nodetypes="cc"
+           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.20869446;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+           d="M 23.258264,28.150282 L 25.251348,25.275053"
+           id="path35561" />
+      </g>
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(8.5099877,0,0,8.5099877,-42.871152,-8.3001577)"
+         d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1  16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1  17.324117 7.6932044 z"
+         sodipodi:ry="0.61871845"
+         sodipodi:rx="0.61871845"
+         sodipodi:cy="7.6932044"
+         sodipodi:cx="16.705399"
+         id="path35563"
+         style="fill:#036def;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(8.5099877,0,0,8.5099877,-42.871152,75.944495)"
+         d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1  16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1  17.324117 7.6932044 z"
+         sodipodi:ry="0.61871845"
+         sodipodi:rx="0.61871845"
+         sodipodi:cy="7.6932044"
+         sodipodi:cx="16.705399"
+         id="path35565"
+         style="fill:#036def;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(8.5099877,0,0,8.5099877,-84.993471,33.822094)"
+         d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1  16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1  17.324117 7.6932044 z"
+         sodipodi:ry="0.61871845"
+         sodipodi:rx="0.61871845"
+         sodipodi:cy="7.6932044"
+         sodipodi:cx="16.705399"
+         id="path35567"
+         style="fill:#f0084f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(8.5099877,0,0,8.5099877,-0.7488995,33.822094)"
+         d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1  16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1  17.324117 7.6932044 z"
+         sodipodi:ry="0.61871845"
+         sodipodi:rx="0.61871845"
+         sodipodi:cy="7.6932044"
+         sodipodi:cx="16.705399"
+         id="path35569"
+         style="fill:#f0084f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         sodipodi:type="arc"
+         style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3688);stroke-width:1.42232776;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+         id="path10651"
+         sodipodi:cx="16.25"
+         sodipodi:cy="16.910715"
+         sodipodi:rx="14.910714"
+         sodipodi:ry="14.910714"
+         d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1  1.3392859,16.910715 A 14.910714 14.910714 0 1 1  31.160714 16.910715 z"
+         transform="matrix(4.7207064,0,0,4.7207064,23.288588,20.169571)" />
+    </g>
+  </g>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     sodipodi:insensitive="true">
+    <rect
+       style="opacity:1;fill:url(#linearGradient2215);fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3417"
+       width="200"
+       height="63.57143"
+       x="2.1798269e-06"
+       y="-0.035714421"
+       ry="0" />
+  </g>
+</svg>
diff --git a/attic/fluttr/data/spinner.svg b/attic/fluttr/data/spinner.svg
new file mode 100644 (file)
index 0000000..62e6a18
--- /dev/null
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2263"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/home/njp/o-hand/svn/clutter/trunk/toys/fluttr/data"
+   sodipodi:docname="spinner.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs2265">
+    <linearGradient
+       id="linearGradient3302">
+      <stop
+         style="stop-color:#dadada;stop-opacity:1;"
+         offset="0"
+         id="stop3304" />
+      <stop
+         id="stop3327"
+         offset="0.73949581"
+         style="stop-color:#d2d2d2;stop-opacity:1;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0.86974788"
+         id="stop3333" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop3306" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3289">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3291" />
+      <stop
+         style="stop-color:#474747;stop-opacity:1;"
+         offset="1"
+         id="stop3293" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3275">
+      <stop
+         id="stop3277"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop3279"
+         offset="1"
+         style="stop-color:#cfcfcf;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#1f2221;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient3139"
+       x1="462.85715"
+       y1="0"
+       x2="462.85715"
+       y2="600.20575"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1,0.7333333)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3275"
+       id="linearGradient3273"
+       x1="478.57144"
+       y1="91.428574"
+       x2="478.57144"
+       y2="345.06439"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient3283"
+       gradientUnits="userSpaceOnUse"
+       x1="478.57144"
+       y1="91.428574"
+       x2="478.57144"
+       y2="345.06439"
+       gradientTransform="matrix(0.9328572,0,0,0.8971429,26.857143,22.628568)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3289"
+       id="linearGradient3287"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.9328572,0,0,0.3085715,26.857139,78.54285)"
+       x1="478.57144"
+       y1="91.428574"
+       x2="478.57144"
+       y2="345.06439" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3302"
+       id="radialGradient3316"
+       cx="200"
+       cy="125"
+       fx="200"
+       fy="125"
+       r="50"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,-1,0,250)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3302"
+       id="radialGradient3331"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.662898,0.7231039,-0.7293767,0.6686485,194.30678,-79.630422)"
+       cx="200"
+       cy="125"
+       fx="200"
+       fy="125"
+       r="50" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#363636"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.75686275"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="152.97332"
+     inkscape:cy="93.594381"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer4"
+     width="800px"
+     height="440px"
+     inkscape:window-width="910"
+     inkscape:window-height="624"
+     inkscape:window-x="4"
+     inkscape:window-y="47" />
+  <metadata
+     id="metadata2268">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     transform="translate(-150,-75)">
+    <path
+       style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 200,77.857143 C 173.88286,77.857143 152.85714,98.882857 152.85714,125 C 152.85714,151.11714 173.88286,172.14286 200,172.14286 C 226.11714,172.14286 247.14286,151.11714 247.14286,125 C 247.14286,98.882857 226.11714,77.857143 200,77.857143 z M 192.60446,93.532143 L 192.60446,114.275 L 207.39554,114.275 L 207.39554,93.532143 C 221.71682,96.858206 232.32232,109.63693 232.32232,125 C 232.32232,142.9089 217.9089,157.32232 200,157.32232 C 182.0911,157.32233 167.67768,142.9089 167.67768,125 C 167.67768,109.63693 178.28317,96.858206 192.60446,93.532143 z "
+       id="rect3295" />
+  </g>
+</svg>
diff --git a/attic/fluttr/libnflick/Makefile.am b/attic/fluttr/libnflick/Makefile.am
new file mode 100644 (file)
index 0000000..faf1134
--- /dev/null
@@ -0,0 +1,62 @@
+noinst_LTLIBRARIES = libnflick.la
+
+INCLUDES = \
+       $(DEPS_CFLAGS)
+       -I$(top_srcdir)                                 \
+       -I$(top_builddir)                               \
+       $(DEPS_CFLAGS)                                  \
+       -DDATADIR=\""$(datadir)"\"                      \
+       -DSYSCONFDIR=\""$(sysconfdir)"\"                \
+       $(NULL) 
+
+libnflick_la_SOURCES = \
+       nflick.h                                \
+       nflick-api-request.c                    \
+       nflick-api-request.h                    \
+       nflick-api-request-private.h            \
+       nflick-api-response.c                   \
+       nflick-api-response.h                   \
+       nflick-api-response-private.h           \
+       nflick-auth-worker.c                    \
+       nflick-auth-worker.h                    \
+       nflick-auth-worker-private.h            \
+       nflick-flickr.h                         \
+       nflick-get-sizes-response.c             \
+       nflick-get-sizes-response.h             \
+       nflick-get-sizes-response-private.h     \
+       nflick-gft-response.c                   \
+       nflick-gft-response.h                   \
+       nflick-gft-response-private.h           \
+       nflick-no-set-response.c                \
+       nflick-no-set-response.h                \
+       nflick-no-set-response-private.h        \
+       nflick-photo-data.c                     \
+       nflick-photo-data.h                     \
+       nflick-photo-list-response.c            \
+       nflick-photo-list-response.h            \
+       nflick-photo-list-response-private.h    \
+       nflick-photo-list-worker.c              \
+       nflick-photo-list-worker.h              \
+       nflick-photo-list-worker-private.h      \
+       nflick-photo-set.c                      \
+       nflick-photo-set.h                      \
+       nflick-photo-set-private.h              \
+       nflick-pixbuf-fetch.c                   \
+       nflick-pixbuf-fetch.h                   \
+       nflick-pixbuf-fetch-private.h           \
+       nflick-set-list-response.c              \
+       nflick-set-list-response.h              \
+       nflick-set-list-response-private.h      \
+       nflick-set-list-worker.c                \
+       nflick-set-list-worker.h                \
+       nflick-set-list-worker-private.h        \
+       nflick-show-worker.c                    \
+       nflick-show-worker.h                    \
+       nflick-show-worker-private.h            \
+       nflick-types.h                          \
+       nflick-worker.c                         \
+       nflick-worker.h                         \
+       nflick-worker-private.h
+
+libnflick_la_LIBADD = $(DEPS_LIBS)
+libnflick_la_LDFLAGS = -version-info 0:1:0
diff --git a/attic/fluttr/libnflick/nflick-api-request-private.h b/attic/fluttr/libnflick/nflick-api-request-private.h
new file mode 100644 (file)
index 0000000..99f84dd
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObjectClass*            ParentClass = NULL;
+
+struct                          _NFlickApiRequestPrivate
+{
+        GHashTable *Hash;
+        gchar *Buffer;
+        gint32 BytesRead;
+};
+
+static void                     nflick_api_request_class_init (NFlickApiRequestClass *klass);
+
+static void                     nflick_api_request_init (NFlickApiRequest *self);
+
+static gboolean                 private_init (NFlickApiRequest *self, NFlickApiRequestPrivate *private);
+
+static void                     private_dispose (NFlickApiRequestPrivate *private);
+
+static void                     nflick_api_request_dispose (NFlickApiRequest *self);
+
+static void                     nflick_api_request_finalize (NFlickApiRequest *self);
+
+static gchar*                   get_path (NFlickApiRequest *self);
+
+static void                     foreach_composer_list (gchar *param, gchar *val, GList **list);
+
+static void                     foreach_composer_str (gchar *val, gchar **str);
+
+static gchar*                   get_path_sig (NFlickApiRequest *self);
+
+static void                     foreach_composer_list_sig (gchar *param, gchar *val, GList **list);
+
+static void                     foreach_composer_str_sig (gchar *val, gchar **str);
+
+static int                      block_reader (NFlickApiRequest *self, gchar *buffer, int len);
+
diff --git a/attic/fluttr/libnflick/nflick-api-request.c b/attic/fluttr/libnflick/nflick-api-request.c
new file mode 100644 (file)
index 0000000..9986143
--- /dev/null
@@ -0,0 +1,396 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-api-request.h"
+#include "nflick-api-request-private.h"
+
+GType                           nflick_api_request_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickApiRequestClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_api_request_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickApiRequest), 
+                        4, 
+                        (GInstanceInitFunc) nflick_api_request_init,
+                };
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickApiRequest",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_api_request_class_init (NFlickApiRequestClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_api_request_dispose;
+        gobjectclass->finalize = (gpointer) nflick_api_request_finalize;
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+}
+
+static void                     nflick_api_request_init (NFlickApiRequest *self)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+
+        self->Private = NULL;
+
+        NFlickApiRequestPrivate *priv = g_new0 (NFlickApiRequestPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickApiRequest *self, NFlickApiRequestPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+        g_return_val_if_fail (private->Hash != NULL, FALSE);
+
+        private->Buffer = NULL;
+        private->BytesRead = 0;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickApiRequestPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Hash != NULL) {
+                g_hash_table_destroy (private->Hash);
+                private->Hash = NULL;
+        }
+
+        if (private->Buffer != NULL) {
+                g_free (private->Buffer);
+                private->Buffer = NULL;
+        }
+}
+
+static void                     nflick_api_request_dispose (NFlickApiRequest *self)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_api_request_finalize (NFlickApiRequest *self)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+NFlickApiRequest*               nflick_api_request_new (const gchar *method)
+{
+        g_return_val_if_fail (method != NULL, NULL);
+
+        NFlickApiRequest *self = g_object_new (NFLICK_TYPE_API_REQUEST, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        nflick_api_request_add_parameter (self, NFLICK_FLICKR_API_PARAM_METHOD, method);
+        nflick_api_request_add_parameter (self, NFLICK_FLICKR_API_PARAM_KEY, NFLICK_FLICKR_API_KEY);
+
+        return self;
+}
+
+void                            nflick_api_request_add_parameter (NFlickApiRequest *self, 
+                                                                  const gchar *param, const gchar *val)
+{
+        g_return_if_fail (NFLICK_IS_API_REQUEST (self));
+        g_return_if_fail (param != NULL);
+
+        g_hash_table_insert (self->Private->Hash, g_strdup (param), g_strdup (val));
+}
+
+static gchar*                   get_path (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), NULL);
+
+        GList *list = NULL;
+        gchar *str = NULL;
+        g_hash_table_foreach (self->Private->Hash, (GHFunc) foreach_composer_list, &list);
+        g_list_foreach (list, (GFunc) foreach_composer_str, &str);
+        g_list_foreach (list, (GFunc) g_free, NULL);
+
+        return str;
+}
+
+static gchar*                   get_path_sig (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), NULL);
+
+        GList *list = NULL;
+        gchar *str = g_strdup_printf ("%s", NFLICK_FLICKR_SHARED_SECRET);
+        g_hash_table_foreach (self->Private->Hash, (GHFunc) foreach_composer_list_sig, &list);
+        g_list_foreach (list, (GFunc) foreach_composer_str_sig, &str);
+        g_list_foreach (list, (GFunc) g_free, NULL);
+
+        return str;
+}
+
+static void                     foreach_composer_list (gchar *param, gchar *val, GList **list)
+{
+         /* Silently ignore empty vals */
+        if (param == NULL || list == NULL)
+                return;
+
+        gchar *str = g_strdup_printf ("%s=%s", param, val);
+        g_return_if_fail (str != NULL);
+
+        *list = g_list_insert_sorted (*list, str, (GCompareFunc) strcmp);
+}
+
+static void                     foreach_composer_str (gchar *val, gchar **str)
+{
+        /* Silently ignore empty vals */
+        if (val == NULL)
+                return;
+
+        gchar *old = *str;
+
+        if (*str != NULL) { 
+                *str = g_strdup_printf ("%s&%s", *str, val);
+                g_free (old);
+        } else
+                *str = g_strdup_printf ("%s", val);
+}
+
+static void                     foreach_composer_list_sig (gchar *param, gchar *val, GList **list)
+{
+         /* Silently ignore empty vals */
+        if (param == NULL || list == NULL)
+                return;
+
+        gchar *str = g_strdup_printf ("%s%s", param, val);
+        g_return_if_fail (str != NULL);
+
+        *list = g_list_insert_sorted (*list, str, (GCompareFunc) strcmp);
+}
+
+static void                     foreach_composer_str_sig (gchar *val, gchar **str)
+{
+        /* Silently ignore empty vals */
+        if (val == NULL)
+                return;
+
+        gchar *old = *str;
+
+        if (*str != NULL) { 
+                *str = g_strdup_printf ("%s%s", *str, val);
+                g_free (old);
+        } else
+                *str = g_strdup_printf ("%s", val);
+}
+
+gboolean                        nflick_api_request_sign (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), FALSE);
+
+        gchar *path_sig = NULL;
+        gpointer ctx = NULL;
+        gpointer ctx_output = NULL;
+        gchar *ascii = NULL;
+        gboolean res = TRUE;
+
+        path_sig = get_path_sig (self); 
+        if (path_sig == NULL)
+                goto Failure;
+
+        ctx = ne_md5_create_ctx ();
+        if (ctx == NULL)
+                goto Failure;
+
+        ne_md5_process_bytes (path_sig, strlen (path_sig), ctx);
+        ctx_output = g_malloc (16);
+        if (ctx_output == NULL)
+                goto Failure;
+
+        ne_md5_finish_ctx (ctx, ctx_output);
+        ascii = g_malloc (33);
+        if (ascii == NULL)
+                goto Failure;
+
+        ne_md5_to_ascii (ctx_output, ascii);
+        if (ascii [32] != 0)
+                goto Failure;
+
+        /* Now it's time to sign it... */
+        nflick_api_request_add_parameter (self, NFLICK_FLICKR_API_PARAM_SIGNATURE, ascii);
+
+        goto Finish;
+
+Failure:
+        res = FALSE;
+        g_warning ("Failure during md5 computation/signing");
+
+Finish:
+        if (path_sig != NULL)
+                g_free (path_sig);
+        if (ctx != NULL)
+                g_free (ctx);
+        if (ctx_output != NULL)
+                g_free (ctx_output);
+        if (ascii != NULL)
+                g_free (ascii);
+
+        return res;
+}
+
+static int                      block_reader (NFlickApiRequest *self, gchar *buffer, int len)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), -1);
+
+        if (self->Private->Buffer == NULL) {
+                self->Private->Buffer = g_malloc (len + 1);
+                memcpy (self->Private->Buffer, buffer, len);
+                self->Private->Buffer [len] = 0;
+                self->Private->BytesRead = 0;
+        } else {
+                gchar *old_ptr = self->Private->Buffer;
+                self->Private->Buffer = g_malloc (self->Private->BytesRead + len + 1);
+                memcpy (self->Private->Buffer, old_ptr, self->Private->BytesRead);
+                memcpy (self->Private->Buffer + self->Private->BytesRead, buffer, len);
+                self->Private->Buffer [len + self->Private->BytesRead] = 0;
+                
+                g_free (old_ptr);
+        }
+
+        self->Private->BytesRead += len;
+        return 0; 
+}
+
+gboolean                        nflick_api_request_exec (NFlickApiRequest *self)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), FALSE);
+
+        gchar *path_str = NULL;     /* The full path */
+        gchar *uri_str = NULL;      /* The actual uri to use */
+        ne_uri *uri = NULL;         /* Neon uri */
+        ne_request *request = NULL; /* Http request */
+        ne_session *session = NULL; /* Neon session */
+        gboolean result = TRUE;     /* result */
+
+        path_str = get_path (self);
+        if (path_str == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+        
+        uri_str = g_strdup_printf ("%s?%s", NFLICK_FLICKR_REST_END_POINT, path_str);
+        if (uri_str == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        uri = g_new0 (ne_uri, 1);
+        if (uri == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Fill-out the params */
+        uri->scheme = "http";
+        uri->port = ne_uri_defaultport (uri->scheme);  
+        uri->host = NFLICK_FLICKR_HOST;
+        uri->path = uri_str;
+
+        /* Create the session */
+        session = ne_session_create (uri->scheme, uri->host, uri->port);
+        if (session == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Create the request */
+        request = ne_request_create (session, "GET", uri->path);
+        if (request == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        ne_add_response_body_reader (request, ne_accept_always, (gpointer) block_reader, self);
+
+        result == (ne_request_dispatch (request) == NE_OK) ? TRUE : FALSE;
+        if (self->Private->Buffer == NULL)
+                result = FALSE;
+
+Done:
+        if (path_str != NULL)
+                g_free (path_str);
+
+        if (uri_str != NULL)
+                g_free (uri_str);
+
+        if (uri != NULL)
+                g_free (uri);
+
+        if (session != NULL)
+                ne_session_destroy (session);
+
+        if (request != NULL)
+                ne_request_destroy (request);
+
+        return result;
+}
+
+gchar*                          nflick_api_request_take_buffer (NFlickApiRequest *self)
+
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (self), NULL);
+
+        gchar *buf = self->Private->Buffer;
+        self->Private->Buffer = NULL;
+
+        return buf;
+}
diff --git a/attic/fluttr/libnflick/nflick-api-request.h b/attic/fluttr/libnflick/nflick-api-request.h
new file mode 100644 (file)
index 0000000..8853e46
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKAPIREQUEST_H__
+#define __NFLICKAPIREQUEST_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <ne_uri.h>
+#include <ne_session.h>
+#include <ne_basic.h>
+#include <ne_utils.h>
+#include <ne_md5.h>
+#include <string.h>
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickApiRequest
+{
+        GObject Parent;
+        NFlickApiRequestPrivate *Private;
+};
+
+struct                          _NFlickApiRequestClass 
+{
+        GObjectClass ParentClass;
+};
+
+GType                           nflick_api_request_get_type (void);
+
+NFlickApiRequest*               nflick_api_request_new (const gchar *method);
+
+void                            nflick_api_request_add_parameter (NFlickApiRequest *self, 
+                                                                  const gchar *param, const gchar *val);
+
+gboolean                        nflick_api_request_exec (NFlickApiRequest *self);
+
+gboolean                        nflick_api_request_sign (NFlickApiRequest *self);
+
+gchar*                          nflick_api_request_take_buffer (NFlickApiRequest *self);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-api-response-private.h b/attic/fluttr/libnflick/nflick-api-response-private.h
new file mode 100644 (file)
index 0000000..38bb074
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObjectClass*            ParentClass = NULL;
+
+struct                          _NFlickApiResponsePrivate
+{
+        gchar *Xml;
+        gchar *Error;
+        gboolean Success;
+        gboolean ParseError;
+};
+
+enum
+{
+        ARG_0,
+        ARG_ERROR,
+        ARG_PARSE_ERROR, 
+        ARG_XML, 
+        ARG_SUCCESS
+};
+
+static void                     nflick_api_response_class_init (NFlickApiResponseClass *klass);
+
+static void                     nflick_api_response_init (NFlickApiResponse *self);
+
+static gboolean                 private_init (NFlickApiResponse *self, NFlickApiResponsePrivate *private);
+
+static void                     private_dispose (NFlickApiResponsePrivate *private);
+
+static void                     nflick_api_response_dispose (NFlickApiResponse *self);
+
+static void                     nflick_api_response_finalize (NFlickApiResponse *self);
+
+static void                     nflick_api_response_get_property (NFlickApiResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec);
+
+
diff --git a/attic/fluttr/libnflick/nflick-api-response.c b/attic/fluttr/libnflick/nflick-api-response.c
new file mode 100644 (file)
index 0000000..1313a9d
--- /dev/null
@@ -0,0 +1,337 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-api-response.h"
+#include "nflick-api-response-private.h"
+
+GType                           nflick_api_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickApiResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_api_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickApiResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_api_response_init,
+                };
+                /* FIXME Make abstract type */
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickApiResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_api_response_class_init (NFlickApiResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_api_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_api_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_api_response_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_ERROR,
+                                         g_param_spec_string
+                                         ("error", "Error", "Message describing the error",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_SUCCESS,
+                                         g_param_spec_boolean 
+                                         ("success", "Success", "If the response is succesfull",
+                                         TRUE, G_PARAM_READABLE));
+        g_object_class_install_property (gobjectclass, ARG_PARSE_ERROR,
+                                         g_param_spec_boolean 
+                                         ("parseerror", "ParseError", "If the error was an xml parsing error",
+                                         FALSE, G_PARAM_READABLE));
+                                        
+        g_object_class_install_property (gobjectclass, ARG_XML,
+                                         g_param_spec_string
+                                         ("xml", "Xml", "Xml message source",
+                                         NULL, G_PARAM_READABLE));
+
+        klass->ParseFunc = NULL;
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+}
+
+static void                     nflick_api_response_init (NFlickApiResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+
+        self->Private = NULL;
+
+        NFlickApiResponsePrivate *priv = g_new0 (NFlickApiResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickApiResponse *self, NFlickApiResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_API_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Error = NULL;
+        private->Xml = NULL;
+        private->Success = TRUE;
+
+        return TRUE;
+}
+
+NFlickApiResponse*              nflick_api_response_new_from_request (GType type, NFlickApiRequest *request)
+{
+        g_return_val_if_fail (NFLICK_IS_API_REQUEST (request), NULL);
+
+        NFlickApiResponse *self = NULL;
+
+        gchar *buffer = nflick_api_request_take_buffer (request);
+        if (buffer == NULL)
+                goto Done;
+
+        self = g_object_new (type, NULL);
+        if (self == NULL)
+                goto Done;
+                
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                self = NULL;
+                goto Done;
+        }
+
+        nflick_api_response_parse (self, buffer);
+
+Done:
+        if (buffer != NULL)
+                g_free (buffer);
+
+        if (self != NULL)
+                return self;
+        else
+                g_return_val_if_reached (NULL);
+}
+
+static void                     private_dispose (NFlickApiResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Error != NULL) {
+                g_free (private->Error);
+                private->Error = NULL;
+        }
+
+        if (private->Xml != NULL) {
+                g_free (private->Xml);
+                private->Xml = NULL;
+        }
+}
+
+static void                     nflick_api_response_dispose (NFlickApiResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_api_response_finalize (NFlickApiResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+void                            nflick_api_response_set_error (NFlickApiResponse *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+        
+        if (self->Private->Error != NULL)
+                g_free (self->Private->Error);
+
+        self->Private->Error = (error != NULL) ? g_strdup (error) : NULL;
+}
+
+void                            nflick_api_response_add_error (NFlickApiResponse *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+
+        if (self->Private->Error == NULL)
+                nflick_api_response_set_error (self, error);
+        else if (error != NULL) {
+                gchar *sum = g_strdup_printf ("%s\n%s", self->Private->Error, error);
+                g_free (self->Private->Error);
+                self->Private->Error = sum;
+        } else
+                self->Private->Error = NULL;
+}
+
+gboolean                        nflick_api_response_parse (NFlickApiResponse *self, const gchar *xml)
+{
+        g_return_val_if_fail (NFLICK_IS_API_RESPONSE (self), FALSE);
+        g_return_val_if_fail (xml != NULL, FALSE);
+        g_return_val_if_fail (self->Private->Xml == NULL, FALSE);
+        g_return_val_if_fail (NFLICK_API_RESPONSE_GET_CLASS (self)->ParseFunc != NULL, FALSE);
+
+        self->Private->Xml = g_strdup (xml);
+
+        xmlDoc *doc = NULL;           /* The xml tree element */
+        xmlNode *root_element = NULL; /* Root element to start parsing */
+        gboolean result = TRUE;       /* If we were sucesfull */
+        gboolean parse_error = FALSE; /* If the error was a parsing error */
+        gchar *stat = NULL;           /* Response stat */
+
+        /* Start here */
+        doc = xmlReadMemory (xml, strlen (xml), NULL, NULL, 0); 
+        if (doc == NULL) {
+                nflick_api_response_add_error (self, gettext ("Couldn't create the xml tree."));
+                result = FALSE;
+                parse_error = TRUE;
+                goto Done;
+        }
+
+        root_element = xmlDocGetRootElement(doc);
+        if (root_element == NULL) {
+                nflick_api_response_add_error (self, gettext ("Couldn't get xml root element."));
+                result = FALSE;
+                parse_error = TRUE;
+                goto Done;
+        }
+
+        if (root_element->type != XML_ELEMENT_NODE || 
+            strcmp (root_element->name, "rsp") != 0) {
+                nflick_api_response_add_error (self, gettext ("Rsp xml root expected, but was not found."));
+                parse_error = TRUE;
+                result = FALSE;
+                goto Done;
+        }
+
+        stat = xmlGetProp (root_element, "stat");
+        if (stat == NULL) {
+                nflick_api_response_add_error (self, gettext ("Response has not stat property."));
+                parse_error = TRUE;
+                result = FALSE;
+                goto Done;
+        }
+        
+        if (strcmp (stat, "ok") == 0) 
+                result = TRUE;
+        else if (strcmp (stat, "fail") == 0) 
+                result = FALSE;
+        else {
+                nflick_api_response_add_error (self, gettext ("Unknown response."));
+                parse_error = TRUE;
+                result = FALSE;
+                goto Done;
+        }
+
+        if (root_element->children == NULL)
+                goto Done;
+
+        xmlNode *cur_node = NULL;
+
+        /* Do the main parsing */
+        for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "err") == 0) {
+                        gchar *err = xmlGetProp (cur_node, "msg");
+                        result = FALSE;
+                        if (err != NULL) { 
+                                nflick_api_response_set_error (self, err);
+                                g_free (err);
+                        }
+                }
+        }
+
+        if (result == FALSE)
+                goto Done;
+
+        /* Forward to our parse func */
+        NFLICK_API_RESPONSE_GET_CLASS (self)->ParseFunc (self, doc, root_element->children, &result, &parse_error);
+
+Done:
+        /* Free */
+        if (doc != NULL) 
+                xmlFreeDoc (doc);
+
+        if (stat != NULL)
+                g_free (stat);
+
+        if (result == FALSE && self->Private->Error == NULL)
+                nflick_api_response_set_error (self, gettext ("Failed to parse xml tree. Unknown error"));
+
+        if (result == FALSE && parse_error == TRUE)
+                g_warning ("Failed to parse xml tree. Error: %s", self->Private->Error);
+        
+        self->Private->Success = result;
+        self->Private->ParseError = parse_error;
+        return result;
+}
+
+static void                     nflick_api_response_get_property (NFlickApiResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec)
+
+{
+        g_return_if_fail (NFLICK_IS_API_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_ERROR:
+                        g_value_set_string (value, self->Private->Error);
+                break;
+        
+                case ARG_PARSE_ERROR:
+                        g_value_set_boolean (value, self->Private->ParseError);
+                break;
+                case ARG_SUCCESS:
+                        g_value_set_boolean (value, self->Private->Success);
+                break;
+       
+                case ARG_XML:
+                        g_value_set_string (value, self->Private->Xml);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-api-response.h b/attic/fluttr/libnflick/nflick-api-response.h
new file mode 100644 (file)
index 0000000..9778872
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKAPIRESPONSE_H__
+#define __NFLICKAPIRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-api-request.h"
+
+struct                          _NFlickApiResponse
+{
+        GObject Parent;
+        NFlickApiResponsePrivate *Private;
+};
+
+struct                          _NFlickApiResponseClass 
+{
+        GObjectClass ParentClass;
+        NFlickApiRequestParseFunc ParseFunc;
+};
+
+GType                           nflick_api_response_get_type (void);
+
+void                            nflick_api_response_set_error (NFlickApiResponse *self, const gchar *error);
+
+void                            nflick_api_response_add_error (NFlickApiResponse *self, const gchar *error);
+
+gboolean                        nflick_api_response_parse (NFlickApiResponse *self, const gchar *xml);
+
+NFlickApiResponse*              nflick_api_response_new_from_request (GType type, NFlickApiRequest *request);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-auth-worker-private.h b/attic/fluttr/libnflick/nflick-auth-worker-private.h
new file mode 100644 (file)
index 0000000..dfdbdac
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickAuthWorkerPrivate
+{
+        gchar *MiniToken;
+        gchar *UserName;
+        gchar *FullName;
+        gchar *Token;
+        gchar *UserNsid;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_USER_NAME,
+        ARG_FULL_NAME,
+        ARG_TOKEN,
+        ARG_USER_NSID
+};
+
+static void                     nflick_auth_worker_class_init (NFlickAuthWorkerClass *klass);
+
+static void                     nflick_auth_worker_init (NFlickAuthWorker *self);
+
+static gboolean                 private_init (NFlickAuthWorker *self, NFlickAuthWorkerPrivate *private);
+
+static void                     private_dispose (NFlickAuthWorkerPrivate *private);
+
+static void                     nflick_auth_worker_dispose (NFlickAuthWorker *self);
+
+static void                     nflick_auth_worker_finalize (NFlickAuthWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickAuthWorker *self);
+
+static void                     nflick_auth_worker_get_property (NFlickAuthWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec);
+
diff --git a/attic/fluttr/libnflick/nflick-auth-worker.c b/attic/fluttr/libnflick/nflick-auth-worker.c
new file mode 100644 (file)
index 0000000..c23d610
--- /dev/null
@@ -0,0 +1,278 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-auth-worker.h"
+#include "nflick-auth-worker-private.h"
+
+GType                           nflick_auth_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickAuthWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_auth_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickAuthWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_auth_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickAuthWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_auth_worker_class_init (NFlickAuthWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_auth_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_auth_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_auth_worker_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_TOKEN,
+                                         g_param_spec_string
+                                         ("token", "Token", "Unique flick full token",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NAME,
+                                         g_param_spec_string
+                                         ("username", "UserName", "Flickr user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_FULL_NAME,
+                                         g_param_spec_string
+                                         ("fullname", "FullName", "Flickr full user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NSID,
+                                         g_param_spec_string
+                                         ("usernsid", "UserNsid", "Unique nsid identyfying user in flickr",
+                                         NULL, G_PARAM_READABLE));
+
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_auth_worker_init (NFlickAuthWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickAuthWorkerPrivate *priv = g_new0 (NFlickAuthWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Authorizing token..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickAuthWorker *self, NFlickAuthWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_AUTH_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->MiniToken = NULL;
+        private->UserName = NULL;
+        private->FullName = NULL;
+        private->UserNsid = NULL;
+        private->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickAuthWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->MiniToken != NULL) {
+                g_free (private->MiniToken);
+                private->MiniToken = NULL;
+        }
+
+        if (private->UserName != NULL) {
+                g_free (private->UserName);
+                private->UserName = NULL;
+        }
+
+        if (private->FullName != NULL) {
+                g_free (private->FullName);
+                private->FullName = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->UserNsid != NULL) {
+                g_free (private->UserNsid);
+                private->UserNsid = NULL;
+        }
+}
+
+static void                     nflick_auth_worker_dispose (NFlickAuthWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_auth_worker_finalize (NFlickAuthWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickAuthWorker *self)
+{
+        NFlickApiRequest *full_token_request = NULL; 
+        NFlickApiResponse *full_token_response = NULL;
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+
+        full_token_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_GET_FULL_TOKEN);
+        if (full_token_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (full_token_request, 
+                                          NFLICK_FLICKR_API_PARAM_MINI_TOKEN, 
+                                          self->Private->MiniToken);
+
+        nflick_api_request_sign (full_token_request);
+        
+        if (nflick_api_request_exec (full_token_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        full_token_response = nflick_api_response_new_from_request (NFLICK_TYPE_GFT_RESPONSE, full_token_request);
+        if (full_token_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, full_token_response) == FALSE)
+                goto Error;
+
+        /* Get out variables */
+        g_object_get (G_OBJECT (full_token_response), 
+                      "username", &self->Private->UserName,
+                      "fullname", &self->Private->FullName,
+                      "usernsid", &self->Private->UserNsid,
+                      "token", &self->Private->Token, NULL);
+
+        if (self->Private->UserName == NULL ||
+            self->Private->FullName == NULL ||
+            self->Private->Token == NULL ||
+            self->Private->UserNsid == NULL)
+                goto Error;
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (full_token_request != NULL) 
+                g_object_unref (full_token_request);
+
+        if (full_token_response != NULL) 
+                g_object_unref (full_token_response);
+
+        return status;
+}
+
+NFlickAuthWorker*               nflick_auth_worker_new (const gchar *minitoken)
+{
+        g_return_val_if_fail (minitoken != NULL, NULL);
+
+        NFlickAuthWorker *self = g_object_new (NFLICK_TYPE_AUTH_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->MiniToken = g_strdup (minitoken);
+        
+        return self;
+}
+
+static void                     nflick_auth_worker_get_property (NFlickAuthWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_AUTH_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_USER_NAME:
+                        g_value_set_string (value, self->Private->UserName);
+                break;
+        
+                case ARG_FULL_NAME:
+                        g_value_set_string (value, self->Private->FullName);
+                break;
+                case ARG_TOKEN:
+                        g_value_set_string (value, self->Private->Token);
+                break;
+       
+                case ARG_USER_NSID:
+                        g_value_set_string (value, self->Private->UserNsid);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-auth-worker.h b/attic/fluttr/libnflick/nflick-auth-worker.h
new file mode 100644 (file)
index 0000000..807e4ec
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKAUTHWORKER_H__
+#define __NFLICKAUTHWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-gft-response.h"
+#include "nflick-types.h"
+
+struct                          _NFlickAuthWorker
+{
+        NFlickWorker Parent;
+        NFlickAuthWorkerPrivate *Private;
+};
+
+struct                          _NFlickAuthWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_auth_worker_get_type (void);
+
+NFlickAuthWorker*               nflick_auth_worker_new (const gchar *minitoken);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-flickr.h b/attic/fluttr/libnflick/nflick-flickr.h
new file mode 100644 (file)
index 0000000..2183262
--- /dev/null
@@ -0,0 +1,69 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKFLICKR_H__
+#define __NFLICKFLICKR_H__
+
+/* Some stock stuff obtained from flickr. That's public, really */
+
+#define                         NFLICK_FLICKR_API_KEY "97f40c6445ca8243d52fff461308fb18"
+
+#define                         NFLICK_FLICKR_SHARED_SECRET "2d434592f898e1ab"
+
+#define                         NFLICK_FLICKR_HOST "www.flickr.com"
+
+#define                         NFLICK_FLICKR_REST_END_POINT "/services/rest/"
+
+/* Request parameters */
+
+#define                         NFLICK_FLICKR_API_PARAM_KEY "api_key"
+
+#define                         NFLICK_FLICKR_API_PARAM_METHOD "method"
+
+#define                         NFLICK_FLICKR_API_PARAM_MINI_TOKEN "mini_token"
+
+#define                         NFLICK_FLICKR_API_PARAM_TOKEN "auth_token"
+
+#define                         NFLICK_FLICKR_API_PARAM_SIGNATURE "api_sig"
+
+#define                         NFLICK_FLICKR_API_PARAM_USER_ID "user_id"
+
+#define                         NFLICK_FLICKR_API_PARAM_PHOTOSET_ID "photoset_id"
+
+#define                         NFLICK_FLICKR_API_PARAM_PHOTO_ID "photo_id"
+
+#define                         NFLICK_FLICKR_API_PARAM_PER_PAGE "per_page"
+
+/* Possible methods */
+
+#define                         NFLICK_FLICKR_API_METHOD_GET_FULL_TOKEN "flickr.auth.getFullToken"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_LIST "flickr.photosets.getList"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_PHOTOS "flickr.photosets.getPhotos"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOS_GET_SIZES "flickr.photos.getSizes"
+
+#define                         NFLICK_FLICKR_API_METHOD_PHOTOS_NOT_IN_SET "flickr.photos.getNotInSet"
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-get-sizes-response-private.h b/attic/fluttr/libnflick/nflick-get-sizes-response-private.h
new file mode 100644 (file)
index 0000000..4853bd5
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickGetSizesResponsePrivate
+{
+        GList *SizesList;
+};
+
+struct                          _SizeData
+{
+        gchar *Uri;
+        gint32 Width;
+        gint32 Height;
+} typedef SizeData;
+
+static void                     nflick_get_sizes_response_class_init (NFlickGetSizesResponseClass *klass);
+
+static void                     nflick_get_sizes_response_init (NFlickGetSizesResponse *self);
+
+static gboolean                 private_init (NFlickGetSizesResponse *self, NFlickGetSizesResponsePrivate *private);
+
+static void                     private_dispose (NFlickGetSizesResponsePrivate *private);
+
+static void                     nflick_get_sizes_response_dispose (NFlickGetSizesResponse *self);
+
+static void                     nflick_get_sizes_response_finalize (NFlickGetSizesResponse *self);
+
+static void                     parse_func (NFlickGetSizesResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
diff --git a/attic/fluttr/libnflick/nflick-get-sizes-response.c b/attic/fluttr/libnflick/nflick-get-sizes-response.c
new file mode 100644 (file)
index 0000000..d7cf12a
--- /dev/null
@@ -0,0 +1,304 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-get-sizes-response.h"
+#include "nflick-get-sizes-response-private.h"
+
+GType                           nflick_get_sizes_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickGetSizesResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_get_sizes_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickGetSizesResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_get_sizes_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickGetSizesResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_get_sizes_response_class_init (NFlickGetSizesResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_get_sizes_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_get_sizes_response_finalize;
+
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_get_sizes_response_init (NFlickGetSizesResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickGetSizesResponsePrivate *priv = g_new0 (NFlickGetSizesResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickGetSizesResponse *self, NFlickGetSizesResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->SizesList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickGetSizesResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->SizesList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->SizesList; iterator; iterator = g_list_next (iterator)) {
+                        SizeData *data = (SizeData *) iterator->data;
+                        if (data != NULL) {
+                                if (data->Uri != NULL)
+                                        g_free (data->Uri);
+
+                                g_free (data);
+                        }
+                }
+
+                g_list_free (private->SizesList);
+                private->SizesList = NULL;
+        }
+}
+
+static void                     nflick_get_sizes_response_dispose (NFlickGetSizesResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_get_sizes_response_finalize (NFlickGetSizesResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickGetSizesResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "sizes") == 0) {
+
+                        xmlNode *sizes_node = NULL;
+                        for (sizes_node = cur_node->children; sizes_node; sizes_node = sizes_node->next) {
+                                
+                                if (sizes_node->type == XML_ELEMENT_NODE && strcmp (sizes_node->name, "size") == 0) {
+
+                                        gint32 width_val = -1;
+                                        gint32 height_val = -1;
+                                        gchar *width = xmlGetProp (sizes_node, "width");
+                                        gchar *height = xmlGetProp (sizes_node, "height");
+                                        gchar *source = xmlGetProp (sizes_node, "source");
+
+                                        if (width != NULL)
+                                                width_val = atoi (width);
+
+                                        if (height != NULL)
+                                                height_val = atoi (height);
+
+                                        if (width != NULL && height != NULL && source != NULL && 
+                                            width_val > 0 && height_val > 0) {
+                                                SizeData *data = g_new0 (SizeData, 1);
+                                                data->Uri = g_strdup (source);
+                                                data->Width = width_val;
+                                                data->Height = height_val;
+                                                self->Private->SizesList = g_list_append (self->Private->SizesList, data);
+                                        }
+
+                                        if (width != NULL)
+                                                g_free (width);
+                                        if (height != NULL)
+                                                g_free (height);
+                                        if (source != NULL)
+                                                g_free (source);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+/* FIXME: Make private */
+gint32                          nflick_get_sizes_response_height_for (gint32 width, gint32 height, gint32 fit_width)
+{
+        g_return_val_if_fail (width > 0, -1);
+        g_return_val_if_fail (height > 0, -1);
+        g_return_val_if_fail (fit_width > 0, -1);
+
+        gdouble aspect = (gdouble) height / (gdouble) width;
+        return aspect * (gdouble) fit_width;
+}
+
+/* FIXME: Make private */
+gint32                          nflick_get_sizes_response_width_for (gint32 width, gint32 height, gint32 fit_height)
+{
+        g_return_val_if_fail (width > 0, -1);
+        g_return_val_if_fail (height > 0, -1);
+        g_return_val_if_fail (fit_height > 0, -1);
+
+        gdouble aspect = (gdouble) width / (gdouble) height;
+        return aspect * (gdouble) fit_height;
+}
+
+gchar*                          nflick_get_sizes_response_find_match (NFlickGetSizesResponse *self, gint32 *width, gint32 *height, gboolean *rotated)
+{
+        g_return_val_if_fail (NFLICK_IS_GET_SIZES_RESPONSE (self), NULL);
+        g_return_val_if_fail (width != NULL, NULL);
+        g_return_val_if_fail (height != NULL, NULL);
+        g_return_val_if_fail (rotated != NULL, NULL);
+        g_return_val_if_fail (*width > 0, NULL);
+        g_return_val_if_fail (*height > 0, NULL);
+
+        GList *iterator;
+        gchar *current_source = NULL;
+        gint32 current_distance = 10000; /* FIXME: Max int */
+        gdouble out_aspect = (gdouble) *height / (gdouble) *width;
+        gint32 out_width = -1;
+        gint32 out_height = -1;
+        gboolean out_rotated = FALSE;
+        
+        for (iterator = self->Private->SizesList; iterator; iterator = g_list_next (iterator)) {
+                SizeData *data = (SizeData *) iterator->data;
+                g_assert (data != NULL);
+
+                gdouble in_aspect = (gdouble) data->Height / (gdouble) data->Width;
+
+                gint32 x_distance = 0;
+                gint32 y_distance = 0;
+                gint32 distance = 0;
+
+                // FIXME: We should analyze the input width and height here!
+                if (in_aspect > 1.0) {
+                        x_distance = abs (data->Width - *height);
+                        y_distance = abs (data->Height - *width);
+
+                        if (data->Width < *height)
+                                x_distance *= 2;
+                        if (data->Height < *width)
+                                y_distance *= 2;
+
+                        distance = x_distance + y_distance;
+
+                        if (distance < current_distance) {
+                                current_distance = distance;
+                                current_source = data->Uri;
+                                out_rotated = TRUE;
+
+                                /* Now let's try doing the fitting */
+                                in_aspect = (gdouble) data->Width / (gdouble) data->Height;
+                                if (in_aspect > out_aspect) {
+                                        out_width = *height;
+                                        out_height = nflick_get_sizes_response_height_for (data->Width, data->Height, out_width);
+                                } else {
+                                        out_height = *width;
+                                        out_width= nflick_get_sizes_response_width_for (data->Width, data->Height, out_height);
+                                }
+                        }
+                } else {
+                        x_distance = abs (data->Width - *width);
+                        y_distance = abs (data->Height - *height);
+
+                        if (data->Width < *width)
+                                x_distance *= 2;
+                        if (data->Height < *height)
+                                y_distance *= 2;
+
+                        distance = x_distance + y_distance;
+
+                        if (distance < current_distance) {
+                                current_distance = distance;
+                                current_source = data->Uri;
+                                out_rotated = FALSE;
+                                
+                                /* Now let's try doing the fitting */
+                                if (in_aspect > out_aspect) {
+                                        out_height = *height;
+                                        out_width = nflick_get_sizes_response_width_for (data->Width, data->Height, out_height);
+                                } else {
+                                        out_width = *width;
+                                        out_height = nflick_get_sizes_response_height_for (data->Width, data->Height, out_width);
+                                }
+                        }
+
+
+                }
+        }
+
+        *width = out_width;
+        *height = out_height;
+        *rotated = out_rotated;
+
+        if (current_source != NULL)
+                return g_strdup (current_source);
+        else
+                return NULL;
+}
diff --git a/attic/fluttr/libnflick/nflick-get-sizes-response.h b/attic/fluttr/libnflick/nflick-get-sizes-response.h
new file mode 100644 (file)
index 0000000..bf2a304
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKGETSIZESRESPONSE_H__
+#define __NFLICKGETSIZESRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickGetSizesResponse
+{
+        NFlickApiResponse Parent;
+        NFlickGetSizesResponsePrivate *Private;
+};
+
+struct                          _NFlickGetSizesResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_get_sizes_response_get_type (void);
+
+gchar*                          nflick_get_sizes_response_find_match (NFlickGetSizesResponse *self, gint32 *width, gint32 *height, gboolean *rotated);
+
+gint32                          nflick_get_sizes_response_height_for (gint32 width, gint32 height, gint32 fit_width);
+
+gint32                          nflick_get_sizes_response_width_for (gint32 width, gint32 height, gint32 fit_height);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-gft-response-private.h b/attic/fluttr/libnflick/nflick-gft-response-private.h
new file mode 100644 (file)
index 0000000..dd8a54d
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickGftResponsePrivate
+{
+        gchar *UserName;
+        gchar *UserNsid;
+        gchar *FullName;
+        gchar *Token;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_USER_NAME,
+        ARG_FULL_NAME,
+        ARG_TOKEN,
+        ARG_USER_NSID
+};
+
+static void                     nflick_gft_response_class_init (NFlickGftResponseClass *klass);
+
+static void                     nflick_gft_response_init (NFlickGftResponse *self);
+
+static gboolean                 private_init (NFlickGftResponse *self, NFlickGftResponsePrivate *private);
+
+static void                     private_dispose (NFlickGftResponsePrivate *private);
+
+static void                     nflick_gft_response_dispose (NFlickGftResponse *self);
+
+static void                     nflick_gft_response_finalize (NFlickGftResponse *self);
+
+static void                     parse_func (NFlickGftResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static gboolean                 all_fields_valid (NFlickGftResponse *self);
+
+static void                     fill_blanks (NFlickGftResponse *self);
+
+static void                     nflick_gft_response_get_property (NFlickGftResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec);
diff --git a/attic/fluttr/libnflick/nflick-gft-response.c b/attic/fluttr/libnflick/nflick-gft-response.c
new file mode 100644 (file)
index 0000000..a38e04d
--- /dev/null
@@ -0,0 +1,281 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-gft-response.h"
+#include "nflick-gft-response-private.h"
+
+GType                           nflick_gft_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickGftResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_gft_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickGftResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_gft_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickGftResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_gft_response_class_init (NFlickGftResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_gft_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_gft_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_gft_response_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_TOKEN,
+                                         g_param_spec_string
+                                         ("token", "Token", "Unique flick full token",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NAME,
+                                         g_param_spec_string
+                                         ("username", "UserName", "Flickr user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_FULL_NAME,
+                                         g_param_spec_string
+                                         ("fullname", "FullName", "Flickr full user name",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_USER_NSID,
+                                         g_param_spec_string
+                                         ("usernsid", "UserNsid", "Unique nsid identyfying user in flickr",
+                                         NULL, G_PARAM_READABLE));
+
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_gft_response_init (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickGftResponsePrivate *priv = g_new0 (NFlickGftResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickGftResponse *self, NFlickGftResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_GFT_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->UserName = NULL;
+        private->FullName = NULL;
+        private->Token = NULL;
+        private->UserNsid = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickGftResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->UserName != NULL) {
+                g_free (private->UserName);
+                private->UserName = NULL;
+        }
+
+        if (private->FullName != NULL) {
+                g_free (private->FullName);
+                private->FullName = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->UserNsid != NULL) {
+                g_free (private->UserNsid);
+                private->UserNsid = NULL;
+        }
+}
+
+
+static void                     nflick_gft_response_dispose (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_gft_response_finalize (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static gboolean                 all_fields_valid (NFlickGftResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_GFT_RESPONSE (self), FALSE);
+
+        if (self->Private->UserNsid != NULL && self->Private->Token != NULL)
+                return TRUE;
+        else
+                return FALSE;
+}
+
+static void                     fill_blanks (NFlickGftResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+
+        if (self->Private->UserName == NULL)
+                self->Private->UserName = g_strdup (gettext ("anonymous"));
+        
+        if (self->Private->FullName == NULL)
+                self->Private->FullName = g_strdup (gettext ("Anonymous"));
+}
+
+static void                     parse_func (NFlickGftResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "auth") == 0) {
+                        
+                        xmlNode *auth_node = NULL;
+                        for (auth_node = cur_node->children; auth_node; auth_node = auth_node->next) {
+                                
+                                /* <user> */
+                                if (auth_node->type == XML_ELEMENT_NODE && strcmp (auth_node->name, "user") == 0) {
+
+                                        /* Nsid */
+                                        gchar *nsid = xmlGetProp (auth_node, "nsid");
+                                        if (nsid != NULL) {
+                                                if (self->Private->UserNsid != NULL)
+                                                        g_free (self->Private->UserNsid);
+                                                self->Private->UserNsid = nsid;
+                                        }
+
+                                        /* UserName */
+                                        gchar *username = xmlGetProp (auth_node, "username");
+                                        if (username != NULL) {
+                                                if (self->Private->UserName != NULL)
+                                                        g_free (self->Private->UserName);
+                                                self->Private->UserName = username;
+                                        }
+
+                                        /* FullName */
+                                        gchar *fullname = xmlGetProp (auth_node, "fullname");
+                                        if (fullname != NULL) {
+                                                if (self->Private->FullName != NULL)
+                                                        g_free (self->Private->FullName);
+                                                self->Private->FullName = fullname;
+                                        }
+                                }
+
+                                /* <token> */
+                                if (auth_node->type == XML_ELEMENT_NODE && strcmp (auth_node->name, "token") == 0) {
+                                        char *token = xmlNodeListGetString (doc, auth_node->xmlChildrenNode, 1);
+                                        if (token != NULL) {
+                                                if (self->Private->Token != NULL)
+                                                        g_free (self->Private->Token);
+                                                self->Private->Token = token;
+                                        }
+                                }               
+                        }
+                }
+        }
+
+        /* Finished */
+        if (all_fields_valid (self) == TRUE) {
+                fill_blanks (self);
+                *result = TRUE;
+                *parse_error = FALSE;
+        } else {
+                *result = FALSE;
+                *parse_error = TRUE;
+                nflick_api_response_add_error ((NFlickApiResponse *) self, 
+                                               gettext ("Some of the required info is missing from the response!"));
+        }
+}
+
+static void                     nflick_gft_response_get_property (NFlickGftResponse *self, guint propid, 
+                                                                  GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_GFT_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_USER_NAME:
+                        g_value_set_string (value, self->Private->UserName);
+                break;
+        
+                case ARG_FULL_NAME:
+                        g_value_set_string (value, self->Private->FullName);
+                break;
+                case ARG_TOKEN:
+                        g_value_set_string (value, self->Private->Token);
+                break;
+       
+                case ARG_USER_NSID:
+                        g_value_set_string (value, self->Private->UserNsid);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-gft-response.h b/attic/fluttr/libnflick/nflick-gft-response.h
new file mode 100644 (file)
index 0000000..cd67b4a
--- /dev/null
@@ -0,0 +1,49 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKGFTRESPONSE_H__
+#define __NFLICKGFTRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+
+struct                          _NFlickGftResponse
+{
+        NFlickApiResponse Parent;
+        NFlickGftResponsePrivate *Private;
+};
+
+struct                          _NFlickGftResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_gft_response_get_type (void);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-no-set-response-private.h b/attic/fluttr/libnflick/nflick-no-set-response-private.h
new file mode 100644 (file)
index 0000000..e71c6aa
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickNoSetResponsePrivate
+{
+        GList *PhotoDataList;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_no_set_response_class_init (NFlickNoSetResponseClass *klass);
+
+static void                     nflick_no_set_response_init (NFlickNoSetResponse *self);
+
+static gboolean                 private_init (NFlickNoSetResponse *self, NFlickNoSetResponsePrivate *private);
+
+static void                     private_dispose (NFlickNoSetResponsePrivate *private);
+
+static void                     nflick_no_set_response_dispose (NFlickNoSetResponse *self);
+
+static void                     nflick_no_set_response_finalize (NFlickNoSetResponse *self);
+
+static void                     parse_func (NFlickNoSetResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_no_set_response_get_property (NFlickNoSetResponse *self, guint propid, 
+                                                                     GValue *value, GParamSpec *pspec);
diff --git a/attic/fluttr/libnflick/nflick-no-set-response.c b/attic/fluttr/libnflick/nflick-no-set-response.c
new file mode 100644 (file)
index 0000000..b215c4e
--- /dev/null
@@ -0,0 +1,199 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-no-set-response.h"
+#include "nflick-no-set-response-private.h"
+
+GType                           nflick_no_set_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickNoSetResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_no_set_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickNoSetResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_no_set_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickNoSetResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_no_set_response_class_init (NFlickNoSetResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_no_set_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_no_set_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_no_set_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_no_set_response_init (NFlickNoSetResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickNoSetResponsePrivate *priv = g_new0 (NFlickNoSetResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickNoSetResponse *self, NFlickNoSetResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_NO_SET_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickNoSetResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_no_set_response_dispose (NFlickNoSetResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_no_set_response_finalize (NFlickNoSetResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickNoSetResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "photos") == 0) {
+
+                        xmlNode *set_node = NULL;
+                        for (set_node = cur_node->children; set_node; set_node = set_node->next) {
+                                
+                                if (set_node->type == XML_ELEMENT_NODE && strcmp (set_node->name, "photo") == 0) {
+
+                                        gchar *id = xmlGetProp (set_node, "id");
+                                        gchar *name = xmlGetProp (set_node, "title");
+
+                                        if (id != NULL && name != NULL) {
+                                                NFlickPhotoData *photo_data = nflick_photo_data_new (id, name);
+
+                                                /* We prepend to add photos in reverse order. Flickr seems to return
+                                                 * photos in oldest-to-newest order */
+
+                                                if (photo_data != NULL) 
+                                                        self->Private->PhotoDataList = g_list_prepend (self->Private->PhotoDataList, photo_data);
+                                        }
+
+                                        if (id != NULL)
+                                                g_free (id);
+                                        if (name != NULL)
+                                                g_free (name);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+static void                     nflick_no_set_response_get_property (NFlickNoSetResponse *self, guint propid, 
+                                                                     GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_NO_SET_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
+
+GList*                          nflick_no_set_response_take_list (NFlickNoSetResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_NO_SET_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoDataList;
+        self->Private->PhotoDataList = NULL;
+
+        return lst;
+}
+
+
diff --git a/attic/fluttr/libnflick/nflick-no-set-response.h b/attic/fluttr/libnflick/nflick-no-set-response.h
new file mode 100644 (file)
index 0000000..623c42f
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKNOSETRESPONSE_H__
+#define __NFLICKNOSETRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-data.h"
+
+struct                          _NFlickNoSetResponse
+{
+        NFlickApiResponse Parent;
+        NFlickNoSetResponsePrivate *Private;
+};
+
+struct                          _NFlickNoSetResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_no_set_response_get_type (void);
+
+GList*                          nflick_no_set_response_take_list (NFlickNoSetResponse *self);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-photo-data.c b/attic/fluttr/libnflick/nflick-photo-data.c
new file mode 100644 (file)
index 0000000..9954732
--- /dev/null
@@ -0,0 +1,75 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-data.h"
+
+GType                           nflick_photo_data_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+                objecttype = g_boxed_type_register_static 
+                        ("NFlickPhotoData", 
+                         (GBoxedCopyFunc) nflick_photo_data_copy,
+                         (GBoxedFreeFunc) nflick_photo_data_free);
+        }
+        
+        return objecttype;
+}
+
+NFlickPhotoData*                nflick_photo_data_copy (const NFlickPhotoData *self)
+{
+        g_return_val_if_fail (self != NULL, NULL);
+
+        NFlickPhotoData *new = g_new (NFlickPhotoData, 1);
+        g_return_val_if_fail (new != NULL, NULL);
+
+        new->Id = (self->Id != NULL) ? g_strdup (self->Id) : NULL;
+        new->Name = (self->Name != NULL) ? g_strdup (self->Name) : NULL;
+        return new;
+}
+
+void                            nflick_photo_data_free (NFlickPhotoData *self)
+{
+        if (self == NULL)
+                return;
+        else {
+                if (self->Id != NULL)
+                        g_free (self->Id);
+                if (self->Name != NULL)
+                        g_free (self->Name);
+                g_free (self);
+        }
+}
+
+NFlickPhotoData*                nflick_photo_data_new (const gchar *id, const gchar *name)
+{
+        NFlickPhotoData *self = g_new (NFlickPhotoData, 1);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        self->Id = (id != NULL) ? g_strdup (id) : NULL;
+        self->Name = (name != NULL) ? g_strdup (name) : NULL;
+
+        return self;
+}
diff --git a/attic/fluttr/libnflick/nflick-photo-data.h b/attic/fluttr/libnflick/nflick-photo-data.h
new file mode 100644 (file)
index 0000000..5a156d2
--- /dev/null
@@ -0,0 +1,44 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTODATA_H__
+#define __NFLICKPHOTODATA_H__
+
+#include <gtk/gtk.h>
+#include "nflick-types.h"
+
+struct _NFlickPhotoData
+{
+        gchar *Id;
+        gchar *Name;
+};
+
+GType                           nflick_photo_data_get_type (void);
+
+NFlickPhotoData*                nflick_photo_data_copy (const NFlickPhotoData *self);
+
+void                            nflick_photo_data_free (NFlickPhotoData *self);
+
+NFlickPhotoData*                nflick_photo_data_new (const gchar *id, const gchar *name);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-photo-list-response-private.h b/attic/fluttr/libnflick/nflick-photo-list-response-private.h
new file mode 100644 (file)
index 0000000..c8920ab
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickPhotoListResponsePrivate
+{
+        GList *PhotoDataList;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_photo_list_response_class_init (NFlickPhotoListResponseClass *klass);
+
+static void                     nflick_photo_list_response_init (NFlickPhotoListResponse *self);
+
+static gboolean                 private_init (NFlickPhotoListResponse *self, NFlickPhotoListResponsePrivate *private);
+
+static void                     private_dispose (NFlickPhotoListResponsePrivate *private);
+
+static void                     nflick_photo_list_response_dispose (NFlickPhotoListResponse *self);
+
+static void                     nflick_photo_list_response_finalize (NFlickPhotoListResponse *self);
+
+static void                     parse_func (NFlickPhotoListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_photo_list_response_get_property (NFlickPhotoListResponse *self, guint propid, 
+                                                                         GValue *value, GParamSpec *pspec);
diff --git a/attic/fluttr/libnflick/nflick-photo-list-response.c b/attic/fluttr/libnflick/nflick-photo-list-response.c
new file mode 100644 (file)
index 0000000..0941181
--- /dev/null
@@ -0,0 +1,195 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-list-response.h"
+#include "nflick-photo-list-response-private.h"
+
+GType                           nflick_photo_list_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoListResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_list_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoListResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_list_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickPhotoListResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_photo_list_response_class_init (NFlickPhotoListResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_list_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_list_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_list_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_photo_list_response_init (NFlickPhotoListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickPhotoListResponsePrivate *priv = g_new0 (NFlickPhotoListResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoListResponse *self, NFlickPhotoListResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickPhotoListResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_photo_list_response_dispose (NFlickPhotoListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_list_response_finalize (NFlickPhotoListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickPhotoListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "photoset") == 0) {
+
+                        xmlNode *set_node = NULL;
+                        for (set_node = cur_node->children; set_node; set_node = set_node->next) {
+                                
+                                if (set_node->type == XML_ELEMENT_NODE && strcmp (set_node->name, "photo") == 0) {
+
+                                        gchar *id = xmlGetProp (set_node, "id");
+                                        gchar *name = xmlGetProp (set_node, "title");
+
+                                        if (id != NULL && name != NULL) {
+                                                NFlickPhotoData *photo_data = nflick_photo_data_new (id, name);
+                                                if (photo_data != NULL) 
+                                                        self->Private->PhotoDataList = g_list_append (self->Private->PhotoDataList, photo_data);
+                                        }
+
+                                        if (id != NULL)
+                                                g_free (id);
+                                        if (name != NULL)
+                                                g_free (name);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+static void                     nflick_photo_list_response_get_property (NFlickPhotoListResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
+
+GList*                          nflick_photo_list_response_take_list (NFlickPhotoListResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoDataList;
+        self->Private->PhotoDataList = NULL;
+
+        return lst;
+}
+
+
diff --git a/attic/fluttr/libnflick/nflick-photo-list-response.h b/attic/fluttr/libnflick/nflick-photo-list-response.h
new file mode 100644 (file)
index 0000000..2b6b3f7
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOLISTRESPONSE_H__
+#define __NFLICKPHOTOLISTRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-data.h"
+
+struct                          _NFlickPhotoListResponse
+{
+        NFlickApiResponse Parent;
+        NFlickPhotoListResponsePrivate *Private;
+};
+
+struct                          _NFlickPhotoListResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_photo_list_response_get_type (void);
+
+GList*                          nflick_photo_list_response_take_list (NFlickPhotoListResponse *self);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-photo-list-worker-private.h b/attic/fluttr/libnflick/nflick-photo-list-worker-private.h
new file mode 100644 (file)
index 0000000..b2b84ab
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickPhotoListWorkerPrivate
+{
+        gchar *Id;
+        gchar *Token;
+        GList *PhotoDataList;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_photo_list_worker_class_init (NFlickPhotoListWorkerClass *klass);
+
+static void                     nflick_photo_list_worker_init (NFlickPhotoListWorker *self);
+
+static gboolean                 private_init (NFlickPhotoListWorker *self, NFlickPhotoListWorkerPrivate *private);
+
+static void                     private_dispose (NFlickPhotoListWorkerPrivate *private);
+
+static void                     nflick_photo_list_worker_dispose (NFlickPhotoListWorker *self);
+
+static void                     nflick_photo_list_worker_finalize (NFlickPhotoListWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickPhotoListWorker *self);
+
+static void                     nflick_photo_list_worker_get_property (NFlickPhotoListWorker *self, guint propid, 
+                                                                       GValue *value, GParamSpec *pspec);
+
diff --git a/attic/fluttr/libnflick/nflick-photo-list-worker.c b/attic/fluttr/libnflick/nflick-photo-list-worker.c
new file mode 100644 (file)
index 0000000..9d75c17
--- /dev/null
@@ -0,0 +1,240 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-list-worker.h"
+#include "nflick-photo-list-worker-private.h"
+
+GType                           nflick_photo_list_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoListWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_list_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoListWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_list_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickPhotoListWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_photo_list_worker_class_init (NFlickPhotoListWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_list_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_list_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_list_worker_get_property;
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_photo_list_worker_init (NFlickPhotoListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickPhotoListWorkerPrivate *priv = g_new0 (NFlickPhotoListWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Loading photoset data..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoListWorker *self, NFlickPhotoListWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Id = NULL;
+        private->Token = NULL;
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickPhotoListWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Id != NULL) {
+                g_free (private->Id);
+                private->Id = NULL;
+        }
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_photo_list_worker_dispose (NFlickPhotoListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_list_worker_finalize (NFlickPhotoListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickPhotoListWorker *self)
+{
+        NFlickApiRequest *get_photolist_request = NULL; 
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        NFlickApiResponse *photo_list_response = NULL;
+
+        get_photolist_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_PHOTOS);
+        if (get_photolist_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (get_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        nflick_api_request_add_parameter (get_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTOSET_ID, 
+                                          self->Private->Id);
+
+        nflick_api_request_sign (get_photolist_request);
+        if (nflick_api_request_exec (get_photolist_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        photo_list_response = nflick_api_response_new_from_request (NFLICK_TYPE_PHOTO_LIST_RESPONSE, get_photolist_request);
+        if (photo_list_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, photo_list_response) == FALSE)
+                goto Error;
+
+        self->Private->PhotoDataList = nflick_photo_list_response_take_list ((NFlickPhotoListResponse *) photo_list_response);
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (get_photolist_request != NULL) 
+                g_object_unref (get_photolist_request);
+
+        if (photo_list_response != NULL) 
+                g_object_unref (photo_list_response);
+
+        return status;
+}
+
+NFlickPhotoListWorker*         nflick_photo_list_worker_new (const gchar *id, const gchar *token)
+{
+        g_return_val_if_fail (id != NULL, NULL);
+
+        NFlickPhotoListWorker *self = g_object_new (NFLICK_TYPE_PHOTO_LIST_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Id = g_strdup (id);
+        self->Private->Token = g_strdup (token);
+        
+        return self;
+}
+
+static void                     nflick_photo_list_worker_get_property (NFlickPhotoListWorker *self, guint propid, 
+                                                                       GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
+
+GList*                          nflick_photo_list_worker_take_list (NFlickPhotoListWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_LIST_WORKER (self), NULL);
+
+        GList *lst = self->Private->PhotoDataList;
+        self->Private->PhotoDataList = NULL;
+
+        return lst;
+}
diff --git a/attic/fluttr/libnflick/nflick-photo-list-worker.h b/attic/fluttr/libnflick/nflick-photo-list-worker.h
new file mode 100644 (file)
index 0000000..03de657
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOLISTWORKER_H__
+#define __NFLICKPHOTOLISTWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-types.h"
+#include "nflick-photo-list-response.h"
+
+struct                          _NFlickPhotoListWorker
+{
+        NFlickWorker Parent;
+        NFlickPhotoListWorkerPrivate *Private;
+};
+
+struct                          _NFlickPhotoListWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                                 nflick_photo_list_worker_get_type (void);
+
+NFlickPhotoListWorker*                nflick_photo_list_worker_new (const gchar *id, const gchar *token);
+
+GList*                                nflick_photo_list_worker_take_list (NFlickPhotoListWorker *self);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-photo-set-private.h b/attic/fluttr/libnflick/nflick-photo-set-private.h
new file mode 100644 (file)
index 0000000..4c6e745
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObjectClass*            ParentClass = NULL;
+
+struct                          _NFlickPhotoSetPrivate
+{
+        gchar *Name;
+        gint32 Count;
+        gchar *Id;
+        gboolean Fetched;
+        GList *PhotoDataList;
+};
+
+enum
+{
+        ARG_0,
+        ARG_COMBO_TEXT,
+        ARG_COUNT,
+        ARG_ID,
+        ARG_FETCHED,
+        ARG_LIST
+};
+
+static void                     nflick_photo_set_class_init (NFlickPhotoSetClass *klass);
+
+static void                     nflick_photo_set_init (NFlickPhotoSet *self);
+
+static gboolean                 private_init (NFlickPhotoSet *self, NFlickPhotoSetPrivate *private);
+
+static void                     private_dispose (NFlickPhotoSetPrivate *private);
+
+static void                     nflick_photo_set_dispose (NFlickPhotoSet *self);
+
+static void                     nflick_photo_set_finalize (NFlickPhotoSet *self);
+
+static void                     nflick_photo_set_get_property (NFlickPhotoSet *self, guint propid, 
+                                                               GValue *value, GParamSpec *pspec);
+
diff --git a/attic/fluttr/libnflick/nflick-photo-set.c b/attic/fluttr/libnflick/nflick-photo-set.c
new file mode 100644 (file)
index 0000000..5bd4483
--- /dev/null
@@ -0,0 +1,242 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-photo-set.h"
+#include "nflick-photo-set-private.h"
+
+GType                           nflick_photo_set_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickPhotoSetClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_photo_set_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickPhotoSet), 
+                        4, 
+                        (GInstanceInitFunc) nflick_photo_set_init,
+                };
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickPhotoSet",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_photo_set_class_init (NFlickPhotoSetClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_photo_set_dispose;
+        gobjectclass->finalize = (gpointer) nflick_photo_set_finalize;
+        gobjectclass->get_property = (gpointer) nflick_photo_set_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_COMBO_TEXT,
+                                         g_param_spec_string
+                                         ("combotext", "ComboText", "A text to put in combobox",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_ID,
+                                         g_param_spec_string
+                                         ("id", "Id", "Photoset id",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_COUNT,
+                                         g_param_spec_int 
+                                         ("count", "Count", "Number of items",
+                                         -5000, 5000, 0, G_PARAM_READABLE));
+        /* FIXME Use actual max/min vals for int */
+
+        g_object_class_install_property (gobjectclass, ARG_FETCHED,
+                                         g_param_spec_boolean 
+                                         ("fetched", "Fetched", "If the photoset information was fetched",
+                                         FALSE, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_LIST,
+                                         g_param_spec_pointer 
+                                         ("list", "List", "A list of all the pointers",
+                                         G_PARAM_READABLE));
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+}
+
+static void                     nflick_photo_set_init (NFlickPhotoSet *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+
+        self->Private = NULL;
+
+        NFlickPhotoSetPrivate *priv = g_new0 (NFlickPhotoSetPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickPhotoSet *self, NFlickPhotoSetPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_PHOTO_SET (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Name = NULL;
+        private->Count = 0;
+        private->Id = NULL;
+        private->Fetched = FALSE;
+        private->PhotoDataList = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickPhotoSetPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Name != NULL) {
+                g_free (private->Name);
+                private->Name = NULL;
+        }
+        
+        if (private->Id != NULL) {
+                g_free (private->Id);
+                private->Id = NULL;
+        }
+
+        if (private->PhotoDataList != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoDataList; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                nflick_photo_data_free ((NFlickPhotoData *) iterator->data);
+                
+                g_list_free (private->PhotoDataList);
+                private->PhotoDataList = NULL;
+        }
+}
+
+static void                     nflick_photo_set_dispose (NFlickPhotoSet *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_photo_set_finalize (NFlickPhotoSet *self)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+NFlickPhotoSet*                 nflick_photo_set_new_no_set (gint32 count)
+{
+        g_return_val_if_fail (count >= 0, NULL);
+
+        return nflick_photo_set_new (gettext ("Photos without a set"), NULL, count);
+}
+
+NFlickPhotoSet*                 nflick_photo_set_new (const gchar *name, const gchar *id, gint32 count)
+{
+        g_return_val_if_fail (name != NULL, NULL);
+        g_return_val_if_fail (count >= 0, NULL);
+
+        NFlickPhotoSet *self = g_object_new (NFLICK_TYPE_PHOTO_SET, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Name = g_strdup (name);
+
+        if (id != NULL)
+                self->Private->Id = g_strdup (id);
+
+        self->Private->Count = count;
+        
+        return self;
+}
+
+void                            nflick_photo_set_give_list (NFlickPhotoSet *self, GList *list)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+        if (self->Private->Fetched != FALSE)
+                return;
+
+        self->Private->PhotoDataList = list;
+        self->Private->Fetched = TRUE;
+        self->Private->Count = g_list_length (list);
+}
+
+static void                     nflick_photo_set_get_property (NFlickPhotoSet *self, guint propid, 
+                                                               GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_PHOTO_SET (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_COMBO_TEXT: {
+                        gchar *str = g_strdup_printf ("%s (%d)", self->Private->Name, self->Private->Count);
+                        g_value_take_string (value, str);
+                } break;
+   
+                case ARG_COUNT: {
+                        g_value_set_int (value, self->Private->Count);
+                } break;
+    
+                case ARG_ID: {
+                        g_value_set_string (value, self->Private->Id);
+                } break;
+
+                case ARG_FETCHED: {
+                        g_value_set_boolean (value, self->Private->Fetched);
+                } break;
+
+                case ARG_LIST: {
+                        g_value_set_pointer (value, self->Private->PhotoDataList);
+                } break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-photo-set.h b/attic/fluttr/libnflick/nflick-photo-set.h
new file mode 100644 (file)
index 0000000..a322962
--- /dev/null
@@ -0,0 +1,53 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPHOTOSET_H__
+#define __NFLICKPHOTOSET_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-data.h"
+
+struct                          _NFlickPhotoSet
+{
+        GObject Parent;
+        NFlickPhotoSetPrivate *Private;
+};
+
+struct                          _NFlickPhotoSetClass 
+{
+        GObjectClass ParentClass;
+};
+
+GType                           nflick_photo_set_get_type (void);
+
+NFlickPhotoSet*                 nflick_photo_set_new (const gchar *name, const gchar *id, gint32 count);
+
+void                            nflick_photo_set_give_list (NFlickPhotoSet *self, GList *list);
+
+NFlickPhotoSet*                 nflick_photo_set_new_no_set (gint32 count);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-pixbuf-fetch-private.h b/attic/fluttr/libnflick/nflick-pixbuf-fetch-private.h
new file mode 100644 (file)
index 0000000..460b369
--- /dev/null
@@ -0,0 +1,37 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+struct                          _PixbufFetchHelper 
+{
+        gint32 Width;
+        gint32 Height;
+        GdkPixbufLoader *Loader;
+        FILE *CacheFile;
+} typedef PixbufFetchHelper;
+
+static int                      block_reader (PixbufFetchHelper *helper, gchar *buffer, int len);
+
+static void                     on_size_prepared (GdkPixbufLoader *loader, gint width, gint height, PixbufFetchHelper *helper);
+
+static gchar*                   get_cache_file (const gchar *token);
+
diff --git a/attic/fluttr/libnflick/nflick-pixbuf-fetch.c b/attic/fluttr/libnflick/nflick-pixbuf-fetch.c
new file mode 100644 (file)
index 0000000..8892907
--- /dev/null
@@ -0,0 +1,172 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-pixbuf-fetch.h"
+#include "nflick-pixbuf-fetch-private.h"
+
+GdkPixbuf*                      nflick_pixbuf_fetch_try_cache (const gchar *token)
+{
+        return NULL;
+}
+
+GdkPixbuf*                      nflick_pixbuf_fetch (const gchar *url, gint32 width, gint32 height, const gchar *cache_token)
+{
+        g_return_val_if_fail (url != NULL, NULL);
+
+        ne_uri *uri = NULL;         /* Neon uri */
+        ne_request *request = NULL; /* Http request */
+        ne_session *session = NULL; /* Neon session */
+        gboolean result = TRUE;     
+        GdkPixbuf *pixbuf = NULL;
+
+        /* Allocate new neon uri */
+        uri = g_new0 (ne_uri, 1);
+        if (uri == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Parse the incoming url into valid neon uri */
+        if (ne_uri_parse (url, uri) || uri->host == NULL || uri->path == NULL) {
+               result = FALSE;
+                goto Done;
+        }
+
+        /* Set defaults. */
+        if (uri->scheme == NULL)
+                uri->scheme = g_strdup ("http");
+        if (uri->port == 0)
+                uri->port = ne_uri_defaultport (uri->scheme);
+
+        /* Create the session */
+        session = ne_session_create (uri->scheme, uri->host, uri->port);
+        if (session == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Create the request */
+        request = ne_request_create (session, "GET", uri->path);
+        if (request == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        /* Allocate our struct */
+        PixbufFetchHelper *helper = g_new0 (PixbufFetchHelper, 1);
+        if (helper == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+        
+        helper->Loader = gdk_pixbuf_loader_new ();
+        if (helper->Loader == NULL) {
+                result = FALSE;
+                goto Done;
+        }
+
+        // Open the cache file if applies...
+        // FIXME: Move this shit as func param
+        
+        if (cache_token != NULL && 1) {
+                gchar *file_name = NULL;
+                file_name = get_cache_file (cache_token);
+                if (file_name != NULL) {
+                        helper->CacheFile = fopen (file_name, "wb");
+                        g_free (file_name);
+                }
+        }
+       
+        g_signal_connect (G_OBJECT (helper->Loader), "size-prepared", (gpointer) on_size_prepared, helper);
+
+        helper->Width = width;
+        helper->Height = height;
+
+        ne_add_response_body_reader (request, ne_accept_always, (gpointer) block_reader, helper);
+
+        result = (ne_request_dispatch (request) == NE_OK) ? TRUE : FALSE;
+
+        if (helper->CacheFile != NULL)
+                fclose (helper->CacheFile);
+        gdk_pixbuf_loader_close (helper->Loader, NULL); 
+        
+        if (result == TRUE) {
+                pixbuf = gdk_pixbuf_loader_get_pixbuf (helper->Loader);
+                if (pixbuf)
+                        g_object_ref (pixbuf);
+        } else {
+                // FIXME: Remove the cached file
+        }
+
+Done:
+        if (uri != NULL) {
+                ne_uri_free (uri);
+                g_free (uri);
+        }
+
+        if (session != NULL)
+                ne_session_destroy (session);
+
+        if (request != NULL)
+                ne_request_destroy (request);
+
+        if (helper != NULL) {
+                if (helper->Loader != NULL)
+                        g_object_unref (helper->Loader);
+                g_free (helper);
+        }
+
+        return pixbuf;
+}
+
+static gchar*                   get_cache_file (const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+
+        return g_build_filename ("cache", token, NULL);
+}
+
+static int                      block_reader (PixbufFetchHelper *helper, gchar *buffer, int len)
+{
+        g_return_val_if_fail (helper != NULL, -1);
+        g_return_val_if_fail (helper->Loader != NULL, -1);
+
+        if (helper->CacheFile != NULL)
+                fwrite (buffer, 1, len, helper->CacheFile);
+
+        gdk_pixbuf_loader_write (helper->Loader, buffer, len, NULL);
+        
+        return 0; 
+}
+
+static void                     on_size_prepared (GdkPixbufLoader *loader, gint width, gint height, PixbufFetchHelper *helper)
+{
+        g_return_if_fail (helper != NULL);
+
+        if (helper->Width == 0 && helper->Height == 0)
+                return;
+
+        if (width != helper->Width && height != helper->Height)
+                gdk_pixbuf_loader_set_size (loader, helper->Width, helper->Height);
+}
+
diff --git a/attic/fluttr/libnflick/nflick-pixbuf-fetch.h b/attic/fluttr/libnflick/nflick-pixbuf-fetch.h
new file mode 100644 (file)
index 0000000..8def879
--- /dev/null
@@ -0,0 +1,40 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKPIXBUFFETCH_H__
+#define __NFLICKPIXBUFFETCH_H__
+
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <ne_uri.h>
+#include <ne_session.h>
+#include <ne_basic.h>
+#include <ne_utils.h>
+#include <string.h>
+#include <stdio.h>
+
+GdkPixbuf*                      nflick_pixbuf_fetch (const gchar *url, int width, int height, const gchar *token);
+
+GdkPixbuf*                      nflick_pixbuf_fetch_try_cache (const gchar *token);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-set-list-response-private.h b/attic/fluttr/libnflick/nflick-set-list-response-private.h
new file mode 100644 (file)
index 0000000..0634c58
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickApiResponse*       ParentClass = NULL;
+
+struct                          _NFlickSetListResponsePrivate
+{
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_set_list_response_class_init (NFlickSetListResponseClass *klass);
+
+static void                     nflick_set_list_response_init (NFlickSetListResponse *self);
+
+static gboolean                 private_init (NFlickSetListResponse *self, NFlickSetListResponsePrivate *private);
+
+static void                     private_dispose (NFlickSetListResponsePrivate *private);
+
+static void                     nflick_set_list_response_dispose (NFlickSetListResponse *self);
+
+static void                     nflick_set_list_response_finalize (NFlickSetListResponse *self);
+
+static void                     parse_func (NFlickSetListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+static void                     nflick_set_list_response_get_property (NFlickSetListResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec);
diff --git a/attic/fluttr/libnflick/nflick-set-list-response.c b/attic/fluttr/libnflick/nflick-set-list-response.c
new file mode 100644 (file)
index 0000000..abaa761
--- /dev/null
@@ -0,0 +1,212 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-set-list-response.h"
+#include "nflick-set-list-response-private.h"
+
+GType                           nflick_set_list_response_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickSetListResponseClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_set_list_response_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickSetListResponse), 
+                        4, 
+                        (GInstanceInitFunc) nflick_set_list_response_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_API_RESPONSE, "NFlickSetListResponse",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_set_list_response_class_init (NFlickSetListResponseClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickApiResponseClass *apiresponseclass = (NFlickApiResponseClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_set_list_response_dispose;
+        gobjectclass->finalize = (gpointer) nflick_set_list_response_finalize;
+        gobjectclass->get_property = (gpointer) nflick_set_list_response_get_property;
+        
+        apiresponseclass->ParseFunc = (gpointer) parse_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_API_RESPONSE);
+}
+
+static void                     nflick_set_list_response_init (NFlickSetListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        self->Private = NULL;
+
+        NFlickSetListResponsePrivate *priv = g_new0 (NFlickSetListResponsePrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickSetListResponse *self, NFlickSetListResponsePrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoSets = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickSetListResponsePrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->PhotoSets != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = private->PhotoSets; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                g_object_unref (iterator->data);
+                
+                g_list_free (private->PhotoSets);
+                private->PhotoSets = NULL;
+        }
+}
+
+GList*                          nflick_set_list_response_take_list (NFlickSetListResponse *self)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self), NULL);
+
+        GList *lst = self->Private->PhotoSets;
+        self->Private->PhotoSets = NULL;
+
+        return lst;
+}
+
+static void                     nflick_set_list_response_dispose (NFlickSetListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_set_list_response_finalize (NFlickSetListResponse *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     parse_func (NFlickSetListResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        g_return_if_fail (children != NULL);
+        g_return_if_fail (doc != NULL);
+        g_return_if_fail (result != NULL && parse_error != NULL);
+
+        xmlNode *cur_node = NULL;
+
+        for (cur_node = children; cur_node; cur_node = cur_node->next) {
+      
+                if (cur_node->type == XML_ELEMENT_NODE && strcmp (cur_node->name, "photosets") == 0) {
+                        
+                        xmlNode *sets_node = NULL;
+                        for (sets_node = cur_node->children; sets_node; sets_node = sets_node->next) {
+                                
+                                if (sets_node->type == XML_ELEMENT_NODE && strcmp (sets_node->name, "photoset") == 0) {
+
+                                        gchar *id = xmlGetProp (sets_node, "id");
+                                        gchar *count = xmlGetProp (sets_node, "photos");
+                                        gchar *title = NULL;
+                                        gint32 count_val = 0;
+                                        NFlickPhotoSet *photo_set = NULL;
+
+                                        xmlNode *this_node = NULL;
+                                        for (this_node = sets_node->children; this_node; this_node = this_node->next) {
+                                                if (this_node->type == XML_ELEMENT_NODE && strcmp (this_node->name, "title") == 0) {
+                                                        if (title != NULL)
+                                                                g_free (title);
+                                                        title = xmlNodeListGetString (doc, this_node->xmlChildrenNode, 1);
+                                                }
+                                        }
+
+                                        count_val = atoi (count);
+
+                                        if (count_val != 0 &&
+                                            id != NULL &&
+                                            title != NULL)
+                                                photo_set = nflick_photo_set_new (title, id, count_val);
+
+                                        if (photo_set != NULL)
+                                                self->Private->PhotoSets = g_list_append (self->Private->PhotoSets, photo_set);
+
+                                        /* Free */
+                                        if (id != NULL)
+                                                g_free (id);
+                                        if (count != NULL)
+                                                g_free (count);
+                                        if (title != NULL)
+                                                g_free (title);
+                                }
+                        }
+                }
+        }
+
+        /* Finished */
+        *result = TRUE;
+        *parse_error = FALSE;
+}
+
+static void                     nflick_set_list_response_get_property (NFlickSetListResponse *self, guint propid, 
+                                                                        GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_RESPONSE (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-set-list-response.h b/attic/fluttr/libnflick/nflick-set-list-response.h
new file mode 100644 (file)
index 0000000..6e0d45d
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSETLISTRESPONSE_H__
+#define __NFLICKSETLISTRESPONSE_H__
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libintl.h>
+#include <string.h>
+#include "nflick-api-response.h"
+#include "nflick-flickr.h"
+#include "nflick-types.h"
+#include "nflick-photo-set.h"
+
+struct                          _NFlickSetListResponse
+{
+        NFlickApiResponse Parent;
+        NFlickSetListResponsePrivate *Private;
+};
+
+struct                          _NFlickSetListResponseClass 
+{
+        NFlickApiResponseClass ParentClass;
+};
+
+GType                           nflick_set_list_response_get_type (void);
+
+GList*                          nflick_set_list_response_take_list (NFlickSetListResponse *self);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-set-list-worker-private.h b/attic/fluttr/libnflick/nflick-set-list-worker-private.h
new file mode 100644 (file)
index 0000000..7dc1742
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorkerClass*       ParentClass = NULL;
+
+struct                          _NFlickSetListWorkerPrivate
+{
+        gchar *UserNsid;
+        gchar *Token;
+        GList *PhotoSets;
+};
+
+enum 
+{
+        ARG_0,
+};
+
+static void                     nflick_set_list_worker_class_init (NFlickSetListWorkerClass *klass);
+
+static void                     nflick_set_list_worker_init (NFlickSetListWorker *self);
+
+static gboolean                 private_init (NFlickSetListWorker *self, NFlickSetListWorkerPrivate *priv);
+
+static void                     private_dispose (NFlickSetListWorkerPrivate *priv);
+
+static void                     nflick_set_list_worker_dispose (NFlickSetListWorker *self);
+
+static void                     nflick_set_list_worker_finalize (NFlickSetListWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickSetListWorker *self);
+
+static void                     nflick_set_list_worker_get_property (NFlickSetListWorker *self, guint propid, 
+                                                                     GValue *value, GParamSpec *pspec);
+
diff --git a/attic/fluttr/libnflick/nflick-set-list-worker.c b/attic/fluttr/libnflick/nflick-set-list-worker.c
new file mode 100644 (file)
index 0000000..024ab1f
--- /dev/null
@@ -0,0 +1,362 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-set-list-worker.h"
+#include "nflick-set-list-worker-private.h"
+
+GType                           nflick_set_list_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickSetListWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_set_list_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickSetListWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_set_list_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickSetListWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_set_list_worker_class_init (NFlickSetListWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_set_list_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_set_list_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_set_list_worker_get_property;
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_set_list_worker_init (NFlickSetListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickSetListWorkerPrivate *priv = g_new0 (NFlickSetListWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, gettext ("Parsing photosets..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickSetListWorker *self, NFlickSetListWorkerPrivate *priv)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_WORKER (self), FALSE);
+        g_return_val_if_fail (priv != NULL, FALSE);
+
+        priv->UserNsid = NULL;
+        priv->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickSetListWorkerPrivate *priv)
+{
+        g_return_if_fail (priv != NULL);
+
+        if (priv->Token != NULL) {
+                g_free (priv->Token);
+                priv->Token = NULL;
+        }
+
+        if (priv->UserNsid != NULL) {
+                g_free (priv->UserNsid);
+                priv->UserNsid = NULL;
+        }
+
+        if (priv->PhotoSets != NULL) {
+
+                GList *iterator;
+        
+                for (iterator = priv->PhotoSets; iterator; iterator = g_list_next (iterator))
+                        if (iterator->data != NULL)
+                                g_object_unref (iterator->data);
+                
+                g_list_free (priv->PhotoSets);
+                priv->PhotoSets = NULL;
+        }
+}
+
+static void                     nflick_set_list_worker_dispose (NFlickSetListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_set_list_worker_finalize (NFlickSetListWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickSetListWorker *self)
+{
+        NFlickApiRequest *get_photosets_request = NULL; 
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        NFlickApiResponse *set_list_response = NULL;
+        gchar *first_id = NULL;
+        NFlickPhotoSet *first_set = NULL; /* Do not dispose, it's not reffed */
+        NFlickApiRequest *first_photolist_request = NULL; 
+        NFlickApiResponse *first_photo_list_response = NULL;
+        GList *first_list = NULL;
+        NFlickApiRequest *unsetted_request = NULL; 
+        NFlickApiResponse *unsetted_response = NULL;
+        GList *unsetted_list = NULL;
+        NFlickPhotoSet *unsetted_set = NULL; /* Do not dispose, it's not reffed */
+
+        get_photosets_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_LIST);
+        if (get_photosets_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (get_photosets_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        nflick_api_request_add_parameter (get_photosets_request, 
+                                          NFLICK_FLICKR_API_PARAM_USER_ID, 
+                                          self->Private->UserNsid);
+
+        nflick_api_request_sign (get_photosets_request);
+        if (nflick_api_request_exec (get_photosets_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        set_list_response = nflick_api_response_new_from_request (NFLICK_TYPE_SET_LIST_RESPONSE, get_photosets_request);
+        if (set_list_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, set_list_response) == FALSE)
+                goto Error;
+
+        self->Private->PhotoSets = nflick_set_list_response_take_list ((NFlickSetListResponse *) set_list_response);
+
+        /* Let's fetch information about the unsetted photos */
+        nflick_worker_set_message ((NFlickWorker *) self, gettext ("Parsing photos without set..."));
+
+        unsetted_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOS_NOT_IN_SET);
+        if (unsetted_request == NULL)
+                goto Error;
+        
+        nflick_api_request_add_parameter (unsetted_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        /* We try to get 500 photos per page. 500 is a maximum value. 
+         * FIXME: We should check if 500 is enough. Someone might have more than 
+         * 500 photos */
+
+        nflick_api_request_add_parameter (unsetted_request, 
+                                          NFLICK_FLICKR_API_PARAM_PER_PAGE,
+                                          "500");
+
+        nflick_api_request_sign (unsetted_request);
+        if (nflick_api_request_exec (unsetted_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        unsetted_response = nflick_api_response_new_from_request (NFLICK_TYPE_NO_SET_RESPONSE, unsetted_request);
+        if (unsetted_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, unsetted_response) == FALSE)
+                goto Error;
+
+        unsetted_list = nflick_no_set_response_take_list ((NFlickNoSetResponse *) unsetted_response);
+        /* FIXME: Here we could expose the "count" property on the PhotoSetResponse and NoSetResponse */
+        unsetted_set = nflick_photo_set_new_no_set (g_list_length (unsetted_list)); 
+        nflick_photo_set_give_list (unsetted_set, unsetted_list);
+
+        /* Append the set to our set list... */
+        self->Private->PhotoSets = g_list_append (self->Private->PhotoSets, 
+                                                   unsetted_set);
+
+        /* If the user has not sets, finish now */
+        if (self->Private->PhotoSets->data == (gpointer) unsetted_set) {
+                goto Done;
+        }
+        /* Now let's try fetching the photos for first photo set */
+        nflick_worker_set_message ((NFlickWorker *) self, gettext ("Loading photoset data..."));
+        
+        GList *sets = self->Private->PhotoSets;
+        GList *set;
+        gint i = g_list_length (sets);
+        
+        for (set = sets; set != NULL; set = set->next) {
+               first_set = (NFlickPhotoSet*)set->data;
+        
+               g_object_get (G_OBJECT (first_set), "id", &first_id, NULL);
+
+               first_photolist_request = nflick_api_request_new
+                                (NFLICK_FLICKR_API_METHOD_PHOTOSETS_GET_PHOTOS);
+               if (first_photolist_request == NULL)
+                       goto Error;
+        
+               nflick_api_request_add_parameter (first_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+               nflick_api_request_add_parameter (first_photolist_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTOSET_ID, 
+                                          first_id);
+
+               nflick_api_request_sign (first_photolist_request);
+               if (nflick_api_request_exec (first_photolist_request) != TRUE) {
+                       nflick_worker_set_network_error ((NFlickWorker *) self);
+                       g_warning ("Error : %s", first_id);
+               }
+
+               if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                       g_warning ("Abort : %s", first_id);
+
+               first_photo_list_response = nflick_api_response_new_from_request 
+                    (NFLICK_TYPE_PHOTO_LIST_RESPONSE, first_photolist_request);
+               if (first_photo_list_response == NULL)
+                       g_warning ("No photos : %s", first_id);
+
+               if (nflick_worker_parse_api_response ((NFlickWorker*) self, 
+                                       first_photo_list_response) == FALSE)
+                       ;
+
+               first_list = nflick_photo_list_response_take_list
+                       ((NFlickPhotoListResponse *) first_photo_list_response);
+               nflick_photo_set_give_list (first_set, first_list);
+        }
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        g_print ("Abort\n");
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+        g_print ("Error\n");
+Done:
+        if (get_photosets_request != NULL) 
+                g_object_unref (get_photosets_request);
+
+        if (set_list_response != NULL) 
+                g_object_unref (set_list_response);
+
+        if (first_photolist_request != NULL) 
+                g_object_unref (first_photolist_request);
+
+        if (unsetted_response != NULL) 
+                g_object_unref (unsetted_response);
+
+        if (unsetted_request != NULL) 
+                g_object_unref (unsetted_request);
+
+        if (first_photo_list_response != NULL) 
+                g_object_unref (first_photo_list_response);
+
+        if (first_id != NULL)
+                g_free (first_id);
+
+        return status;
+}
+
+NFlickSetListWorker*            nflick_set_list_worker_new (const gchar *usernsid, const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+        g_return_val_if_fail (usernsid != NULL, NULL);
+
+        NFlickSetListWorker *self = g_object_new (NFLICK_TYPE_SET_LIST_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Token = g_strdup (token);
+        self->Private->UserNsid = g_strdup (usernsid);
+        self->Private->PhotoSets = NULL;
+
+        return self;
+}
+
+GList*                          nflick_set_list_worker_take_list (NFlickSetListWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_SET_LIST_WORKER (self), NULL);
+
+        GList *lst = self->Private->PhotoSets;
+        self->Private->PhotoSets = NULL;
+
+        return lst;
+}
+
+static void                     nflick_set_list_worker_get_property (NFlickSetListWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_SET_LIST_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-set-list-worker.h b/attic/fluttr/libnflick/nflick-set-list-worker.h
new file mode 100644 (file)
index 0000000..d7105c7
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSETLISTWORKER_H__
+#define __NFLICKSETLISTWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-set-list-response.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-types.h"
+#include "nflick-no-set-response.h"
+
+struct                          _NFlickSetListWorker
+{
+        NFlickWorker Parent;
+        NFlickSetListWorkerPrivate *Private;
+};
+
+struct                          _NFlickSetListWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_set_list_worker_get_type (void);
+
+NFlickSetListWorker*            nflick_set_list_worker_new (const gchar *usernsid, const gchar *token);
+
+GList*                          nflick_set_list_worker_take_list (NFlickSetListWorker *self);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-show-worker-private.h b/attic/fluttr/libnflick/nflick-show-worker-private.h
new file mode 100644 (file)
index 0000000..417fa75
--- /dev/null
@@ -0,0 +1,57 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static NFlickWorker*            ParentClass = NULL;
+
+struct                          _NFlickShowWorkerPrivate
+{
+        gchar *PhotoId;
+        gchar *Token;
+        gint32 Width;
+        gint32 Height;
+        GdkPixbuf *Pixbuf;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_PIXBUF,
+};
+
+static void                     nflick_show_worker_class_init (NFlickShowWorkerClass *klass);
+
+static void                     nflick_show_worker_init (NFlickShowWorker *self);
+
+static gboolean                 private_init (NFlickShowWorker *self, NFlickShowWorkerPrivate *private);
+
+static void                     private_dispose (NFlickShowWorkerPrivate *private);
+
+static void                     nflick_show_worker_dispose (NFlickShowWorker *self);
+
+static void                     nflick_show_worker_finalize (NFlickShowWorker *self);
+
+static NFlickWorkerStatus       thread_func (NFlickShowWorker *self);
+
+static void                     nflick_show_worker_get_property (NFlickShowWorker *self, guint propid, 
+                                                                GValue *value, GParamSpec *pspec);
+
diff --git a/attic/fluttr/libnflick/nflick-show-worker.c b/attic/fluttr/libnflick/nflick-show-worker.c
new file mode 100644 (file)
index 0000000..10bc3d5
--- /dev/null
@@ -0,0 +1,264 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-show-worker.h"
+#include "nflick-show-worker-private.h"
+
+GType                           nflick_show_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickShowWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_show_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickShowWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_show_worker_init,
+                };
+                objecttype = g_type_register_static (NFLICK_TYPE_WORKER, "NFlickShowWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_show_worker_class_init (NFlickShowWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+        NFlickWorkerClass *workerclass = (NFlickWorkerClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_show_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_show_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_show_worker_get_property;
+
+        g_object_class_install_property (gobjectclass, ARG_PIXBUF,
+                                         g_param_spec_object 
+                                         ("pixbuf", "Pixbuf", "Pixbuf",
+                                         GDK_TYPE_PIXBUF, G_PARAM_READABLE));
+        
+        workerclass->ThreadFunc = (NFlickWorkerThreadFunc) thread_func;
+
+        ParentClass = g_type_class_ref (NFLICK_TYPE_WORKER);
+}
+
+static void                     nflick_show_worker_init (NFlickShowWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickShowWorkerPrivate *priv = g_new0 (NFlickShowWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) {
+                self->Private = priv;
+                nflick_worker_set_message ((NFlickWorker *) self, 
+                                           gettext ("Loading photo..."));
+        } else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickShowWorker *self, NFlickShowWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_SHOW_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->PhotoId = NULL;
+        private->Token = NULL;
+
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickShowWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Token != NULL) {
+                g_free (private->Token);
+                private->Token = NULL;
+        }
+
+        if (private->PhotoId != NULL) {
+                g_free (private->PhotoId);
+                private->PhotoId = NULL;
+        }
+
+        if (private->Pixbuf != NULL) {
+                g_object_unref (private->Pixbuf);
+                private->Pixbuf = NULL;
+        }
+}
+
+static void                     nflick_show_worker_dispose (NFlickShowWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_show_worker_finalize (NFlickShowWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static NFlickWorkerStatus       thread_func (NFlickShowWorker *self)
+{
+        NFlickApiRequest *get_sizes_request = NULL; 
+        NFlickApiResponse *get_sizes_response = NULL;
+        gchar *uri = NULL;
+        NFlickWorkerStatus status = NFLICK_WORKER_STATUS_OK;
+        gdouble vbox_aspect = (gdouble) self->Private->Width / (gdouble) self->Private->Height;
+        gdouble pixbuf_aspect = -1;
+        gint32 final_width = -1;
+        gint32 final_height = -1;
+        gboolean rotated = FALSE;
+
+        get_sizes_request = nflick_api_request_new (NFLICK_FLICKR_API_METHOD_PHOTOS_GET_SIZES);
+        if (get_sizes_request == NULL)
+                goto Error;
+
+        nflick_api_request_add_parameter (get_sizes_request, 
+                                          NFLICK_FLICKR_API_PARAM_TOKEN, 
+                                          self->Private->Token);
+
+        nflick_api_request_add_parameter (get_sizes_request, 
+                                          NFLICK_FLICKR_API_PARAM_PHOTO_ID, 
+                                          self->Private->PhotoId);
+
+        nflick_api_request_sign (get_sizes_request);
+        if (nflick_api_request_exec (get_sizes_request) != TRUE) {
+                nflick_worker_set_network_error ((NFlickWorker *) self);
+                goto Error;
+        }
+
+        if (nflick_worker_is_aborted ((NFlickWorker *) self) == TRUE)
+                goto Abort;
+
+        get_sizes_response = nflick_api_response_new_from_request (NFLICK_TYPE_GET_SIZES_RESPONSE, get_sizes_request);
+        if (get_sizes_response == NULL)
+                goto Error;
+
+        if (nflick_worker_parse_api_response ((NFlickWorker*) self, get_sizes_response) == FALSE)
+                goto Error;
+
+        final_width = self->Private->Width;
+        final_height = self->Private->Height;
+
+        uri = nflick_get_sizes_response_find_match ((NFlickGetSizesResponse *) get_sizes_response, 
+                                                    &final_width, &final_height, &rotated);
+
+        if (uri == NULL)
+                goto Error;
+
+        self->Private->Pixbuf = nflick_pixbuf_fetch (uri, final_width, final_height, NULL);
+        if (self->Private->Pixbuf == NULL)
+                goto Error;
+
+        if (rotated == TRUE) {
+                GdkPixbuf *pxbuf = gdk_pixbuf_rotate_simple (self->Private->Pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
+                if (pxbuf != NULL) {
+                        g_object_unref (self->Private->Pixbuf);
+                        self->Private->Pixbuf = pxbuf;
+                }
+        }
+
+        /* All ok */
+        goto Done;
+
+Abort:
+        status = NFLICK_WORKER_STATUS_ABORTED;
+        goto Done;
+
+Error:
+        status = NFLICK_WORKER_STATUS_ERROR;
+
+Done:
+        if (get_sizes_request != NULL) 
+                g_object_unref (get_sizes_request);
+
+        if (get_sizes_response != NULL) 
+                g_object_unref (get_sizes_response);
+
+        if (uri != NULL)
+                g_free (uri);
+
+        return status;
+}
+
+NFlickShowWorker*               nflick_show_worker_new (const gchar *photoid, gint32 width, gint32 height, const gchar *token)
+{
+        g_return_val_if_fail (token != NULL, NULL);
+        g_return_val_if_fail (photoid != NULL, NULL);
+
+        NFlickShowWorker *self = g_object_new (NFLICK_TYPE_SHOW_WORKER, NULL);
+        g_return_val_if_fail (self != NULL, NULL);
+
+        if (self->Private == NULL) {
+                g_object_unref (self);
+                return NULL;
+        }
+
+        self->Private->Token = g_strdup (token);
+        self->Private->PhotoId= g_strdup (photoid);
+        self->Private->Width = width;
+        self->Private->Height = height;
+
+        return self;
+}
+
+static void                     nflick_show_worker_get_property (NFlickShowWorker *self, guint propid, 
+                                                                 GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_SHOW_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+               
+                case ARG_PIXBUF:
+                        g_value_set_object (value, self->Private->Pixbuf);
+                break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-show-worker.h b/attic/fluttr/libnflick/nflick-show-worker.h
new file mode 100644 (file)
index 0000000..a17faf9
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKSHOWWORKER_H__
+#define __NFLICKSHOWWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-worker.h"
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-get-sizes-response.h"
+#include "nflick-set-list-response.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-set.h"
+#include "nflick-types.h"
+#include "nflick-pixbuf-fetch.h"
+
+struct                          _NFlickShowWorker
+{
+        NFlickWorker Parent;
+        NFlickShowWorkerPrivate *Private;
+};
+
+struct                          _NFlickShowWorkerClass 
+{
+        NFlickWorkerClass ParentClass;
+};
+
+GType                           nflick_show_worker_get_type (void);
+
+NFlickShowWorker*               nflick_show_worker_new (const gchar *photoid, gint32 width, gint32 height, const gchar *token);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-types.h b/attic/fluttr/libnflick/nflick-types.h
new file mode 100644 (file)
index 0000000..61b0e46
--- /dev/null
@@ -0,0 +1,514 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKTYPES_H__
+#define __NFLICKTYPES_H__
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+/* Window */
+
+typedef struct                  _NFlickWindowClass NFlickWindowClass;
+
+typedef struct                  _NFlickWindow NFlickWindow;
+
+typedef struct                  _NFlickWindowPrivate NFlickWindowPrivate;
+
+#define                         NFLICK_TYPE_WINDOW (nflick_window_get_type ())
+
+#define                         NFLICK_IS_WINDOW(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WINDOW))
+
+#define                         NFLICK_WINDOW(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WINDOW, NFlickWindow))
+
+#define                         NFLICK_WINDOW_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WINDOW, NFlickWindowClass))
+
+/* Wait dialog */
+
+#define                         NFLICK_WAIT_DIALOG_RESPONSE_ABORTED 1000
+
+#define                         NFLICK_WAIT_DIALOG_RESPONSE_ERROR 1001
+
+#define                         NFLICK_WAIT_DIALOG_RESPONSE_OK 1002
+
+typedef struct                  _NFlickWaitDialogClass NFlickWaitDialogClass;
+
+typedef struct                  _NFlickWaitDialog NFlickWaitDialog;
+
+typedef struct                  _NFlickWaitDialogPrivate NFlickWaitDialogPrivate;
+
+#define                         NFLICK_TYPE_WAIT_DIALOG (nflick_wait_dialog_get_type ())
+
+#define                         NFLICK_IS_WAIT_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WAIT_DIALOG))
+
+#define                         NFLICK_WAIT_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WAIT_DIALOG, NFlickWaitDialog))
+
+#define                         NFLICK_WAIT_DIALOG_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WAIT_DIALOG, NFlickWaitDialogClass))
+
+/* Token dialog */
+
+typedef struct                  _NFlickTokenDialogClass NFlickTokenDialogClass;
+
+typedef struct                  _NFlickTokenDialog NFlickTokenDialog;
+
+typedef struct                  _NFlickTokenDialogPrivate NFlickTokenDialogPrivate;
+
+#define                         NFLICK_TYPE_TOKEN_DIALOG (nflick_token_dialog_get_type ())
+
+#define                         NFLICK_IS_TOKEN_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_TOKEN_DIALOG))
+
+#define                         NFLICK_TOKEN_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_TOKEN_DIALOG, NFlickTokenDialog))
+
+#define                         NFLICK_TOKEN_DIALOG_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_TOKEN_DIALOG, NFlickTokenDialogClass))
+
+/* Cache dialog */
+
+typedef struct                  _NFlickCacheDialogClass NFlickCacheDialogClass;
+
+typedef struct                  _NFlickCacheDialog NFlickCacheDialog;
+
+typedef struct                  _NFlickCacheDialogPrivate NFlickCacheDialogPrivate;
+
+#define                         NFLICK_TYPE_CACHE_DIALOG (nflick_cache_dialog_get_type ())
+
+#define                         NFLICK_IS_CACHE_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_CACHE_DIALOG))
+
+#define                         NFLICK_CACHE_DIALOG(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_CACHE_DIALOG, NFlickCacheDialog))
+
+#define                         NFLICK_CACHE_DIALOG_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_CACHE_DIALOG, NFlickCacheDialogClass))
+
+/* Welcome VBox */
+
+typedef struct                  _NFlickWelcomeVBoxClass NFlickWelcomeVBoxClass;
+
+typedef struct                  _NFlickWelcomeVBox NFlickWelcomeVBox;
+
+typedef struct                  _NFlickWelcomeVBoxPrivate NFlickWelcomeVBoxPrivate;
+
+#define                         NFLICK_TYPE_WELCOME_VBOX (nflick_welcome_vbox_get_type ())
+
+#define                         NFLICK_IS_WELCOME_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WELCOME_VBOX))
+
+#define                         NFLICK_WELCOME_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WELCOME_VBOX, NFlickWelcomeVBox)
+
+#define                         NFLICK_WELCOME_VBOX_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WELCOME_VBOX, NFlickWelcomeVBoxClass))
+
+/* Show VBox */
+
+typedef struct                  _NFlickShowVBoxClass NFlickShowVBoxClass;
+
+typedef struct                  _NFlickShowVBox NFlickShowVBox;
+
+typedef struct                  _NFlickShowVBoxPrivate NFlickShowVBoxPrivate;
+
+#define                         NFLICK_TYPE_SHOW_VBOX (nflick_show_vbox_get_type ())
+
+#define                         NFLICK_IS_SHOW_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SHOW_VBOX))
+
+#define                         NFLICK_SHOW_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SHOW_VBOX, NFlickShowVBox)
+
+#define                         NFLICK_SHOW_VBOX_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SHOW_VBOX, NFlickShowVBoxClass))
+
+/* Worker */
+
+typedef struct                  _NFlickWorkerClass NFlickWorkerClass;
+
+typedef struct                  _NFlickWorker NFlickWorker;
+
+typedef struct                  _NFlickWorkerPrivate NFlickWorkerPrivate;
+
+#define                         NFLICK_TYPE_WORKER (nflick_worker_get_type ())
+
+#define                         NFLICK_IS_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_WORKER))
+
+#define                         NFLICK_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_WORKER, NFlickWorker)
+
+#define                         NFLICK_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_WORKER, NFlickWorkerClass))
+
+enum                            
+{
+        NFLICK_WORKER_STATUS_IDLE,
+        NFLICK_WORKER_STATUS_OK,
+        NFLICK_WORKER_STATUS_ABORTED,
+        NFLICK_WORKER_STATUS_RUNNING,
+        NFLICK_WORKER_STATUS_ERROR
+
+}                               typedef NFlickWorkerStatus;
+
+typedef                         NFlickWorkerStatus (*NFlickWorkerThreadFunc) (NFlickWorker *self);
+
+typedef                         gboolean (*NFlickWorkerIdleFunc) (NFlickWorker *self);
+
+/* Api request */
+
+typedef struct                  _NFlickApiRequestClass NFlickApiRequestClass;
+
+typedef struct                  _NFlickApiRequest NFlickApiRequest;
+
+typedef struct                  _NFlickApiRequestPrivate NFlickApiRequestPrivate;
+
+#define                         NFLICK_TYPE_API_REQUEST (nflick_api_request_get_type ())
+
+#define                         NFLICK_IS_API_REQUEST(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_API_REQUEST))
+
+#define                         NFLICK_API_REQUEST(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_API_REQUEST, NFlickApiRequest)
+
+#define                         NFLICK_API_REQUEST_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_API_REQUEST, NFlickApiRequestClass))
+
+/* Api response */
+
+typedef struct                  _NFlickApiResponseClass NFlickApiResponseClass;
+
+typedef struct                  _NFlickApiResponse NFlickApiResponse;
+
+typedef struct                  _NFlickApiResponsePrivate NFlickApiResponsePrivate;
+
+#define                         NFLICK_TYPE_API_RESPONSE (nflick_api_response_get_type ())
+
+#define                         NFLICK_IS_API_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_API_RESPONSE))
+
+#define                         NFLICK_API_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_API_RESPONSE, NFlickApiResponse)
+
+typedef                         void (*NFlickApiRequestParseFunc) \
+                                (NFlickApiResponse *self, xmlDoc *doc, xmlNode *children, gboolean *result, gboolean *parse_error);
+
+#define                         NFLICK_API_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_API_RESPONSE, NFlickApiResponseClass))
+
+/* Gft response */
+
+typedef struct                  _NFlickGftResponseClass NFlickGftResponseClass;
+
+typedef struct                  _NFlickGftResponse NFlickGftResponse;
+
+typedef struct                  _NFlickGftResponsePrivate NFlickGftResponsePrivate;
+
+#define                         NFLICK_TYPE_GFT_RESPONSE (nflick_gft_response_get_type ())
+
+#define                         NFLICK_IS_GFT_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_GFT_RESPONSE))
+
+#define                         NFLICK_GFT_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_GFT_RESPONSE, NFlickGftResponse)
+
+#define                         NFLICK_GFT_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_GFT_RESPONSE, NFlickGftResponseClass))
+
+/* Photo set */
+
+typedef struct                  _NFlickPhotoSetClass NFlickPhotoSetClass;
+
+typedef struct                  _NFlickPhotoSet NFlickPhotoSet;
+
+typedef struct                  _NFlickPhotoSetPrivate NFlickPhotoSetPrivate;
+
+#define                         NFLICK_TYPE_PHOTO_SET (nflick_photo_set_get_type ())
+
+#define                         NFLICK_IS_PHOTO_SET(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_SET))
+
+#define                         NFLICK_PHOTO_SET(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_SET, NFlickPhotoSet)
+
+#define                         NFLICK_PHOTO_SET_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_SET, NFlickPhotoSetClass))
+
+/* Thmb table */
+
+typedef struct                  _NFlickThmbTableClass NFlickThmbTableClass;
+
+typedef struct                  _NFlickThmbTable NFlickThmbTable;
+
+typedef struct                  _NFlickThmbTablePrivate NFlickThmbTablePrivate;
+
+#define                         NFLICK_TYPE_THMB_TABLE (nflick_thmb_table_get_type ())
+
+#define                         NFLICK_IS_THMB_TABLE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_THMB_TABLE))
+
+#define                         NFLICK_THMB_TABLE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_THMB_TABLE, NFlickThmbTable)
+
+#define                         NFLICK_THMB_TABLE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_THMB_TABLE, NFlickThmbTableClass))
+
+/* Thmb image */
+
+typedef struct                  _NFlickThmbImageClass NFlickThmbImageClass;
+
+typedef struct                  _NFlickThmbImage NFlickThmbImage;
+
+typedef struct                  _NFlickThmbImagePrivate NFlickThmbImagePrivate;
+
+#define                         NFLICK_TYPE_THMB_IMAGE (nflick_thmb_image_get_type ())
+
+#define                         NFLICK_IS_THMB_IMAGE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_THMB_IMAGE))
+
+#define                         NFLICK_THMB_IMAGE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_THMB_IMAGE, NFlickThmbImage)
+
+#define                         NFLICK_THMB_IMAGE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_THMB_IMAGE, NFlickThmbImageClass))
+
+/* Set list response */
+
+typedef struct                  _NFlickSetListResponseClass NFlickSetListResponseClass;
+
+typedef struct                  _NFlickSetListResponse NFlickSetListResponse;
+
+typedef struct                  _NFlickSetListResponsePrivate NFlickSetListResponsePrivate;
+
+#define                         NFLICK_TYPE_SET_LIST_RESPONSE (nflick_set_list_response_get_type ())
+
+#define                         NFLICK_IS_SET_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SET_LIST_RESPONSE))
+
+#define                         NFLICK_SET_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SET_LIST_RESPONSE, NFlickSetListResponse)
+
+#define                         NFLICK_SET_LIST_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SET_LIST_RESPONSE, NFlickSetListResponseClass))
+
+/* Photo list response */
+
+typedef struct                  _NFlickPhotoListResponseClass NFlickPhotoListResponseClass;
+
+typedef struct                  _NFlickPhotoListResponse NFlickPhotoListResponse;
+
+typedef struct                  _NFlickPhotoListResponsePrivate NFlickPhotoListResponsePrivate;
+
+#define                         NFLICK_TYPE_PHOTO_LIST_RESPONSE (nflick_photo_list_response_get_type ())
+
+#define                         NFLICK_IS_PHOTO_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_LIST_RESPONSE))
+
+#define                         NFLICK_PHOTO_LIST_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_LIST_RESPONSE, NFlickPhotoListResponse)
+
+#define                         NFLICK_PHOTO_LIST_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_LIST_RESPONSE, NFlickPhotoListResponseClass))
+
+/* No set response */
+
+typedef struct                  _NFlickNoSetResponseClass NFlickNoSetResponseClass;
+
+typedef struct                  _NFlickNoSetResponse NFlickNoSetResponse;
+
+typedef struct                  _NFlickNoSetResponsePrivate NFlickNoSetResponsePrivate;
+
+#define                         NFLICK_TYPE_NO_SET_RESPONSE (nflick_no_set_response_get_type ())
+
+#define                         NFLICK_IS_NO_SET_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_NO_SET_RESPONSE))
+
+#define                         NFLICK_NO_SET_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_NO_SET_RESPONSE, NFlickNoSetResponse)
+
+#define                         NFLICK_NO_SET_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_NO_SET_RESPONSE, NFlickNoSetResponseClass))
+
+/* GetSizes response */
+
+typedef struct                  _NFlickGetSizesResponseClass NFlickGetSizesResponseClass;
+
+typedef struct                  _NFlickGetSizesResponse NFlickGetSizesResponse;
+
+typedef struct                  _NFlickGetSizesResponsePrivate NFlickGetSizesResponsePrivate;
+
+#define                         NFLICK_TYPE_GET_SIZES_RESPONSE (nflick_get_sizes_response_get_type ())
+
+#define                         NFLICK_IS_GET_SIZES_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_GET_SIZES_RESPONSE))
+
+#define                         NFLICK_GET_SIZES_RESPONSE(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_GET_SIZES_RESPONSE, NFlickGetSizesResponse)
+
+#define                         NFLICK_GET_SIZES_RESPONSE_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_GET_SIZES_RESPONSE, NFlickGetSizesResponseClass))
+
+/* Auth worker */
+
+typedef struct                  _NFlickAuthWorkerClass NFlickAuthWorkerClass;
+
+typedef struct                  _NFlickAuthWorker NFlickAuthWorker;
+
+typedef struct                  _NFlickAuthWorkerPrivate NFlickAuthWorkerPrivate;
+
+#define                         NFLICK_TYPE_AUTH_WORKER (nflick_auth_worker_get_type ())
+
+#define                         NFLICK_IS_AUTH_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_AUTH_WORKER))
+
+#define                         NFLICK_AUTH_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_AUTH_WORKER, NFlickAuthWorker)
+
+#define                         NFLICK_AUTH_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_AUTH_WORKER, NFlickAuthWorkerClass))
+
+/* Show worker */
+
+typedef struct                  _NFlickShowWorkerClass NFlickShowWorkerClass;
+
+typedef struct                  _NFlickShowWorker NFlickShowWorker;
+
+typedef struct                  _NFlickShowWorkerPrivate NFlickShowWorkerPrivate;
+
+#define                         NFLICK_TYPE_SHOW_WORKER (nflick_show_worker_get_type ())
+
+#define                         NFLICK_IS_SHOW_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SHOW_WORKER))
+
+#define                         NFLICK_SHOW_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SHOW_WORKER, NFlickShowWorker)
+
+#define                         NFLICK_SHOW_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SHOW_WORKER, NFlickShowWorkerClass))
+
+/* Set worker */
+
+typedef struct                  _NFlickSetListWorkerClass NFlickSetListWorkerClass;
+
+typedef struct                  _NFlickSetListWorker NFlickSetListWorker;
+
+typedef struct                  _NFlickSetListWorkerPrivate NFlickSetListWorkerPrivate;
+
+#define                         NFLICK_TYPE_SET_LIST_WORKER (nflick_set_list_worker_get_type ())
+
+#define                         NFLICK_IS_SET_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SET_LIST_WORKER))
+
+#define                         NFLICK_SET_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SET_LIST_WORKER, NFlickSetListWorker)
+
+#define                         NFLICK_SET_LIST_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SET_LIST_WORKER, NFlickSetListWorkerClass))
+
+/* Photo list worker */
+
+typedef struct                  _NFlickPhotoListWorkerClass NFlickPhotoListWorkerClass;
+
+typedef struct                  _NFlickPhotoListWorker NFlickPhotoListWorker;
+
+typedef struct                  _NFlickPhotoListWorkerPrivate NFlickPhotoListWorkerPrivate;
+
+#define                         NFLICK_TYPE_PHOTO_LIST_WORKER (nflick_photo_list_worker_get_type ())
+
+#define                         NFLICK_IS_PHOTO_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTO_LIST_WORKER))
+
+#define                         NFLICK_PHOTO_LIST_WORKER(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTO_LIST_WORKER, NFlickPhotoListWorker)
+
+#define                         NFLICK_PHOTO_LIST_WORKER_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTO_LIST_WORKER, NFlickPhotoListWorkerClass))
+
+/* Photos vbox */
+
+typedef struct                  _NFlickPhotosVBoxClass NFlickPhotosVBoxClass;
+
+typedef struct                  _NFlickPhotosVBox NFlickPhotosVBox;
+
+typedef struct                  _NFlickPhotosVBoxPrivate NFlickPhotosVBoxPrivate;
+
+#define                         NFLICK_TYPE_PHOTOS_VBOX (nflick_photos_vbox_get_type ())
+
+#define                         NFLICK_IS_PHOTOS_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_PHOTOS_VBOX))
+
+#define                         NFLICK_PHOTOS_VBOX(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_PHOTOS_VBOX, NFlickPhotosVBox)
+
+#define                         NFLICK_PHOTOS_VBOX_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_PHOTOS_VBOX, NFlickPhotosVBoxClass))
+
+/* Set Combo */
+
+typedef struct                  _NFlickSetComboClass NFlickSetComboClass;
+
+typedef struct                  _NFlickSetCombo NFlickSetCombo;
+
+typedef struct                  _NFlickSetComboPrivate NFlickSetComboPrivate;
+
+#define                         NFLICK_TYPE_SET_COMBO (nflick_set_combo_get_type ())
+
+#define                         NFLICK_IS_SET_COMBO(obj) \
+                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NFLICK_TYPE_SET_COMBO))
+
+#define                         NFLICK_SET_COMBO(obj) \
+                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NFLICK_TYPE_SET_COMBO, NFlickSetCombo)
+
+#define                         NFLICK_SET_COMBO_GET_CLASS(obj) \
+                                (G_TYPE_INSTANCE_GET_CLASS ((obj), NFLICK_TYPE_SET_COMBO, NFlickSetComboClass))
+
+/* Processor */
+
+typedef                         void (*NFlickProcessorFreeFunc) (gpointer data);
+
+typedef                         gboolean (*NFlickProcessorJobFunc) (gpointer data, gchar **error);
+
+typedef                         gboolean (*NFlickProcessorErrorFunc) (gchar *msg);
+
+typedef                         gboolean (*NFlickProcessorDoneFunc) (gpointer data);
+
+typedef struct                  _NFlickProcessorResult NFlickProcessorResult;
+
+/* Model */
+
+typedef struct                  _NFlickModel NFlickModel;
+
+/* Photo data */
+
+typedef struct                  _NFlickPhotoData NFlickPhotoData;
+
+#define                         NFLICK_TYPE_PHOTO_DATA (nflick_photo_data_get_type ())
+
+/* End */
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick-worker-private.h b/attic/fluttr/libnflick/nflick-worker-private.h
new file mode 100644 (file)
index 0000000..884f364
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+static GObject*                 ParentClass = NULL;
+
+struct                          _NFlickWorkerPrivate
+{
+        GThread *Thread;
+        gboolean Started;
+        GMutex *Mutex;
+        NFlickWorkerStatus Status;
+        gchar *Error;
+        gchar *Message;
+
+        NFlickWorkerIdleFunc AbortedIdle;
+        NFlickWorkerIdleFunc OkIdle;
+        NFlickWorkerIdleFunc ErrorIdle;
+        NFlickWorkerIdleFunc MsgChangeIdle;
+        gpointer CustomData;
+        
+        gboolean AbortRequested;
+};
+
+enum 
+{
+        ARG_0,
+        ARG_ERROR,
+        ARG_MESSAGE,
+        ARG_STATUS
+};
+
+#define                         WORKER_LOCK(obj) (g_mutex_lock (obj->Private->Mutex))
+
+#define                         WORKER_UNLOCK(obj) (g_mutex_unlock (obj->Private->Mutex))
+
+static void                     nflick_worker_class_init (NFlickWorkerClass *klass);
+
+static void                     nflick_worker_init (NFlickWorker *self);
+
+static gboolean                 private_init (NFlickWorker *self, NFlickWorkerPrivate *private);
+
+static void                     private_dispose (NFlickWorkerPrivate *private);
+
+static void                     nflick_worker_dispose (NFlickWorker *self);
+
+static void                     nflick_worker_finalize (NFlickWorker *self);
+
+static void                     thread_start (NFlickWorker *self);
+
+static void                     set_error_no_lock (NFlickWorker *self, const gchar *error);
+
+static void                     nflick_worker_get_property (NFlickWorker *self, guint propid, 
+                                                            GValue *value, GParamSpec *pspec);
+
diff --git a/attic/fluttr/libnflick/nflick-worker.c b/attic/fluttr/libnflick/nflick-worker.c
new file mode 100644 (file)
index 0000000..b618a72
--- /dev/null
@@ -0,0 +1,454 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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 "nflick-worker.h"
+#include "nflick-worker-private.h"
+
+GType                           nflick_worker_get_type (void)
+{
+        static GType objecttype = 0;
+
+        if (!objecttype) {
+
+                static const GTypeInfo objectinfo = {
+                        sizeof (NFlickWorkerClass), 
+                        NULL, 
+                        NULL,
+                        (GClassInitFunc) nflick_worker_class_init,
+                        NULL,
+                        NULL, 
+                        sizeof (NFlickWorker), 
+                        4, 
+                        (GInstanceInitFunc) nflick_worker_init,
+                };
+                objecttype = g_type_register_static (G_TYPE_OBJECT, "NFlickWorker",
+                                                     &objectinfo, 0);
+        }
+        return objecttype;
+}
+
+static void                     nflick_worker_class_init (NFlickWorkerClass *klass)
+{
+        GObjectClass *gobjectclass = (GObjectClass *) klass;
+
+        gobjectclass->dispose = (gpointer) nflick_worker_dispose;
+        gobjectclass->finalize = (gpointer) nflick_worker_finalize;
+        gobjectclass->get_property = (gpointer) nflick_worker_get_property;
+        
+        g_object_class_install_property (gobjectclass, ARG_ERROR,
+                                         g_param_spec_string
+                                         ("error", "Error", "Message describing the error",
+                                         NULL, G_PARAM_READABLE));
+
+        g_object_class_install_property (gobjectclass, ARG_STATUS,
+                                         g_param_spec_int 
+                                         ("status", "Status", "Current worker status",
+                                         -5000, 5000, NFLICK_WORKER_STATUS_IDLE, G_PARAM_READABLE));
+        /* FIXME Use actual max/min vals for int */
+                                         
+        g_object_class_install_property (gobjectclass, ARG_MESSAGE,
+                                         g_param_spec_string
+                                         ("message", "Message", "Message describing the thread status",
+                                         NULL, G_PARAM_READABLE));
+
+        ParentClass = g_type_class_ref (G_TYPE_OBJECT);
+
+        klass->ThreadFunc = NULL;
+}
+
+static void                     nflick_worker_init (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        self->Private = NULL;
+
+        NFlickWorkerPrivate *priv = g_new0 (NFlickWorkerPrivate, 1);
+        g_return_if_fail (priv != NULL);
+        
+        if (private_init (self, priv) == TRUE) 
+                self->Private = priv;
+        else {
+                private_dispose (priv);
+                g_free (priv);
+                self->Private = NULL;
+        }
+}
+
+static gboolean                 private_init (NFlickWorker *self, NFlickWorkerPrivate *private)
+{
+        g_return_val_if_fail (NFLICK_IS_WORKER (self), FALSE);
+        g_return_val_if_fail (private != NULL, FALSE);
+
+        private->Thread = NULL;
+
+        private->Mutex = g_mutex_new ();
+        g_return_val_if_fail (private->Mutex != NULL, FALSE);
+
+        private->Started = FALSE;
+        private->Status = NFLICK_WORKER_STATUS_IDLE;
+        private->Error = NULL;
+        private->AbortRequested = FALSE;
+        
+        /* Null the idle functions */
+        private->OkIdle = NULL;
+        private->AbortedIdle = NULL;
+        private->MsgChangeIdle = NULL;
+        private->ErrorIdle = NULL;
+        private->CustomData = NULL;
+        
+        /* Initialize the message to a stubby one */
+        private->Message = g_strdup (gettext ("Working..."));
+        
+        return TRUE;
+}
+
+static void                     private_dispose (NFlickWorkerPrivate *private)
+{
+        g_return_if_fail (private != NULL);
+
+        if (private->Thread != NULL) {
+                g_thread_join (private->Thread);
+                private->Thread = NULL;
+        }
+
+        if (private->Mutex != NULL) {
+                g_mutex_free (private->Mutex);
+                private->Mutex = NULL;
+        }
+
+        if (private->Error != NULL) {
+                g_free (private->Error);
+                private->Error = NULL;
+        }
+
+        if (private->Message != NULL) {
+                g_free (private->Message);
+                private->Message = NULL;
+        }
+}
+
+void                            nflick_worker_start (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        WORKER_LOCK (self);
+        if (self->Private->Started == TRUE) {
+                g_warning ("Worker was already started");
+        } else {
+                self->Private->Thread = g_thread_create ((GThreadFunc) thread_start, self, TRUE, NULL);
+                /* FIXME Check for NULL */
+        }
+
+        WORKER_UNLOCK (self);
+}
+
+static void                     thread_start (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        WORKER_LOCK (self);
+
+        /* Get the class and call the proper function */
+        NFlickWorkerClass *klass = (NFlickWorkerClass *) G_OBJECT_GET_CLASS (self);
+        g_assert (klass != NULL);
+
+        if (klass->ThreadFunc == NULL) {
+                g_warning ("No thread func");
+                set_error_no_lock (self, gettext ("Internal threading error, no thread function. "
+                                                  "Please file a bug report."));
+                self->Private->Status = NFLICK_WORKER_STATUS_ERROR;
+                
+                if (self->Private->ErrorIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->ErrorIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+                                    
+
+                WORKER_UNLOCK (self);
+                goto Done;
+        }
+
+        self->Private->Status = NFLICK_WORKER_STATUS_RUNNING;
+        WORKER_UNLOCK (self);
+
+        /* Here we're waiting, waiting, waiting... */
+        NFlickWorkerStatus status = klass->ThreadFunc (self);
+        
+        WORKER_LOCK (self);
+        
+        /* Our last chance for an abort */
+        if (self->Private->AbortRequested == TRUE)
+                status = NFLICK_WORKER_STATUS_ABORTED;
+        
+        self->Private->Status = status;
+        
+        switch (status) {
+                
+                case NFLICK_WORKER_STATUS_RUNNING:
+                case NFLICK_WORKER_STATUS_IDLE:
+                self->Private->Status = NFLICK_WORKER_STATUS_ERROR;
+                set_error_no_lock (self, gettext ("Internal threading error, thread in running after function done. "
+                                                  "Please file a bug report."));
+                /* Fire error func */
+                if (self->Private->ErrorIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->ErrorIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+                break;
+                
+                case NFLICK_WORKER_STATUS_ERROR:
+                if (self->Private->Error == NULL)
+                        set_error_no_lock (self, gettext ("Error in thread, but no error was set. "
+                                                          "Please file a bug report."));
+                /* Fire error func */
+                if (self->Private->ErrorIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->ErrorIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+                break;
+                
+                case NFLICK_WORKER_STATUS_OK:
+                /* Fire ok func */
+                if (self->Private->OkIdle != NULL) 
+                        /*g_idle_add ((GSourceFunc) self->Private->OkIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);*/
+                       g_timeout_add_full (G_PRIORITY_HIGH_IDLE,
+                                            1000,
+                                            (GSourceFunc) self->Private->OkIdle,
+                                            (self->Private->CustomData 
+                                            != NULL) ? self->Private->CustomData 
+                                               : self,
+                                            NULL);
+
+                break;
+                
+                case NFLICK_WORKER_STATUS_ABORTED:
+                /* Fire aborted func */
+                if (self->Private->AbortedIdle != NULL) 
+                        g_idle_add ((GSourceFunc) self->Private->AbortedIdle, 
+                                    (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+
+                break;
+        }
+        
+        WORKER_UNLOCK (self);
+
+        Done:
+        return;
+}
+
+static void                     set_error_no_lock (NFlickWorker *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        if (self->Private->Error != NULL)
+                g_free (self->Private->Error);
+
+        self->Private->Error = g_strdup (error);
+}
+
+void                            nflick_worker_set_message (NFlickWorker *self, const gchar *msg)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        WORKER_LOCK (self);
+        if (self->Private->Message != NULL)
+                g_free (self->Private->Message);
+        
+        self->Private->Message = g_strdup (msg);
+        
+        /* Notify */
+        if (self->Private->MsgChangeIdle != NULL) 
+                g_idle_add ((GSourceFunc) self->Private->MsgChangeIdle, 
+                            (self->Private->CustomData != NULL) ? self->Private->CustomData : self);
+        
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_network_error (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        nflick_worker_set_error (self, gettext ("A network error occured while trying to connect to flickr. "
+                                                "Please check your connection settings."));
+}
+
+gboolean                        nflick_worker_parse_api_response (NFlickWorker *self, NFlickApiResponse *response)
+{
+        g_return_val_if_fail (NFLICK_IS_WORKER (self), FALSE);
+        g_return_val_if_fail (NFLICK_IS_API_RESPONSE (response), FALSE);
+
+        gboolean success = FALSE;
+
+        g_object_get (G_OBJECT (response), "success", &success, NULL);
+
+        if (success == TRUE)
+                return TRUE;
+        else {
+                gboolean parse_error = FALSE;
+                gchar *error = NULL;
+
+                g_object_get (G_OBJECT (response), "error", &error, "parseerror", &parse_error, NULL);
+                
+                if (parse_error == TRUE) {
+                        gchar *e = g_strdup_printf ("%s\n\n%s", 
+                                                    gettext ("An error occurred while parsing the flickr api response. "
+                                                             "Please file a bug report. Error details: "), error);
+                        nflick_worker_set_error (self, e);
+                        if (e != NULL)
+                                g_free (e);
+                } else 
+                        nflick_worker_set_error (self, error);
+                
+                if (error != NULL)
+                        g_free (error);
+
+                return FALSE;
+        }
+}
+
+void                            nflick_worker_set_error (NFlickWorker *self, const gchar *error)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        g_return_if_fail (error != NULL);
+
+        WORKER_LOCK (self);
+        set_error_no_lock (self, error);
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_custom_data (NFlickWorker *self, gpointer data)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->CustomData = data;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_aborted_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->AbortedIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_ok_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->OkIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_set_error_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->ErrorIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+void                            nflick_worker_request_abort (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->AbortRequested = TRUE;
+        WORKER_UNLOCK (self);
+}
+
+gboolean                        nflick_worker_is_aborted (NFlickWorker *self)
+{
+        g_return_val_if_fail (NFLICK_IS_WORKER (self), FALSE);
+        
+        WORKER_LOCK (self);
+        gboolean ret = self->Private->AbortRequested;
+        WORKER_UNLOCK (self);
+        
+        return ret;
+}
+
+void                            nflick_worker_set_msg_change_idle (NFlickWorker *self, NFlickWorkerIdleFunc func)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        WORKER_LOCK (self);
+        self->Private->MsgChangeIdle = func;
+        WORKER_UNLOCK (self);
+}
+
+static void                     nflick_worker_dispose (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+
+        if (self->Private != NULL)
+                private_dispose (self->Private);
+
+        G_OBJECT_CLASS (ParentClass)->dispose (G_OBJECT (self));
+}
+
+static void                     nflick_worker_finalize (NFlickWorker *self)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        
+        if (self->Private != NULL) {
+                g_free (self->Private);
+                self->Private = NULL;
+        }
+
+        G_OBJECT_CLASS (ParentClass)->finalize (G_OBJECT (self));
+}
+
+static void                     nflick_worker_get_property (NFlickWorker *self, guint propid, 
+                                                            GValue *value, GParamSpec *pspec)
+{
+        g_return_if_fail (NFLICK_IS_WORKER (self));
+        g_assert (self->Private != NULL);
+                
+        switch (propid) {
+                
+                case ARG_ERROR:
+                        WORKER_LOCK (self);
+                        g_value_set_string (value, self->Private->Error);
+                        WORKER_UNLOCK (self);
+                break;
+        
+                case ARG_STATUS:
+                        WORKER_LOCK (self);
+                        g_value_set_int (value, self->Private->Status);
+                        WORKER_UNLOCK (self);
+                break;
+        
+                case ARG_MESSAGE:
+                        WORKER_LOCK (self);
+                        g_value_set_string (value, self->Private->Message);
+                        WORKER_UNLOCK (self);
+                        break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (G_OBJECT (self), propid, pspec);
+                break;
+        }
+}
diff --git a/attic/fluttr/libnflick/nflick-worker.h b/attic/fluttr/libnflick/nflick-worker.h
new file mode 100644 (file)
index 0000000..b1c1a4f
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************************/
+/*                                                                            */
+/* GPL license, Copyright (c) 2005-2006 by:                                   */
+/*                                                                            */
+/* Authors:                                                                   */
+/*      Michael Dominic K. <michaldominik@gmail.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.                      */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef __NFLICKWORKER_H__
+#define __NFLICKWORKER_H__
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include "nflick-api-response.h"
+#include "nflick-types.h"
+
+struct                          _NFlickWorker
+{
+        GObject Parent;
+        NFlickWorkerPrivate *Private;
+};
+
+struct                          _NFlickWorkerClass 
+{
+        GObjectClass ParentClass;
+        NFlickWorkerThreadFunc ThreadFunc;
+};
+
+GType                           nflick_worker_get_type (void);
+
+void                            nflick_worker_start (NFlickWorker *self);
+
+void                            nflick_worker_set_error (NFlickWorker *self, const gchar *error);
+
+void                            nflick_worker_set_custom_data (NFlickWorker *self, gpointer data);
+
+void                            nflick_worker_set_aborted_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_ok_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_error_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_msg_change_idle (NFlickWorker *self, NFlickWorkerIdleFunc func);
+
+void                            nflick_worker_set_message (NFlickWorker *self, const gchar *msg);
+
+void                            nflick_worker_request_abort (NFlickWorker *self);
+
+gboolean                        nflick_worker_is_aborted (NFlickWorker *self);
+
+void                            nflick_worker_set_network_error (NFlickWorker *self);
+
+gboolean                        nflick_worker_parse_api_response (NFlickWorker *self, NFlickApiResponse *response);
+
+#endif
diff --git a/attic/fluttr/libnflick/nflick.h b/attic/fluttr/libnflick/nflick.h
new file mode 100644 (file)
index 0000000..3769917
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+/* A simple header file which includes all of the necessary nflick headers */
+
+#ifndef NFLICK_H
+#define NFLICK_H
+
+#include "nflick-api-request.h"
+#include "nflick-api-response.h"
+#include "nflick-auth-worker.h"
+#include "nflick-flickr.h"
+#include "nflick-get-sizes-response.h"
+#include "nflick-gft-response.h"
+#include "nflick-no-set-response.h"
+#include "nflick-photo-data.h"
+#include "nflick-photo-list-response.h"
+#include "nflick-photo-list-worker.h"
+#include "nflick-photo-set.h"
+#include "nflick-pixbuf-fetch.h"
+#include "nflick-set-list-response.h"
+#include "nflick-set-list-worker.h"
+#include "nflick-show-worker.h"
+#include "nflick-types.h"
+#include "nflick-worker.h"
+
+
+#endif
diff --git a/attic/fluttr/ltmain.sh b/attic/fluttr/ltmain.sh
new file mode 120000 (symlink)
index 0000000..72940b6
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/libtool/ltmain.sh
\ No newline at end of file
diff --git a/attic/fluttr/src/Makefile.am b/attic/fluttr/src/Makefile.am
new file mode 100644 (file)
index 0000000..aee400c
--- /dev/null
@@ -0,0 +1,42 @@
+bin_PROGRAMS=fluttr
+
+PKGDATADIR = $(datadir)/fluttr
+AM_CFLAGS = \
+       $(DEPS_CFLAGS)                          \
+       $(GCC_FLAGS)                            \
+       -I$(top_builddir)                       \
+       -I$(top_srcdir)                         \
+       -D_GNU_SOURCE                           \
+       -DPKGDATADIR=\"$(PKGDATADIR)\"
+
+fluttr_LDADD  = $(DEPS_LIBS)                   \
+       $(top_builddir)/libnflick/libnflick.la  
+
+fluttr_SOURCES = \
+       main.c                                  \
+       eggsequence.c                           \
+       eggsequence.h                           \
+       fluttr-auth.c                           \
+       fluttr-auth.h                           \
+       fluttr-behave.c                         \
+       fluttr-behave.h                         \
+       fluttr-library.c                        \
+       fluttr-library.h                        \
+       fluttr-library-row.c                    \
+       fluttr-library-row.h                    \
+       fluttr-list.c                           \
+       fluttr-list.h                           \
+       fluttr-list-view.c                      \
+       fluttr-list-view.h                      \
+       fluttr-photo.c                          \
+       fluttr-photo.h                          \
+       fluttr-set.c                            \
+       fluttr-set.h                            \
+       fluttr-set-view.c                       \
+       fluttr-set-view.h                       \
+       fluttr-settings.c                       \
+       fluttr-settings.h                       \
+       fluttr-spinner.c                        \
+       fluttr-spinner.h                        \
+       fluttr-viewer.c                         \
+       fluttr-viewer.h                         
diff --git a/attic/fluttr/src/eggsequence.c b/attic/fluttr/src/eggsequence.c
new file mode 100644 (file)
index 0000000..979a512
--- /dev/null
@@ -0,0 +1,1709 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#include "eggsequence.h"
+
+typedef struct _EggSequenceNode EggSequenceNode;
+
+struct _EggSequence
+{
+    EggSequenceNode *   end_node;
+    GDestroyNotify      data_destroy_notify;
+    gboolean            access_prohibited;
+};
+
+struct _EggSequenceNode
+{
+    gint n_nodes;
+    EggSequenceNode *parent;    
+    EggSequenceNode *left;
+    EggSequenceNode *right;
+    gpointer data;             /* For the end node, this field points
+                                * to the sequence
+                                */
+};
+
+static EggSequenceNode *node_new           (gpointer           data);
+static EggSequenceNode *node_get_first     (EggSequenceNode   *node);
+static EggSequenceNode *node_get_last      (EggSequenceNode   *node);
+static EggSequenceNode *node_get_prev      (EggSequenceNode   *node);
+static EggSequenceNode *node_get_next      (EggSequenceNode   *node);
+static gint             node_get_pos       (EggSequenceNode   *node);
+static EggSequenceNode *node_get_by_pos    (EggSequenceNode   *node,
+                                           gint               pos);
+static EggSequenceNode *node_find_closest  (EggSequenceNode   *haystack,
+                                           EggSequenceNode   *needle,
+                                           EggSequenceNode   *end,
+                                           EggSequenceIterCompareFunc cmp,
+                                           gpointer           user_data);
+static gint             node_get_length    (EggSequenceNode   *node);
+static void             node_free          (EggSequenceNode   *node,
+                                           EggSequence       *seq);
+static void             node_cut           (EggSequenceNode   *split);
+static void             node_insert_after  (EggSequenceNode   *node,
+                                           EggSequenceNode   *second);
+static void             node_insert_before (EggSequenceNode   *node,
+                                           EggSequenceNode   *new);
+static void             node_unlink        (EggSequenceNode   *node);
+static void             node_insert_sorted (EggSequenceNode   *node,
+                                           EggSequenceNode   *new,
+                                           EggSequenceNode   *end,
+                                           EggSequenceIterCompareFunc cmp_func,
+                                           gpointer           cmp_data);
+
+static EggSequence *
+get_sequence (EggSequenceNode *node)
+{
+    return (EggSequence *)node_get_last (node)->data;
+}
+
+static void
+check_seq_access (EggSequence *seq)
+{
+    if (G_UNLIKELY (seq->access_prohibited))
+    {
+       g_warning ("Accessing a sequence while it is "
+                  "being sorted or searched is not allowed");
+    }
+}
+
+static void
+check_iter_access (EggSequenceIter *iter)
+{
+    check_seq_access (get_sequence (iter));
+}
+
+static gboolean
+is_end (EggSequenceIter *iter)
+{
+    EggSequence *seq = get_sequence (iter);
+    
+    return seq->end_node == iter;
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * egg_sequence_new:
+ * @data_destroy: A #GDestroyNotify function, or %NULL
+ * 
+ * Creates a new EggSequence. The @data_destroy function will be called
+ * on all items when the sequence is destroyed and on items that are
+ * removed from the sequence.
+ * 
+ * Return value: A new #EggSequence
+ * 
+ * Since: 2.14
+ **/
+EggSequence *
+egg_sequence_new (GDestroyNotify data_destroy)
+{
+    EggSequence *seq = g_new (EggSequence, 1);
+    seq->data_destroy_notify = data_destroy;
+    
+    seq->end_node = node_new (seq);
+    
+    seq->access_prohibited = FALSE;
+    
+    return seq;
+}
+
+/**
+ * egg_sequence_free:
+ * @seq: a #EggSequence
+ * 
+ * Frees the memory allocated for @seq. If @seq has a destroy notify
+ * function associated with it, that function is called on all items in
+ * @seq.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_free (EggSequence *seq)
+{
+    g_return_if_fail (seq != NULL);
+    
+    check_seq_access (seq);
+    
+    node_free (seq->end_node, seq);
+    
+    g_free (seq);
+}
+
+/**
+ * egg_sequence_foreach_range:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * @func: a #GFunc
+ * @user_data: user data passed to @func
+ * 
+ * Calls @func for each item in the range (@begin, @end) passing
+ * @user_data to the function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_foreach_range (EggSequenceIter *begin,
+                           EggSequenceIter *end,
+                           GFunc            func,
+                           gpointer         user_data)
+{
+    EggSequence *seq;
+    EggSequenceIter *iter;
+    
+    g_return_if_fail (func != NULL);
+    g_return_if_fail (begin != NULL);
+    g_return_if_fail (end != NULL);
+    
+    seq = get_sequence (begin);
+    
+    seq->access_prohibited = TRUE;
+    
+    iter = begin;
+    while (iter != end)
+    {
+       EggSequenceIter *next = node_get_next (iter);
+       
+       func (iter->data, user_data);
+       
+       iter = next;
+    }
+    
+    seq->access_prohibited = FALSE;
+}
+
+/**
+ * egg_sequence_foreach:
+ * @seq: a #EggSequence
+ * @func: the function to call for each item in @seq
+ * @data: user data passed to @func
+ * 
+ * Calls @func for each item in the sequence passing @user_data
+ * to the function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_foreach (EggSequence *seq,
+                     GFunc        func,
+                     gpointer     data)
+{
+    EggSequenceIter *begin, *end;
+    
+    check_seq_access (seq);
+    
+    begin = egg_sequence_get_begin_iter (seq);
+    end   = egg_sequence_get_end_iter (seq);
+    
+    egg_sequence_foreach_range (begin, end, func, data);
+}
+
+/**
+ * egg_sequence_range_get_midpoint:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Finds an iterator somewhere in the range (@begin, @end). This
+ * iterator will be close to the middle of the range, but is not
+ * guaranteed to be <emphasize>exactly</emphasize> in the middle.
+ *
+ * The @begin and @end iterators must both point to the same sequence and
+ * @begin must come before or be equal to @end in the sequence.
+ * 
+ * Return value: A #EggSequenceIter which is close to the middle of
+ * the (@begin, @end) range.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_range_get_midpoint (EggSequenceIter *begin,
+                                EggSequenceIter *end)
+{
+    int begin_pos, end_pos, mid_pos;
+    
+    g_return_val_if_fail (begin != NULL, NULL);
+    g_return_val_if_fail (end != NULL, NULL);
+    g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL);
+
+    begin_pos = node_get_pos (begin);
+    end_pos = node_get_pos (end);
+
+    g_return_val_if_fail (end_pos >= begin_pos, NULL);
+    
+    mid_pos = begin_pos + (end_pos - begin_pos) / 2;
+
+    return node_get_by_pos (begin, mid_pos);
+}
+
+/**
+ * egg_sequence_iter_compare:
+ * @a: a #EggSequenceIter
+ * @b: a #EggSequenceIter
+ * 
+ * Returns a negative number if @a comes before @b, 0 if they are equal,
+ * and a positive number if @a comes after @b.
+ *
+ * The @a and @b iterators must point into the same sequence.
+ * 
+ * Return value: A negative number if @a comes before @b, 0 if they are
+ * equal, and a positive number if @a comes after @b.
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_iter_compare (EggSequenceIter *a,
+                          EggSequenceIter *b)
+{
+    gint a_pos, b_pos;
+    
+    g_return_val_if_fail (a != NULL, 0);
+    g_return_val_if_fail (b != NULL, 0);
+    g_return_val_if_fail (get_sequence (a) == get_sequence (b), 0);
+    
+    check_iter_access (a);
+    check_iter_access (b);
+    
+    a_pos = node_get_pos (a);
+    b_pos = node_get_pos (b);
+    
+    if (a_pos == b_pos)
+       return 0;
+    else if (a_pos > b_pos)
+       return 1;
+    else
+       return -1;
+}
+
+/**
+ * egg_sequence_append:
+ * @seq: a #EggSequencePointer
+ * @data: the data for the new item
+ * 
+ * Adds a new item to the end of @seq.
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_append (EggSequence *seq,
+                    gpointer     data)
+{
+    EggSequenceNode *node;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    node = node_new (data);
+    node_insert_before (seq->end_node, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_prepend:
+ * @seq: a #EggSequence
+ * @data: the data for the new item
+ * 
+ * Adds a new item to the front of @seq
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_prepend (EggSequence *seq,
+                     gpointer     data)
+{
+    EggSequenceNode *node, *first;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    node = node_new (data);
+    first = node_get_first (seq->end_node);
+    
+    node_insert_before (first, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_insert_before:
+ * @iter: a #EggSequenceIter
+ * @data: the data for the new item
+ * 
+ * Inserts a new item just before the item pointed to by @iter.
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_before (EggSequenceIter *iter,
+                           gpointer         data)
+{
+    EggSequenceNode *node;
+    
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    check_iter_access (iter);
+    
+    node = node_new (data);
+    
+    node_insert_before (iter, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_remove:
+ * @iter: a #EggSequenceIter
+ * 
+ * Removes the item pointed to by @iter. It is an error to pass the
+ * end iterator to this function.
+ *
+ * If the sequnce has a data destroy function associated with it, this
+ * function is called on the data for the removed item.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_remove (EggSequenceIter *iter)
+{
+    EggSequence *seq;
+    
+    g_return_if_fail (iter != NULL);
+    g_return_if_fail (!is_end (iter));
+    
+    check_iter_access (iter);
+    
+    seq = get_sequence (iter); 
+    
+    node_unlink (iter);
+    node_free (iter, seq);
+}
+
+/**
+ * egg_sequence_remove_range:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Removes all items in the (@begin, @end) range.
+ *
+ * If the sequence has a data destroy function associated with it, this
+ * function is called on the data for the removed items.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_remove_range (EggSequenceIter *begin,
+                          EggSequenceIter *end)
+{
+    g_return_if_fail (get_sequence (begin) == get_sequence (end));
+
+    check_iter_access (begin);
+    check_iter_access (end);
+    
+    egg_sequence_move_range (NULL, begin, end);
+}
+
+/**
+ * egg_sequence_move_range:
+ * @dest: a #EggSequenceIter
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Inserts the (@begin, @end) range at the destination pointed to by ptr.
+ * The @begin and @end iters must point into the same sequence. It is
+ * allowed for @dest to point to a different sequence than the one pointed
+ * into by @begin and @end.
+ * 
+ * If @dest is NULL, the range indicated by @begin and @end is
+ * removed from the sequence. If @dest iter points to a place within
+ * the (@begin, @end) range, the range does not move.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_move_range (EggSequenceIter *dest,
+                        EggSequenceIter *begin,
+                        EggSequenceIter *end)
+{
+    EggSequence *src_seq;
+    EggSequenceNode *first;
+    
+    g_return_if_fail (begin != NULL);
+    g_return_if_fail (end != NULL);
+    
+    check_iter_access (begin);
+    check_iter_access (end);
+    if (dest)
+       check_iter_access (dest);
+    
+    src_seq = get_sequence (begin);
+    
+    g_return_if_fail (src_seq == get_sequence (end));
+
+    /* Dest points to begin or end? */
+    if (dest == begin || dest == end)
+       return;
+
+    /* begin comes after end? */
+    if (egg_sequence_iter_compare (begin, end) >= 0)
+       return;
+
+    /* dest points somewhere in the (begin, end) range? */
+    if (dest && get_sequence (dest) == src_seq &&
+       egg_sequence_iter_compare (dest, begin) > 0 &&
+       egg_sequence_iter_compare (dest, end) < 0)
+    {
+       return;
+    }
+    
+    src_seq = get_sequence (begin);
+
+    first = node_get_first (begin);
+
+    node_cut (begin);
+
+    node_cut (end);
+
+    if (first != begin)
+       node_insert_after (node_get_last (first), end);
+
+    if (dest)
+       node_insert_before (dest, begin);
+    else
+       node_free (begin, src_seq);
+}
+
+typedef struct
+{
+    GCompareDataFunc    cmp_func;
+    gpointer           cmp_data;
+    EggSequenceNode    *end_node;
+} SortInfo;
+
+/* This function compares two iters using a normal compare
+ * function and user_data passed in in a SortInfo struct
+ */
+static gint
+iter_compare (EggSequenceIter *node1,
+             EggSequenceIter *node2,
+             gpointer data)
+{
+    const SortInfo *info = data;
+    gint retval;
+    
+    if (node1 == info->end_node)
+       return 1;
+    
+    if (node2 == info->end_node)
+       return -1;
+    
+    retval = info->cmp_func (node1->data, node2->data, info->cmp_data);
+    
+    return retval;
+}
+
+/**
+ * egg_sequence_sort:
+ * @seq: a #EggSequence
+ * @cmp_func: the #GCompareDataFunc used to sort @seq. This function is
+ *       passed two items of @seq and should return 0 if they are equal,
+ *       a negative value fi the first comes before the second, and a
+ *       positive value if the second comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ * 
+ * Sorts @seq using @cmp_func.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort (EggSequence      *seq,
+                  GCompareDataFunc  cmp_func,
+                  gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, seq->end_node };
+    
+    check_seq_access (seq);
+    
+    egg_sequence_sort_iter (seq, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_insert_sorted:
+ * @seq: a #EggSequence
+ * @data: the data to insert
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ *
+ * Inserts @data into @queue using @func to determine the new position.
+ * @seq must already be sorted according to @cmp_func; otherwise the
+ * new position of is undefined.
+ *
+ * Return value: A #EggSequenceIter pointing to the new item.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_sorted (EggSequence       *seq,
+                           gpointer           data,
+                           GCompareDataFunc   cmp_func,
+                           gpointer           cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    g_return_val_if_fail (cmp_func != NULL, NULL);
+    
+    info.end_node = seq->end_node;
+    check_seq_access (seq);
+    
+    return egg_sequence_insert_sorted_iter (seq, data, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_sort_changed:
+ * @iter: A #EggSequenceIter
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ *
+ * Moves the data pointed to a new position as indicated by @cmp_func. This
+ * function should be called for items in a sequence already sorted according
+ * to @cmp_func whenever some aspect of an item changes so that @cmp_func
+ * may return different values for that item.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_changed (EggSequenceIter  *iter,
+                          GCompareDataFunc  cmp_func,
+                          gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_if_fail (!is_end (iter));
+    
+    info.end_node = get_sequence (iter)->end_node;
+    check_iter_access (iter);
+    
+    egg_sequence_sort_changed_iter (iter, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_search:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ * 
+ * Returns an iterator pointing to the position where @data would
+ * be inserted according to @cmp_func and @cmp_data.
+ * 
+ * Return value: An #EggSequenceIter pointing to the position where @data
+ * would have been inserted according to @cmp_func and @cmp_data.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_search (EggSequence      *seq,
+                    gpointer          data,
+                    GCompareDataFunc  cmp_func,
+                    gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    info.end_node = seq->end_node;
+    check_seq_access (seq);
+    
+    return egg_sequence_search_iter (seq, data, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_sort_iter:
+ * @seq: a #EggSequence
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_sort(), but uses a #EggSequenceIterCompareFunc instead
+ * of a GCompareDataFunc as the compare function
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_iter (EggSequence                *seq,
+                       EggSequenceIterCompareFunc  cmp_func,
+                       gpointer                    cmp_data)
+{
+    EggSequence *tmp;
+    EggSequenceNode *begin, *end;
+    
+    g_return_if_fail (seq != NULL);
+    g_return_if_fail (cmp_func != NULL);
+    
+    check_seq_access (seq);
+    
+    begin = egg_sequence_get_begin_iter (seq);
+    end   = egg_sequence_get_end_iter (seq);
+    
+    tmp = egg_sequence_new (NULL);
+    
+    egg_sequence_move_range (egg_sequence_get_begin_iter (tmp), begin, end);
+    
+    tmp->access_prohibited = TRUE;
+    seq->access_prohibited = TRUE;
+    
+    while (egg_sequence_get_length (tmp) > 0)
+    {
+       EggSequenceNode *node = egg_sequence_get_begin_iter (tmp);
+       
+       node_unlink (node);
+       
+       node_insert_sorted (seq->end_node, node, seq->end_node, cmp_func, cmp_data);
+    }
+    
+    tmp->access_prohibited = FALSE;
+    seq->access_prohibited = FALSE;
+    
+    egg_sequence_free (tmp);
+}
+
+/**
+ * egg_sequence_sort_changed_iter:
+ * @iter: a #EggSequenceIter
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_sort_changed(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_changed_iter (EggSequenceIter            *iter,
+                               EggSequenceIterCompareFunc  iter_cmp,
+                               gpointer                    cmp_data)
+{
+    EggSequence *seq;
+    EggSequenceIter *next, *prev;
+    
+    g_return_if_fail (!is_end (iter));
+    
+    check_iter_access (iter);
+
+    /* If one of the neighbours is equal to iter, then
+     * don't move it. This ensures that sort_changed() is
+     * a stable operation.
+     */
+
+    next = node_get_next (iter);
+    prev = node_get_prev (iter);
+
+    if (prev != iter && iter_cmp (prev, iter, cmp_data) == 0)
+       return;
+
+    if (!is_end (next) && iter_cmp (next, iter, cmp_data) == 0)
+       return;
+    
+    seq = get_sequence (iter);
+    
+    seq->access_prohibited = TRUE;
+    
+    node_unlink (iter);
+    node_insert_sorted (seq->end_node, iter, seq->end_node, iter_cmp, cmp_data);
+    
+    seq->access_prohibited = FALSE;
+}
+
+/**
+ * egg_sequence_insert_sorted_iter:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ * 
+ * Like egg_sequence_insert_sorted(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Return value: A #EggSequenceIter pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_sorted_iter   (EggSequence                *seq,
+                                  gpointer                    data,
+                                  EggSequenceIterCompareFunc  iter_cmp,
+                                  gpointer                    cmp_data)
+{
+    EggSequenceNode *new_node;
+    EggSequence *tmp_seq;
+    
+    check_seq_access (seq);
+
+    /* Create a new temporary sequence and put the new node into
+     * that. The reason for this is that the user compare function
+     * will be called with the new node, and if it dereferences, 
+     * "is_end" will be called on it. But that will crash if the
+     * node is not actually in a sequence.
+     *
+     * node_insert_sorted() makes sure the node is unlinked before
+     * is is inserted.
+     *
+     * The reason we need the "iter" versions at all is that that
+     * is the only kind of compare functions GtkTreeView can use.
+     */
+    tmp_seq = egg_sequence_new (NULL);
+    new_node = egg_sequence_append (tmp_seq, data);
+
+    node_insert_sorted (seq->end_node, new_node,
+                       seq->end_node, iter_cmp, cmp_data);
+
+    egg_sequence_free (tmp_seq);
+    
+    return new_node;
+}
+
+/**
+ * egg_sequence_search_iter:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_search(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Return value: A #EggSequenceIter pointing to the position in @seq
+ * where @data would have been inserted according to @cmp_func and @cmp_data.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_search_iter (EggSequence                *seq,
+                         gpointer                    data,
+                         EggSequenceIterCompareFunc  cmp_func,
+                         gpointer                    cmp_data)
+{
+    EggSequenceNode *node;
+    EggSequenceNode *dummy;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    seq->access_prohibited = TRUE;
+
+    dummy = node_new (data);
+    
+    node = node_find_closest (seq->end_node, dummy,
+                             seq->end_node, cmp_func, cmp_data);
+
+    node_free (dummy, NULL);
+    
+    seq->access_prohibited = FALSE;
+    
+    return node;
+}
+
+/**
+ * egg_sequence_iter_get_sequence:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the #EggSequence that @iter points into.
+ * 
+ * Return value: The #EggSequence that @iter points into.
+ * 
+ * Since: 2.14
+ **/
+EggSequence *
+egg_sequence_iter_get_sequence (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return get_sequence (iter);
+}
+
+/**
+ * egg_sequence_get:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the data that @iter points to.
+ * 
+ * Return value: The data that @iter points to
+ * 
+ * Since: 2.14
+ **/
+gpointer
+egg_sequence_get (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    g_return_val_if_fail (!is_end (iter), NULL);
+    
+    return iter->data;
+}
+
+/**
+ * egg_sequence_set:
+ * @iter: a #EggSequenceIter
+ * @data: new data for the item
+ * 
+ * Changes the data for the item pointed to by @iter to be @data. If
+ * the sequence has a data destroy function associated with it, that
+ * function is called on the existing data that @iter pointed to.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_set (EggSequenceIter *iter,
+                 gpointer         data)
+{
+    EggSequence *seq;
+    
+    g_return_if_fail (iter != NULL);
+    g_return_if_fail (!is_end (iter));
+    
+    seq = get_sequence (iter);
+
+    /* If @data is identical to iter->data, it is destroyed
+     * here. This will work right in case of ref-counted objects. Also
+     * it is similar to what ghashtables do.
+     *
+     * For non-refcounted data it's a little less convenient, but
+     * code relying on self-setting not destroying would be
+     * pretty dubious anyway ...
+     */
+    
+    if (seq->data_destroy_notify)
+       seq->data_destroy_notify (iter->data);
+    
+    iter->data = data;
+}
+
+/**
+ * egg_sequence_get_length:
+ * @seq: a #EggSequence
+ * 
+ * Returns the length of @seq
+ * 
+ * Return value: The length of @seq
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_get_length (EggSequence *seq)
+{
+    return node_get_length (seq->end_node) - 1;
+}
+
+/**
+ * egg_sequence_get_end_iter:
+ * @seq: a #EggSequence 
+ * 
+ * Returns the end iterator for @seg
+ * 
+ * Return value: The end iterator for @seq
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_end_iter (EggSequence *seq)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    g_assert (is_end (seq->end_node));
+    
+    return seq->end_node;
+}
+
+/**
+ * egg_sequence_get_begin_iter:
+ * @seq: a #EggSequence
+ * 
+ * Returns the begin iterator for @seq.
+ * 
+ * Return value: The begin iterator for @seq.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_begin_iter (EggSequence *seq)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    return node_get_first (seq->end_node);
+}
+
+static int
+clamp_position (EggSequence *seq,
+               int          pos)
+{
+    gint len = egg_sequence_get_length (seq);
+    
+    if (pos > len || pos < 0)
+       pos = len;
+    
+    return pos;
+}
+
+/*
+ * if pos > number of items or -1, will return end pointer
+ */
+/**
+ * egg_sequence_get_iter_at_pos:
+ * @seq: a #EggSequence
+ * @pos: a position in @seq, or -1 for the end.
+ * 
+ * Returns the iterator as position @pos. If @pos is negative or larger
+ * than the number of items in @seq, the end iterator is returned.
+ * 
+ * Return value: The #EggSequenceIter at position @pos
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_iter_at_pos (EggSequence *seq,
+                             gint         pos)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    pos = clamp_position (seq, pos);
+    
+    return node_get_by_pos (seq->end_node, pos);
+}
+
+/**
+ * egg_sequence_move:
+ * @src: a #EggSequenceIter pointing to the item to move
+ * @dest: a #EggSequenceIter pointing to the position to which
+ *        the item is moved.
+ *
+ * Move the item pointed to by @src to the position indicated by @dest.
+ * After calling this function @dest will point to the position immediately
+ * after @src.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_move (EggSequenceIter *src,
+                  EggSequenceIter *dest)
+{
+    g_return_if_fail (src != NULL);
+    g_return_if_fail (dest != NULL);
+    g_return_if_fail (!is_end (src));
+    
+    if (src == dest)
+       return;
+    
+    node_unlink (src);
+    node_insert_before (dest, src);
+}
+
+/* EggSequenceIter */
+
+/**
+ * egg_sequence_iter_is_end:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns whether @iter is the end iterator
+ * 
+ * Return value: Whether @iter is the end iterator.
+ * 
+ * Since: 2.14
+ **/
+gboolean
+egg_sequence_iter_is_end (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, FALSE);
+    
+    return is_end (iter);
+}
+
+/**
+ * egg_sequence_iter_is_begin:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns whether @iter is the begin iterator
+ * 
+ * Return value: Whether @iter is the begin iterator
+ * 
+ * Since: 2.14
+ **/
+gboolean
+egg_sequence_iter_is_begin (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, FALSE);
+    
+    return (node_get_prev (iter) == iter);
+}
+
+/**
+ * egg_sequence_iter_get_position:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the position of @iter
+ * 
+ * Return value: The position of @iter
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_iter_get_position (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, -1);
+    
+    return node_get_pos (iter);
+}
+
+/**
+ * egg_sequence_iter_next:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns an iterator pointing to the next position after @iter. If
+ * @iter is the end iterator, the end iterator is returned.
+ * 
+ * Return value: A #EggSequenceIter pointing to the next position after @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_next (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return node_get_next (iter);
+}
+
+/**
+ * egg_sequence_iter_prev:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns an iterator pointing to the previous position before @iter. If
+ * @iter is the begin iterator, the begin iterator is returned.
+ * 
+ * Return value: A #EggSequenceIter pointing to the previous position before
+ * @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_prev (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return node_get_prev (iter);
+}
+
+/**
+ * egg_sequence_iter_move:
+ * @iter: a #EggSequenceIter
+ * @delta: A positive or negative number indicating how many positions away
+ *    from @iter the returned #EggSequenceIter will be.
+ *
+ * Returns the #EggSequenceIter which is @delta positions away from @iter.
+ * If @iter is closer than -@delta positions to the beginning of the sequence,
+ * the begin iterator is returned. If @iter is closer than @delta positions
+ * to the end of the queue, the end iterator is returned.
+ *
+ * Return value: a #EggSequenceIter which is @delta positions away from @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_move (EggSequenceIter *iter,
+                       gint             delta)
+{
+    gint new_pos;
+    
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    new_pos = node_get_pos (iter) + delta;
+    
+    new_pos = clamp_position (get_sequence (iter), new_pos);
+    
+    return node_get_by_pos (iter, new_pos);
+}
+
+/**
+ * egg_sequence_swap:
+ * @a: a #EggSequenceIter
+ * @b: a #EggSequenceIter
+ * 
+ * Swaps the items pointed to by @a and @b
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_swap (EggSequenceIter *a,
+                  EggSequenceIter *b)
+{
+    EggSequenceNode *leftmost, *rightmost, *rightmost_next;
+    int a_pos, b_pos;
+    
+    g_return_if_fail (!egg_sequence_iter_is_end (a));
+    g_return_if_fail (!egg_sequence_iter_is_end (b));
+    
+    if (a == b)
+       return;
+    
+    a_pos = egg_sequence_iter_get_position (a);
+    b_pos = egg_sequence_iter_get_position (b);
+    
+    if (a_pos > b_pos)
+    {
+       leftmost = b;
+       rightmost = a;
+    }
+    else
+    {
+       leftmost = a;
+       rightmost = b;
+    }
+    
+    rightmost_next = node_get_next (rightmost);
+    
+    /* Situation is now like this:
+     *
+     *     ..., leftmost, ......., rightmost, rightmost_next, ...
+     *
+     */
+    egg_sequence_move (rightmost, leftmost);
+    egg_sequence_move (leftmost, rightmost_next);
+}
+
+/*
+ * Implementation of the node_* methods
+ */
+static void
+node_update_fields (EggSequenceNode *node)
+{
+    g_assert (node != NULL);
+    
+    node->n_nodes = 1;
+    
+    if (node->left)
+       node->n_nodes += node->left->n_nodes;
+    
+    if (node->right)
+       node->n_nodes += node->right->n_nodes;
+}
+
+#define NODE_LEFT_CHILD(n)  (((n)->parent) && ((n)->parent->left) == (n))
+#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
+
+static void
+node_rotate (EggSequenceNode *node)
+{
+    EggSequenceNode *tmp, *old;
+    
+    g_assert (node->parent);
+    g_assert (node->parent != node);
+    
+    if (NODE_LEFT_CHILD (node))
+    {
+       /* rotate right */
+       tmp = node->right;
+       
+       node->right = node->parent;
+       node->parent = node->parent->parent;
+       if (node->parent)
+       {
+           if (node->parent->left == node->right)
+               node->parent->left = node;
+           else
+               node->parent->right = node;
+       }
+       
+       g_assert (node->right);
+       
+       node->right->parent = node;
+       node->right->left = tmp;
+       
+       if (node->right->left)
+           node->right->left->parent = node->right;
+       
+       old = node->right;
+    }
+    else
+    {
+       /* rotate left */
+       tmp = node->left;
+       
+       node->left = node->parent;
+       node->parent = node->parent->parent;
+       if (node->parent)
+       {
+           if (node->parent->right == node->left)
+               node->parent->right = node;
+           else
+               node->parent->left = node;
+       }
+       
+       g_assert (node->left);
+       
+       node->left->parent = node;
+       node->left->right = tmp;
+       
+       if (node->left->right)
+           node->left->right->parent = node->left;
+       
+       old = node->left;
+    }
+    
+    node_update_fields (old);
+    node_update_fields (node);
+}
+
+static EggSequenceNode *
+splay (EggSequenceNode *node)
+{
+    while (node->parent)
+    {
+       if (!node->parent->parent)
+       {
+           /* zig */
+           node_rotate (node);
+       }
+       else if ((NODE_LEFT_CHILD (node) && NODE_LEFT_CHILD (node->parent)) ||
+                (NODE_RIGHT_CHILD (node) && NODE_RIGHT_CHILD (node->parent)))
+       {
+           /* zig-zig */
+           node_rotate (node->parent);
+           node_rotate (node);
+       }
+       else
+       {
+           /* zig-zag */
+           node_rotate (node);
+           node_rotate (node);
+       }
+    }
+    
+    return node;
+}
+
+static EggSequenceNode *
+node_new (gpointer data)
+{
+    EggSequenceNode *node = g_slice_new0 (EggSequenceNode);
+
+    node->parent = NULL;
+    node->parent = NULL;
+    node->left = NULL;
+    node->right = NULL;
+    
+    node->data = data;
+    node->n_nodes = 1;
+    
+    return node;
+}
+
+static EggSequenceNode *
+find_min (EggSequenceNode *node)
+{
+    splay (node);
+    
+    while (node->left)
+       node = node->left;
+    
+    return node;
+}
+
+static EggSequenceNode *
+find_max (EggSequenceNode *node)
+{
+    splay (node);
+    
+    while (node->right)
+       node = node->right;
+    
+    return node;
+}
+
+static EggSequenceNode *
+node_get_first   (EggSequenceNode    *node)
+{
+    return splay (find_min (node));
+}
+
+static EggSequenceNode *
+node_get_last    (EggSequenceNode    *node)
+{
+    return splay (find_max (node));
+}
+
+static gint
+get_n_nodes (EggSequenceNode *node)
+{
+    if (node)
+       return node->n_nodes;
+    else
+       return 0;
+}
+
+static EggSequenceNode *
+node_get_by_pos  (EggSequenceNode *node,
+                 gint             pos)
+{
+    gint i;
+    
+    g_assert (node != NULL);
+    
+    splay (node);
+    
+    while ((i = get_n_nodes (node->left)) != pos)
+    {
+       if (i < pos)
+       {
+           node = node->right;
+           pos -= (i + 1);
+       }
+       else
+       {
+           node = node->left;
+           g_assert (node->parent != NULL);
+       }
+    }
+    
+    return splay (node);
+}
+
+static EggSequenceNode *
+node_get_prev  (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    if (node->left)
+    {
+       node = node->left;
+       while (node->right)
+           node = node->right;
+    }
+    
+    return splay (node);
+}
+
+static EggSequenceNode *
+node_get_next         (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    if (node->right)
+    {
+       node = node->right;
+       while (node->left)
+           node = node->left;
+    }
+    
+    return splay (node);
+}
+
+static gint
+node_get_pos (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    return get_n_nodes (node->left);
+}
+
+/* Return closest node _strictly_ bigger than @needle (does always exist because
+ * there is an end_node)
+ */
+static EggSequenceNode *
+node_find_closest (EggSequenceNode           *haystack,
+                  EggSequenceNode            *needle,
+                  EggSequenceNode            *end,
+                  EggSequenceIterCompareFunc  cmp_func,
+                  gpointer                    cmp_data)
+{
+    EggSequenceNode *best;
+    gint c;
+    
+    g_assert (haystack);
+    
+    haystack = splay (haystack);
+    
+    do
+    {
+       best = haystack;
+
+       /* cmp_func can't be called with the end node (it may be user-supplied) */
+       if (haystack == end)
+           c = 1;
+       else
+           c = cmp_func (haystack, needle, cmp_data);
+
+       /* In the following we don't break even if c == 0. Instaed we go on searching
+        * along the 'bigger' nodes, so that we find the last one that is equal
+        * to the needle.
+        */
+       if (c > 0)
+           haystack = haystack->left;
+       else
+           haystack = haystack->right;
+    }
+    while (haystack != NULL);
+    
+     /* If the best node is smaller or equal to the data, then move one step
+     * to the right to make sure the best one is strictly bigger than the data
+     */
+    if (best != end && c <= 0)
+       best = node_get_next (best);
+    
+    return best;
+}
+
+static void
+node_free (EggSequenceNode *node,
+          EggSequence     *seq)
+{
+    GQueue *stack = g_queue_new ();
+
+    splay (node);
+    
+    g_queue_push_head (stack, node);
+    
+    while (!g_queue_is_empty (stack))
+    {
+       node = g_queue_pop_head (stack);
+       
+       if (node)
+       {
+           g_queue_push_head (stack, node->right);
+           g_queue_push_head (stack, node->left);
+           
+           if (seq && seq->data_destroy_notify && node != seq->end_node)
+               seq->data_destroy_notify (node->data);
+           
+           g_slice_free (EggSequenceNode, node);
+       }
+    }
+    
+    g_queue_free (stack);
+}
+
+/* Splits into two trees, left and right. 
+ * @node will be part of the right tree
+ */
+
+static void
+node_cut (EggSequenceNode *node)
+{
+    splay (node);
+
+    g_assert (node->parent == NULL);
+    
+    if (node->left)
+       node->left->parent = NULL;
+    
+    node->left = NULL;
+    node_update_fields (node);
+}
+
+static void
+node_insert_before (EggSequenceNode *node,
+                   EggSequenceNode *new)
+{
+    g_assert (node != NULL);
+    g_assert (new != NULL);
+    
+    splay (node);
+    
+    new = splay (find_min (new));
+    g_assert (new->left == NULL);
+    
+    if (node->left)
+       node->left->parent = new;
+    
+    new->left = node->left;
+    new->parent = node;
+    
+    node->left = new;
+    
+    node_update_fields (new);
+    node_update_fields (node);
+}
+
+static void
+node_insert_after (EggSequenceNode *node,
+                  EggSequenceNode *new)
+{
+    g_assert (node != NULL);
+    g_assert (new != NULL);
+    
+    splay (node);
+    
+    new = splay (find_max (new));
+    g_assert (new->right == NULL);
+    g_assert (node->parent == NULL);
+    
+    if (node->right)
+       node->right->parent = new;
+    
+    new->right = node->right;
+    new->parent = node;
+    
+    node->right = new;
+    
+    node_update_fields (new);
+    node_update_fields (node);
+}
+
+static gint
+node_get_length (EggSequenceNode    *node)
+{
+    g_assert (node != NULL);
+    
+    splay (node);
+    return node->n_nodes;
+}
+
+static void
+node_unlink (EggSequenceNode *node)
+{
+    EggSequenceNode *right, *left;
+    
+    splay (node);
+    
+    left = node->left;
+    right = node->right;
+    
+    node->parent = node->left = node->right = NULL;
+    node_update_fields (node);
+    
+    if (right)
+    {
+       right->parent = NULL;
+       
+       right = node_get_first (right);
+       g_assert (right->left == NULL);
+       
+       right->left = left;
+       if (left)
+       {
+           left->parent = right;
+           node_update_fields (right);
+       }
+    }
+    else if (left)
+    {
+       left->parent = NULL;
+    }
+}
+
+static void
+node_insert_sorted (EggSequenceNode *node,
+                   EggSequenceNode *new,
+                   EggSequenceNode *end,
+                   EggSequenceIterCompareFunc cmp_func,
+                   gpointer cmp_data)
+{
+    EggSequenceNode *closest;
+    
+    closest = node_find_closest (node, new, end, cmp_func, cmp_data);
+
+    node_unlink (new);
+    
+    node_insert_before (closest, new);
+}
+
+static gint
+node_calc_height (EggSequenceNode *node)
+{
+    gint left_height;
+    gint right_height;
+    
+    if (node)
+    {
+       left_height = 0;
+       right_height = 0;
+       
+       if (node->left)
+           left_height = node_calc_height (node->left);
+       
+       if (node->right)
+           right_height = node_calc_height (node->right);
+       
+       return MAX (left_height, right_height) + 1;
+    }
+    
+    return 0;
+}
+
+/* Self test functions */
+
+static void
+check_node (EggSequenceNode *node)
+{
+    if (node)
+    {
+       g_assert (node->parent != node);
+       g_assert (node->n_nodes ==
+                 1 + get_n_nodes (node->left) + get_n_nodes (node->right));
+       check_node (node->left);
+       check_node (node->right);
+    }
+}
+
+void
+egg_sequence_self_test (EggSequence *seq)
+{
+    EggSequenceNode *node = splay (seq->end_node);
+    
+    check_node (node);
+}
diff --git a/attic/fluttr/src/eggsequence.h b/attic/fluttr/src/eggsequence.h
new file mode 100644 (file)
index 0000000..107db47
--- /dev/null
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __GSEQUENCE_H__
+#define __GSEQUENCE_H__
+
+typedef struct _EggSequence      EggSequence;
+typedef struct _EggSequenceNode  EggSequenceIter;
+
+
+
+typedef gint (* EggSequenceIterCompareFunc) (EggSequenceIter *a,
+                                            EggSequenceIter *b,
+                                            gpointer         data);
+
+/* EggSequence */
+EggSequence *   egg_sequence_new                  (GDestroyNotify          data_destroy);
+void            egg_sequence_free                 (EggSequence            *seq);
+gint            egg_sequence_get_length           (EggSequence            *seq);
+void           egg_sequence_foreach              (EggSequence            *seq,
+                                                  GFunc                   func,
+                                                  gpointer                data);
+void           egg_sequence_foreach_range        (EggSequenceIter        *begin,
+                                                  EggSequenceIter        *end,
+                                                  GFunc                   func,
+                                                  gpointer                data);
+void            egg_sequence_sort                 (EggSequence            *seq,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_iter            (EggSequence            *seq,
+                                                  EggSequenceIterCompareFunc      cmp_func,
+                                                  gpointer                cmp_data);
+
+/* Getting iters */
+EggSequenceIter *egg_sequence_get_begin_iter       (EggSequence            *seq);
+EggSequenceIter *egg_sequence_get_end_iter         (EggSequence            *seq);
+EggSequenceIter *egg_sequence_get_iter_at_pos      (EggSequence            *seq,
+                                                   gint                    pos);
+EggSequenceIter *egg_sequence_append               (EggSequence            *seq,
+                                                  gpointer                data);
+EggSequenceIter *egg_sequence_prepend              (EggSequence            *seq,
+                                                  gpointer                data);
+EggSequenceIter *egg_sequence_insert_before        (EggSequenceIter *        iter,
+                                                  gpointer                data);
+void            egg_sequence_move                (EggSequenceIter *       src,
+                                                  EggSequenceIter *       dest);
+void            egg_sequence_swap                (EggSequenceIter *       a,
+                                                  EggSequenceIter *       b);
+EggSequenceIter *egg_sequence_insert_sorted        (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+EggSequenceIter *egg_sequence_insert_sorted_iter   (EggSequence                  *seq,
+                                                  gpointer                data,
+                                                  EggSequenceIterCompareFunc      iter_cmp,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_changed         (EggSequenceIter *       iter,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_changed_iter    (EggSequenceIter *       iter,
+                                                  EggSequenceIterCompareFunc      iter_cmp,
+                                                  gpointer                cmp_data);
+
+void            egg_sequence_remove               (EggSequenceIter *        iter);
+void            egg_sequence_remove_range         (EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+void            egg_sequence_move_range           (EggSequenceIter *        iter,
+                                                  EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+EggSequenceIter *egg_sequence_search               (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+EggSequenceIter *egg_sequence_search_iter         (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  EggSequenceIterCompareFunc     cmp_func,
+                                                  gpointer                cmp_data);
+
+/* dereferencing */
+gpointer        egg_sequence_get                  (EggSequenceIter *        iter);
+void           egg_sequence_set                  (EggSequenceIter *       iter,
+                                                  gpointer                data);
+
+
+/* operations on EggSequenceIter * */
+gboolean        egg_sequence_iter_is_begin        (EggSequenceIter *        iter);
+gboolean        egg_sequence_iter_is_end          (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_next            (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_prev            (EggSequenceIter *        iter);
+gint            egg_sequence_iter_get_position    (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_move            (EggSequenceIter *        iter,
+                                                  gint                    leap);
+EggSequence *   egg_sequence_iter_get_sequence    (EggSequenceIter *        iter);
+
+
+/* search */
+gint            egg_sequence_iter_compare         (EggSequenceIter *a,
+                                                  EggSequenceIter *        b);
+EggSequenceIter *egg_sequence_range_get_midpoint   (EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+
+#endif /* __GSEQUENCE_H__ */
diff --git a/attic/fluttr/src/fluttr-auth.c b/attic/fluttr/src/fluttr-auth.c
new file mode 100644 (file)
index 0000000..9507012
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include "fluttr-auth.h"
+
+#include <libnflick/nflick.h>
+#include <GL/gl.h>
+
+G_DEFINE_TYPE (FluttrAuth, fluttr_auth, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_AUTH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_AUTH, \
+       FluttrAuthPrivate))
+       
+#define FONT "DejaVu Sans Book"
+
+
+struct _FluttrAuthPrivate
+{
+       gchar                   *mini_token;
+       gchar                   *username;
+       gchar                   *fullname;
+       gchar                   *token;
+       gchar                   *usernsid;
+       
+       NFlickWorker            *worker;
+
+       GdkPixbuf               *logo;
+       ClutterActor            *messagebox;
+       ClutterActor            *throbber;
+       ClutterActor            *text;
+       
+       ClutterTimeline         *timeline;
+       ClutterAlpha            *alpha;
+       ClutterBehaviour        *behave;
+};
+
+enum
+{
+       PROP_0,
+       PROP_MINI_TOKEN,
+       PROP_USERNAME,
+       PROP_FULLNAME,
+       PROP_TOKEN,
+       PROP_USERNSID
+};
+
+enum
+{
+       SUCCESSFUL,
+       ERROR,
+       LAST_SIGNAL
+};
+
+static guint _auth_signals[LAST_SIGNAL] = { 0 };
+
+static gboolean                 
+on_thread_abort_idle (FluttrAuth *auth)
+{
+        g_return_val_if_fail (FLUTTR_IS_AUTH (auth), FALSE);
+
+       g_signal_emit (auth, _auth_signals[ERROR], 0, "Aborted");       
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_ok_idle (FluttrAuth *auth)
+{
+        FluttrAuthPrivate *priv;
+        
+        g_return_val_if_fail (FLUTTR_IS_AUTH (auth), FALSE);
+        priv = FLUTTR_AUTH_GET_PRIVATE(auth);
+        
+        g_object_get (G_OBJECT (priv->worker), 
+                      "username", &priv->username, 
+                      "fullname", &priv->fullname, 
+                      "token", &priv->token, 
+                      "usernsid", &priv->usernsid, 
+                      NULL);
+
+        g_signal_emit (auth, _auth_signals[SUCCESSFUL], 0, "");
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_error_idle (FluttrAuth *auth)
+{
+        FluttrAuthPrivate *priv;
+        gchar *error = NULL;
+        
+        g_return_val_if_fail (FLUTTR_IS_AUTH (auth), FALSE);
+        priv = FLUTTR_AUTH_GET_PRIVATE(auth);
+        
+        /* Get the actual error */
+        g_object_get (G_OBJECT (priv->worker), "error", &error, NULL);
+        if (error == NULL) {
+                error = g_strdup_printf (gettext ("Internal error. "));
+                g_warning ("No error set on worker!");
+        }
+       g_signal_emit (auth, _auth_signals[ERROR], 0, error);
+
+        g_free (error);
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_msg_change_idle (FluttrAuth *auth)
+{
+        FluttrAuthPrivate *priv;
+        gchar *msg = NULL;
+        
+        g_return_val_if_fail (FLUTTR_IS_AUTH (auth), FALSE);
+        priv = FLUTTR_AUTH_GET_PRIVATE(auth);
+        
+        /* Get the new message */
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                g_print ("%s", msg);
+        }
+        
+        g_free (msg);
+
+        return FALSE;
+}
+
+
+/* This function does th emain work of creating and configuring the worker 
+   thread. the majority of this code is taken from
+   NFlick the n800 Flickr photo browser by MDK (see: README) */
+void
+fluttr_auth_go (FluttrAuth *auth)
+{
+       FluttrAuthPrivate *priv;
+       NFlickWorker *worker;
+        NFlickWorkerStatus status;
+        
+               g_return_if_fail (FLUTTR_IS_AUTH (auth));
+       priv = FLUTTR_AUTH_GET_PRIVATE(auth);
+       
+       /* Create the worker */
+        worker = (NFlickWorker*)nflick_auth_worker_new (priv->mini_token);
+        
+        /* Check if the worker is in the right state */
+        g_object_get (G_OBJECT (worker), "status", &status, NULL);
+        
+        if (status != NFLICK_WORKER_STATUS_IDLE) {
+                g_warning ("Bad worker status"); 
+                return;
+        }
+        
+        g_object_ref (worker);
+        priv->worker = worker;
+        
+        /* Get the initial message */
+        gchar *msg = NULL;
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                /* FIXME Escape markup */
+               g_print ("%s", msg);
+        }
+        
+        /* Set the callback functions */
+        nflick_worker_set_custom_data (worker, auth);
+        nflick_worker_set_aborted_idle (worker, 
+                                  (NFlickWorkerIdleFunc) on_thread_abort_idle);
+        
+        nflick_worker_set_error_idle (worker, 
+                                  (NFlickWorkerIdleFunc) on_thread_error_idle);
+        
+        nflick_worker_set_ok_idle (worker, 
+                                     (NFlickWorkerIdleFunc) on_thread_ok_idle);
+        
+        nflick_worker_set_msg_change_idle (worker, 
+                             (NFlickWorkerIdleFunc) on_thread_msg_change_idle);
+                                        
+        nflick_worker_start (priv->worker);
+        
+        /* Free */
+        g_free (msg);
+}
+
+
+/* Slide in or out the notification popp, depending on priv->pop_visible */
+static void
+fluttr_auth_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+       return;
+}              
+               
+/* GObject Stuff */
+
+static void
+fluttr_auth_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+       FluttrAuthPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_AUTH (object));
+       priv = FLUTTR_AUTH_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_MINI_TOKEN:
+                       if (priv->mini_token != NULL)
+                               g_free (priv->mini_token);
+                       priv->mini_token =g_strdup (g_value_get_string (value));
+                       break;
+               case PROP_USERNAME:
+                       if (priv->username != NULL)
+                               g_free (priv->username);
+                       priv->username =g_strdup (g_value_get_string (value));
+                       break;
+
+               case PROP_FULLNAME:
+                       if (priv->fullname != NULL)
+                               g_free (priv->fullname);
+                       priv->fullname =g_strdup (g_value_get_string (value));
+                       break;
+               
+               case PROP_TOKEN:
+                       if (priv->token != NULL)
+                               g_free (priv->token);
+                       priv->token =g_strdup (g_value_get_string (value));
+                       break;
+               
+               case PROP_USERNSID:
+                       if (priv->usernsid != NULL)
+                               g_free (priv->usernsid);
+                       priv->usernsid =g_strdup (g_value_get_string (value));
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_auth_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrAuthPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_AUTH (object));
+       priv = FLUTTR_AUTH_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_MINI_TOKEN:
+                       g_value_set_string (value, priv->mini_token);
+                       break;
+               case PROP_USERNAME:
+                       g_value_set_string (value, priv->username);
+                       break;
+
+               case PROP_FULLNAME:
+                       g_value_set_string (value, priv->fullname);
+                       break;
+               
+               case PROP_TOKEN:
+                       g_value_set_string (value, priv->token);
+                       break;
+               
+               case PROP_USERNSID:
+                       g_value_set_string (value, priv->usernsid);
+                       break;                  
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void
+fluttr_auth_paint (ClutterActor *actor)
+{
+       FluttrAuth        *auth;
+       FluttrAuthPrivate *priv;
+
+       auth = FLUTTR_AUTH(actor);
+
+       priv = FLUTTR_AUTH_GET_PRIVATE(auth);
+
+       glPushMatrix();
+       
+       gint i;
+       gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor)); 
+       for (i = 0; i < len; i++) {
+               ClutterActor* child;
+
+               child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+               if (child) {
+                       clutter_actor_paint (child);
+               }
+       }
+
+       glPopMatrix();
+}
+
+static void 
+fluttr_auth_dispose (GObject *object)
+{
+       FluttrAuth         *self = FLUTTR_AUTH(object);
+       FluttrAuthPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_auth_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_auth_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_auth_parent_class)->finalize (object);
+}
+
+static void
+fluttr_auth_class_init (FluttrAuthClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+       ClutterActorClass   *parent_class; 
+
+       parent_class = CLUTTER_ACTOR_CLASS (fluttr_auth_parent_class);
+
+       actor_class->paint           = fluttr_auth_paint;
+       
+       gobject_class->finalize     = fluttr_auth_finalize;
+       gobject_class->dispose      = fluttr_auth_dispose;
+       gobject_class->get_property = fluttr_auth_get_property;
+       gobject_class->set_property = fluttr_auth_set_property; 
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrAuthPrivate));
+       
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_MINI_TOKEN,
+                g_param_spec_string ("mini-token",
+                "Mini Token",
+                "The Flickr mini-token",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_USERNAME,
+                g_param_spec_string ("username",
+                "Username",
+                "The Flickr username",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                  
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_FULLNAME,
+                g_param_spec_string ("fullname",
+                "Fullname",
+                "The users full name",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_TOKEN,
+                g_param_spec_string ("token",
+                "Token",
+                "The Flickr token",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_USERNSID,
+                g_param_spec_string ("usernsid",
+                "Usernsid",
+                "The Flickr usernsid",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                                                  
+
+       /* Class signals */
+       _auth_signals[SUCCESSFUL] =
+               g_signal_new ("successful",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrAuthClass, successful),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1, G_TYPE_STRING);
+                            
+       _auth_signals[ERROR] =
+               g_signal_new ("error",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrAuthClass, error),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1, G_TYPE_STRING);                         
+
+}
+
+static void
+fluttr_auth_init (FluttrAuth *self)
+{
+       FluttrAuthPrivate *priv;
+       priv = FLUTTR_AUTH_GET_PRIVATE (self);
+       
+       priv->mini_token = NULL;
+}
+
+ClutterActor*
+fluttr_auth_new (const char *mini_token)
+{
+       ClutterGroup         *auth;
+
+       auth = g_object_new (FLUTTR_TYPE_AUTH, 
+                            "mini-token", mini_token,
+                             NULL);
+       if (0) fluttr_auth_alpha_func (NULL, 0, NULL);
+       return CLUTTER_ACTOR (auth);
+}
+
diff --git a/attic/fluttr/src/fluttr-auth.h b/attic/fluttr/src/fluttr-auth.h
new file mode 100644 (file)
index 0000000..f46a267
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_FLUTTR_AUTH_H
+#define _HAVE_FLUTTR_AUTH_H
+
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_AUTH fluttr_auth_get_type()
+
+#define FLUTTR_AUTH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_AUTH, \
+       FluttrAuth))
+
+#define FLUTTR_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_AUTH, \
+       FluttrAuthClass))
+
+#define FLUTTR_IS_AUTH(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_AUTH))
+
+#define FLUTTR_IS_AUTH_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_AUTH))
+
+#define FLUTTR_AUTH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_AUTH, \
+       FluttrAuthClass))
+
+typedef struct _FluttrAuth FluttrAuth;
+typedef struct _FluttrAuthClass FluttrAuthClass;
+typedef struct _FluttrAuthPrivate FluttrAuthPrivate;
+
+struct _FluttrAuth
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrAuthPrivate   *priv;
+};
+
+struct _FluttrAuthClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*successful) (FluttrAuth *auth, gchar *null);
+       void (*error) (FluttrAuth *auth, gchar *msg);
+       void (*_fluttr_auth_3) (void);
+       void (*_fluttr_auth_4) (void);
+}; 
+
+GType fluttr_auth_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_auth_new (const char *mini_token);
+
+void
+fluttr_auth_go (FluttrAuth *auth);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-behave.c b/attic/fluttr/src/fluttr-behave.c
new file mode 100644 (file)
index 0000000..c676f70
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+
+/* This is a utility ClutterBehaviour-derived class, in which you can set the
+   alphanotify function. It is useful for situations where you do not need the
+   full capabilities of the ClutterBehvaiour class, you just want a function to
+   be called for each iteration along the timeline
+*/
+
+#include "fluttr-behave.h"
+
+#include "math.h"
+
+G_DEFINE_TYPE (FluttrBehave, fluttr_behave, CLUTTER_TYPE_BEHAVIOUR);
+
+#define FLUTTR_BEHAVE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_BEHAVE, \
+       FluttrBehavePrivate))
+
+struct _FluttrBehavePrivate
+{
+       FluttrBehaveAlphaFunc     func;
+       gpointer                data;
+};
+
+guint32 
+alpha_sine_inc_func (ClutterAlpha *alpha,
+                    gpointer      dummy)
+{
+       ClutterTimeline *timeline;
+       gint current_frame_num, n_frames;
+       gdouble x, sine;
+  
+       timeline = clutter_alpha_get_timeline (alpha);
+
+       current_frame_num = clutter_timeline_get_current_frame (timeline);
+       n_frames = clutter_timeline_get_n_frames (timeline);
+
+       x = (gdouble) (current_frame_num * 0.5f * M_PI) / n_frames ;
+       /* sine = (sin (x - (M_PI / 0.5f)) + 1.0f) * 0.5f; */
+  
+       sine = (sin (x - (M_PI / 0.5f))) ;
+  
+       return (guint32)(sine * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);
+}
+
+guint32 
+alpha_linear_inc_func (ClutterAlpha *alpha,
+                      gpointer      dummy)
+{
+       ClutterTimeline *timeline;
+       gint current_frame_num, n_frames;
+       gdouble x;
+  
+       timeline = clutter_alpha_get_timeline (alpha);
+
+       current_frame_num = clutter_timeline_get_current_frame (timeline);
+       n_frames = clutter_timeline_get_n_frames (timeline);
+
+       x = (gdouble) (current_frame_num) / n_frames ;
+       /* sine = (sin (x - (M_PI / 0.5f)) + 1.0f) * 0.5f; */
+  
+       return (guint32)(x * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);      
+}
+
+static void
+fluttr_behave_alpha_notify (ClutterBehaviour *behave, guint32 alpha_value)
+{
+       FluttrBehave *fluttr_behave = FLUTTR_BEHAVE(behave);
+       FluttrBehavePrivate *priv;
+       
+       priv = FLUTTR_BEHAVE_GET_PRIVATE (fluttr_behave);
+       
+       if (priv->func != NULL) {
+               priv->func (behave, alpha_value, priv->data);
+       }
+}
+
+static void
+fluttr_behave_class_init (FluttrBehaveClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
+
+       behave_class->alpha_notify = fluttr_behave_alpha_notify;
+       
+       g_type_class_add_private (gobject_class, sizeof (FluttrBehavePrivate));
+}
+
+static void
+fluttr_behave_init (FluttrBehave *self)
+{
+       FluttrBehavePrivate *priv;
+       
+       priv = FLUTTR_BEHAVE_GET_PRIVATE (self);
+       
+       priv->func = NULL;
+       priv->data = NULL;
+}
+
+ClutterBehaviour*
+fluttr_behave_new (ClutterAlpha                *alpha,
+                FluttrBehaveAlphaFunc   func,
+                gpointer                data)
+{
+       FluttrBehave *behave;
+       FluttrBehavePrivate *priv;
+       
+       behave = g_object_new (FLUTTR_TYPE_BEHAVE, 
+                              "alpha", alpha,
+                              NULL);
+
+       priv = FLUTTR_BEHAVE_GET_PRIVATE (behave);  
+       
+       priv->func = func;
+       priv->data = data;
+               
+       return CLUTTER_BEHAVIOUR(behave);
+}
diff --git a/attic/fluttr/src/fluttr-behave.h b/attic/fluttr/src/fluttr-behave.h
new file mode 100644 (file)
index 0000000..c4b7629
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+/* This is a utility ClutterBehaviour-derived class, in which you can set the
+   alphanotify function. It is useful for situations where you do not need the
+   full capabilities of the ClutterBehvaiour class, you just want a function to
+   be called for each iteration along the timeline
+*/
+
+#ifndef _FLUTTR_BEHAVE_H_
+#define _FLUTTR_BEHAVE_H_
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+#define FLUTTR_TYPE_BEHAVE (fluttr_behave_get_type ())
+
+#define FLUTTR_BEHAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+       FLUTTR_TYPE_BEHAVE, \
+       FluttrBehave))
+
+#define FLUTTR_BEHAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_BEHAVE, \
+       FluttrBehaveClass))
+
+#define CLUTTER_IS_BEHAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+       FLUTTR_TYPE_BEHAVE))
+
+#define CLUTTER_IS_BEHAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+       FLUTTR_TYPE_BEHAVE))
+
+#define FLUTTR_BEHAVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_BEHAVE, \
+       FluttrBehaveClass))
+
+typedef struct _FluttrBehave        FluttrBehave;
+typedef struct _FluttrBehaveClass   FluttrBehaveClass;
+typedef struct _FluttrBehavePrivate FluttrBehavePrivate;
+struct _FluttrBehave
+{
+       ClutterBehaviour        parent; 
+};
+
+struct _FluttrBehaveClass
+{
+       ClutterBehaviourClass   parent_class;
+};
+
+typedef void (*FluttrBehaveAlphaFunc) (ClutterBehaviour  *behave, 
+                                    guint32            alpha_value,
+                                    gpointer           data);
+
+GType fluttr_behave_get_type (void) G_GNUC_CONST;
+
+ClutterBehaviour* 
+fluttr_behave_new (ClutterAlpha                *alpha,
+                FluttrBehaveAlphaFunc   func,
+                gpointer                data);
+
+guint32 
+alpha_sine_inc_func (ClutterAlpha *alpha,
+                    gpointer      dummy);      
+                    
+guint32 
+alpha_linear_inc_func (ClutterAlpha *alpha,
+                      gpointer      dummy);                     
+
+#endif /* _FLUTTR_BEHAVE_H_ */
+
diff --git a/attic/fluttr/src/fluttr-library-row.c b/attic/fluttr/src/fluttr-library-row.c
new file mode 100644 (file)
index 0000000..315d2d3
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include "fluttr-library-row.h"
+
+G_DEFINE_TYPE (FluttrLibraryRow, fluttr_library_row, G_TYPE_OBJECT);
+
+#define FLUTTR_LIBRARY_ROW_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), FLUTTR_TYPE_LIBRARY_ROW, \
+       FluttrLibraryRowPrivate))
+       
+#define FONT "DejaVu Sans Book"
+
+
+struct _FluttrLibraryRowPrivate
+{      
+       gchar                   *id;
+       gchar                   *name;
+       NFlickPhotoSet          *set;
+       GdkPixbuf               *pixbuf;
+       
+       ClutterActor            *photo;
+};
+
+enum
+{
+       PROP_0,
+       PROP_ID,
+       PROP_NAME,
+       PROP_PHOTO,
+       PROP_SET,
+       PROP_PIXBUF
+};
+
+/* GObject Stuff */
+
+static void
+fluttr_library_row_set_property (GObject      *object, 
+                                guint         prop_id,
+                                const GValue *value, 
+                                GParamSpec   *pspec)
+{
+       FluttrLibraryRowPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_LIBRARY_ROW (object));
+       priv = FLUTTR_LIBRARY_ROW_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_ID:
+                       if (priv->id != NULL)
+                               g_free (priv->id);
+                       priv->id = g_strdup (g_value_get_string (value));
+                       break;
+               case PROP_NAME:
+                       if (priv->name != NULL)
+                               g_free (priv->name);
+                       priv->name =g_strdup (g_value_get_string (value));
+                       break;
+               
+               case PROP_PHOTO:
+                       priv->photo = g_value_get_object (value);
+                       break;
+       
+               case PROP_SET:
+                       priv->set = g_value_get_object (value);
+                       break;
+                       
+               case PROP_PIXBUF:
+                       if (priv->pixbuf)
+                               g_object_unref (priv->pixbuf);
+                       priv->pixbuf = g_value_get_object (value);
+                       break;  
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_library_row_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrLibraryRowPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_LIBRARY_ROW (object));
+       priv = FLUTTR_LIBRARY_ROW_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_ID:
+                       g_value_set_string (value, priv->id);
+                       break;
+               
+               case PROP_NAME:
+                       g_value_set_string (value, priv->name);
+                       break;
+                       
+               case PROP_PHOTO:
+                       g_value_set_object (value, G_OBJECT (priv->photo));
+                       break;
+                       
+               case PROP_SET:
+                       g_value_set_object (value, G_OBJECT (priv->set));
+                       break;
+               
+               case PROP_PIXBUF:
+                       g_value_set_object (value, G_OBJECT (priv->pixbuf));
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void 
+fluttr_library_row_dispose (GObject *object)
+{
+       FluttrLibraryRow         *self = FLUTTR_LIBRARY_ROW(object);
+       FluttrLibraryRowPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_library_row_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_library_row_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_library_row_parent_class)->finalize (object);
+}
+
+static void
+fluttr_library_row_class_init (FluttrLibraryRowClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+       gobject_class->finalize     = fluttr_library_row_finalize;
+       gobject_class->dispose      = fluttr_library_row_dispose;
+       gobject_class->get_property = fluttr_library_row_get_property;
+       gobject_class->set_property = fluttr_library_row_set_property;  
+
+       g_type_class_add_private (gobject_class, 
+                                 sizeof (FluttrLibraryRowPrivate));
+               
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_ID,
+                g_param_spec_string ("id",
+                "ID",
+                "The Flickr photo id",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_NAME,
+                g_param_spec_string ("name",
+                "Name",
+                "The Flickr photo name",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_PHOTO,
+                g_param_spec_object ("photo",
+                "Photo",
+                "The FluttrPhoto actor",
+                CLUTTER_TYPE_ACTOR,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                  
+                       
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_SET,
+                g_param_spec_object ("set",
+                "Set",
+                "The NFlick photo set",
+                NFLICK_TYPE_PHOTO_SET,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_PIXBUF,
+                g_param_spec_object ("pixbuf",
+                "Pixbuf",
+                "The GdkPixbuf representing this photo",
+                GDK_TYPE_PIXBUF,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                  
+}
+
+static void
+fluttr_library_row_init (FluttrLibraryRow *self)
+{
+       FluttrLibraryRowPrivate *priv;
+       priv = FLUTTR_LIBRARY_ROW_GET_PRIVATE (self);
+       
+       priv->set = NULL;
+       priv->pixbuf = NULL;
+}
+
+FluttrLibraryRow*
+fluttr_library_row_new (gchar *id, gchar *name, NFlickPhotoSet *set)
+{
+       GObject         *row;
+
+       row = g_object_new (FLUTTR_TYPE_LIBRARY_ROW, 
+                           "id", id,
+                           "name", name,
+                           "set", set,
+                           NULL);
+
+       return FLUTTR_LIBRARY_ROW(row);
+}
+
diff --git a/attic/fluttr/src/fluttr-library-row.h b/attic/fluttr/src/fluttr-library-row.h
new file mode 100644 (file)
index 0000000..e5012db
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libnflick/nflick.h>
+
+#ifndef _HAVE_FLUTTR_LIBRARY_ROW_H
+#define _HAVE_FLUTTR_LIBRARY_ROW_H
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_LIBRARY_ROW fluttr_library_row_get_type()
+
+#define FLUTTR_LIBRARY_ROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_LIBRARY_ROW, \
+       FluttrLibraryRow))
+
+#define FLUTTR_LIBRARY_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_LIBRARY_ROW, \
+       FluttrLibraryRowClass))
+
+#define FLUTTR_IS_LIBRARY_ROW(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_LIBRARY_ROW))
+
+#define FLUTTR_IS_LIBRARY_ROW_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_LIBRARY_ROW))
+
+#define FLUTTR_LIBRARY_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_LIBRARY_ROW, \
+       FluttrLibraryRowClass))
+
+typedef struct _FluttrLibraryRow FluttrLibraryRow;
+typedef struct _FluttrLibraryRowClass FluttrLibraryRowClass;
+typedef struct _FluttrLibraryRowPrivate FluttrLibraryRowPrivate;
+
+struct _FluttrLibraryRow
+{
+       GObject         parent;
+       
+       /* private */
+       FluttrLibraryRowPrivate   *priv;
+};
+
+struct _FluttrLibraryRowClass 
+{
+       /*< private >*/
+       GObjectClass parent_class;
+}; 
+
+GType                           
+fluttr_library_row_get_type (void);
+
+FluttrLibraryRow*
+fluttr_library_row_new (gchar *id, gchar *name, NFlickPhotoSet *set);
+
+G_END_DECLS
+
+#endif
+
diff --git a/attic/fluttr/src/fluttr-library.c b/attic/fluttr/src/fluttr-library.c
new file mode 100644 (file)
index 0000000..394f6ea
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2007 Matthew Allum
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Matthew Allum  <mallum@openedhand.com>
+ */
+
+#include "fluttr-library.h"
+#include <string.h>
+
+G_DEFINE_TYPE (FluttrLibrary, fluttr_library, G_TYPE_OBJECT);
+
+#define LIBRARY_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FLUTTR_TYPE_LIBRARY, FluttrLibraryPrivate))
+
+typedef struct _FluttrLibraryPrivate FluttrLibraryPrivate;
+
+enum
+{
+       REORDERED,
+       LIBRARY_ROW_CHANGED,
+       LIBRARY_ROW_ADDED,
+       FILTER,
+       LAST_SIGNAL
+};
+
+static guint _library_signals[LAST_SIGNAL] = { 0 };
+
+struct _FluttrLibraryPrivate
+{
+       FluttrFilterRowFunc     filter;
+       gpointer                filter_data;
+       FluttrCompareRowFunc    sort;
+       gpointer                sort_data;
+       EggSequence             *library_rows;
+};
+
+static void
+fluttr_library_get_property (GObject *object, guint property_id,
+                            GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, 
+                                                          pspec);
+       }
+}
+
+static void
+fluttr_library_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, 
+                                                          pspec);
+       }
+}
+
+static void
+fluttr_library_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (fluttr_library_parent_class)->dispose)
+               G_OBJECT_CLASS (fluttr_library_parent_class)->dispose (object);
+}
+
+static void
+fluttr_library_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_library_parent_class)->finalize (object);
+}
+
+static void
+fluttr_library_class_init (FluttrLibraryClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (FluttrLibraryPrivate));
+
+       object_class->get_property = fluttr_library_get_property;
+       object_class->set_property = fluttr_library_set_property;
+       object_class->dispose = fluttr_library_dispose;
+       object_class->finalize = fluttr_library_finalize;
+
+       _library_signals[REORDERED] =
+               g_signal_new ("library_rows-reordered",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (FluttrLibraryClass, reordered),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
+       _library_signals[FILTER] =
+               g_signal_new ("filter-changed",
+                            G_OBJECT_CLASS_TYPE (object_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrLibraryClass, filter_change),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
+
+       _library_signals[LIBRARY_ROW_CHANGED] =
+               g_signal_new ("library_row-changed",
+                            G_OBJECT_CLASS_TYPE (object_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrLibraryClass, library_row_change),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__OBJECT,
+                            G_TYPE_NONE, 1, FLUTTR_TYPE_LIBRARY_ROW);
+
+       _library_signals[LIBRARY_ROW_ADDED] =
+               g_signal_new ("library_row-added",
+                            G_OBJECT_CLASS_TYPE (object_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrLibraryClass, library_row_added),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__OBJECT,
+                            G_TYPE_NONE, 1, FLUTTR_TYPE_LIBRARY_ROW);
+
+}
+
+static void
+fluttr_library_init (FluttrLibrary *self)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(self);
+
+       priv->library_rows = egg_sequence_new (NULL);
+}
+
+static gboolean 
+check_filter (FluttrLibrary *library, EggSequenceIter *iter)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);  
+       gboolean res;
+
+       if (priv->filter == NULL)
+               return TRUE;
+
+       res = priv->filter(library, (FluttrLibraryRow*)egg_sequence_get (iter), 
+                          priv->filter_data); 
+       return res;
+}
+
+guint
+fluttr_library_row_count (FluttrLibrary *library)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);  
+       EggSequenceIter     *iter;
+       gint                 n = 0;
+
+       if (priv->filter == NULL)
+               return egg_sequence_get_length (priv->library_rows);    
+
+       iter = egg_sequence_get_begin_iter (priv->library_rows);
+
+       while (!egg_sequence_iter_is_end (iter)) {
+               if (check_filter (library, iter))
+                       n++;
+               iter = egg_sequence_iter_next (iter);
+       }
+
+       return n;
+}
+
+FluttrLibraryRow*
+fluttr_library_get_library_row (FluttrLibrary *library, gint index)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       EggSequenceIter     *iter;
+       gint                 n = 0;
+
+       if (priv->filter == NULL)
+               return (FluttrLibraryRow*)egg_sequence_get 
+                            (egg_sequence_get_iter_at_pos (priv->library_rows, index));
+
+       iter = egg_sequence_get_begin_iter (priv->library_rows);
+
+       while (!egg_sequence_iter_is_end (iter)) {
+               if (check_filter (library, iter)) {
+                       if (n == index)
+                               return (FluttrLibraryRow*)egg_sequence_get (iter);
+                       n++;
+               }
+               iter = egg_sequence_iter_next (iter);
+       }
+
+       return NULL;
+}
+/*
+static void
+on_library_row_changed (GObject *obj, GParamSpec   *arg1,
+                                  gpointer      data)
+{
+       return;
+       FluttrLibrary        *library = FLUTTR_LIBRARY(data);
+       FluttrLibraryPrivate *priv;
+
+       priv = LIBRARY_PRIVATE(library);
+
+       if (!strcmp(g_param_spec_get_name(arg1), "thumbnail"))
+               return;
+
+       if (priv->sort) {
+               egg_sequence_sort (priv->library_rows, 
+                               (GCompareDataFunc)priv->sort, priv->sort_data);
+               g_signal_emit (library, _library_signals[REORDERED], 0);
+       }
+
+       g_signal_emit (library, _library_signals[LIBRARY_ROW_CHANGED], 0, 
+                                                       FLUTTR_LIBRARY_ROW(obj));
+} 
+*/
+
+void
+fluttr_library_append_library_row (FluttrLibrary *library, FluttrLibraryRow *library_row)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       EggSequenceIter     *iter;
+
+       g_object_ref (library_row);
+
+       if (priv->sort)
+               iter = egg_sequence_insert_sorted (priv->library_rows, (gpointer)library_row,
+                                                 (GCompareDataFunc)priv->sort,
+                                                  priv->sort_data);
+       else
+               iter = egg_sequence_append (priv->library_rows, (gpointer)library_row);
+
+       if (check_filter (library, iter))
+               g_signal_emit (library, _library_signals[LIBRARY_ROW_ADDED], 0, library_row);
+}
+
+
+void
+fluttr_library_foreach (FluttrLibrary      *library, 
+                       FluttrForeachRowFunc   func,
+                       gpointer           data)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       EggSequenceIter     *iter;
+
+       iter = egg_sequence_get_begin_iter (priv->library_rows);
+
+       while (!egg_sequence_iter_is_end (iter)) {
+               if (check_filter (library, iter))
+                       if (func (library, 
+                                 (FluttrLibraryRow*)egg_sequence_get (iter),
+                                 data) == FALSE)
+                               return;
+       
+               iter = egg_sequence_iter_next (iter);
+       }
+}
+
+void
+fluttr_library_set_sort_func (FluttrLibrary     *library, 
+                             FluttrCompareRowFunc  func, 
+                             gpointer          userdata)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+
+       priv->sort      = func;
+       priv->sort_data = userdata;
+
+       if (func) {
+               egg_sequence_sort (priv->library_rows, (GCompareDataFunc)func, userdata);
+               g_signal_emit (library, _library_signals[REORDERED], 0);
+       }
+}
+
+void
+fluttr_library_set_filter (FluttrLibrary    *library,
+                          FluttrFilterRowFunc  filter, 
+                          gpointer         data)
+{
+       FluttrLibraryPrivate *priv = LIBRARY_PRIVATE(library);
+       FluttrFilterRowFunc      prev_filter;
+
+       prev_filter = priv->filter;
+
+       priv->filter      = filter;
+       priv->filter_data = data;
+
+       if (prev_filter != priv->filter)
+               g_signal_emit (library, _library_signals[FILTER], 0);
+}
+
+FluttrLibrary*
+fluttr_library_new ()
+{
+       return g_object_new (FLUTTR_TYPE_LIBRARY, NULL);
+}
+
diff --git a/attic/fluttr/src/fluttr-library.h b/attic/fluttr/src/fluttr-library.h
new file mode 100644 (file)
index 0000000..42c9bef
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 Matthew Allum
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Matthew Allum  <mallum@openedhand.com>
+ */
+#ifndef _FLUTTR_LIBRARY
+#define _FLUTTR_LIBRARY
+
+#include <clutter/clutter.h>
+//#include <libgnomevfs/gnome-vfs.h>
+#include <glib-object.h>
+#include "fluttr-library-row.h"
+#include "eggsequence.h"
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_LIBRARY fluttr_library_get_type()
+
+#define FLUTTR_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_LIBRARY, \
+       FluttrLibrary))
+
+#define FLUTTR_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_LIBRARY, \
+       FluttrLibraryClass))
+
+#define FLUTTR_IS_LIBRARY(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_LIBRARY))
+
+#define FLUTTR_IS_LIBRARY_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_LIBRARY))
+
+#define FLUTTR_LIBRARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_LIBRARY, \
+       FluttrLibraryClass))
+
+typedef struct {
+       GObject         parent;
+
+} FluttrLibrary;
+
+typedef struct {
+       GObjectClass parent_class;
+
+       void (*reordered) (FluttrLibrary *library);
+       void (*filter_change) (FluttrLibrary *library);
+       void (*library_row_change) (FluttrLibrary *library, FluttrLibraryRow *library_row);
+       void (*library_row_added) (FluttrLibrary *library, FluttrLibraryRow *library_row);
+
+} FluttrLibraryClass;
+
+typedef gint (*FluttrCompareRowFunc) (FluttrLibraryRow *a,
+                                    FluttrLibraryRow *b,
+                                    gpointer        data);
+
+typedef gboolean  (*FluttrFilterRowFunc) (FluttrLibrary    *library,
+                                        FluttrLibraryRow *library_row,
+                                        gpointer         data);
+
+typedef gboolean (*FluttrForeachRowFunc) (FluttrLibrary    *library,
+                                        FluttrLibraryRow *library_row,
+                                        gpointer         data);
+
+GType fluttr_library_get_type (void);
+
+FluttrLibrary*
+fluttr_library_new ();
+
+guint
+fluttr_library_row_count (FluttrLibrary *library);
+
+FluttrLibraryRow*
+fluttr_library_get_library_row (FluttrLibrary *library, gint index);
+
+void
+fluttr_library_append_library_row (FluttrLibrary *library, FluttrLibraryRow *library_row);
+
+void
+fluttr_library_set_filter (FluttrLibrary    *library,
+                         FluttrFilterRowFunc  filter, 
+                         gpointer         data);
+
+void
+fluttr_library_set_sort_func (FluttrLibrary     *library, 
+                            FluttrCompareRowFunc  func, 
+                            gpointer          userdata);
+
+void
+fluttr_library_foreach (FluttrLibrary      *library, 
+                     FluttrForeachRowFunc   func,
+                     gpointer           data);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-list-view.c b/attic/fluttr/src/fluttr-list-view.c
new file mode 100644 (file)
index 0000000..7e05f83
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include <GL/gl.h>
+
+#include "fluttr-list-view.h"
+
+G_DEFINE_TYPE (FluttrListView, fluttr_list_view, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_LIST_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_LIST_VIEW, \
+       FluttrListViewPrivate))
+       
+struct _FluttrListViewPrivate
+{
+       FluttrLibrary           *library;
+       FluttrSet               *set;
+       GList                   *photos;
+       
+       gint                     active_photo;
+       ClutterActor            *active_actor;
+       gint                     active_col;
+       
+       gint                     n_cols;
+};
+
+enum
+{
+       PROP_0,
+       PROP_LIBRARY,
+       PROP_SET,
+       PROP_COLS
+};
+
+static ClutterGroupClass       *parent_class = NULL;
+
+FluttrPhoto*
+fluttr_list_view_get_active (FluttrListView *list_view)
+{
+       FluttrListViewPrivate *priv;
+               
+       g_return_val_if_fail (FLUTTR_IS_LIST_VIEW (list_view), NULL);
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(list_view);
+       
+       return FLUTTR_PHOTO (priv->active_actor);
+}
+
+void 
+fluttr_list_view_advance (FluttrListView *list_view, gint n)
+{
+       FluttrListViewPrivate *priv;
+       gint len;
+       gint i = 0;
+       ClutterActor *photo = NULL;
+       guint width = fluttr_photo_get_default_width ();
+       guint height = fluttr_photo_get_default_height ();
+       ClutterActor *stage = clutter_stage_get_default ();
+       gint stage_height;
+       gint min = -1 * fluttr_photo_get_default_height ();
+       gint x1;
+       gint active_row = 0;
+       gint offset = height/2;
+       gint padding = width /6;
+               
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (list_view));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(list_view);
+
+       len = g_list_length (priv->photos);
+       g_object_get (G_OBJECT (stage), "height", &stage_height, NULL);
+       stage_height += fluttr_photo_get_default_height ();
+       
+       /* Make sure we are within the bounds of the number of albums */
+       priv->active_photo+= n;
+       if (priv->active_photo < 0) {
+               priv->active_photo  = 0;
+       } else if (priv->active_photo > len-1) {
+               priv->active_photo = len -1;
+       } else
+               ;
+       /* Find the magic row */        
+       active_row = 0;
+       gint row = 0;
+       gint col = 0;
+       
+       for (i = 0; i < len; i++) {
+               if (i == priv->active_photo) {
+                       active_row = row;
+                       break;
+               }
+               col++;
+               if (col > (priv->n_cols-1)) {
+                       col = 0;
+                       row++;
+               }
+       }
+       
+       /* Figure out the base x value */
+       x1 = ((width) * priv->n_cols ) + (padding*(priv->n_cols-1));
+       x1 = (CLUTTER_STAGE_WIDTH ()/2)-(x1/2);
+       
+       /* Iterate through actors, calculating their new x positions, and make
+          sure they are on the right place (left, right or center) */
+       col = 0;
+       row = 0;
+       gint less = priv->active_photo - (priv->n_cols * 2);
+       gint more = priv->active_photo + (priv->n_cols * 3);
+       
+       offset = -1 * ((height) + padding) * active_row;
+       offset += (CLUTTER_STAGE_HEIGHT () /2) - (height/2);
+       
+       for (i = 0; i < len; i++) {
+               photo = (ClutterActor*)g_list_nth_data (priv->photos, i);
+                
+               gint x = x1 + (col * (width + padding));
+               gint y = offset;
+               if (y > stage_height)
+                       y = stage_height;
+               else if (y < min)
+                       y = min;
+               
+               fluttr_photo_update_position (FLUTTR_PHOTO (photo), x, y);
+               
+               col++;
+               if (col > (priv->n_cols-1)) {
+                       col = 0;
+                       row++;
+                       offset += height + padding;
+               }       
+               if ((i > less) && (i < more)) {
+                       GdkPixbuf *pixbuf = NULL;
+                       g_object_get (G_OBJECT (photo), 
+                                     "pixbuf", &pixbuf, NULL);
+                       
+                       if (!pixbuf) {
+                               fluttr_photo_fetch_pixbuf (FLUTTR_PHOTO 
+                                                               (photo));
+                       }
+               }
+               
+               if (i == priv->active_photo) {
+                       fluttr_photo_set_active (FLUTTR_PHOTO (photo), TRUE);
+                       priv->active_actor = photo;
+                       
+               } else
+                       fluttr_photo_set_active (FLUTTR_PHOTO (photo), FALSE);
+       }
+       if (priv->active_actor)
+               clutter_actor_raise_top (priv->active_actor);
+}
+
+static gboolean
+_peg (ClutterActor *photo)
+{
+       guint size = fluttr_photo_get_default_size ();
+       fluttr_photo_update_position (FLUTTR_PHOTO (photo), 
+                                     clutter_actor_get_x (photo), 
+                                     CLUTTER_STAGE_HEIGHT () + size);
+       return FALSE;
+}
+
+/* We make all the 'viewable' photos fall down, leaving just the main one */
+void
+fluttr_list_view_activate (FluttrListView *list_view)
+{
+       FluttrListViewPrivate *priv;
+       gint len;
+       gint i = 0;
+       ClutterActor *photo = NULL;
+       gint active_row = 0;
+       guint size = fluttr_photo_get_default_size ();
+       gint x_center = (CLUTTER_STAGE_WIDTH () /2) - (size /2);
+       gint y_center = (CLUTTER_STAGE_HEIGHT ()/2) - (size /2);
+               
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (list_view));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(list_view);
+
+       len =  g_list_length (priv->photos);
+       
+       /* Find the active row */       
+       active_row = 0;
+       gint row = 0;
+       gint col = 0;
+       
+       for (i = 0; i < len; i++) {
+               if (i == priv->active_photo) {
+                       active_row = row;
+                       break;
+               }
+               col++;
+               if (col > (priv->n_cols-1)) {
+                       col = 0;
+                       row++;
+               }
+       }
+       
+       /* Iterate through actors, calculating their new x positions, and make
+          sure they are on the right place (left, right or center) */
+       col = 0;
+       row = 0;
+       
+       for (i = 0; i < len; i++) {
+               photo = (ClutterActor*)g_list_nth_data (priv->photos, i);
+                
+               if (i == priv->active_photo) {
+                       fluttr_photo_update_position (FLUTTR_PHOTO (photo),
+                                                     x_center, y_center);
+               
+               } else {
+                       if ((row >= active_row-2) && (row <= active_row +3)) {
+                                                       
+                                                                                               
+                               fluttr_photo_update_position 
+                                       (FLUTTR_PHOTO (photo), 
+                                        clutter_actor_get_x (photo), 
+                                        clutter_actor_get_y (photo) - 20);
+
+                               /*fluttr_photo_update_position 
+                                       (FLUTTR_PHOTO (photo), 
+                                        clutter_actor_get_x (photo), 
+                                        CLUTTER_STAGE_HEIGHT () + size);*/
+                               g_timeout_add (300, (GSourceFunc)_peg, photo);
+
+                       }
+               }
+               col++;
+               if (col > (priv->n_cols-1)) {
+                       col = 0;
+                       row++;
+               }               
+       }
+}
+
+void
+fluttr_list_view_advance_row (FluttrListView *view, gint n)
+{
+       FluttrListViewPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (view));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(view);
+       
+       fluttr_list_view_advance (view, (priv->n_cols * n));
+}
+
+void
+fluttr_list_view_advance_col (FluttrListView *list_view, gint n)
+{
+       fluttr_list_view_advance (list_view, n);
+}
+
+/* Empty the group*/
+static void
+fluttr_list_view_empty (FluttrListView *view)
+{
+       FluttrListViewPrivate *priv;
+       gint i;
+       ClutterActor* child;
+       gint len;
+       
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (view));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(view);
+       
+       len = g_list_length (priv->photos);
+       
+       for (i = 0; i < len; i++) {
+               child = (ClutterActor*)g_list_nth_data (priv->photos, i);
+               clutter_group_remove (CLUTTER_GROUP (view), child);
+               
+       }
+       g_list_free (priv->photos);
+}
+                       
+/* Populate the group */
+static void
+fluttr_list_view_populate (FluttrListView *view)
+{
+       FluttrListViewPrivate *priv;
+       GList *photos = NULL;
+       GList *p;
+       gint x =(CLUTTER_STAGE_WIDTH ()/2)-(fluttr_photo_get_default_width()/2);
+       gint y =(CLUTTER_STAGE_HEIGHT()/2)
+               -(fluttr_photo_get_default_height()/2);
+       
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (view));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(view);
+       
+       photos = fluttr_set_get_photos (FLUTTR_SET (priv->set));
+       priv->photos = NULL;
+       
+       /* Go through each photodata in the list, creating a FluttrPhoto, and 
+          adding it to the group */
+       
+       for (p = photos; p != NULL; p = p->next) {
+               FluttrPhotoData *data = (FluttrPhotoData*)p->data;
+               ClutterActor *photo = fluttr_photo_new ();
+               clutter_actor_set_size (photo, 
+                                       fluttr_photo_get_default_width (),
+                                       fluttr_photo_get_default_height ());
+               clutter_actor_set_position (photo, x, y);
+               clutter_group_add (CLUTTER_GROUP (view), photo);
+               
+               g_object_set (G_OBJECT (photo), 
+                             "photoid", data->id,
+                             "name", data->name,
+                             NULL);
+               
+               /* Now lets set the pixbuf if we have it */
+               if (data->pixbuf)
+                       g_object_set (G_OBJECT (photo), "pixbuf", data->pixbuf,
+                             NULL);
+               
+               clutter_actor_show_all (photo);
+               priv->photos = g_list_append (priv->photos, photo);
+       }
+       priv->active_photo = 0;
+       priv->active_actor = NULL;
+}
+
+/* GObject Stuff */
+
+static void
+fluttr_list_view_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+       FluttrListViewPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (object));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_LIBRARY:
+                       if (priv->library != NULL)
+                               g_object_unref (priv->library);
+                       priv->library =g_value_get_object (value);
+                       if (priv->library)
+                                g_object_ref (priv->library);
+                       /* Connect to the library signals */
+                       break;
+                       
+               case PROP_SET:
+                       if (priv->set)
+                               g_object_unref (priv->set);
+                       priv->set = g_value_get_object (value);
+                       if (priv->set != NULL) {
+                               g_object_ref (priv->set);
+                               /* Empty the group*/
+                               fluttr_list_view_empty (
+                                                    FLUTTR_LIST_VIEW (object));
+                               
+                               /* Populate the group */
+                               fluttr_list_view_populate (
+                                                   FLUTTR_LIST_VIEW (object));
+                       }
+                       break;
+               
+               case PROP_COLS:
+                       priv->n_cols = g_value_get_int (value);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_list_view_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrListViewPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_LIST_VIEW (object));
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_LIBRARY:
+                       g_value_set_object (value, priv->library);
+                       break;  
+               
+               case PROP_SET:
+                       g_value_set_object (value, priv->library);
+                       break;          
+               
+               case PROP_COLS:
+                       g_value_set_int (value, priv->n_cols);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void
+fluttr_list_view_paint (ClutterActor *actor)
+{
+        FluttrListView        *list;
+       FluttrListViewPrivate *priv;
+       gint height;
+       gint buf = -1 * fluttr_photo_get_default_width ();
+
+       list = FLUTTR_LIST_VIEW(actor);
+
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE(list);
+
+       glPushMatrix();
+       
+       g_object_get (G_OBJECT (clutter_stage_get_default ()), "height", 
+                     &height, NULL);
+       gint i;
+       gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor)); 
+       for (i = 0; i < len; i++) {
+               ClutterActor* child;
+                child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+               
+               gint y;
+               g_object_get (G_OBJECT (child), "y", &y, NULL);
+                
+                if (y < buf || y > height) {
+                        fluttr_photo_set_visible (FLUTTR_PHOTO (child), FALSE);
+                        continue;
+                } else {
+                        fluttr_photo_set_visible (FLUTTR_PHOTO (child), TRUE);
+                }
+                if (child) {
+                        clutter_actor_paint (child);
+               }
+       }
+       glPopMatrix();
+}
+
+static void 
+fluttr_list_view_dispose (GObject *object)
+{
+       FluttrListView         *self = FLUTTR_LIST_VIEW(object);
+       FluttrListViewPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void 
+fluttr_list_view_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+fluttr_list_view_class_init (FluttrListViewClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+       
+       parent_class = CLUTTER_GROUP_CLASS (klass);
+
+       actor_class->paint           = fluttr_list_view_paint;
+       
+       gobject_class->finalize     = fluttr_list_view_finalize;
+       gobject_class->dispose      = fluttr_list_view_dispose;
+       gobject_class->get_property = fluttr_list_view_get_property;
+       gobject_class->set_property = fluttr_list_view_set_property;    
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrListViewPrivate));
+               
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_LIBRARY,
+                g_param_spec_object ("library",
+                "Library",
+                "The underlying Fluttr Library",
+                FLUTTR_TYPE_LIBRARY,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_SET,
+                g_param_spec_object ("set",
+                "Set",
+                "The underlying Fluttr Photo set",
+                FLUTTR_TYPE_SET,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_COLS,
+                g_param_spec_int ("cols",
+                "Columns",
+                "The number of photo columns",
+                1, 10, 3,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+
+}
+
+static void
+fluttr_list_view_init (FluttrListView *self)
+{
+       FluttrListViewPrivate *priv;
+
+       priv = FLUTTR_LIST_VIEW_GET_PRIVATE (self);
+       
+       priv->active_photo = 0;
+       priv->active_col = 0;
+       priv->set = NULL;
+       
+}
+
+ClutterActor*
+fluttr_list_view_new (void)
+{
+       ClutterGroup         *list_view;
+
+       list_view = g_object_new (FLUTTR_TYPE_LIST_VIEW, 
+                                 NULL);
+       
+       return CLUTTER_ACTOR (list_view);
+}
+
diff --git a/attic/fluttr/src/fluttr-list-view.h b/attic/fluttr/src/fluttr-list-view.h
new file mode 100644 (file)
index 0000000..901e6c3
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-`hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include "fluttr-library.h"
+#include "fluttr-photo.h"
+#include "fluttr-set.h"
+
+#include <libnflick/nflick.h>
+
+#ifndef _HAVE_FLUTTR_LIST_VIEW_H
+#define _HAVE_FLUTTR_LIST_VIEW_H
+
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_LIST_VIEW fluttr_list_view_get_type()
+
+#define FLUTTR_LIST_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_LIST_VIEW, \
+       FluttrListView))
+
+#define FLUTTR_LIST_VIEWCLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_LIST_VIEW, \
+       FluttrListViewClass))
+
+#define FLUTTR_IS_LIST_VIEW(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_LIST_VIEW))
+
+#define FLUTTR_IS_LIST_VIEW_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_LIST_VIEW))
+
+#define FLUTTR_LIST_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_LIST_VIEW, \
+       FluttrListViewClass))
+
+typedef struct _FluttrListView FluttrListView;
+typedef struct _FluttrListViewClass FluttrListViewClass;
+typedef struct _FluttrListViewPrivate FluttrListViewPrivate;
+
+struct _FluttrListView
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrListViewPrivate   *priv;
+};
+
+struct _FluttrListViewClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*_fluttr_list_view_1) (void);
+       void (*_fluttr_list_view_2) (void);
+       void (*_fluttr_list_view_3) (void);
+       void (*_fluttr_list_view_4) (void);
+}; 
+
+GType fluttr_list_view_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_list_view_new ();
+
+FluttrPhoto*
+fluttr_list_view_get_active (FluttrListView *list_view);
+
+void
+fluttr_list_view_activate (FluttrListView *list_view);
+
+void 
+fluttr_list_view_advance (FluttrListView *list_view, gint n);
+
+void
+fluttr_list_view_advance_row (FluttrListView *list_view, gint n);
+
+void
+fluttr_list_view_advance_col (FluttrListView *list_view, gint n);
+
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-list.c b/attic/fluttr/src/fluttr-list.c
new file mode 100644 (file)
index 0000000..0fe38ee
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include <GL/gl.h>
+
+#include "fluttr-list.h"
+
+#include "fluttr-spinner.h"
+#include "fluttr-behave.h"
+
+G_DEFINE_TYPE (FluttrList, fluttr_list, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_LIST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_LIST, \
+       FluttrListPrivate))
+       
+#define FONT "DejaVu Sans Book"
+
+
+struct _FluttrListPrivate
+{
+       gchar                   *mini_token;
+       gchar                   *username;
+       gchar                   *fullname;
+       gchar                   *token;
+       gchar                   *usernsid;
+       
+       NFlickWorker            *worker;
+
+       GdkPixbuf               *logo;
+       ClutterActor            *group;
+       ClutterActor            *message;
+       ClutterActor            *spinner;
+       ClutterActor            *text;
+       gchar                   *msg;
+       gboolean                 popping;
+       
+       ClutterTimeline         *timeline;
+       ClutterAlpha            *alpha;
+       ClutterBehaviour        *behave;
+       
+       ClutterTimeline         *text_time;
+       ClutterAlpha            *text_alpha;
+       ClutterBehaviour        *text_behave;   
+};
+
+enum
+{
+       PROP_0,
+       PROP_MINI_TOKEN,
+       PROP_USERNAME,
+       PROP_FULLNAME,
+       PROP_TOKEN,
+       PROP_USERNSID
+};
+
+enum
+{
+       SUCCESSFUL,
+       ERROR,
+       LAST_SIGNAL
+};
+
+static guint _list_signals[LAST_SIGNAL] = { 0 };
+
+static void
+close_message_window (FluttrList *list)
+{
+        FluttrListPrivate *priv;
+        
+        g_return_if_fail (FLUTTR_IS_LIST (list));
+        priv = FLUTTR_LIST_GET_PRIVATE(list);
+        
+        priv->popping = FALSE;
+        clutter_timeline_start (priv->timeline);
+       fluttr_spinner_spin (FLUTTR_SPINNER (priv->spinner), FALSE);
+}
+
+static gboolean                 
+on_thread_abort_idle (FluttrList *list)
+{
+        g_return_val_if_fail (FLUTTR_IS_LIST (list), FALSE);
+        
+        close_message_window (list);
+
+       g_signal_emit (list, _list_signals[ERROR], 0, "Aborted");       
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_ok_idle (FluttrList *list)
+{
+        FluttrListPrivate *priv;
+        
+        g_return_val_if_fail (FLUTTR_IS_LIST (list), FALSE);
+        priv = FLUTTR_LIST_GET_PRIVATE(list);
+        
+        close_message_window (list);
+                
+        g_signal_emit (list, _list_signals[SUCCESSFUL], 0, priv->worker);
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_error_idle (FluttrList *list)
+{
+        FluttrListPrivate *priv;
+        gchar *error = NULL;
+        
+        g_return_val_if_fail (FLUTTR_IS_LIST (list), FALSE);
+        priv = FLUTTR_LIST_GET_PRIVATE(list);
+        
+        close_message_window (list);
+        
+        /* Get the actual error */
+        g_object_get (G_OBJECT (priv->worker), "error", &error, NULL);
+        if (error == NULL) {
+                error = g_strdup_printf (gettext ("Internal error. "));
+                g_warning ("No error set on worker!");
+        }
+       g_signal_emit (list, _list_signals[ERROR], 0, error);
+
+        g_free (error);
+
+        return FALSE;
+}
+
+/* Copy the new message and start the fade effect if not already started */
+static gboolean                 
+on_thread_msg_change_idle (FluttrList *list)
+{
+        FluttrListPrivate *priv;
+        gchar *msg;
+        
+        g_return_val_if_fail (FLUTTR_IS_LIST (list), FALSE);
+        priv = FLUTTR_LIST_GET_PRIVATE(list);
+        
+        /* Get the new message */
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                g_print ("%s\n", msg);
+        }
+        priv->msg = g_strdup (msg);
+        
+        if (clutter_timeline_is_playing (priv->text_time))
+               ;//clutter_timeline_rewind (priv->text_time);
+       
+        else
+               clutter_timeline_start (priv->text_time);
+
+       return FALSE;
+}
+
+
+/* This function does th emain work of creating and configuring the worker 
+   thread. the majority of this code is taken from
+   NFlick the n800 Flickr photo browser by MDK (see: README) */
+void
+fluttr_list_go (FluttrList *list)
+{
+       FluttrListPrivate *priv;
+       NFlickWorker *worker;
+        NFlickWorkerStatus status;
+        
+               g_return_if_fail (FLUTTR_IS_LIST (list));
+       priv = FLUTTR_LIST_GET_PRIVATE(list);
+       
+       /* Set to opaque and start spinner */
+       fluttr_spinner_spin (FLUTTR_SPINNER (priv->spinner), TRUE);
+       clutter_timeline_start (priv->timeline);
+       clutter_actor_set_opacity (CLUTTER_ACTOR (list), 255);          
+       
+       /* Create the worker */
+        worker = (NFlickWorker*)nflick_set_list_worker_new (priv->usernsid,
+                                                           priv->token);
+        
+        /* Check if the worker is in the right state */
+        g_object_get (G_OBJECT (worker), "status", &status, NULL);
+        
+        if (status != NFLICK_WORKER_STATUS_IDLE) {
+                g_warning ("Bad worker status"); 
+                return;
+        }
+        
+        g_object_ref (worker);
+        priv->worker = worker;
+        
+        /* Get the initial message */
+        gchar *msg = NULL;
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                /* FIXME Escape markup */
+               g_print ("%s", msg);
+        }
+        
+        /* Set the callback functions */
+        nflick_worker_set_custom_data (worker, list);
+        nflick_worker_set_aborted_idle (worker, 
+                                  (NFlickWorkerIdleFunc) on_thread_abort_idle);
+        
+        nflick_worker_set_error_idle (worker, 
+                                  (NFlickWorkerIdleFunc) on_thread_error_idle);
+        
+        nflick_worker_set_ok_idle (worker, 
+                                     (NFlickWorkerIdleFunc) on_thread_ok_idle);
+        
+        nflick_worker_set_msg_change_idle (worker, 
+                             (NFlickWorkerIdleFunc) on_thread_msg_change_idle);
+                                        
+        nflick_worker_start (priv->worker);
+        
+        /* Free */
+        g_free (msg);
+}
+
+
+/* Slide in or out the notification popp, depending on priv->pop_visible */
+static void
+fluttr_list_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+       FluttrListPrivate *priv;
+       gfloat scale;
+       gfloat factor;
+       guint width, height;    
+       gint x, y;
+       
+               g_return_if_fail (FLUTTR_IS_LIST (data));
+       priv = FLUTTR_LIST_GET_PRIVATE(data);
+       
+       factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->popping) 
+               scale = factor;
+       else
+               scale = 1.0 - factor;
+       
+       clutter_actor_set_scale (CLUTTER_ACTOR (priv->group), scale, scale);
+       
+       /* Set new size */
+       clutter_actor_get_size (CLUTTER_ACTOR (priv->group), &width, &height);
+       width *= scale;
+       height *= scale;
+       
+       x = (CLUTTER_STAGE_WIDTH () /2) - (width /2);
+       y = (CLUTTER_STAGE_HEIGHT () /2) - (height /2);
+       
+       g_object_set (G_OBJECT (priv->group), 
+                     "y", y, 
+                     "x", x,
+                     NULL);
+       clutter_actor_set_opacity (CLUTTER_ACTOR (priv->group), 255 * scale);
+       clutter_actor_set_opacity (CLUTTER_ACTOR (priv->text), 255 * scale);
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}
+
+/* Fade out text, change text, then fade in, all within one play of the timeline
+   just to keep things interesting :) */
+static void
+fluttr_list_text_alpha_func (ClutterBehaviour *behave,
+                            guint              alpha_value,
+                            gpointer           data)
+{
+       FluttrListPrivate *priv;
+       gfloat factor;
+       
+               g_return_if_fail (FLUTTR_IS_LIST (data));
+       priv = FLUTTR_LIST_GET_PRIVATE(data);
+       
+       factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->msg != NULL && factor > 0.5) {
+               gchar *text = priv->msg;
+               gint x, y;
+               clutter_label_set_text (CLUTTER_LABEL (priv->text),
+                                       text);
+       
+               /* Calculate the new position */
+               x = (CLUTTER_STAGE_WIDTH () /2) 
+                               - (clutter_actor_get_width (priv->text)/2);
+               y = (CLUTTER_STAGE_HEIGHT () /20) * 18;
+                       clutter_actor_set_position (priv->text, x, y);
+                       clutter_actor_set_position (priv->text, x, y);
+               g_free (priv->msg);
+               priv->msg = NULL;
+               
+       }
+       if (factor < 0.5) {
+               factor *= 2;
+               factor = 1.0 - factor;
+       } else {
+               factor -= 0.5;
+               factor /= 0.5;
+       }
+       clutter_actor_set_opacity (CLUTTER_ACTOR (priv->text), 255 * factor);
+       /*clutter_actor_rotate_x (CLUTTER_ACTOR (priv->text), 
+                               360 * factor,
+                       clutter_actor_get_height (CLUTTER_ACTOR (priv->text))/2,
+                       0);
+       */
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}      
+               
+/* GObject Stuff */
+
+static void
+fluttr_list_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+       FluttrListPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_LIST (object));
+       priv = FLUTTR_LIST_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_MINI_TOKEN:
+                       if (priv->mini_token != NULL)
+                               g_free (priv->mini_token);
+                       priv->mini_token =g_strdup (g_value_get_string (value));
+                       break;
+               case PROP_USERNAME:
+                       if (priv->username != NULL)
+                               g_free (priv->username);
+                       priv->username =g_strdup (g_value_get_string (value));
+                       break;
+
+               case PROP_FULLNAME:
+                       if (priv->fullname != NULL)
+                               g_free (priv->fullname);
+                       priv->fullname =g_strdup (g_value_get_string (value));
+                       break;
+               
+               case PROP_TOKEN:
+                       if (priv->token != NULL)
+                               g_free (priv->token);
+                       priv->token =g_strdup (g_value_get_string (value));
+                       break;
+               
+               case PROP_USERNSID:
+                       if (priv->usernsid != NULL)
+                               g_free (priv->usernsid);
+                       priv->usernsid =g_strdup (g_value_get_string (value));
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_list_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrListPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_LIST (object));
+       priv = FLUTTR_LIST_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_MINI_TOKEN:
+                       g_value_set_string (value, priv->mini_token);
+                       break;
+               case PROP_USERNAME:
+                       g_value_set_string (value, priv->username);
+                       break;
+
+               case PROP_FULLNAME:
+                       g_value_set_string (value, priv->fullname);
+                       break;
+               
+               case PROP_TOKEN:
+                       g_value_set_string (value, priv->token);
+                       break;
+               
+               case PROP_USERNSID:
+                       g_value_set_string (value, priv->usernsid);
+                       break;                  
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void
+fluttr_list_paint (ClutterActor *actor)
+{
+       FluttrList        *list;
+       FluttrListPrivate *priv;
+
+       list = FLUTTR_LIST(actor);
+
+       priv = FLUTTR_LIST_GET_PRIVATE(list);
+
+       glPushMatrix();
+       
+       gint i;
+       gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor)); 
+       for (i = 0; i < len; i++) {
+               ClutterActor* child;
+
+               child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+               if (child) {
+                       clutter_actor_paint (child);
+               }
+       }
+
+       glPopMatrix();
+}
+
+static void 
+fluttr_list_dispose (GObject *object)
+{
+       FluttrList         *self = FLUTTR_LIST(object);
+       FluttrListPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_list_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_list_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_list_parent_class)->finalize (object);
+}
+
+static void
+fluttr_list_class_init (FluttrListClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+       ClutterActorClass   *parent_class; 
+
+       parent_class = CLUTTER_ACTOR_CLASS (fluttr_list_parent_class);
+
+       actor_class->paint           = fluttr_list_paint;
+       
+       gobject_class->finalize     = fluttr_list_finalize;
+       gobject_class->dispose      = fluttr_list_dispose;
+       gobject_class->get_property = fluttr_list_get_property;
+       gobject_class->set_property = fluttr_list_set_property; 
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrListPrivate));
+       
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_MINI_TOKEN,
+                g_param_spec_string ("mini-token",
+                "Mini Token",
+                "The Flickr mini-token",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_USERNAME,
+                g_param_spec_string ("username",
+                "Username",
+                "The Flickr username",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                  
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_FULLNAME,
+                g_param_spec_string ("fullname",
+                "Fullname",
+                "The users full name",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_TOKEN,
+                g_param_spec_string ("token",
+                "Token",
+                "The Flickr token",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_USERNSID,
+                g_param_spec_string ("usernsid",
+                "Usernsid",
+                "The Flickr usernsid",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                                                  
+
+       /* Class signals */
+       _list_signals[SUCCESSFUL] =
+               g_signal_new ("successful",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrListClass, successful),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__OBJECT,
+                            G_TYPE_NONE, 1, NFLICK_TYPE_WORKER);
+                            
+       _list_signals[ERROR] =
+               g_signal_new ("error",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrListClass, error),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1, G_TYPE_STRING);                         
+
+}
+
+static void
+fluttr_list_init (FluttrList *self)
+{
+       FluttrListPrivate *priv;
+       gint size = CLUTTER_STAGE_HEIGHT ()/9;
+       gint width, height;
+       ClutterActor *message;
+       GdkPixbuf *msg_buf = NULL;
+       guint font_size;
+       gchar *font;
+       ClutterColor text_color = { 0xff, 0xff, 0xff, 0xff };   
+       
+       priv = FLUTTR_LIST_GET_PRIVATE (self);
+       
+       priv->mini_token = NULL;
+
+       width = CLUTTER_STAGE_WIDTH ()/4;
+       height = CLUTTER_STAGE_HEIGHT ()/4;
+               
+       /* Group */
+       priv->group = clutter_group_new ();
+       clutter_group_add (CLUTTER_GROUP (self),priv->group); 
+       clutter_actor_set_size (priv->group, width, height);
+       clutter_actor_set_position (priv->group, 
+                                   (CLUTTER_STAGE_WIDTH ()/2) - (width/2),
+                                   (CLUTTER_STAGE_HEIGHT ()/2) - (height/2));  
+       
+       /* message box */
+       message = clutter_texture_new ();
+       priv->message = message;
+       msg_buf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR \
+                                                       "/message.svg",
+                                                   width,
+                                                   height,
+                                                   FALSE,
+                                                   NULL);
+       clutter_texture_set_pixbuf (CLUTTER_TEXTURE (message), msg_buf, NULL);
+       clutter_group_add (CLUTTER_GROUP (priv->group),message); 
+       clutter_actor_set_size (message, width, height);
+       clutter_actor_set_position (message, -(width/2),-(height/2));
+       
+       
+       /* Spinner */
+       priv->spinner = fluttr_spinner_new ();
+       clutter_group_add (CLUTTER_GROUP (priv->group), priv->spinner);
+       clutter_actor_set_size (priv->spinner, size, size);
+       clutter_actor_set_position (priv->spinner, -(size/2), -(size/2));
+                                   
+       priv->timeline = clutter_timeline_new (40, 80);
+       priv->alpha = clutter_alpha_new_full (priv->timeline,
+                                             alpha_sine_inc_func,
+                                             NULL, NULL);
+       priv->behave = fluttr_behave_new (priv->alpha,
+                                         fluttr_list_alpha_func,
+                                         (gpointer)self);
+       priv->popping = TRUE;
+       
+       /* This is the msg label */
+       font_size = CLUTTER_STAGE_HEIGHT () /20;
+       font = g_strdup_printf ("%s %d", FONT, font_size);
+       
+       priv->text = clutter_label_new_full (font, " ", &text_color);
+       clutter_actor_set_opacity (priv->text, 0);
+       clutter_label_set_line_wrap (CLUTTER_LABEL (priv->text), FALSE);
+       clutter_group_add (CLUTTER_GROUP (self), priv->text);
+       clutter_actor_set_size (priv->text, 
+                               CLUTTER_STAGE_WIDTH (),
+                               font_size * 2); 
+       
+       priv->text_time = clutter_timeline_new (40, 50);
+       priv->text_alpha = clutter_alpha_new_full (priv->text_time,
+                                             alpha_sine_inc_func,
+                                             NULL, NULL);
+       priv->text_behave = fluttr_behave_new (priv->text_alpha,
+                                         fluttr_list_text_alpha_func,
+                                         (gpointer)self);      
+       
+        clutter_actor_show_all (priv->group);
+        clutter_actor_show_all (CLUTTER_ACTOR (self));
+        g_free (font); 
+}
+
+ClutterActor*
+fluttr_list_new (void)
+{
+       ClutterGroup         *list;
+
+       list = g_object_new (FLUTTR_TYPE_LIST, 
+                            NULL);
+       
+       clutter_actor_set_opacity (CLUTTER_ACTOR (list), 0);
+       
+       return CLUTTER_ACTOR (list);
+}
+
diff --git a/attic/fluttr/src/fluttr-list.h b/attic/fluttr/src/fluttr-list.h
new file mode 100644 (file)
index 0000000..7cd14cf
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-`hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libnflick/nflick.h>
+
+#ifndef _HAVE_FLUTTR_LIST_H
+#define _HAVE_FLUTTR_LIST_H
+
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_LIST fluttr_list_get_type()
+
+#define FLUTTR_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_LIST, \
+       FluttrList))
+
+#define FLUTTR_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_LIST, \
+       FluttrListClass))
+
+#define FLUTTR_IS_LIST(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_LIST))
+
+#define FLUTTR_IS_LIST_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_LIST))
+
+#define FLUTTR_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_LIST, \
+       FluttrListClass))
+
+typedef struct _FluttrList FluttrList;
+typedef struct _FluttrListClass FluttrListClass;
+typedef struct _FluttrListPrivate FluttrListPrivate;
+
+struct _FluttrList
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrListPrivate   *priv;
+};
+
+struct _FluttrListClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*successful) (FluttrList *list, NFlickWorker *worker);
+       void (*error) (FluttrList *list, gchar *msg);
+       void (*_fluttr_list_3) (void);
+       void (*_fluttr_list_4) (void);
+}; 
+
+GType fluttr_list_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_list_new (void);
+
+void
+fluttr_list_go (FluttrList *list);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-photo.c b/attic/fluttr/src/fluttr-photo.c
new file mode 100644 (file)
index 0000000..061c901
--- /dev/null
@@ -0,0 +1,983 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include "GL/gl.h"
+
+#include "fluttr-photo.h"
+
+#include "fluttr-behave.h"
+#include "fluttr-settings.h"
+
+
+G_DEFINE_TYPE (FluttrPhoto, fluttr_photo, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_PHOTO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_PHOTO, \
+       FluttrPhotoPrivate))
+       
+#define FONT "DejaVu Sans Book"
+#define FRAME 1
+#define X_ANGLE 90
+
+#define ACT_SCALE 0.3
+
+static GdkPixbuf       *default_pic = NULL;
+
+struct _FluttrPhotoPrivate
+{
+       gchar                   *photoid;
+       gchar                   *name;
+       NFlickPhotoSet          *set;
+       gboolean                 visible;
+       
+       /* The all-important pixbuf fetching variables */
+       NFlickWorker            *worker;
+       GdkPixbuf               *pixbuf;
+       
+       /* Transformation code */
+       gint                     new_x;
+       gint                     new_y;
+       gfloat                   new_scale;
+       ClutterTimeline         *trans_time;
+       ClutterAlpha            *trans_alpha;
+       ClutterBehaviour        *trans_behave;
+
+       
+       /* The actual actors */
+       ClutterActor            *bg;
+       ClutterActor            *frame;
+       ClutterActor            *clip;
+       ClutterActor            *texture;
+       ClutterActor            *options; /* The 'flip' side */
+       
+       /* Swap pixbuf code */
+       ClutterTimeline         *swap_time;
+       ClutterAlpha            *swap_alpha;
+       ClutterBehaviour        *swap_behave;
+       
+       /* Activate animation */
+       gboolean                 active;
+       gfloat                   scale;
+       ClutterTimeline         *act_time;
+       ClutterAlpha            *act_alpha;
+       ClutterBehaviour        *act_behave;    
+       
+       /* Activate animation */
+       gboolean                 opt_in;
+       ClutterTimeline         *opt_time;
+       ClutterAlpha            *opt_alpha;
+       ClutterBehaviour        *opt_behave;    
+};
+
+enum
+{
+       PROP_0,
+       PROP_ID,
+       PROP_NAME,
+       PROP_PIXBUF,
+       PROP_SET
+};
+
+enum
+{
+       LOADED,
+       ERROR,
+       ACTIVATED,
+       LAST_SIGNAL
+};
+
+static guint _photo_signals[LAST_SIGNAL] = { 0 };
+
+void
+_fluttr_photo_fetch_pixbuf (FluttrPhoto *photo, guint width, guint height);
+
+
+/*
+ * If visible is set to false, the texture actor will be destroyed, else, it
+ * will be created again
+ */
+void
+fluttr_photo_set_visible (FluttrPhoto *photo, gboolean visible)
+{
+       FluttrPhotoPrivate *priv;
+       gint width = fluttr_photo_get_default_width ();
+       gint height = fluttr_photo_get_default_height ();
+       guint w, h;
+               
+       g_return_if_fail (FLUTTR_IS_PHOTO (photo));
+       priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+       
+       if (priv->visible == visible)
+               return;
+        if (visible) {
+               priv->texture = clutter_texture_new_from_pixbuf (default_pic);
+               clutter_group_add (CLUTTER_GROUP (priv->clip), priv->texture);
+               clutter_actor_set_size (priv->texture, 
+                                       width -(FRAME*2), 
+                                       height -(FRAME*2));
+               clutter_actor_set_position (priv->texture, FRAME, FRAME);     
+               if (priv->pixbuf) {
+                       clutter_texture_set_pixbuf (CLUTTER_TEXTURE (
+                                                       priv->texture),
+                                                   priv->pixbuf, NULL);
+                       clutter_actor_set_scale (priv->texture, 0.6, 0.6);
+                       clutter_actor_get_abs_size (priv->texture, &w, &h);
+                       
+                       clutter_actor_set_position (priv->texture, 
+                                                   (width/2) - (w/2),
+                                                   (height/2) - (h/2));
+                }
+                clutter_actor_show_all (priv->texture);
+        } else {
+                clutter_group_remove (CLUTTER_GROUP (priv->clip),priv->texture);
+                if (CLUTTER_IS_ACTOR (priv->texture))
+                        clutter_actor_destroy (priv->texture);
+                priv->texture = NULL;
+        }
+        priv->visible = visible;
+        
+}
+
+/* Will return the default size of the FluttrPhoto square for the current stage */
+guint
+fluttr_photo_get_default_size (void)
+{
+       guint width = CLUTTER_STAGE_WIDTH ();
+       guint height = CLUTTER_STAGE_HEIGHT ();
+       
+       if (width > height)
+               return height/3;
+       else
+               return width /3;
+}
+
+guint
+fluttr_photo_get_default_width (void)
+{
+       return fluttr_photo_get_default_size ();
+}
+
+guint
+fluttr_photo_get_default_height (void)
+{
+       return fluttr_photo_get_default_width () * 0.8;
+}
+
+void
+fluttr_photo_show_options (FluttrPhoto *photo, gboolean show)
+{
+       FluttrPhotoPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_PHOTO (photo));
+       priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+       
+       if (priv->opt_in == show)
+               return;
+       priv->opt_in = show;
+       
+       if (!clutter_timeline_is_playing (priv->opt_time))
+               clutter_timeline_start (priv->opt_time);
+       else
+               clutter_timeline_rewind (priv->opt_time);
+}
+
+/* If active, scale the photo, if not, scale it down */
+void
+fluttr_photo_set_active (FluttrPhoto *photo, gboolean active)
+{
+       FluttrPhotoPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_PHOTO (photo));
+       priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+       
+       if (priv->active == active)
+               return;
+       
+       priv->active = active;
+       
+       if (!clutter_timeline_is_playing (priv->act_time))
+               clutter_timeline_start (priv->act_time);
+       else
+               clutter_timeline_rewind (priv->act_time);
+}
+
+
+/* Set the new x and y position of the actor, and start (or rewind) the main
+   timeline */
+void
+fluttr_photo_update_position (FluttrPhoto *photo, gint x, gint y)
+{
+        FluttrPhotoPrivate *priv;
+        
+        g_return_if_fail (FLUTTR_IS_PHOTO (photo));
+        priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+        
+        if ((priv->new_x == x) && (priv->new_y == y)) {
+               return;
+        }
+        priv->new_x = x;
+        priv->new_y = y;
+        /*clutter_actor_set_position (photo, x, y);
+        
+        */
+        if (clutter_timeline_is_playing (priv->trans_time))
+               clutter_timeline_rewind (priv->trans_time);
+        else   
+               clutter_timeline_start (priv->trans_time);      
+        
+}
+
+/* Allows smooth transforms (position & size) on th widget...looks goooood*/
+static void
+fluttr_photo_trans_alpha_func (ClutterBehaviour *behave,
+                              guint             alpha_value,
+                              gpointer          data)
+{
+        FluttrPhotoPrivate *priv;
+        gfloat factor;
+        gint old_x, old_y;
+        gint x, y;
+        
+        
+        g_return_if_fail (FLUTTR_IS_PHOTO (data));
+        priv = FLUTTR_PHOTO_GET_PRIVATE(data);
+        
+        /* Calculate the factor */
+        factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+        
+        /* Load up the orignal values */
+        old_x = clutter_actor_get_x (CLUTTER_ACTOR (data));
+        old_y = clutter_actor_get_y (CLUTTER_ACTOR (data));
+        
+        /* We first calculate the new x pos */
+        if (old_x == priv->new_x) {
+               x = 0;
+               //g_print ("Same x %d\n", x);
+        } else if (old_x < priv->new_x) {
+               /* We're moving to the positive */
+               if (old_x < 0)
+                       x = ((-1*old_x)+priv->new_x) * factor;
+               else
+                       x = (priv->new_x - old_x) * factor;
+        } else {
+               /* We're moving to the left */
+               if (priv->new_x < 0) 
+                       x = ((-1*priv->new_x)+old_x) * -1 * factor;
+               else
+                       x = (old_x - priv->new_x) * -1 * factor;
+        }
+        
+        /* Then the new y pos */
+        if (old_y == priv->new_y) {
+               y = 0;
+               //g_print ("Same y %d %d\n", y, priv->new_y);
+        
+        } else if (old_y < priv->new_y) {
+               /* We're moving to the bottom */
+               if (old_y < 0)
+                       y = ((-1*old_y)+priv->new_y) * factor;
+               else
+                       y = (priv->new_y - old_y) * factor;
+        } else {
+               /* We're moving to the top */
+               if (priv->new_y < 0) 
+                       y = ((-1*priv->new_y)+old_y) * -1 * factor;
+               else
+                       y = (old_y - priv->new_y) * -1 * factor;
+        }
+               
+        x += old_x;
+        y += old_y;    
+               
+        clutter_actor_set_position (CLUTTER_ACTOR (data), x, y);
+        /*g_print ("%s %d %d\n", priv->photoid, x, y);*/
+        
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));        
+}
+
+/* Fade out text, change text, then fade in, all within one play of the timeline
+   just to keep things interesting :) */
+static void
+fluttr_photo_swap_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+        FluttrPhotoPrivate *priv;
+       gfloat factor;
+       guint width = fluttr_photo_get_default_width ();
+       guint height = fluttr_photo_get_default_height ();
+       guint w, h;
+
+        
+        g_return_if_fail (FLUTTR_IS_PHOTO (data));
+        priv = FLUTTR_PHOTO_GET_PRIVATE(data);
+       
+       /* If we are not visible, return */
+        if (!priv->visible || priv->texture == NULL) {
+                clutter_timeline_stop (priv->swap_time);
+                return;
+       }
+        factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->pixbuf != NULL && factor > 0.5 && priv->texture) {
+               clutter_texture_set_pixbuf (CLUTTER_TEXTURE (priv->texture),
+                                           priv->pixbuf, NULL);
+               clutter_actor_set_scale (priv->texture, 0.6, 0.6);
+               clutter_actor_get_abs_size (priv->texture, &w, &h);
+               
+               clutter_actor_set_position (priv->texture, 
+                                           (width/2) - (w/2),
+                                           (height/2) - (h/2));    
+                clutter_actor_show_all (priv->texture);
+       }
+       if (factor < 0.5) {
+               factor *= 2;
+               factor = 1.0 - factor;
+       } else {
+               factor -= 0.5;
+               factor /= 0.5;
+       }
+       
+       if (priv->texture)
+               clutter_actor_set_opacity (CLUTTER_ACTOR (priv->texture),
+                                          255 * factor);
+       //clutter_actor_set_opacity (CLUTTER_ACTOR (priv->frame), 255 * factor);
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}
+
+/* Moves the pixbuf texture on the z axis when it is active*/
+static void
+fluttr_photo_act_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+        FluttrPhotoPrivate *priv;
+       gfloat factor;
+       guint size = fluttr_photo_get_default_size ();
+       
+       g_return_if_fail (FLUTTR_IS_PHOTO (data));
+        priv = FLUTTR_PHOTO_GET_PRIVATE(data);
+
+       factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->active)
+               priv->scale = 1 + (ACT_SCALE * factor);
+       else
+               priv->scale = (1 +ACT_SCALE)- (ACT_SCALE *factor);
+       
+       
+       size = size * priv->scale;
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));
+}
+
+static void
+fluttr_photo_opt_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+        FluttrPhotoPrivate *priv;
+       gfloat factor;
+       guint width = fluttr_photo_get_default_width ();
+       gfloat sw;
+       
+        g_return_if_fail (FLUTTR_IS_PHOTO (data));
+        priv = FLUTTR_PHOTO_GET_PRIVATE(data);
+       
+       factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->opt_in) {
+               sw = (CLUTTER_STAGE_WIDTH ()/(float)width) * factor;
+               if (sw > priv->scale)
+                       priv->scale = sw;
+               clutter_actor_set_opacity (priv->texture, 255-(255*factor));
+               clutter_actor_set_opacity (priv->frame, 255-(255*factor));
+               
+       //      clutter_actor_rotate_y (CLUTTER_ACTOR (data), 180 *factor,
+       //                              width /2, 0);
+       } else {
+               sw = (CLUTTER_STAGE_WIDTH ()/(float)width) * (1.0 - factor);
+               if (sw >ACT_SCALE + 1.0)
+                       priv->scale = sw;
+               clutter_actor_set_opacity (priv->texture, (255*factor));
+               clutter_actor_set_opacity (priv->frame, (255*factor));
+               
+             //clutter_actor_rotate_y (CLUTTER_ACTOR (data), 180+ (180*factor),
+               //                      width /2, 0);                   
+       }
+       
+       if (factor > 0.9)
+               g_signal_emit (data, _photo_signals[ACTIVATED], 0, "");
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}
+
+
+static gboolean                 
+on_thread_abort_idle (FluttrPhoto *photo)
+{
+        g_return_val_if_fail (FLUTTR_IS_PHOTO (photo), FALSE);
+
+       g_signal_emit (photo, _photo_signals[ERROR], 0, "Aborted");     
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_ok_idle (FluttrPhoto *photo)
+{
+        FluttrPhotoPrivate *priv;
+        GdkPixbuf *pixbuf;
+        gchar *filename, *name;
+        
+        g_return_val_if_fail (FLUTTR_IS_PHOTO (photo), FALSE);
+        priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+        
+        if (priv->pixbuf)
+               return FALSE;
+        
+        /* Get pixbuf from worker */
+        g_object_get (G_OBJECT (priv->worker), "pixbuf", &pixbuf, NULL);
+        priv->pixbuf = pixbuf;  
+        g_object_ref (G_OBJECT (priv->pixbuf));  
+        
+        /* If we are not visible, we don't start the time line */
+        if (!priv->visible)
+                return FALSE;    
+        
+       if (!clutter_timeline_is_playing (priv->swap_time))
+               clutter_timeline_start (priv->swap_time);
+
+       g_signal_emit (photo, _photo_signals[LOADED], 0, "");
+       
+       /* Save the pixbuf */
+       GError *err = NULL;
+       name = g_strdup_printf ("%d/%s.png", 
+                               fluttr_photo_get_default_width (),
+                               priv->photoid);
+       filename = g_build_filename (g_get_home_dir (),
+                                    ".fluttr-thumbs",
+                                    name,
+                                    NULL);
+       gdk_pixbuf_save (pixbuf, filename, "png", &err, NULL);
+       
+       if (err)
+       {
+               g_free (filename);
+               filename = g_build_filename (g_get_home_dir (),
+                                            ".fluttr-thumbs",
+                                            NULL);
+               g_mkdir_with_parents (filename, 0700);
+       }
+
+       g_free (filename);
+       g_free (name);
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_error_idle (FluttrPhoto *photo)
+{
+        FluttrPhotoPrivate *priv;
+        gchar *error = NULL;
+        
+        g_return_val_if_fail (FLUTTR_IS_PHOTO (photo), FALSE);
+        priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+        
+        /* Get the actual error */
+        g_object_get (G_OBJECT (priv->worker), "error", &error, NULL);
+        if (error == NULL) {
+                error = g_strdup_printf (gettext ("Internal error. "));
+                g_warning ("No error set on worker!");
+        }
+       g_signal_emit (photo, _photo_signals[ERROR], 0, error);
+
+        g_free (error);
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_msg_change_idle (FluttrPhoto *photo)
+{
+        FluttrPhotoPrivate *priv;
+        gchar *msg = NULL;
+        
+        g_return_val_if_fail (FLUTTR_IS_PHOTO (photo), FALSE);
+        priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+        
+        /* Get the new message */
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                ;//g_print ("%s", msg);
+        }
+        
+        g_free (msg);
+
+        return FALSE;
+}
+
+/* Check if we have already download the pixbuf */
+static GdkPixbuf*
+_check_cache (FluttrPhoto *photo)
+{
+        FluttrPhotoPrivate *priv;
+        GdkPixbuf *pixbuf = NULL;
+       
+       g_return_val_if_fail (FLUTTR_IS_PHOTO (photo), NULL);
+        priv = FLUTTR_PHOTO_GET_PRIVATE(photo);                gchar *name, *filename;
+       
+       name = g_strdup_printf ("%d/%s.png", 
+                               fluttr_photo_get_default_width (),
+                               priv->photoid);
+       filename = g_build_filename (g_get_home_dir (),
+                                    ".fluttr-thumbs",
+                                    name,
+                                    NULL);
+       pixbuf =  gdk_pixbuf_new_from_file (filename, NULL);
+       
+       g_free (filename);
+       g_free (name);
+       
+       return pixbuf;
+}
+
+/* Start the pixbuf worker */
+void
+_fluttr_photo_fetch_pixbuf (FluttrPhoto *photo, guint width, guint height)
+{
+        FluttrPhotoPrivate *priv;
+        FluttrSettings *settings = fluttr_settings_get_default ();
+       NFlickWorker *worker;
+        NFlickWorkerStatus status;
+              
+        gchar *token = NULL;
+       
+        g_return_if_fail (FLUTTR_IS_PHOTO (photo));
+        priv = FLUTTR_PHOTO_GET_PRIVATE(photo);        
+        
+        if (priv->pixbuf != NULL) {
+               /*g_warning ("Pixbuf already set");*/
+               return;
+       }
+       
+       priv->pixbuf = _check_cache (photo);
+       if (priv->pixbuf) {
+               if (!clutter_timeline_is_playing (priv->swap_time))
+                       clutter_timeline_start (priv->swap_time);
+
+               g_signal_emit (photo, _photo_signals[LOADED], 0, "");   
+               return; 
+       }
+       
+       if (priv->worker != NULL) {
+               /*g_warning ("Fetching has already started");*/
+               return;
+       }       
+       g_object_get (G_OBJECT (settings), "token", &token, NULL);
+       
+       worker = (NFlickWorker *)nflick_show_worker_new (priv->photoid, 
+                                                              width, 
+                                                              height, 
+                                                              token);
+        /* Check if the worker is in the right state */
+        g_object_get (G_OBJECT (worker), "status", &status, NULL);
+        
+        if (status != NFLICK_WORKER_STATUS_IDLE) {
+                g_warning ("Bad worker status"); 
+                return;
+        }
+        
+        g_object_ref (worker);
+        priv->worker = worker;
+        
+        /* Get the initial message */
+        gchar *msg = NULL;
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                /* FIXME Escape markup */
+               //g_print ("%s", msg);
+        }
+        
+        /* Set the callback functions */
+        nflick_worker_set_custom_data (worker, photo);
+        nflick_worker_set_aborted_idle (worker, 
+                                 (NFlickWorkerIdleFunc) on_thread_abort_idle);
+                                          
+        nflick_worker_set_error_idle (worker, 
+                                  (NFlickWorkerIdleFunc) on_thread_error_idle);
+        
+        nflick_worker_set_ok_idle (worker, 
+                                     (NFlickWorkerIdleFunc) on_thread_ok_idle);
+        
+        nflick_worker_set_msg_change_idle (worker, 
+                             (NFlickWorkerIdleFunc) on_thread_msg_change_idle);
+                                        
+        nflick_worker_start (priv->worker);
+        
+        /* Free */
+        g_free (msg);
+}
+
+void
+fluttr_photo_fetch_pixbuf (FluttrPhoto *photo)
+{
+        guint size = fluttr_photo_get_default_size ();
+       size *= 2.0;
+
+       _fluttr_photo_fetch_pixbuf (photo, size, size);
+}
+
+
+/* GObject Stuff */
+
+static void
+fluttr_photo_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+       FluttrPhotoPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_PHOTO (object));
+       priv = FLUTTR_PHOTO_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_ID:
+                       if (priv->photoid != NULL)
+                               g_free (priv->photoid);
+                       priv->photoid = g_strdup (g_value_get_string (value));
+                       break;
+               case PROP_NAME:
+                       if (priv->name != NULL)
+                               g_free (priv->name);
+                       priv->name =g_strdup (g_value_get_string (value));
+                       break;  
+               case PROP_PIXBUF:
+                       if (priv->pixbuf != NULL)
+                               g_object_unref (G_OBJECT (priv->pixbuf));
+                       priv->pixbuf = g_value_get_object (value);
+                       clutter_timeline_start (priv->swap_time);
+                       break;
+               
+               case PROP_SET:
+                       priv->set = g_value_get_object (value);
+                       break;          
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_photo_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrPhotoPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_PHOTO (object));
+       priv = FLUTTR_PHOTO_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_ID:
+                       g_value_set_string (value, priv->photoid);
+                       break;
+               
+               case PROP_NAME:
+                       g_value_set_string (value, priv->name);
+                       
+               case PROP_PIXBUF:
+                       g_value_set_object (value, G_OBJECT (priv->pixbuf));
+                       break;
+                       
+               case PROP_SET:
+                       g_value_set_object (value, G_OBJECT (priv->set));
+                       break;
+                       
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void
+fluttr_photo_paint (ClutterActor *actor)
+{
+       FluttrPhoto        *photo;
+       FluttrPhotoPrivate *priv;
+
+       photo = FLUTTR_PHOTO(actor);
+
+       priv = FLUTTR_PHOTO_GET_PRIVATE(photo);
+       
+        glPushMatrix();
+       
+       gfloat x, y;
+       guint width = fluttr_photo_get_default_width ();
+       guint height = fluttr_photo_get_default_height ();
+       
+       x = (priv->scale * width) - (width);
+       x /= 2;
+       x *= -1;
+       
+       y = (priv->scale * height) - (height);
+       y /= 2;
+       y *= -1;        
+       
+       glTranslatef (x, y, 0);
+       glScalef (priv->scale, priv->scale, 1);
+       
+       gint i;
+       gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor)); 
+       for (i = 0; i < len; i++) {
+               ClutterActor* child;
+
+               child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+               if (child) {
+                       clutter_actor_paint (child);
+               }
+       }
+
+       glPopMatrix();
+}
+
+static void 
+fluttr_photo_dispose (GObject *object)
+{
+       FluttrPhoto         *self = FLUTTR_PHOTO(object);
+       FluttrPhotoPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_photo_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_photo_finalize (GObject *object)
+{
+       FluttrPhotoPrivate *priv;
+
+       priv = FLUTTR_PHOTO_GET_PRIVATE(object);
+       
+       G_OBJECT_CLASS (fluttr_photo_parent_class)->finalize (object);
+}
+
+static void
+fluttr_photo_class_init (FluttrPhotoClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+       ClutterActorClass   *parent_class; 
+
+       parent_class = CLUTTER_ACTOR_CLASS (fluttr_photo_parent_class);
+
+       actor_class->paint           = fluttr_photo_paint;
+       
+       gobject_class->finalize     = fluttr_photo_finalize;
+       gobject_class->dispose      = fluttr_photo_dispose;
+       gobject_class->get_property = fluttr_photo_get_property;
+       gobject_class->set_property = fluttr_photo_set_property;        
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrPhotoPrivate));
+       
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_ID,
+                g_param_spec_string ("photoid",
+                "PhotoID",
+                "The Flickr photo id",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_NAME,
+                g_param_spec_string ("name",
+                "Name",
+                "The Flickr photo name",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                       
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_PIXBUF,
+                g_param_spec_object ("pixbuf",
+                "Pixbuf",
+                "The GdkPixbuf of the photo",
+                GDK_TYPE_PIXBUF,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));         
+
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_SET,
+                g_param_spec_object ("set",
+                "Set",
+                "The Flickr set",
+                NFLICK_TYPE_PHOTO_SET,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                                          
+
+       /* Class signals */
+       _photo_signals[LOADED] =
+               g_signal_new ("pixbuf-loaded",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrPhotoClass, pixbuf_loaded),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1, G_TYPE_STRING);
+                            
+       _photo_signals[ERROR] =
+               g_signal_new ("error",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrPhotoClass, fetch_error),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1,G_TYPE_STRING);
+                            
+       _photo_signals[ACTIVATED] =
+               g_signal_new ("activated",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrPhotoClass, activated),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1,G_TYPE_STRING);
+
+}
+
+static void
+fluttr_photo_init (FluttrPhoto *self)
+{
+       FluttrPhotoPrivate *priv;
+       ClutterColor rect_col   = { 0xff, 0xff, 0xff, 0xff };
+       ClutterColor bg_col = {0x00, 0x00, 0x00, 0xff};
+       ClutterActor *bg;
+       gint width = fluttr_photo_get_default_width ();
+       gint height = fluttr_photo_get_default_height ();
+               
+       priv = FLUTTR_PHOTO_GET_PRIVATE (self);
+       
+       priv->pixbuf = NULL;
+       priv->scale = 1.0;
+       priv->visible = TRUE;
+       
+       /* The black frame */
+       bg = clutter_rectangle_new_with_color (&bg_col);
+       priv->bg = bg;
+       clutter_group_add (CLUTTER_GROUP (self), bg);   
+       clutter_actor_set_size (bg, width, height);
+       clutter_actor_set_position (bg, 0, 0);
+       clutter_actor_show (bg);
+       
+       /* The white frame */
+       priv->frame = clutter_rectangle_new_with_color (&rect_col);
+       clutter_group_add (CLUTTER_GROUP (self), priv->frame);  
+       clutter_actor_set_size (priv->frame, width, height);
+       clutter_actor_set_position (priv->frame, 0, 0);
+
+       /*Load the default pixbuf */
+       if (default_pic == NULL) {
+               default_pic = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR \
+                                                       "/picture.svg",
+                                                       width -(FRAME*2),
+                                                       height -(FRAME*2),
+                                                       FALSE,
+                                                       NULL);
+       }
+       /* The picture clip region */
+       priv->clip = clutter_group_new ();
+       clutter_group_add (CLUTTER_GROUP (self),priv->clip);
+       clutter_actor_set_size (priv->clip, 
+                               width -(FRAME*2), 
+                               height -(FRAME*2));
+       clutter_actor_set_position (priv->clip, 0, 0);
+       clutter_actor_set_clip (priv->clip,
+                               FRAME, FRAME,
+                               width -(FRAME*2),
+                               height -(FRAME*2));
+       
+       /* The pixture texture */
+       priv->texture = clutter_texture_new_from_pixbuf (default_pic);
+       clutter_group_add (CLUTTER_GROUP (priv->clip), priv->texture);
+       clutter_actor_set_size (priv->texture, 
+                               width -(FRAME*2), 
+                               height -(FRAME*2));
+       clutter_actor_set_position (priv->texture, FRAME, FRAME);
+       
+       /* Set up options */
+       priv->options = clutter_group_new ();
+       clutter_group_add (CLUTTER_GROUP (self), priv->options);
+       clutter_actor_set_size (priv->options, width, height);
+       clutter_actor_set_position (priv->options, 0, 0);
+       clutter_actor_set_rotation (priv->options,
+                                   CLUTTER_X_AXIS, 90, 0, height, 0);
+               
+       /* Setup the transformation */
+       priv->new_x = priv->new_y = priv->new_scale = 0;
+       priv->trans_time = clutter_timeline_new (40, 40);
+       priv->trans_alpha = clutter_alpha_new_full (priv->trans_time,
+                                             alpha_linear_inc_func,
+                                             NULL, NULL);
+       priv->trans_behave = fluttr_behave_new (priv->trans_alpha,
+                                         fluttr_photo_trans_alpha_func,
+                                         (gpointer)self);      
+                                         
+       /* Setup the pixbuf swap */
+       priv->pixbuf = NULL;
+       priv->swap_time = clutter_timeline_new (40, 40);
+       priv->swap_alpha = clutter_alpha_new_full (priv->swap_time,
+                                             alpha_linear_inc_func,
+                                             NULL, NULL);
+       priv->swap_behave = fluttr_behave_new (priv->swap_alpha,
+                                         fluttr_photo_swap_alpha_func,
+                                         (gpointer)self);
+                                         
+       /* Setup the activating line */
+       priv->act_time = clutter_timeline_new (60, 240);
+       priv->act_alpha = clutter_alpha_new_full (priv->act_time,
+                                                  alpha_linear_inc_func,
+                                                  NULL, NULL);
+       priv->act_behave = fluttr_behave_new (priv->act_alpha,
+                                              fluttr_photo_act_alpha_func,
+                                              (gpointer)self);
+                                              
+       /* Setup the option line */
+       priv->opt_time = clutter_timeline_new (60, 80);
+       priv->opt_alpha = clutter_alpha_new_full (priv->opt_time,
+                                                  alpha_linear_inc_func,
+                                                  NULL, NULL);
+       priv->opt_behave = fluttr_behave_new (priv->opt_alpha,
+                                              fluttr_photo_opt_alpha_func,
+                                              (gpointer)self);
+
+       clutter_actor_lower_bottom (bg);
+        clutter_actor_show_all (priv->clip);
+        clutter_actor_show_all (priv->options);
+        clutter_actor_show_all (CLUTTER_ACTOR (self));
+}
+
+ClutterActor*
+fluttr_photo_new (void)
+{
+       ClutterGroup         *photo;
+
+       photo = g_object_new (FLUTTR_TYPE_PHOTO, 
+                            NULL);
+       return CLUTTER_ACTOR (photo);
+}
+
diff --git a/attic/fluttr/src/fluttr-photo.h b/attic/fluttr/src/fluttr-photo.h
new file mode 100644 (file)
index 0000000..c952f69
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libnflick/nflick.h>
+
+#ifndef _HAVE_FLUTTR_PHOTO_H
+#define _HAVE_FLUTTR_PHOTO_H
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_PHOTO fluttr_photo_get_type()
+
+#define FLUTTR_PHOTO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_PHOTO, \
+       FluttrPhoto))
+
+#define FLUTTR_PHOTO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_PHOTO, \
+       FluttrPhotoClass))
+
+#define FLUTTR_IS_PHOTO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_PHOTO))
+
+#define FLUTTR_IS_PHOTO_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_PHOTO))
+
+#define FLUTTR_PHOTO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_PHOTO, \
+       FluttrPhotoClass))
+
+typedef struct _FluttrPhoto FluttrPhoto;
+typedef struct _FluttrPhotoClass FluttrPhotoClass;
+typedef struct _FluttrPhotoPrivate FluttrPhotoPrivate;
+
+struct _FluttrPhoto
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrPhotoPrivate   *priv;
+};
+
+struct _FluttrPhotoClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*pixbuf_loaded) (FluttrPhoto *photo, gchar *null);
+       void (*fetch_error) (FluttrPhoto *photo, gchar *msg);
+       void (*activated) (FluttrPhoto *photo, gchar *msg);
+       void (*_fluttr_photo_4) (void);
+}; 
+
+GType fluttr_photo_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_photo_new (void);
+
+void
+fluttr_photo_fetch_pixbuf (FluttrPhoto *photo);
+
+void
+fluttr_photo_update_position (FluttrPhoto *photo, gint x, gint y);
+
+guint
+fluttr_photo_get_default_size (void);
+
+guint
+fluttr_photo_get_default_width (void);
+
+guint
+fluttr_photo_get_default_height (void);
+
+void
+fluttr_photo_show_options (FluttrPhoto *photo, gboolean show);
+
+void
+fluttr_photo_set_active (FluttrPhoto *photo, gboolean active);
+
+void
+fluttr_photo_set_visible (FluttrPhoto *photo, gboolean visible);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-set-view.c b/attic/fluttr/src/fluttr-set-view.c
new file mode 100644 (file)
index 0000000..6d0f849
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include <GL/gl.h>
+
+#include "fluttr-set-view.h"
+
+G_DEFINE_TYPE (FluttrSetView, fluttr_set_view, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_SET_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_SET_VIEW, \
+       FluttrSetViewPrivate))
+       
+struct _FluttrSetViewPrivate
+{
+       GList                   *sets;
+       gint                     active_set;
+       ClutterActor            *active_actor;
+       gint                     active_col;
+};
+
+enum
+{
+       PROP_0,
+       PROP_LIBRARY
+};
+
+#define N_COLS 3
+
+static ClutterGroupClass       *parent_class = NULL;
+
+FluttrSet*
+fluttr_set_view_get_active (FluttrSetView *set_view)
+{
+       FluttrSetViewPrivate *priv;
+               
+       g_return_val_if_fail (FLUTTR_IS_SET_VIEW (set_view), NULL);
+       priv = FLUTTR_SET_VIEW_GET_PRIVATE(set_view);
+       
+       return FLUTTR_SET (priv->active_actor);
+}
+
+void 
+fluttr_set_view_advance (FluttrSetView *set_view, gint n)
+{
+       FluttrSetViewPrivate *priv;
+       gint len;
+       gint i = 0;
+       ClutterActor *set = NULL;
+       guint width = fluttr_set_get_default_width ();
+       guint height = fluttr_set_get_default_height ();
+       gint x1;
+       gint active_row = 0;
+       gint offset = height/2;
+       gint padding = width/2;
+               
+       g_return_if_fail (FLUTTR_IS_SET_VIEW (set_view));
+       priv = FLUTTR_SET_VIEW_GET_PRIVATE(set_view);
+
+       len = clutter_group_get_n_children (CLUTTER_GROUP (set_view));
+       
+       /* Make sure we are within the bounds of the number of albums */
+       priv->active_set+= n;
+       if (priv->active_set < 0) {
+               priv->active_set  = 0;
+       } else if (priv->active_set > len-1) {
+               priv->active_set = len -1;
+       } else
+               ;
+       /* Find the magic row */        
+       active_row = 0;
+       gint row = 0;
+       gint col = 0;
+       
+       for (i = 0; i < len; i++) {
+               if (i == priv->active_set) {
+                       active_row = row;
+                       break;
+               }
+               col++;
+               if (col > (N_COLS-1)) {
+                       col = 0;
+                       row++;
+               }
+       }
+       
+       /* Figure out the base x value */
+       x1 = ((width) * N_COLS ) + (padding*(N_COLS-1));
+       x1 = (CLUTTER_STAGE_WIDTH ()/2)-(x1/2);
+       
+       /* Iterate through actors, calculating their new x positions, and make
+          sure they are on the right place (left, right or center) */
+       col = 0;
+       row = 0;
+
+       offset = -1 * ((height) + padding) * active_row;
+       offset += (CLUTTER_STAGE_HEIGHT () /2) - (height/2);
+       
+       for (i = 0; i < len; i++) {
+               set = clutter_group_get_nth_child (CLUTTER_GROUP (set_view), i);
+                
+               gint x = x1 + (col * (width + padding));
+               gint y = offset;
+               fluttr_set_update_position (FLUTTR_SET (set), x, y);
+               
+               col++;
+               if (col > (N_COLS-1)) {
+                       col = 0;
+                       row++;
+                       offset += height + padding;
+               }
+               if (i == priv->active_set) {
+                       priv->active_actor = set;       
+                       fluttr_set_set_active (FLUTTR_SET (set), TRUE);
+               } else
+                       fluttr_set_set_active (FLUTTR_SET (set), FALSE);        
+                       
+               /* Update the position of the ring */
+       }
+}
+
+/* We make all the 'viewable' sets fall down, leaving just the main one */
+void
+fluttr_set_view_activate (FluttrSetView *set_view)
+{
+       ;
+}
+
+void
+fluttr_set_view_advance_row (FluttrSetView *set_view, gint n)
+{
+       fluttr_set_view_advance (set_view, (N_COLS * n));
+}
+
+void
+fluttr_set_view_advance_col (FluttrSetView *set_view, gint n)
+{
+       fluttr_set_view_advance (set_view, n);
+}
+
+void
+fluttr_set_view_add_set (FluttrSetView *set_view, FluttrSet *set)
+{
+       gint x = CLUTTER_STAGE_WIDTH () /2;
+       gint y = CLUTTER_STAGE_HEIGHT ()/2;
+       g_return_if_fail (FLUTTR_IS_SET_VIEW (set_view));
+       
+       
+       clutter_group_add (CLUTTER_GROUP (set_view), CLUTTER_ACTOR (set));
+       clutter_actor_set_position (CLUTTER_ACTOR (set), x, y);
+       clutter_actor_show_all (CLUTTER_ACTOR (set));
+}
+
+/* GObject Stuff */
+
+static void
+fluttr_set_view_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+       FluttrSetViewPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_SET_VIEW (object));
+       priv = FLUTTR_SET_VIEW_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_set_view_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrSetViewPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_SET_VIEW (object));
+       priv = FLUTTR_SET_VIEW_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void
+fluttr_set_view_paint (ClutterActor *actor)
+{
+       FluttrSetView        *set;
+       FluttrSetViewPrivate *priv;
+
+       set = FLUTTR_SET_VIEW(actor);
+
+       priv = FLUTTR_SET_VIEW_GET_PRIVATE(set);
+
+       glPushMatrix();
+       
+       gint i;
+       gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor)); 
+       for (i = 0; i < len; i++) {
+               ClutterActor* child;
+
+               child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+               if (child) {
+                       clutter_actor_paint (child);
+               }
+       }
+
+       glPopMatrix();
+}
+
+static void 
+fluttr_set_view_dispose (GObject *object)
+{
+       FluttrSetView         *self = FLUTTR_SET_VIEW(object);
+       FluttrSetViewPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void 
+fluttr_set_view_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+fluttr_set_view_class_init (FluttrSetViewClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+       
+       parent_class = CLUTTER_GROUP_CLASS (klass);
+
+       actor_class->paint           = fluttr_set_view_paint;
+       
+       gobject_class->finalize     = fluttr_set_view_finalize;
+       gobject_class->dispose      = fluttr_set_view_dispose;
+       gobject_class->get_property = fluttr_set_view_get_property;
+       gobject_class->set_property = fluttr_set_view_set_property;     
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrSetViewPrivate));
+               
+}
+
+static void
+fluttr_set_view_init (FluttrSetView *self)
+{
+       FluttrSetViewPrivate *priv;
+       priv = FLUTTR_SET_VIEW_GET_PRIVATE (self);
+       
+       priv->active_set = 0;
+       priv->active_col = 0;
+       
+}
+
+ClutterActor*
+fluttr_set_view_new (void)
+{
+       ClutterGroup         *set_view;
+
+       set_view = g_object_new (FLUTTR_TYPE_SET_VIEW, 
+                                 NULL);
+
+       return CLUTTER_ACTOR (set_view);
+}
+
diff --git a/attic/fluttr/src/fluttr-set-view.h b/attic/fluttr/src/fluttr-set-view.h
new file mode 100644 (file)
index 0000000..a316bfe
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-`hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libnflick/nflick.h>
+
+#include "fluttr-set.h"
+
+
+#ifndef _HAVE_FLUTTR_SET_VIEW_H
+#define _HAVE_FLUTTR_SET_VIEW_H
+
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_SET_VIEW fluttr_set_view_get_type()
+
+#define FLUTTR_SET_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_SET_VIEW, \
+       FluttrSetView))
+
+#define FLUTTR_SET_VIEWCLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_SET_VIEW, \
+       FluttrSetViewClass))
+
+#define FLUTTR_IS_SET_VIEW(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_SET_VIEW))
+
+#define FLUTTR_IS_SET_VIEW_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_SET_VIEW))
+
+#define FLUTTR_SET_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_SET_VIEW, \
+       FluttrSetViewClass))
+
+typedef struct _FluttrSetView FluttrSetView;
+typedef struct _FluttrSetViewClass FluttrSetViewClass;
+typedef struct _FluttrSetViewPrivate FluttrSetViewPrivate;
+
+struct _FluttrSetView
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrSetViewPrivate   *priv;
+};
+
+struct _FluttrSetViewClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*_fluttr_set_view_1) (void);
+       void (*_fluttr_set_view_2) (void);
+       void (*_fluttr_set_view_3) (void);
+       void (*_fluttr_set_view_4) (void);
+}; 
+
+GType fluttr_set_view_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_set_view_new (void);
+
+void
+fluttr_set_view_add_set (FluttrSetView *set_view, FluttrSet *set);
+
+FluttrSet*
+fluttr_set_view_get_active (FluttrSetView *set_view);
+
+void
+fluttr_set_view_activate (FluttrSetView *set_view);
+
+void 
+fluttr_set_view_advance (FluttrSetView *set_view, gint n);
+
+void
+fluttr_set_view_advance_row (FluttrSetView *set_view, gint n);
+
+void
+fluttr_set_view_advance_col (FluttrSetView *set_view, gint n);
+
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-set.c b/attic/fluttr/src/fluttr-set.c
new file mode 100644 (file)
index 0000000..f54b1b4
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include "fluttr-set.h"
+
+#include "fluttr-behave.h"
+#include "fluttr-settings.h"
+#include "fluttr-photo.h"
+
+
+G_DEFINE_TYPE (FluttrSet, fluttr_set, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_SET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_SET, \
+       FluttrSetPrivate))
+       
+#define FONT "DejaVu Sans Book"
+#define FRAME 2
+#define X_ANGLE 90
+
+#define ACT_SCALE 0.3
+
+struct _FluttrSetPrivate
+{
+       gchar                   *setid;
+       gchar                   *name;
+       NFlickPhotoSet          *set;
+       GList                   *photos;
+       
+       /* The all-important pixbuf fetching variables */
+       NFlickWorker            *worker;
+
+       
+       /* The actual actors */
+       ClutterActor            *text;
+       ClutterActor            *photo1;
+       ClutterActor            *photo2;
+       ClutterActor            *photo3;
+       
+       /* Transformation code */
+       gint                     new_x;
+       gint                     new_y;
+       gfloat                   new_scale;
+       ClutterTimeline         *trans_time;
+       ClutterAlpha            *trans_alpha;
+       ClutterBehaviour        *trans_behave;
+               
+       /* Activate animation */
+       gboolean                 active;
+       gfloat                   scale;
+       ClutterTimeline         *act_time;
+       ClutterAlpha            *act_alpha;
+       ClutterBehaviour        *act_behave;    
+};
+
+enum
+{
+       PROP_0,
+       PROP_ID,
+       PROP_NAME,
+       PROP_SET
+};
+
+void
+_fluttr_set_fetch_pixbuf (FluttrSet *set, guint width, guint height);
+
+/* Will return the default size of the FluttrSet square for the current stage */
+guint
+fluttr_set_get_default_size (void)
+{
+       guint width = CLUTTER_STAGE_WIDTH ();
+       guint height = CLUTTER_STAGE_HEIGHT ();
+       
+       if (width > height)
+               return height/3;
+       else
+               return width /3;
+}
+
+guint
+fluttr_set_get_default_width (void)
+{
+       return fluttr_set_get_default_size ();
+}
+
+guint
+fluttr_set_get_default_height (void)
+{
+       return fluttr_set_get_default_width () * 1.4;
+}
+
+/* If active, scale the set, if not, scale it down */
+void
+fluttr_set_set_active (FluttrSet *set, gboolean active)
+{
+       FluttrSetPrivate *priv;
+       ClutterColor act   = { 0x00, 0x55, 0xff, 0xff };
+       ClutterColor inact   = { 0xff, 0xff, 0xff, 0xff };
+       
+       g_return_if_fail (FLUTTR_IS_SET (set));
+       priv = FLUTTR_SET_GET_PRIVATE(set);
+       
+       if (priv->active == active)
+               return;
+       
+       priv->active = active;
+       
+       if (active)
+               clutter_label_set_color (CLUTTER_LABEL (priv->text), &act);
+       else
+               clutter_label_set_color (CLUTTER_LABEL (priv->text), &inact);
+}
+
+
+/* Set the new x and y position of the actor, and start (or rewind) the main
+   timeline */
+void
+fluttr_set_update_position (FluttrSet *set, gint x, gint y)
+{
+        FluttrSetPrivate *priv;
+        
+        g_return_if_fail (FLUTTR_IS_SET (set));
+        priv = FLUTTR_SET_GET_PRIVATE(set);
+        
+        if ((priv->new_x == x) && (priv->new_y == y)) {
+               return;
+        }
+        priv->new_x = x;
+        priv->new_y = y;
+        /*clutter_actor_set_position (set, x, y);
+        
+        */
+        if (clutter_timeline_is_playing (priv->trans_time))
+               clutter_timeline_rewind (priv->trans_time);
+        else   
+               clutter_timeline_start (priv->trans_time);      
+        
+}
+
+/* Allows smooth transforms (position & size) on th widget...looks goooood*/
+static void
+fluttr_set_trans_alpha_func (ClutterBehaviour *behave,
+                              guint             alpha_value,
+                              gpointer          data)
+{
+        FluttrSetPrivate *priv;
+        gfloat factor;
+        gint old_x, old_y;
+        gint x, y;
+        
+        
+        g_return_if_fail (FLUTTR_IS_SET (data));
+        priv = FLUTTR_SET_GET_PRIVATE(data);
+        
+        /* Calculate the factor */
+        factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+        
+        /* Load up the orignal values */
+        old_x = clutter_actor_get_x (CLUTTER_ACTOR (data));
+        old_y = clutter_actor_get_y (CLUTTER_ACTOR (data));
+        
+        /* We first calculate the new x pos */
+        if (old_x == priv->new_x) {
+               x = 0;
+               //g_print ("Same x %d\n", x);
+        } else if (old_x < priv->new_x) {
+               /* We're moving to the positive */
+               if (old_x < 0)
+                       x = ((-1*old_x)+priv->new_x) * factor;
+               else
+                       x = (priv->new_x - old_x) * factor;
+        } else {
+               /* We're moving to the left */
+               if (priv->new_x < 0) 
+                       x = ((-1*priv->new_x)+old_x) * -1 * factor;
+               else
+                       x = (old_x - priv->new_x) * -1 * factor;
+        }
+        
+        /* Then the new y pos */
+        if (old_y == priv->new_y) {
+               y = 0;
+               //g_print ("Same y %d %d\n", y, priv->new_y);
+        
+        } else if (old_y < priv->new_y) {
+               /* We're moving to the bottom */
+               if (old_y < 0)
+                       y = ((-1*old_y)+priv->new_y) * factor;
+               else
+                       y = (priv->new_y - old_y) * factor;
+        } else {
+               /* We're moving to the top */
+               if (priv->new_y < 0) 
+                       y = ((-1*priv->new_y)+old_y) * -1 * factor;
+               else
+                       y = (old_y - priv->new_y) * -1 * factor;
+        }
+               
+        x += old_x;
+        y += old_y;    
+               
+        clutter_actor_set_position (CLUTTER_ACTOR (data), x, y);
+        /*g_print ("%s %d %d\n", priv->setid, x, y);*/
+        
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));        
+}
+
+
+/* Moves the pixbuf texture on the y axis when it is active*/
+static void
+fluttr_set_act_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+        FluttrSetPrivate *priv;
+       gfloat factor;
+       guint size = fluttr_set_get_default_size ();
+       
+       g_return_if_fail (FLUTTR_IS_SET (data));
+        priv = FLUTTR_SET_GET_PRIVATE(data);
+       
+       factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->active)
+               priv->scale = 1 + (ACT_SCALE * factor);
+       else
+               priv->scale = (1 +ACT_SCALE)- (ACT_SCALE *factor);
+       
+       
+       priv->scale = size * priv->scale;
+       
+       //clutter_actor_set_scale (CLUTTER_ACTOR (data), y
+       //clutter_actor_set_position (CLUTTER_ACTOR (data), x, y);
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));
+}
+
+static void
+_refresh_thumbs (FluttrSet *set, const gchar *id, const gchar *name)
+{
+       FluttrSetPrivate *priv;
+       gint i = 0;
+       ClutterActor *photo = NULL;
+       
+       g_return_if_fail (FLUTTR_IS_SET (set));
+       priv = FLUTTR_SET_GET_PRIVATE(set);
+       
+       i = g_list_length (priv->photos);
+       
+       if (i > 3)
+               return;
+       else if (i == 1)
+               photo = priv->photo1;
+       else if (i == 2)
+               photo = priv->photo2;
+       else
+               photo = priv->photo3;
+
+       if (photo) {
+               g_object_set (G_OBJECT (photo),
+                             "photoid", id,
+                             "name", name,
+                             NULL);
+               fluttr_photo_fetch_pixbuf (FLUTTR_PHOTO (photo));
+       }
+       
+       
+}
+
+void
+fluttr_set_append_photo (FluttrSet *set, const gchar *id, const gchar *name)
+{
+       FluttrPhotoData *data;
+       FluttrSetPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_SET (set));
+       priv = FLUTTR_SET_GET_PRIVATE(set);
+       
+       data = g_new0 (FluttrPhotoData, 1);     
+       
+       data->id = g_strdup (id);
+       data->name = g_strdup (id);
+       data->pixbuf = NULL;
+       
+       priv->photos = g_list_append (priv->photos, (gpointer)data);
+       
+       _refresh_thumbs (set, id, name);
+}
+
+GList*
+fluttr_set_get_photos (FluttrSet *set)
+{
+       FluttrSetPrivate *priv;
+
+       g_return_val_if_fail (FLUTTR_IS_SET (set), NULL);
+       priv = FLUTTR_SET_GET_PRIVATE(set);
+       
+       return priv->photos;
+}
+
+static void
+_update_text (FluttrSet *set)
+{
+       FluttrSetPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_SET (set));
+       priv = FLUTTR_SET_GET_PRIVATE(set);
+       
+       clutter_label_set_text (CLUTTER_LABEL (priv->text),
+                                               priv->name);
+       
+       g_object_set (G_OBJECT (priv->text),
+                     "x", (fluttr_set_get_default_width ()/2)
+                          - (clutter_actor_get_width (priv->text)/2),
+                     NULL);
+}
+
+/* GObject Stuff */
+
+static void
+fluttr_set_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+       FluttrSetPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_SET (object));
+       priv = FLUTTR_SET_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_ID:
+                       if (priv->setid != NULL)
+                               g_free (priv->setid);
+                       priv->setid = g_strdup (g_value_get_string (value));
+                       break;
+               case PROP_NAME:
+                       if (priv->name != NULL)
+                               g_free (priv->name);
+                       priv->name =g_strdup (g_value_get_string (value));
+                       _update_text (FLUTTR_SET (object));
+                       break;  
+               
+               case PROP_SET:
+                       priv->set = g_value_get_object (value);
+                       break;          
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_set_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrSetPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_SET (object));
+       priv = FLUTTR_SET_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_ID:
+                       g_value_set_string (value, priv->setid);
+                       break;
+               
+               case PROP_NAME:
+                       g_value_set_string (value, priv->name);
+                       
+               case PROP_SET:
+                       g_value_set_object (value, G_OBJECT (priv->set));
+                       break;
+                       
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void 
+fluttr_set_dispose (GObject *object)
+{
+       FluttrSet         *self = FLUTTR_SET(object);
+       FluttrSetPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_set_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_set_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_set_parent_class)->finalize (object);
+}
+
+static void
+fluttr_set_class_init (FluttrSetClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *parent_class; 
+
+       parent_class = CLUTTER_ACTOR_CLASS (fluttr_set_parent_class);
+
+       gobject_class->finalize     = fluttr_set_finalize;
+       gobject_class->dispose      = fluttr_set_dispose;
+       gobject_class->get_property = fluttr_set_get_property;
+       gobject_class->set_property = fluttr_set_set_property;  
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrSetPrivate));
+       
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_ID,
+                g_param_spec_string ("setid",
+                "SetID",
+                "The Flickr set id",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_NAME,
+                g_param_spec_string ("name",
+                "Name",
+                "The Flickr set name",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));         
+
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_SET,
+                g_param_spec_object ("set",
+                "Set",
+                "The Flickr set",
+                NFLICK_TYPE_PHOTO_SET,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));                                          
+  
+
+}
+
+static void
+fluttr_set_init (FluttrSet *self)
+{
+       FluttrSetPrivate *priv;
+       ClutterColor rect_col   = { 0xff, 0xff, 0xff, 0xff };
+       ClutterActor *label, *photo;
+       gint width = fluttr_set_get_default_width ();
+       gint height = fluttr_set_get_default_height ();
+       gchar *font;
+               
+       priv = FLUTTR_SET_GET_PRIVATE (self);
+       
+       /* Create the text label */
+       font = g_strdup_printf ("%s %d", FONT, height/12);
+       label = clutter_label_new_full (font, "Set name", &rect_col);
+       priv->text = label;
+       clutter_label_set_line_wrap (CLUTTER_LABEL (label), FALSE);
+       clutter_actor_set_size (label, width, height/12);
+       clutter_actor_set_position (label, 0, height-(height/12));
+       clutter_group_add (CLUTTER_GROUP (self), label);
+       
+       /* Set up the photos */
+       photo = fluttr_photo_new ();
+       priv->photo1 = photo;
+       clutter_actor_set_size (photo, fluttr_photo_get_default_width ()/2,
+                                      fluttr_photo_get_default_height ()/2);
+       clutter_group_add (CLUTTER_GROUP (self), photo);
+       clutter_actor_set_position (photo, 
+                               (width/2)-(clutter_actor_get_width(photo)/2),
+                               (height/2)-(clutter_actor_get_height(photo)/2));
+       clutter_actor_set_rotation (photo, CLUTTER_Z_AXIS, 30,
+                                   clutter_actor_get_width (photo) / 2,
+                                   clutter_actor_get_height (photo) / 2, 0);
+       
+       
+       photo = fluttr_photo_new ();
+       priv->photo2 = photo;
+       clutter_actor_set_size (photo, fluttr_photo_get_default_width ()/2,
+                                      fluttr_photo_get_default_height ()/2);
+       clutter_group_add (CLUTTER_GROUP (self), photo);
+       clutter_actor_set_position (photo, 
+                               (width/2)-(clutter_actor_get_width(photo)/2),
+                               (height/2)-(clutter_actor_get_height(photo)/2));
+       clutter_actor_set_rotation (photo, CLUTTER_Z_AXIS, -20,
+                                   clutter_actor_get_width (photo) / 2,
+                                   clutter_actor_get_height (photo) / 2, 0);
+       
+       
+       photo = fluttr_photo_new ();
+       priv->photo3 = photo;
+       clutter_actor_set_size (photo, fluttr_photo_get_default_width ()/2,
+                                      fluttr_photo_get_default_height ()/2);
+       clutter_group_add (CLUTTER_GROUP (self), photo);        
+       clutter_actor_set_position (photo, 
+                               (width/2)-(clutter_actor_get_width(photo)/2),
+                               (height/2)-(clutter_actor_get_height(photo)/2));
+       clutter_actor_set_rotation (photo, CLUTTER_Z_AXIS, 0,
+                                   clutter_actor_get_width (photo) / 2,
+                                   clutter_actor_get_height (photo) / 2, 0);
+       
+       
+       /* Setup the transformation */
+       priv->new_x = priv->new_y = priv->new_scale = 0;
+       priv->trans_time = clutter_timeline_new (40, 40);
+       priv->trans_alpha = clutter_alpha_new_full (priv->trans_time,
+                                             alpha_linear_inc_func,
+                                             NULL, NULL);
+       priv->trans_behave = fluttr_behave_new (priv->trans_alpha,
+                                         fluttr_set_trans_alpha_func,
+                                         (gpointer)self);              
+                                         
+       /* Setup the activating line */
+       priv->act_time = clutter_timeline_new (60, 240);
+       priv->act_alpha = clutter_alpha_new_full (priv->act_time,
+                                                  alpha_linear_inc_func,
+                                                  NULL, NULL);
+       priv->act_behave = fluttr_behave_new (priv->act_alpha,
+                                              fluttr_set_act_alpha_func,
+                                              (gpointer)self);
+
+}
+
+ClutterActor*
+fluttr_set_new (NFlickPhotoSet *photo_set)
+{
+       ClutterGroup         *set;
+       gchar                *setid;
+       gchar                *name;
+       
+       g_object_get (G_OBJECT (photo_set), 
+                     "id", &setid,
+                     "combotext", &name,
+                     NULL);
+
+       set = g_object_new (FLUTTR_TYPE_SET, 
+                           "setid", setid,
+                           "name", name,
+                           "set", photo_set,
+                            NULL);
+       return CLUTTER_ACTOR (set);
+}
+
diff --git a/attic/fluttr/src/fluttr-set.h b/attic/fluttr/src/fluttr-set.h
new file mode 100644 (file)
index 0000000..8171518
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libnflick/nflick.h>
+
+#ifndef _HAVE_FLUTTR_SET_H
+#define _HAVE_FLUTTR_SET_H
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_SET fluttr_set_get_type()
+
+#define FLUTTR_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_SET, \
+       FluttrSet))
+
+#define FLUTTR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_SET, \
+       FluttrSetClass))
+
+#define FLUTTR_IS_SET(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_SET))
+
+#define FLUTTR_IS_SET_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_SET))
+
+#define FLUTTR_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_SET, \
+       FluttrSetClass))
+
+typedef struct _FluttrSet FluttrSet;
+typedef struct _FluttrSetClass FluttrSetClass;
+typedef struct _FluttrSetPrivate FluttrSetPrivate;
+
+struct _FluttrSet
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrSetPrivate   *priv;
+};
+
+struct _FluttrSetClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*pixbuf_loaded) (FluttrSet *set, gchar *null);
+       void (*fetch_error) (FluttrSet *set, gchar *msg);
+       void (*_fluttr_set_3) (void);
+       void (*_fluttr_set_4) (void);
+}; 
+
+typedef struct {
+       gchar           *id;
+       gchar           *name;
+       GdkPixbuf       *pixbuf;
+
+} FluttrPhotoData;
+
+GType fluttr_set_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_set_new (NFlickPhotoSet *photo_set);
+
+void
+fluttr_set_append_photo (FluttrSet *set, const gchar *id, const gchar *name);
+
+GList*
+fluttr_set_get_photos (FluttrSet *set);
+
+void
+fluttr_set_fetch_pixbuf (FluttrSet *set);
+
+void
+fluttr_set_update_position (FluttrSet *set, gint x, gint y);
+
+guint
+fluttr_set_get_default_size (void);
+
+guint
+fluttr_set_get_default_width (void);
+
+guint
+fluttr_set_get_default_height (void);
+
+void
+fluttr_set_set_options (FluttrSet *set, ClutterActor *options);
+
+void
+fluttr_set_set_active (FluttrSet *set, gboolean active);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-settings.c b/attic/fluttr/src/fluttr-settings.c
new file mode 100644 (file)
index 0000000..75b6623
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include "fluttr-settings.h"
+
+
+G_DEFINE_TYPE (FluttrSettings, fluttr_settings, G_TYPE_OBJECT);
+
+#define FLUTTR_SETTINGS_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), FLUTTR_TYPE_SETTINGS, \
+       FluttrSettingsPrivate))
+       
+
+struct _FluttrSettingsPrivate
+{      
+       gchar           *username;
+       gchar           *fullname;
+       gchar           *token;
+       gchar           *usernsid;
+};
+
+enum
+{
+       PROP_0,
+       PROP_USERNAME,
+       PROP_FULLNAME,
+       PROP_TOKEN,
+       PROP_USERNSID
+};
+
+static FluttrSettings* global_settings = NULL;
+
+/* GObject Stuff */
+
+static void
+fluttr_settings_set_property (GObject      *object, 
+                                guint         prop_id,
+                                const GValue *value, 
+                                GParamSpec   *pspec)
+{
+       FluttrSettingsPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_SETTINGS (object));
+       priv = FLUTTR_SETTINGS_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_USERNAME:
+                       priv->username = g_strdup (g_value_get_string (value));
+                       break;
+               case PROP_FULLNAME:
+                       priv->fullname = g_strdup (g_value_get_string (value));
+                       break;  
+       
+               case PROP_TOKEN:
+                       priv->token = g_strdup (g_value_get_string (value));
+                       break;
+               
+               case PROP_USERNSID:
+                       priv->usernsid = g_strdup (g_value_get_string (value));
+                       break;  
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_settings_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrSettingsPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_SETTINGS (object));
+       priv = FLUTTR_SETTINGS_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_USERNAME:
+                       g_value_set_string (value, priv->username);
+                       break;
+               case PROP_FULLNAME:
+                       g_value_set_string (value, priv->fullname);
+                       break;  
+       
+               case PROP_TOKEN:
+                       g_value_set_string (value, priv->token);
+                       break;
+               
+               case PROP_USERNSID:
+                       g_value_set_string (value, priv->usernsid);
+                       break;                  
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void 
+fluttr_settings_dispose (GObject *object)
+{
+       FluttrSettings         *self = FLUTTR_SETTINGS(object);
+       FluttrSettingsPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_settings_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_settings_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_settings_parent_class)->finalize (object);
+}
+
+static void
+fluttr_settings_class_init (FluttrSettingsClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+
+       gobject_class->finalize     = fluttr_settings_finalize;
+       gobject_class->dispose      = fluttr_settings_dispose;
+       gobject_class->get_property = fluttr_settings_get_property;
+       gobject_class->set_property = fluttr_settings_set_property;     
+
+       g_type_class_add_private (gobject_class, 
+                                 sizeof (FluttrSettingsPrivate));
+               
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_USERNAME,
+                g_param_spec_string ("username",
+                "Username",
+                "The Flickr username",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_FULLNAME,
+                g_param_spec_string ("fullname",
+                "Fullname",
+                "The Flickr fullname",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                       
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_TOKEN,
+                g_param_spec_string ("token",
+                "Token",
+                "The Flickr token",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_USERNSID,
+                g_param_spec_string ("usernsid",
+                "Usernsid",
+                "The Flickr usernsid",
+                NULL,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+}
+
+static void
+fluttr_settings_init (FluttrSettings *self)
+{
+       FluttrSettingsPrivate *priv;
+       priv = FLUTTR_SETTINGS_GET_PRIVATE (self);
+}
+
+FluttrSettings*
+fluttr_settings_new (void)
+{
+       global_settings = (FluttrSettings*) g_object_new (FLUTTR_TYPE_SETTINGS, 
+                                           NULL);
+       
+       return global_settings;
+}
+
+FluttrSettings*
+fluttr_settings_get_default (void)
+{
+       if (global_settings == NULL)
+               global_settings = fluttr_settings_new ();
+       
+       return global_settings;
+}
+
diff --git a/attic/fluttr/src/fluttr-settings.h b/attic/fluttr/src/fluttr-settings.h
new file mode 100644 (file)
index 0000000..59604ab
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+
+#include <config.h>
+#include <glib-object.h>
+
+#ifndef _HAVE_FLUTTR_SETTINGS_H
+#define _HAVE_FLUTTR_SETTINGS_H
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_SETTINGS fluttr_settings_get_type()
+
+#define FLUTTR_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_SETTINGS, \
+       FluttrSettings))
+
+#define FLUTTR_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_SETTINGS, \
+       FluttrSettingsClass))
+
+#define FLUTTR_IS_SETTINGS(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_SETTINGS))
+
+#define FLUTTR_IS_SETTINGS_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_SETTINGS))
+
+#define FLUTTR_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_SETTINGS, \
+       FluttrSettingsClass))
+
+typedef struct _FluttrSettings FluttrSettings;
+typedef struct _FluttrSettingsClass FluttrSettingsClass;
+typedef struct _FluttrSettingsPrivate FluttrSettingsPrivate;
+
+struct _FluttrSettings
+{
+       GObject         parent;
+       
+       /* private */
+       FluttrSettingsPrivate   *priv;
+};
+
+struct _FluttrSettingsClass 
+{
+       /*< private >*/
+       GObjectClass parent_class;
+}; 
+
+GType                           
+fluttr_settings_get_type (void);
+
+FluttrSettings*
+fluttr_settings_new (void);
+
+FluttrSettings*
+fluttr_settings_get_default (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/attic/fluttr/src/fluttr-spinner.c b/attic/fluttr/src/fluttr-spinner.c
new file mode 100644 (file)
index 0000000..b31066c
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include "fluttr-spinner.h"
+
+#include "fluttr-behave.h"     
+
+G_DEFINE_TYPE (FluttrSpinner, fluttr_spinner, CLUTTER_TYPE_TEXTURE);
+
+#define FLUTTR_SPINNER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_SPINNER, \
+       FluttrSpinnerPrivate))
+       
+#define FONT "DejaVu Sans Book"
+
+static GdkPixbuf               *spinner_pixbuf = NULL;
+
+
+struct _FluttrSpinnerPrivate
+{
+       ClutterTimeline         *timeline;
+       ClutterAlpha            *alpha;
+       ClutterBehaviour        *behave;
+};
+
+
+/* Starts the timeline */
+void
+fluttr_spinner_spin (FluttrSpinner *spinner, gboolean spin)
+{
+       FluttrSpinnerPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_SPINNER (spinner));
+       priv = FLUTTR_SPINNER_GET_PRIVATE (spinner);
+       
+       if (spin)
+               clutter_timeline_start (priv->timeline);
+       else
+               clutter_timeline_stop (priv->timeline);
+}
+
+
+/* Spins the spinner texture on its y-axis */
+static void
+fluttr_spinner_alpha_func (ClutterBehaviour *behave,
+                          guint             alpha_value,
+                          gpointer          data)
+{
+       FluttrSpinnerPrivate *priv;
+       gfloat factor;
+       gfloat angle;
+       
+       g_return_if_fail (FLUTTR_IS_SPINNER (data));
+       priv = FLUTTR_SPINNER_GET_PRIVATE (data);
+       
+       /* First we calculate the factor (how far we are along the timeline
+          between 0-1
+       */
+       factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       /* Calculate the angle */
+       angle = factor * 360.0;
+       
+       /* Set the new angle */
+       clutter_actor_set_rotation (CLUTTER_ACTOR (data), CLUTTER_Z_AXIS, angle,
+                       clutter_actor_get_width (CLUTTER_ACTOR (data)) / 2,
+                       clutter_actor_get_height (CLUTTER_ACTOR (data)) / 2, 0);
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}              
+               
+/* GObject Stuff */
+
+static void 
+fluttr_spinner_dispose (GObject *object)
+{
+       FluttrSpinner         *self = FLUTTR_SPINNER(object);
+       FluttrSpinnerPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_spinner_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_spinner_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_spinner_parent_class)->finalize (object);
+}
+
+static void
+fluttr_spinner_class_init (FluttrSpinnerClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *parent_class; 
+
+       parent_class = CLUTTER_ACTOR_CLASS (fluttr_spinner_parent_class);
+
+       gobject_class->finalize     = fluttr_spinner_finalize;
+       gobject_class->dispose      = fluttr_spinner_dispose;
+       
+       g_type_class_add_private (gobject_class, sizeof (FluttrSpinnerPrivate));
+}
+
+static void
+fluttr_spinner_init (FluttrSpinner *self)
+{
+       FluttrSpinnerPrivate *priv;
+       priv = FLUTTR_SPINNER_GET_PRIVATE (self);
+       
+       priv->timeline = clutter_timeline_new (40, 50);
+       clutter_timeline_set_loop (priv->timeline, TRUE);
+       priv->alpha = clutter_alpha_new_full (priv->timeline,
+                                             alpha_linear_inc_func,
+                                             NULL, NULL);
+       priv->behave = fluttr_behave_new (priv->alpha,
+                                         fluttr_spinner_alpha_func,
+                                         (gpointer)self);
+}
+
+ClutterActor*
+fluttr_spinner_new (void)
+{
+       ClutterGroup         *spinner;
+
+       spinner = g_object_new (FLUTTR_TYPE_SPINNER, 
+                               NULL);
+
+       if (spinner_pixbuf == NULL) {
+               spinner_pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR \
+                                                       "/spinner.svg",
+                                                   CLUTTER_STAGE_HEIGHT ()/9,
+                                                   CLUTTER_STAGE_HEIGHT ()/9,
+                                                   FALSE,
+                                                   NULL);
+       }
+       if (spinner_pixbuf)
+               clutter_texture_set_pixbuf (CLUTTER_TEXTURE (spinner),
+                                           spinner_pixbuf, NULL);
+       else
+               g_print ("Could not load spinner\n");   
+       return CLUTTER_ACTOR (spinner);
+}
+
diff --git a/attic/fluttr/src/fluttr-spinner.h b/attic/fluttr/src/fluttr-spinner.h
new file mode 100644 (file)
index 0000000..7bfb364
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-`hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#ifndef _HAVE_FLUTTR_SPINNER_H
+#define _HAVE_FLUTTR_SPINNER_H
+
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_SPINNER fluttr_spinner_get_type()
+
+#define FLUTTR_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_SPINNER, \
+       FluttrSpinner))
+
+#define FLUTTR_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_SPINNER, \
+       FluttrSpinnerClass))
+
+#define FLUTTR_IS_SPINNER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_SPINNER))
+
+#define FLUTTR_IS_SPINNER_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_SPINNER))
+
+#define FLUTTR_SPINNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_SPINNER, \
+       FluttrSpinnerClass))
+
+typedef struct _FluttrSpinner FluttrSpinner;
+typedef struct _FluttrSpinnerClass FluttrSpinnerClass;
+typedef struct _FluttrSpinnerPrivate FluttrSpinnerPrivate;
+
+struct _FluttrSpinner
+{
+       ClutterTexture         parent;
+       
+       /* private */
+       FluttrSpinnerPrivate   *priv;
+};
+
+struct _FluttrSpinnerClass 
+{
+       /*< private >*/
+       ClutterTextureClass parent_class;
+}; 
+
+GType fluttr_spinner_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_spinner_new (void);
+
+void
+fluttr_spinner_spin (FluttrSpinner *spinner, gboolean spin);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/fluttr-viewer.c b/attic/fluttr/src/fluttr-viewer.c
new file mode 100644 (file)
index 0000000..fa1c367
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include <GL/gl.h>
+
+#include "fluttr-viewer.h"
+
+#include "fluttr-spinner.h"
+#include "fluttr-behave.h"
+#include "fluttr-settings.h"
+
+G_DEFINE_TYPE (FluttrViewer, fluttr_viewer, CLUTTER_TYPE_GROUP);
+
+#define FLUTTR_VIEWER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+       FLUTTR_TYPE_VIEWER, \
+       FluttrViewerPrivate))
+       
+#define FONT "DejaVu Sans Book"
+
+
+struct _FluttrViewerPrivate
+{
+       gchar                   *mini_token;
+       gchar                   *username;
+       gchar                   *fullname;
+       gchar                   *token;
+       gchar                   *usernsid;
+       
+       NFlickWorker            *worker;
+
+       GdkPixbuf               *logo;
+       ClutterActor            *group;
+       ClutterActor            *texture;
+       ClutterActor            *spinner;
+
+       gchar                   *msg;
+
+       gboolean                 popping;
+       gboolean                 show;
+       
+       ClutterTimeline         *timeline;
+       ClutterAlpha            *alpha;
+       ClutterBehaviour        *behave;
+       
+       /* Swap pixbuf code */
+       GdkPixbuf               *pixbuf;
+       ClutterTimeline         *swap_time;
+       ClutterAlpha            *swap_alpha;
+       ClutterBehaviour        *swap_behave;           
+
+};
+
+enum
+{
+       PROP_0,
+       PROP_PIXBUF
+};
+
+enum
+{
+       SUCCESSFUL,
+       ERROR,
+       LAST_SIGNAL
+};
+
+static guint _viewer_signals[LAST_SIGNAL] = { 0 };
+
+
+void
+fluttr_viewer_show (FluttrViewer *viewer, gboolean show)
+{
+        FluttrViewerPrivate *priv;
+        
+        g_return_if_fail (FLUTTR_IS_VIEWER (viewer));
+        priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+        
+        priv->popping = show;
+        if (show == TRUE)
+               clutter_actor_set_opacity (priv->texture, 0);
+        if (!clutter_timeline_is_playing (priv->timeline))
+               clutter_timeline_start (priv->timeline);
+}      
+
+static void
+close_message_window (FluttrViewer *viewer)
+{
+        FluttrViewerPrivate *priv;
+        
+        g_return_if_fail (FLUTTR_IS_VIEWER (viewer));
+        priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+        
+}
+
+static gboolean                 
+on_thread_abort_idle (FluttrViewer *viewer)
+{
+        g_return_val_if_fail (FLUTTR_IS_VIEWER (viewer), FALSE);
+        
+        close_message_window (viewer);
+
+       g_signal_emit (viewer, _viewer_signals[ERROR], 0, "Aborted");   
+       
+       g_print ("Aborted\n");  
+
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_ok_idle (FluttrViewer *viewer)
+{
+        FluttrViewerPrivate *priv;
+        GdkPixbuf *pixbuf;
+        
+        g_return_val_if_fail (FLUTTR_IS_VIEWER (viewer), FALSE);
+        priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+        
+        close_message_window (viewer);
+        
+        /* Get pixbuf from worker */
+        g_object_get (G_OBJECT (priv->worker), "pixbuf", &pixbuf, NULL);
+        priv->pixbuf = pixbuf;        
+        
+       if (!clutter_timeline_is_playing (priv->swap_time))
+               clutter_timeline_start (priv->swap_time);
+        
+        g_signal_emit (viewer, _viewer_signals[SUCCESSFUL], 0, priv->worker);
+        
+        return FALSE;
+}
+
+static gboolean                 
+on_thread_error_idle (FluttrViewer *viewer)
+{
+        FluttrViewerPrivate *priv;
+        gchar *error = NULL;
+        
+        g_return_val_if_fail (FLUTTR_IS_VIEWER (viewer), FALSE);
+        priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+        
+        close_message_window (viewer);
+        
+        /* Get the actual error */
+        g_object_get (G_OBJECT (priv->worker), "error", &error, NULL);
+        if (error == NULL) {
+                error = g_strdup_printf (gettext ("Internal error. "));
+                g_warning ("No error set on worker!");
+        }
+       g_signal_emit (viewer, _viewer_signals[ERROR], 0, error);
+       
+       g_print ("%s\n", error);
+       
+        g_free (error);
+
+        return FALSE;
+}
+
+/* Copy the new message and start the fade effect if not already started */
+static gboolean                 
+on_thread_msg_change_idle (FluttrViewer *viewer)
+{
+        FluttrViewerPrivate *priv;
+        gchar *msg;
+        
+        g_return_val_if_fail (FLUTTR_IS_VIEWER (viewer), FALSE);
+        priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+        
+        /* Get the new message */
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                g_print ("%s\n", msg);
+        }
+        priv->msg = g_strdup (msg);
+
+       return FALSE;
+}
+
+
+/* This function does th emain work of creating and configuring the worker 
+   thread. the majority of this code is taken from
+   NFlick the n800 Flickr photo browser by MDK (see: README) */
+void
+fluttr_viewer_go (FluttrViewer *viewer, FluttrPhoto *photo)
+{
+        FluttrViewerPrivate *priv;
+        FluttrSettings *settings = fluttr_settings_get_default ();
+       NFlickWorker *worker;
+        NFlickWorkerStatus status;
+        gint width = CLUTTER_STAGE_WIDTH ();
+        gint height = CLUTTER_STAGE_HEIGHT();
+              
+        gchar *token = NULL;
+        gchar *photoid = NULL;
+       
+        g_return_if_fail (FLUTTR_IS_VIEWER (viewer));
+        priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+        
+        if (priv->worker)
+               nflick_worker_request_abort (priv->worker);
+        
+        fluttr_spinner_spin (FLUTTR_SPINNER (priv->spinner), TRUE);
+        clutter_actor_set_opacity (priv->spinner, 255);
+        
+               
+       g_object_get (G_OBJECT (settings), "token", &token, NULL);
+       g_object_get (G_OBJECT (photo), "photoid", &photoid, NULL);
+       
+       worker = (NFlickWorker *)nflick_show_worker_new (photoid, 
+                                                        width, 
+                                                        height, 
+                                                        token);
+        /* Check if the worker is in the right state */
+        g_object_get (G_OBJECT (worker), "status", &status, NULL);
+        
+        if (status != NFLICK_WORKER_STATUS_IDLE) {
+                g_warning ("Bad worker status"); 
+                return;
+        }
+        
+        g_object_ref (worker);
+        priv->worker = worker;
+        
+        /* Get the initial message */
+        gchar *msg = NULL;
+        g_object_get (G_OBJECT (priv->worker), "message", &msg, NULL);
+        if (msg != NULL) {
+                /* FIXME Escape markup */
+               //g_print ("%s", msg);
+        }
+        
+        /* Set the callback functions */
+        nflick_worker_set_custom_data (worker, viewer);
+        nflick_worker_set_aborted_idle (worker, 
+                                 (NFlickWorkerIdleFunc) on_thread_abort_idle);
+                                          
+        nflick_worker_set_error_idle (worker, 
+                                  (NFlickWorkerIdleFunc) on_thread_error_idle);
+        
+        nflick_worker_set_ok_idle (worker, 
+                                     (NFlickWorkerIdleFunc) on_thread_ok_idle);
+        
+        nflick_worker_set_msg_change_idle (worker, 
+                             (NFlickWorkerIdleFunc) on_thread_msg_change_idle);
+                                        
+        nflick_worker_start (priv->worker);
+        
+        /* Free */
+        g_free (msg);
+}
+
+
+/* Slide in or out the notification popp, depending on priv->pop_visible */
+static void
+fluttr_viewer_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+       FluttrViewerPrivate *priv;
+       gfloat factor;
+
+               g_return_if_fail (FLUTTR_IS_VIEWER (data));
+       priv = FLUTTR_VIEWER_GET_PRIVATE(data);
+       
+       factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->popping) 
+               clutter_actor_set_opacity (CLUTTER_ACTOR (data), 255 * factor);
+       else
+               clutter_actor_set_opacity (CLUTTER_ACTOR (data), 
+                                          255- (255*factor));
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}
+
+/* Fade out text, change text, then fade in, all within one play of the timeline
+   just to keep things interesting :) */
+static void
+fluttr_viewer_swap_alpha_func (ClutterBehaviour *behave,
+                             guint             alpha_value,
+                             gpointer          data)
+{
+       FluttrViewerPrivate *priv;
+       gfloat factor;
+       guint width = CLUTTER_STAGE_WIDTH ();
+       guint height = CLUTTER_STAGE_HEIGHT ();
+       guint w, h;
+       
+               g_return_if_fail (FLUTTR_IS_VIEWER (data));
+       priv = FLUTTR_VIEWER_GET_PRIVATE(data);
+       
+       factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       
+       if (priv->pixbuf != NULL && factor > 0.5) {
+               clutter_texture_set_pixbuf (CLUTTER_TEXTURE (priv->texture),
+                                           priv->pixbuf, NULL);
+               clutter_actor_get_size (priv->texture, &w, &h);
+               
+               clutter_actor_set_position (priv->texture, 
+                                           (width/2) - (w/2),
+                                           (height/2) - (h/2));    
+       }
+       if (factor < 0.5) {
+               factor *= 2;
+               factor = 1.0 - factor;
+       } else {
+               factor -= 0.5;
+               factor /= 0.5;
+       }
+       
+       clutter_actor_set_opacity (CLUTTER_ACTOR (priv->texture), 
+                                          255 * factor);
+       clutter_actor_set_opacity (priv->spinner, 255 * (1-factor));
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(data)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(data));       
+}
+
+       
+/* GObject Stuff */
+
+static void
+fluttr_viewer_set_property (GObject      *object, 
+                           guint         prop_id,
+                           const GValue *value, 
+                           GParamSpec   *pspec)
+{
+       FluttrViewerPrivate *priv;
+
+       g_return_if_fail (FLUTTR_IS_VIEWER (object));
+       priv = FLUTTR_VIEWER_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_PIXBUF:
+                       if (priv->pixbuf != NULL)
+                               g_object_unref (G_OBJECT (priv->pixbuf));
+                       priv->pixbuf = g_value_get_object (value);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, 
+                                                          pspec);
+                       break;
+       }
+}
+
+static void
+fluttr_viewer_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+       FluttrViewerPrivate *priv;
+       
+       g_return_if_fail (FLUTTR_IS_VIEWER (object));
+       priv = FLUTTR_VIEWER_GET_PRIVATE(object);
+
+       switch (prop_id) {
+               case PROP_PIXBUF:
+                       g_value_set_object (value, priv->pixbuf);
+                       break;          
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+                                                          pspec);
+               break;
+       } 
+}
+
+static void
+fluttr_viewer_paint (ClutterActor *actor)
+{
+       FluttrViewer        *viewer;
+       FluttrViewerPrivate *priv;
+
+       viewer = FLUTTR_VIEWER(actor);
+
+       priv = FLUTTR_VIEWER_GET_PRIVATE(viewer);
+
+       glPushMatrix();
+       
+       gint i;
+       gint len = clutter_group_get_n_children (CLUTTER_GROUP (actor)); 
+       for (i = 0; i < len; i++) {
+               ClutterActor* child;
+
+               child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+               if (child) {
+                       clutter_actor_paint (child);
+               }
+       }
+
+       glPopMatrix();
+}
+
+static void 
+fluttr_viewer_dispose (GObject *object)
+{
+       FluttrViewer         *self = FLUTTR_VIEWER(object);
+       FluttrViewerPrivate  *priv;  
+
+       priv = self->priv;
+  
+       G_OBJECT_CLASS (fluttr_viewer_parent_class)->dispose (object);
+}
+
+static void 
+fluttr_viewer_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (fluttr_viewer_parent_class)->finalize (object);
+}
+
+static void
+fluttr_viewer_class_init (FluttrViewerClass *klass)
+{
+       GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+       ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+       ClutterActorClass   *parent_class; 
+
+       parent_class = CLUTTER_ACTOR_CLASS (fluttr_viewer_parent_class);
+
+       actor_class->paint           = fluttr_viewer_paint;
+       
+       gobject_class->finalize     = fluttr_viewer_finalize;
+       gobject_class->dispose      = fluttr_viewer_dispose;
+       gobject_class->get_property = fluttr_viewer_get_property;
+       gobject_class->set_property = fluttr_viewer_set_property;       
+
+       g_type_class_add_private (gobject_class, sizeof (FluttrViewerPrivate));
+       
+       /* Class properties */
+       g_object_class_install_property 
+               (gobject_class,
+                PROP_PIXBUF,
+                g_param_spec_object ("pixbuf",
+                "Pixbuf",
+                "The current pixbuf",
+                GDK_TYPE_PIXBUF,
+                G_PARAM_CONSTRUCT|G_PARAM_READWRITE)); 
+                                                                
+
+       /* Class signals */
+       _viewer_signals[SUCCESSFUL] =
+               g_signal_new ("successful",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrViewerClass, successful),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__OBJECT,
+                            G_TYPE_NONE, 1, NFLICK_TYPE_WORKER);
+                            
+       _viewer_signals[ERROR] =
+               g_signal_new ("error",
+                            G_OBJECT_CLASS_TYPE (gobject_class),
+                            G_SIGNAL_RUN_FIRST,
+                            G_STRUCT_OFFSET (FluttrViewerClass, error),
+                            NULL, NULL,
+                            g_cclosure_marshal_VOID__STRING,
+                            G_TYPE_NONE, 1, G_TYPE_STRING);                         
+
+}
+
+static void
+fluttr_viewer_init (FluttrViewer *self)
+{
+       FluttrViewerPrivate *priv;
+       gint width, height;
+       ClutterActor *message;
+       
+       priv = FLUTTR_VIEWER_GET_PRIVATE (self);
+       
+       priv->mini_token = NULL;
+       priv->popping = FALSE;
+
+       width = CLUTTER_STAGE_WIDTH ();
+       height = CLUTTER_STAGE_HEIGHT ();
+               
+       /* message box */
+       message = clutter_texture_new ();
+       priv->texture = message;
+       clutter_group_add (CLUTTER_GROUP (self),message); 
+       clutter_actor_set_size (message, width, height);
+       clutter_actor_set_position (message, -(width/2),-(height/2));
+       
+       /* Spinner */
+       priv->spinner = fluttr_spinner_new ();
+       clutter_group_add (CLUTTER_GROUP (self),priv->spinner); 
+       clutter_actor_set_size (priv->spinner, (height/6)-11, (height/6)-11);
+       clutter_actor_set_position (priv->spinner, width-(height/6),height-(height/6)); 
+                                   
+       /* Setup the pixbuf swap */
+       priv->pixbuf = NULL;
+       priv->swap_time = clutter_timeline_new (40, 40);
+       priv->swap_alpha = clutter_alpha_new_full (priv->swap_time,
+                                                  alpha_linear_inc_func,
+                                                  NULL, NULL);
+       priv->swap_behave = fluttr_behave_new (priv->swap_alpha,
+                                              fluttr_viewer_swap_alpha_func,
+                                              (gpointer)self);
+                                                                           
+       priv->timeline = clutter_timeline_new (40, 80);
+       priv->alpha = clutter_alpha_new_full (priv->timeline,
+                                             alpha_sine_inc_func,
+                                             NULL, NULL);
+       priv->behave = fluttr_behave_new (priv->alpha,
+                                         fluttr_viewer_alpha_func,
+                                         (gpointer)self);
+               
+}
+
+ClutterActor*
+fluttr_viewer_new (void)
+{
+       ClutterGroup         *viewer;
+
+       viewer = g_object_new (FLUTTR_TYPE_VIEWER, 
+                            NULL);
+       
+       clutter_actor_set_opacity (CLUTTER_ACTOR (viewer), 0);
+       
+       return CLUTTER_ACTOR (viewer);
+}
+
diff --git a/attic/fluttr/src/fluttr-viewer.h b/attic/fluttr/src/fluttr-viewer.h
new file mode 100644 (file)
index 0000000..43cb9ba
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-`hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include <libnflick/nflick.h>
+
+#include "fluttr-photo.h"
+
+#ifndef _HAVE_FLUTTR_VIEWER_H
+#define _HAVE_FLUTTR_VIEWER_H
+
+
+G_BEGIN_DECLS
+
+#define FLUTTR_TYPE_VIEWER fluttr_viewer_get_type()
+
+#define FLUTTR_VIEWER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       FLUTTR_TYPE_VIEWER, \
+       FluttrViewer))
+
+#define FLUTTR_VIEWER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+       FLUTTR_TYPE_VIEWER, \
+       FluttrViewerClass))
+
+#define FLUTTR_IS_VIEWER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       FLUTTR_TYPE_VIEWER))
+
+#define FLUTTR_IS_VIEWER_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       FLUTTR_TYPE_VIEWER))
+
+#define FLUTTR_VIEWER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+       FLUTTR_TYPE_VIEWER, \
+       FluttrViewerClass))
+
+typedef struct _FluttrViewer FluttrViewer;
+typedef struct _FluttrViewerClass FluttrViewerClass;
+typedef struct _FluttrViewerPrivate FluttrViewerPrivate;
+
+struct _FluttrViewer
+{
+       ClutterGroup         parent;
+       
+       /* private */
+       FluttrViewerPrivate   *priv;
+};
+
+struct _FluttrViewerClass 
+{
+       /*< private >*/
+       ClutterGroupClass parent_class;
+
+       void (*successful) (FluttrViewer *viewer, NFlickWorker *worker);
+       void (*error) (FluttrViewer *viewer, gchar *msg);
+       void (*_fluttr_viewer_3) (void);
+       void (*_fluttr_viewer_4) (void);
+}; 
+
+GType fluttr_viewer_get_type (void) G_GNUC_CONST;
+
+ClutterActor* 
+fluttr_viewer_new (void);
+
+void
+fluttr_viewer_go (FluttrViewer *viewer, FluttrPhoto *photo);
+
+void
+fluttr_viewer_show (FluttrViewer *viewer, gboolean show);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/fluttr/src/main.c b/attic/fluttr/src/main.c
new file mode 100644 (file)
index 0000000..c394c3f
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2007 Neil J. Patel
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * Author: Neil J. Patel  <njp@o-hand.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <clutter/clutter.h>
+
+#include "fluttr-auth.h"
+#include "fluttr-behave.h"
+#include "fluttr-library.h"
+#include "fluttr-library-row.h"
+#include "fluttr-list.h"
+#include "fluttr-list-view.h"
+#include "fluttr-photo.h"
+#include "fluttr-settings.h"
+#include "fluttr-set-view.h"
+#include "fluttr-set.h"
+#include "fluttr-viewer.h"
+
+#include <libnflick/nflick.h>
+
+typedef enum {
+       FLUTTR_VIEW_SETS,
+       FLUTTR_VIEW_PHOTOS,
+       FLUTTR_VIEW_PHOTO
+
+} FluttrView;
+
+typedef struct {
+       FluttrLibrary           *library;
+       
+       ClutterActor            *stage;
+       ClutterActor            *auth;
+       ClutterActor            *sets;
+       ClutterActor            *list;
+       ClutterActor            *list_view;
+       ClutterActor            *viewer;
+       
+       /* Current view info */
+       FluttrView               view;
+       gulong                   sig;
+       
+       /* Flickr info */
+       gchar                   *username;
+       gchar                   *fullname;
+       gchar                   *token;
+       gchar                   *usernsid;
+       
+       /* The swapping timeline */
+       ClutterActor            *in;
+       ClutterActor            *out;
+       ClutterTimeline         *timeline;
+       ClutterAlpha            *alpha;
+       ClutterBehaviour        *behave;
+
+} Fluttr;
+
+static void            browse_input_cb (ClutterStage *stage, 
+                                        ClutterEvent *event,
+                                        Fluttr       *fluttr);
+
+static void            create_background (ClutterActor *bg,
+                                          guint width, 
+                                          guint height);
+
+static gboolean        check_credentials (Fluttr *fluttr);
+
+static void            auth_successful (FluttrAuth *auth, gchar *null, 
+                                        Fluttr *fluttr);
+static void            auth_error (FluttrAuth *auth, gchar *msg, 
+                                   Fluttr *fluttr);
+                                   
+static void            list_get_successful (FluttrAuth *auth, 
+                                            NFlickWorker *worker, 
+                                            Fluttr *fluttr);
+static void            list_get_error (FluttrAuth *auth, gchar *msg, 
+                                       Fluttr *fluttr);
+static void            _swap_alpha_func (ClutterBehaviour *behave,
+                                         guint             alpha_value,
+                                         gpointer         data);
+
+
+/* Commmand line options */
+static gint     cols = 3;
+static gboolean  fullscreen = FALSE;
+static gint     stage_width = 800;
+static gint     stage_height = 440;
+
+static GOptionEntry entries[] = 
+{
+       { "columns", 
+         'c', 0, 
+         G_OPTION_ARG_INT, 
+         &cols, 
+         "Number of picture columns in the view", 
+         "3" },
+        
+       { "fullscreen", 
+         'f', 0, 
+         G_OPTION_ARG_NONE, 
+         &fullscreen, 
+         "Launch Juke in fullscreen mode", 
+         NULL },
+
+       { "width", 
+         'w', 0, 
+         G_OPTION_ARG_INT, 
+         &stage_width, 
+         "Width of the Fluttr window", 
+         "800" },
+         
+       { "height", 
+         'h', 0, 
+         G_OPTION_ARG_INT, 
+         &stage_height, 
+         "Height of the Fluttr window", 
+         "440" },      
+
+       { NULL }
+};
+
+
+                                         
+static gboolean
+_auth_timeout (Fluttr *fluttr)
+{
+       fluttr_auth_go (FLUTTR_AUTH (fluttr->auth));
+       return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+       Fluttr *fluttr = g_new0 (Fluttr, 1);
+       GOptionContext *context;
+       ClutterActor *stage, *background, *list;
+       ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
+       FluttrSettings *settings = NULL;
+       gchar *filename, *folder;
+       
+       g_thread_init (NULL);
+       clutter_init (&argc, &argv);            
+
+       /* Load options */
+       context = g_option_context_new (" - Fluttr Options");
+       g_option_context_add_main_entries (context, entries, NULL);
+       g_option_context_parse (context, &argc, &argv, NULL);   
+               
+       /* Check that there are enough arguments */
+       if (argc < 2 && !(check_credentials (fluttr))) {
+               g_print ("\n\nYou need to start Fluttr with your Flickr "\
+                         "authorisation code, which is available here:\n"\
+                         "http://www.flickr.com/auth-72157600141007022\n\n");
+               return 0;
+       }
+       
+       /* Create a new library */
+       fluttr->library = NULL;
+       fluttr->view = FLUTTR_VIEW_SETS;
+       
+       stage = clutter_stage_get_default ();
+       fluttr->stage = stage;
+       clutter_actor_set_size (stage, stage_width, stage_height);
+       clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+        
+        if (fullscreen)
+               g_object_set (stage, "fullscreen", TRUE, NULL);
+
+       /* Make sure the sized thumbnail path is created */
+       folder = g_strdup_printf ("%d", fluttr_photo_get_default_width ());
+       filename = g_build_filename (g_get_home_dir (),
+                                    ".fluttr-thumbs",
+                                    folder,
+                                    NULL);     
+       g_mkdir (filename, 0775);
+       g_free (filename);
+       g_free (folder);
+       
+       
+       if (fluttr->username == NULL) {
+               /* Authorise the mini-token */
+               g_print ("Authenticating : %s\n", argv[1]);             
+                fluttr->auth = fluttr_auth_new (argv[1]);
+               g_signal_connect (G_OBJECT (fluttr->auth), "successful",
+                                 G_CALLBACK (auth_successful), fluttr);
+               g_signal_connect (G_OBJECT (fluttr->auth), "error",
+                                 G_CALLBACK (auth_error), fluttr);
+                                 
+               clutter_actor_set_size (fluttr->auth, 800, 440);
+               clutter_actor_set_position (fluttr->auth, 0, 0);
+               clutter_group_add (CLUTTER_GROUP (fluttr->stage), fluttr->auth);
+       
+               g_timeout_add (1500, (GSourceFunc)_auth_timeout, 
+                              (gpointer)fluttr);
+       }
+       
+       /* Background */
+       background = clutter_texture_new ();
+       clutter_actor_set_position (background, 0, 0);
+       create_background (background, CLUTTER_STAGE_WIDTH (), 
+                                      CLUTTER_STAGE_HEIGHT ());        
+       clutter_group_add (CLUTTER_GROUP (stage), background);          
+       
+       /* Set up the list worker */
+       list = fluttr_list_new ();
+       fluttr->list = list;
+       g_object_set (G_OBJECT (list),
+                     "username", fluttr->username,
+                     "fullname", fluttr->fullname,
+                     "token", fluttr->token,
+                     "usernsid", fluttr->usernsid,
+                     NULL);    
+       g_signal_connect (G_OBJECT (list), "successful",
+                                 G_CALLBACK (list_get_successful), fluttr);
+       g_signal_connect (G_OBJECT (list), "error",
+                                 G_CALLBACK (list_get_error), fluttr);
+                                 
+       clutter_actor_set_size (list, 800, 480);
+       clutter_actor_set_position (list, 0, 0);
+       clutter_group_add (CLUTTER_GROUP (fluttr->stage), list);
+       
+       
+       /* If we have a username etc, we want to start the list fetcher */
+       if (fluttr->username != NULL) {
+               /* We update the settings singleton */
+               settings = fluttr_settings_get_default ();
+               g_object_set (G_OBJECT (settings),
+                             "username", fluttr->username,
+                             "fullname", fluttr->fullname,
+                             "token", fluttr->token,
+                             "usernsid", fluttr->usernsid,
+                             NULL);
+               fluttr_list_go (FLUTTR_LIST (fluttr->list));
+       }
+       
+       /* Sets view */
+       ClutterActor *sets = fluttr_set_view_new ();
+       fluttr->sets = sets;
+       clutter_group_add (CLUTTER_GROUP (fluttr->stage), sets);
+       clutter_actor_set_size (sets, 
+                               CLUTTER_STAGE_WIDTH (),
+                               CLUTTER_STAGE_HEIGHT());
+       clutter_actor_set_position (sets, 0, 0);
+       
+       /* The list view */
+       fluttr->list_view = fluttr_list_view_new ();
+       g_object_set (G_OBJECT (fluttr->list_view), "cols", cols, NULL);
+       clutter_group_add (CLUTTER_GROUP (fluttr->stage), fluttr->list_view);
+       clutter_actor_set_size (fluttr->list_view, CLUTTER_STAGE_WIDTH (),
+                               CLUTTER_STAGE_HEIGHT ());
+       clutter_actor_set_position (fluttr->list_view, 0, 0);
+       clutter_actor_set_opacity (fluttr->list_view, 0);       
+       
+       clutter_actor_show_all (fluttr->stage);     
+       
+       /* The viewer */
+       fluttr->viewer = fluttr_viewer_new ();
+       clutter_group_add (CLUTTER_GROUP (fluttr->stage), fluttr->viewer);
+       clutter_actor_set_size (fluttr->viewer, CLUTTER_STAGE_WIDTH (),
+                                               CLUTTER_STAGE_HEIGHT ());
+       clutter_actor_set_position (fluttr->viewer, 0, 0);
+       clutter_actor_set_opacity (fluttr->viewer, 0);  
+       
+       clutter_actor_show_all (fluttr->stage);   
+       
+       /* Setup the view swa behaviour */
+       fluttr->in = fluttr->out = NULL;
+       fluttr->timeline = clutter_timeline_new (40, 60);
+       fluttr->alpha = clutter_alpha_new_full (fluttr->timeline,
+                                             alpha_linear_inc_func,
+                                             NULL, NULL);
+       fluttr->behave = fluttr_behave_new (fluttr->alpha,
+                                           _swap_alpha_func,
+                                           (gpointer)fluttr);  
+       
+       /* Receive all input events */
+       g_signal_connect (stage, 
+                         "event",
+                         G_CALLBACK (browse_input_cb),
+                         (gpointer)fluttr);    
+       
+       clutter_main(); 
+       return 0;
+}
+
+/* Fade out text, change text, then fade in, all within one play of the timeline
+   just to keep things interesting :) */
+static void
+_swap_alpha_func (ClutterBehaviour *behave,
+                 guint             alpha_value,
+                 gpointer          data)
+{
+        Fluttr    *fluttr = (Fluttr*)data;
+        gfloat factor;
+       factor = (gfloat) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
+       ClutterActor *stage = clutter_stage_get_default ();
+       
+       clutter_actor_set_opacity (CLUTTER_ACTOR (fluttr->in), 255 * factor);
+       clutter_actor_set_opacity (CLUTTER_ACTOR (fluttr->out),
+                                  255- (255*factor));
+       
+       if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(stage)))
+               clutter_actor_queue_redraw (CLUTTER_ACTOR(stage));      
+}
+
+/* If available, load setting from the users key file */
+static gboolean
+check_credentials (Fluttr *fluttr)
+{
+       gchar *path;
+       gchar *res = NULL;
+       GKeyFile *keyf = NULL;
+       
+       path = g_build_filename (g_get_home_dir (), ".fluttr", NULL);
+       
+       if ( (g_file_test (path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))){
+               
+               keyf = g_key_file_new ();
+               g_key_file_load_from_file (keyf, path, 0, NULL);
+               
+               /* Try loading the username form the file, if it works, then we
+                  already have the credentials, else we set everything to NULL
+               */
+               res = g_key_file_get_string (keyf, "fluttr", "username", NULL);
+               if (res == NULL) {
+                       /* Somethings wrong, so just set the varibales to NULL*/
+                       fluttr->username = NULL;
+                       fluttr->fullname = NULL;
+                       fluttr->token = NULL;
+                       fluttr->usernsid = NULL;
+                       g_free (path);
+                       return FALSE;                   
+               }
+               
+               fluttr->username = g_strdup (res);
+               
+               res = NULL;
+               res = g_key_file_get_string (keyf, "fluttr", "fullname", NULL);
+               fluttr->fullname = g_strdup (res);
+               
+               res = NULL;
+               res = g_key_file_get_string (keyf, "fluttr", "token", NULL);
+               fluttr->token = g_strdup (res);
+               
+               res = NULL;
+               res = g_key_file_get_string (keyf, "fluttr", "usernsid", NULL);
+               fluttr->usernsid = g_strdup (res);                              
+               
+
+               g_print ("Loaded Credentials:\n\t%s\n\t%s\n\t%s\n\t%s\n",
+                        fluttr->username,
+                        fluttr->fullname,
+                        fluttr->token,
+                        fluttr->usernsid);
+                               
+               g_free (path);          
+               return TRUE;
+       } else {
+               /* Doesn't exist, so just set the varibales to NULL */
+               fluttr->username = NULL;
+               fluttr->fullname = NULL;
+               fluttr->token = NULL;
+               fluttr->usernsid = NULL;
+               g_free (path);          
+               return FALSE;
+       }
+}
+
+/* Authorisation Call backs */
+static void            
+auth_successful (FluttrAuth *auth, gchar *null, Fluttr *fluttr)
+{
+       gchar *c;
+       GKeyFile *kf = g_key_file_new();
+       gchar *file = g_build_filename(g_get_home_dir(), ".fluttr", NULL);
+       FluttrSettings *settings;
+
+       /* Load the details */
+       g_object_get (G_OBJECT (fluttr->auth), 
+                      "username", &fluttr->username, 
+                      "fullname", &fluttr->fullname, 
+                      "token", &fluttr->token, 
+                      "usernsid", &fluttr->usernsid, 
+                      NULL);                 
+
+       /* Save the details for next time */
+                      
+       g_key_file_set_string (kf, "fluttr", "username", fluttr->username);
+       g_key_file_set_string (kf, "fluttr", "fullname", fluttr->fullname);
+       g_key_file_set_string (kf, "fluttr", "token", fluttr->token);
+       g_key_file_set_string (kf, "fluttr", "usernsid", fluttr->usernsid);
+       
+       c = g_key_file_to_data(kf, NULL, NULL);
+       g_key_file_free(kf);
+
+       g_file_set_contents(file, c, -1, NULL);
+       g_free(c);
+       g_free(file);                      
+       
+       g_print ("Auth Successful:\n\t%s\n\t%s\n\t%s\n\t%s\n",
+                fluttr->username,
+                fluttr->fullname,
+                fluttr->token,
+                fluttr->usernsid);
+
+       /* Start the list fetcher */
+       g_object_set (G_OBJECT (fluttr->list),
+                     "username", fluttr->username,
+                     "fullname", fluttr->fullname,
+                     "token", fluttr->token,
+                     "usernsid", fluttr->usernsid,
+                     NULL);            
+
+       /* We update the settings singleton */
+       settings = fluttr_settings_get_default ();
+       g_object_set (G_OBJECT (settings),
+                     "username", fluttr->username,
+                     "fullname", fluttr->fullname,
+                     "token", fluttr->token,
+                     "usernsid", fluttr->usernsid,
+                     NULL);
+       fluttr_list_go (FLUTTR_LIST (fluttr->list));    
+}
+
+static void            
+auth_error (FluttrAuth *auth, gchar *msg, Fluttr *fluttr)
+{
+       g_critical ("Auth Unsuccessful : %s\n", msg);
+}
+
+/* get list callbacks */
+
+/* Go through the list of sets, and poplulate the Fluttr library with 
+   FluttrLibraryRows */
+static void            
+list_get_successful (FluttrAuth *auth, NFlickWorker *worker, Fluttr *fluttr)
+{
+       GList *list = NULL;
+       GList *l = NULL;
+       list = nflick_set_list_worker_take_list ((NFlickSetListWorker*) worker);
+       gint i = 0;
+       gint j = 0;
+       
+       g_print ("\n");
+       for (l = list; l != NULL; l = l->next) {
+               ClutterActor *set = fluttr_set_new (l->data);
+               GList *photos = NULL;
+               GList *photo;   
+               gchar *id = NULL;
+               g_object_get (G_OBJECT (l->data), "combotext", &id, NULL);
+               g_print ("%s : ", id);
+               
+               g_object_get (G_OBJECT (l->data), "list", &photos, NULL);
+               
+               g_print ("%d loaded\n", g_list_length (photos));
+               
+               for (photo = photos; photo!=NULL ;photo = photo->next) {
+                       NFlickPhotoData *p = (NFlickPhotoData*)photo->data;
+                       
+                       fluttr_set_append_photo (FLUTTR_SET (set),
+                                                p->Id, 
+                                                p->Name);
+                       
+                       i++;
+               }
+               fluttr_set_view_add_set (FLUTTR_SET_VIEW (fluttr->sets), 
+                                        FLUTTR_SET (set));
+               j++;
+       }
+       fluttr_set_view_advance (FLUTTR_SET_VIEW (fluttr->sets), 0);
+       
+       g_print ("%d Photo(s) in %d set(s)\n", i, j);
+}
+
+static void
+list_get_error (FluttrAuth *auth, gchar *msg, Fluttr *fluttr)
+{
+       g_critical ("Auth Unsuccessful : %s\n", msg);
+}
+
+static void 
+photo_input_cb (ClutterStage *stage,
+                ClutterEvent *event,
+                Fluttr       *fluttr)
+{
+       FluttrPhoto *photo = NULL;
+       
+       
+       /* First check for app wide keybinding */
+       if (event->type == CLUTTER_KEY_RELEASE) {
+               ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+
+               switch (clutter_key_event_symbol (kev)) {
+               case CLUTTER_Left:
+               case CLUTTER_Right:
+               case CLUTTER_Up:
+               case CLUTTER_Down:
+               case CLUTTER_Return:
+               case CLUTTER_space:
+               case CLUTTER_KP_Enter:
+               case CLUTTER_Escape:
+                       fluttr_list_view_advance_col 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view), 0);
+                       photo = fluttr_list_view_get_active 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view));
+                       fluttr->view = FLUTTR_VIEW_PHOTOS;
+                       fluttr_viewer_show (FLUTTR_VIEWER (fluttr->viewer),
+                                           FALSE);
+                       fluttr_photo_show_options (photo, FALSE);
+                       
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void
+_show_viewer (FluttrPhoto *photo, gchar *null, Fluttr *fluttr)
+{
+       fluttr_viewer_show (FLUTTR_VIEWER (fluttr->viewer), TRUE);
+       
+       g_signal_handler_disconnect (G_OBJECT (photo), fluttr->sig);
+}
+
+static void 
+list_input_cb (ClutterStage *stage,
+                ClutterEvent *event,
+                Fluttr       *fluttr)
+{
+       FluttrPhoto *photo = NULL;
+       
+       
+       /* First check for app wide keybinding */
+       if (event->type == CLUTTER_KEY_RELEASE) {
+               ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+
+               switch (clutter_key_event_symbol (kev)) {
+               case CLUTTER_Left:
+                       fluttr_list_view_advance_col 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view), -1);
+                       break;
+               case CLUTTER_Right:
+                       fluttr_list_view_advance_col 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view), 1);
+                       break;
+               case CLUTTER_Up:
+                       fluttr_list_view_advance_row 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view), -1);
+                       break;
+               case CLUTTER_Down:
+                       fluttr_list_view_advance_row 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view), 1);
+                       break;
+               case CLUTTER_Return:
+               case CLUTTER_space:
+               case CLUTTER_KP_Enter:
+                       fluttr_list_view_activate (FLUTTR_LIST_VIEW 
+                                                               (fluttr->list_view));
+                       photo = fluttr_list_view_get_active 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view));
+                       fluttr_photo_show_options (photo, TRUE);
+                       fluttr->view = FLUTTR_VIEW_PHOTO;
+                       
+                       fluttr_viewer_go (FLUTTR_VIEWER (fluttr->viewer),photo);
+                       fluttr->sig = g_signal_connect (photo, "activated",
+                                         G_CALLBACK (_show_viewer), fluttr);
+                       break;
+               case CLUTTER_Escape:
+                       fluttr->in = fluttr->sets;
+                       fluttr->out = fluttr->list_view;
+                       if (!clutter_timeline_is_playing (fluttr->timeline))
+                               clutter_timeline_start (fluttr->timeline);
+                       /*
+                       clutter_actor_set_opacity (fluttr->list_view, 0);
+                       clutter_actor_set_opacity (fluttr->sets, 255);
+                       */
+                       fluttr->view = FLUTTR_VIEW_SETS; 
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void 
+sets_input_cb (ClutterStage *stage,
+                ClutterEvent *event,
+                Fluttr       *fluttr)
+{
+       FluttrSet *set = NULL;
+       
+       
+       /* First check for app wide keybinding */
+       if (event->type == CLUTTER_KEY_RELEASE) {
+               ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+
+               switch (clutter_key_event_symbol (kev)) {
+               case CLUTTER_Left:
+                       fluttr_set_view_advance_col 
+                                       (FLUTTR_SET_VIEW (fluttr->sets), -1);
+                       break;
+               case CLUTTER_Right:
+                       fluttr_set_view_advance_col 
+                                       (FLUTTR_SET_VIEW (fluttr->sets), 1);
+                       break;
+               case CLUTTER_Up:
+                       fluttr_set_view_advance_row 
+                                       (FLUTTR_SET_VIEW (fluttr->sets), -1);
+                       break;
+               case CLUTTER_Down:
+                       fluttr_set_view_advance_row 
+                                       (FLUTTR_SET_VIEW (fluttr->sets), 1);
+                       break;
+               case CLUTTER_Return:
+               case CLUTTER_space:
+               case CLUTTER_KP_Enter:
+                       fluttr_set_view_activate (FLUTTR_SET_VIEW 
+                                                               (fluttr->sets));
+                       set = fluttr_set_view_get_active (FLUTTR_SET_VIEW 
+                                                               (fluttr->sets));
+                       if (set) {
+                               g_object_set (G_OBJECT (fluttr->list_view),
+                                             "set", set, NULL);
+                               fluttr->in = fluttr->list_view;
+                               fluttr->out = fluttr->sets;
+                               if (!clutter_timeline_is_playing (
+                                                       fluttr->timeline))
+                                       clutter_timeline_start (
+                                                       fluttr->timeline);
+                               fluttr->view = FLUTTR_VIEW_PHOTOS; 
+                               fluttr_list_view_advance 
+                                       (FLUTTR_LIST_VIEW (fluttr->list_view), 0);
+                       }
+                       break;
+               case CLUTTER_Escape:
+                       clutter_main_quit();
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+
+static void 
+browse_input_cb (ClutterStage *stage,
+                ClutterEvent *event,
+                Fluttr       *fluttr)
+{
+       /* First check for app wide keybinding */
+       if (event->type == CLUTTER_KEY_RELEASE) {
+               ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+
+               switch (clutter_key_event_symbol (kev)) {
+               
+               case CLUTTER_Escape:
+                       if (fluttr->view == FLUTTR_VIEW_SETS)
+                               clutter_main_quit();
+                       break;
+               default:
+                       break;
+               }
+       }
+       /* if we have got here, we can pass the input onto the right place */
+       if (fluttr->view == FLUTTR_VIEW_SETS)
+               sets_input_cb (stage, event, fluttr);
+       else if (fluttr->view == FLUTTR_VIEW_PHOTOS)
+               list_input_cb (stage, event, fluttr);
+       else
+               photo_input_cb (stage, event, fluttr);
+}
+
+static void 
+create_background (ClutterActor *bg, guint width, guint height)
+{
+       GdkPixbuf *pixbuf = NULL;
+       
+       pixbuf = gdk_pixbuf_new_from_file_at_scale (PKGDATADIR \
+                                                       "/background.svg",
+                                                   width,
+                                                   height,
+                                                   FALSE,
+                                                   NULL);
+       if (pixbuf)
+               clutter_texture_set_pixbuf (CLUTTER_TEXTURE (bg), pixbuf, NULL);
+       else
+               g_print ("Could not load pixbuf\n");            
+}
+
diff --git a/attic/gcr/Makefile b/attic/gcr/Makefile
new file mode 100644 (file)
index 0000000..7e88452
--- /dev/null
@@ -0,0 +1,88 @@
+# A generic buildfiles to build single executable directory projects depending
+# only on pkg-config ability to build. It automatically names the project on
+# the toplevel directory you're in.
+#
+# Setting additional CFLAGS like $ export CFLAGS=-Wall -Werror # can help you
+# track issues down better after compilation.
+#
+# 20071008
+# Øyvind Kolås (c) 2007 <pippin@gimp.org>  placed in the Public Domain.
+##
+
+PKGMODULES = clutter-gegl-0.7
+
+# you only need to change the following if you want to change where the
+# generated tarball gets scp'd to:
+
+SCP_DESTINATION=pug.vpn:tmp
+
+BINARY=$(shell basename `pwd`)#
+PACKAGE=../$(BINARY).tar.bz2 # you can use both .gz and .bz2 as extension here
+
+CFLAGS=-Wall 
+LIBS = -rdynamic
+
+
+##
+# end of template configuration.
+#
+
+# This makefile uses the current directory as the only target binary, and
+# expects a single of the .c files to contain a main function.
+
+
+
+all: $(BINARY)
+
+# The help available also contains brief information about the different
+# build rules supported.
+help: 
+       @echo ''
+       @echo 'Available targets in this make system'
+       @echo ''
+       @echo '  (none)   builds $(BINARY)'
+       @echo '  dist     create $(PACKAGE)'
+       @echo '  clean    rm *.o *~ and foo and bar'
+       @echo '  run      ./$(BINARY)'
+       @echo '  gdb      gdb ./$(BINARY)'
+       @echo '  gdb2     gdb ./$(BINARY) --g-fatal-warnings'
+       @echo '  scp      scp $(PACKAGE) $(SCP_DESTINATION)'
+       @echo '  help     this help'
+       @echo ''
+
+
+LIBS+= $(shell pkg-config --libs $(PKGMODULES) | sed -e 's/-Wl,\-\-export\-dynamic//')
+INCS= $(shell pkg-config --cflags $(PKGMODULES))
+
+CFILES  = $(wildcard *.c)
+OBJECTS = $(subst ./,,$(CFILES:.c=.o))
+HFILES  = $(wildcard *.h)
+%.o: %.c $(HFILES)
+       $(CC) -g $(CFLAGS) $(INCS) -c $< -o$@
+$(BINARY): $(OBJECTS)
+       $(CC) -o $@ $(OBJECTS) $(LIBS)
+
+#$(BINARY): $(CFILES)
+#      $(LD) $(CFLAGS) $(INCS) $(CFILES) $(LIBS) -o $@
+test: run
+run: $(BINARY)
+       ./$(BINARY)
+
+../$(BINARY).tar.gz: clean $(CFILES) $(HFILES)
+       cd ..;tar czvhf $(BINARY).tar.gz $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.gz
+../$(BINARY).tar.bz2: clean $(CFILES) $(HFILES)
+       cd ..;tar cjvhf $(BINARY).tar.bz2 $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.bz2
+
+dist: $(PACKAGE) 
+       echo $(PACKAGE) 
+scp: dist
+       scp $(PACKAGE) $(SCP_DESTINATION)
+
+gdb: all
+       gdb --args ./$(BINARY)
+gdb2: all
+       gdb --args ./$(BINARY) -demo --g-fatal-warnings
+clean:
+       rm -fvr *.o $(BINARY) *~ *.patch 
diff --git a/attic/gcr/README b/attic/gcr/README
new file mode 100644 (file)
index 0000000..4843649
--- /dev/null
@@ -0,0 +1,28 @@
+gcr - gegl clutter recorder
+===========================
+
+A setup to use interface Clutter with a worker thread using ffmpeg to
+encode a Clutter program to video in realtime using GEGL.
+
+This screen recorder has not been written for casual recordings, it requires
+you to modify the source of the program you want to record.
+
+The easiest way to integrate gcr in your project is to add a call to:
+
+gcr_prepare ("/tmp/path_to_output.mpg");  /* to prepare for recording */
+
+gcr_start (); /* to start recording */
+
+
+gcr_stop ();  /* to stop recording (currently not implemented, just quit your
+                 application instead) */
+
+The workflow I've been using is to encode to mpeg with high bitrate (hardcoded
+in the .c file), and then afterwards transcode this to Theora or some other
+codec suitable for distribution.
+
+The includes test example links with clutter-gegl, and also includes a custom
+cursor code.
+
+
+/Øyvind K.
diff --git a/attic/gcr/custom-cursor.c b/attic/gcr/custom-cursor.c
new file mode 100644 (file)
index 0000000..dfda6e7
--- /dev/null
@@ -0,0 +1,392 @@
+#include <clutter/clutter.h>
+#include "custom-cursor.h"
+#include <cogl/cogl.h>
+#include <string.h>
+
+G_DEFINE_TYPE (CustomCursor, custom_cursor, CLUTTER_TYPE_ACTOR);
+
+enum
+{
+  PROP_0,
+  PROP_NORMAL,
+  PROP_PRESSED,
+  PROP_HOT_X,
+  PROP_HOT_Y
+};
+
+
+#define CUSTOM_CURSOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CUSTOM_TYPE_CURSOR, CustomCursorPrivate))
+
+
+typedef struct
+{
+  gint            id;
+  gint            x;
+  gint            y;
+  gint            pressed;
+  CustomCursorState state;
+} DeviceInfo;
+
+#define MAX_DEVICES 40
+
+struct _CustomCursorPrivate
+{
+  gint          hot_x;
+  gint          hot_y;
+
+  ClutterActor *normal;
+  ClutterActor *pressed;
+
+  DeviceInfo    device[MAX_DEVICES];
+  gint          device_count;
+};
+
+static void
+custom_cursor_allocate (ClutterActor          *self,
+                      const ClutterActorBox *box,
+                      gboolean               origin_changed)
+{
+  CustomCursorPrivate *priv = CUSTOM_CURSOR (self)->priv;
+
+  /* chain up to set actor->allocation */
+  CLUTTER_ACTOR_CLASS (custom_cursor_parent_class)->allocate (self, box,
+                                                            origin_changed);
+
+  /* Make sure children also get there allocations */
+  if (priv->normal)
+    clutter_actor_allocate_preferred_size (priv->normal, origin_changed);
+
+  if (priv->pressed)
+    clutter_actor_allocate_preferred_size (priv->pressed, origin_changed);
+
+}
+
+
+static void
+custom_cursor_set_property (GObject      *object,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  CustomCursor        *cursor;
+  CustomCursorPrivate *priv;
+
+  cursor = CUSTOM_CURSOR(object);
+  priv = cursor->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_HOT_X:
+      priv->hot_x = g_value_get_int (value);
+      break;
+    case PROP_HOT_Y:
+      priv->hot_y = g_value_get_int (value);
+      break;
+    case PROP_NORMAL:
+      if (priv->normal)
+        g_object_unref (priv->normal);
+      priv->normal = g_value_dup_object (value);
+      clutter_actor_set_parent (priv->normal, CLUTTER_ACTOR (cursor));
+      break;
+    case PROP_PRESSED:
+      if (priv->pressed)
+        g_object_unref (priv->pressed);
+      priv->pressed = g_value_dup_object (value);
+      clutter_actor_set_parent (priv->pressed, CLUTTER_ACTOR (cursor));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (cursor));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+custom_cursor_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  CustomCursorPrivate *priv = CUSTOM_CURSOR (object)->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_HOT_X:
+      g_value_set_int (value, priv->hot_x);
+      break;
+    case PROP_HOT_Y:
+      g_value_set_int (value, priv->hot_y);
+      break;
+    case PROP_NORMAL:
+      g_value_set_object (value, priv->normal);
+      break;
+    case PROP_PRESSED:
+      g_value_set_object (value, priv->pressed);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    } 
+}
+
+static void
+custom_cursor_pick (ClutterActor       *self,
+                  const ClutterColor *color)
+{
+  /* The cursor is not pickable at all 
+   */
+}
+
+static void
+custom_cursor_paint (ClutterActor       *self)
+{
+  CustomCursorPrivate *priv = CUSTOM_CURSOR (self)->priv;
+  gint no;
+
+
+  for (no=0; no<priv->device_count; no++)
+    {
+      cogl_push_matrix ();
+
+      cogl_translate (priv->device[no].x, priv->device[no].y, 0);
+      cogl_translate (-priv->hot_x, -priv->hot_y, 0);
+
+      switch (priv->device[no].state)
+        {
+          case CUSTOM_CURSOR_NORMAL:
+            if (priv->normal)
+              clutter_actor_paint (priv->normal);
+            else
+              {
+#define LENGTH 30
+#define GAP 15
+                cogl_color (&((ClutterColor){0x00, 0x00, 0x00, 0x77}));
+                cogl_rectangle (-LENGTH-GAP, -2, LENGTH, 4);
+                cogl_rectangle (GAP, -2, LENGTH, 4);
+                cogl_rectangle (-2, -LENGTH-GAP, 4, LENGTH);
+                cogl_rectangle (-2, GAP, 4, LENGTH);
+
+                cogl_color (&((ClutterColor){0xff, 0xff, 0xff, 0xaa}));
+                cogl_rectangle (-LENGTH-GAP, -1, LENGTH, 2);
+                cogl_rectangle (GAP, -1, LENGTH, 2);
+                cogl_rectangle (-1, -LENGTH-GAP, 2, LENGTH);
+                cogl_rectangle (-1, GAP, 2, LENGTH);
+            }
+            break;
+          case CUSTOM_CURSOR_PRESSED:
+            if (priv->pressed)
+              clutter_actor_paint (priv->pressed);
+            else
+              {
+                cogl_color (&((ClutterColor){0xff, 0xff, 0xff, 0x77}));
+                cogl_path_ellipse (0, 0, CLUTTER_UNITS_FROM_INT (52),
+                                         CLUTTER_UNITS_FROM_INT (52));
+                cogl_path_arc (0, 0, CLUTTER_UNITS_FROM_INT (38),
+                                     CLUTTER_UNITS_FROM_INT (38),
+                                     0, 1027);
+                cogl_path_fill ();
+
+                cogl_color (&((ClutterColor){0x45, 0x66, 0xff, 0x55}));
+                cogl_path_ellipse (0, 0, CLUTTER_UNITS_FROM_INT (50),
+                                         CLUTTER_UNITS_FROM_INT (50));
+                cogl_path_arc (0, 0, CLUTTER_UNITS_FROM_INT (40),
+                                     CLUTTER_UNITS_FROM_INT (40),
+                                     0, 1027);
+                cogl_path_fill ();
+              }
+        }
+      cogl_pop_matrix ();
+    }
+}
+
+
+
+static void
+custom_cursor_class_init (CustomCursorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  gobject_class->set_property = custom_cursor_set_property;
+  gobject_class->get_property = custom_cursor_get_property;
+  actor_class->pick = custom_cursor_pick;
+  actor_class->paint = custom_cursor_paint;
+  actor_class->allocate = custom_cursor_allocate;
+
+  g_type_class_add_private (gobject_class, sizeof (CustomCursorPrivate));
+
+#define PARAM_FLAGS (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |\
+                     G_PARAM_STATIC_BLURB |                     \
+                     G_PARAM_READABLE | G_PARAM_WRITABLE)
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_HOT_X,
+                                   g_param_spec_int ("hot-x",
+                                                     "hot-Y",
+                                                     "x coordinate of cursor tip",
+                                                     0, G_MAXINT,
+                                                     0,
+                                                     PARAM_FLAGS));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_HOT_Y,
+                                   g_param_spec_int ("hot-y",
+                                                     "hot Y",
+                                                     "Y coordinate of cursor tip",
+                                                     0, G_MAXINT,
+                                                     0,
+                                                     PARAM_FLAGS));
+
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_NORMAL,
+                                   g_param_spec_object ("normal",
+                                                     "Normal",
+                                                     "Actor to show when moving the mouse around",
+                                                     CLUTTER_TYPE_ACTOR,
+                                                     PARAM_FLAGS));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_PRESSED,
+                                   g_param_spec_object ("pressed",
+                                                     "Pressed",
+                                                     "Actor to show when a mouse button is pressed",
+                                                     CLUTTER_TYPE_ACTOR,
+                                                     PARAM_FLAGS));
+
+#undef PARAM_FLAGS
+}
+
+static void
+custom_cursor_init (CustomCursor *self)
+{
+  CustomCursorPrivate *priv;
+
+  self->priv = priv = CUSTOM_CURSOR_GET_PRIVATE (self);
+
+  priv->normal = NULL;
+  priv->pressed = NULL;
+  priv->hot_x = 0;
+  priv->hot_y = 0;
+  priv->device_count = 0;
+}
+
+static gint
+get_device_no (CustomCursorPrivate *priv,
+               gint device_id)
+{
+  gint i;
+  for (i=0; i<priv->device_count; i++)
+    {
+      if (priv->device[i].id == device_id)
+          return i;
+    }
+  g_assert (priv->device_count+1 < MAX_DEVICES);
+  priv->device[priv->device_count].id = device_id;
+  priv->device_count++;
+  return priv->device_count-1;
+}
+
+static gboolean soft_cursor_capture (ClutterActor *stage,
+                                     ClutterEvent *event,
+                                     gpointer      data)
+{
+  CustomCursor        *self = CUSTOM_CURSOR (data);
+  CustomCursorPrivate *priv = self->priv;
+
+  switch (clutter_event_type (event))
+    {
+      case CLUTTER_MOTION:
+      case CLUTTER_BUTTON_PRESS:
+      case CLUTTER_BUTTON_RELEASE:
+        {
+          gint x, y;
+          gint id = clutter_event_get_device_id (event);
+          gint no = get_device_no (priv, id);
+          clutter_event_get_coords (event, &x, &y);
+
+#if 0
+          gchar c;
+
+          switch (clutter_event_type (event))
+            {
+              case CLUTTER_MOTION:
+                c = 'm';
+                break;
+              case CLUTTER_BUTTON_PRESS:
+                c = 'p';
+                break;
+              case CLUTTER_BUTTON_RELEASE:
+                c = 'r';
+                break;
+              default:
+                c = '?';
+            }
+  
+          g_print ("%c%c%c%c %i,%i\n", 
+              id!=0?' ':c,
+              id!=1?' ':c,
+              id!=2?' ':c,
+              id!=3?' ':c, 
+              id!=4?' ':c, 
+              x, y);
+#endif
+          
+          if (clutter_event_type (event) == CLUTTER_BUTTON_PRESS)
+            {
+              priv->device[no].state = CUSTOM_CURSOR_PRESSED;
+            }
+          else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE)
+            {
+              priv->device[no].state = CUSTOM_CURSOR_NORMAL;
+            }
+          custom_cursor (x,y, id);
+        }
+      default:
+        break;
+    }
+  return FALSE;
+}
+
+/* always returns the same cursor */
+ClutterActor *
+custom_cursor (gint x,
+             gint y,
+             gint device_id)
+{
+  static ClutterActor *cursor = NULL;
+  CustomCursorPrivate *priv;
+
+  if (!cursor)
+    {
+      ClutterActor *stage = clutter_stage_get_default ();
+      cursor = g_object_new (CUSTOM_TYPE_CURSOR, NULL);
+
+/*if(0)      clutter_x11_enable_xinput ();*/
+      priv = CUSTOM_CURSOR (cursor)->priv;
+      priv->device_count = 0;
+
+      clutter_container_add_actor (CLUTTER_CONTAINER (stage), cursor);
+      clutter_actor_show (cursor);
+      g_signal_connect (stage, "captured-event",
+                        G_CALLBACK (soft_cursor_capture), cursor);
+      if(0)clutter_stage_hide_cursor (CLUTTER_STAGE (stage));
+    }
+  else
+    {
+      priv = CUSTOM_CURSOR (cursor)->priv;
+    }
+
+  {
+    gint no = get_device_no (priv, device_id);
+    priv->device[no].x = x;
+    priv->device[no].y = y;
+  }
+
+  clutter_actor_queue_redraw (cursor);
+  clutter_actor_raise_top (cursor);
+  return cursor;
+}
+
+
+
diff --git a/attic/gcr/custom-cursor.h b/attic/gcr/custom-cursor.h
new file mode 100644 (file)
index 0000000..f40f830
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * CustomCursor.
+ *
+ * Copyright (C) 2008 OpenedHand, authored by Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CUSTOM_CURSOR_H__
+#define __CUSTOM_CURSOR_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-actor.h>
+
+
+G_BEGIN_DECLS
+
+#define CUSTOM_TYPE_CURSOR              (custom_cursor_get_type ())
+#define CUSTOM_CURSOR(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), CUSTOM_TYPE_CURSOR, CustomCursor))
+#define CUSTOM_CURSORCLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), CUSTOM_TYPE_CURSOR, CustomCursorClass))
+#define CLUTTER_IS_CAIRO(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CUSTOM_TYPE_CURSOR))
+#define CLUTTER_IS_CAIRO_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), CUSTOM_TYPE_CURSOR))
+#define CUSTOM_CURSORGET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), CUSTOM_TYPE_CURSOR, CustomCursorClass))
+
+typedef struct _CustomCursor            CustomCursor;
+typedef struct _CustomCursorClass       CustomCursorClass;
+typedef struct _CustomCursorPrivate     CustomCursorPrivate;
+
+typedef enum {
+  CUSTOM_CURSOR_NORMAL,
+  CUSTOM_CURSOR_PRESSED
+}CustomCursorState;
+
+struct _CustomCursor
+{
+  ClutterActor       parent;
+  CustomCursorPrivate  *priv;
+};
+
+struct _CustomCursorClass 
+{
+  /*< private >*/
+  ClutterActorClass parent_class;
+
+  void (*_custom_cursor_1) (void);
+  void (*_custom_cursor_2) (void);
+  void (*_custom_cursor_3) (void);
+  void (*_custom_cursor_4) (void);
+}; 
+
+GType  custom_cursor_get_type (void) G_GNUC_CONST;
+
+
+/* update positional data for cursor, first call to this function enables custom cursors,
+ * subsequent calls will update the position of the given device_id (needs to be called
+ * during pointer grabs) */
+
+ClutterActor * custom_cursor (gint x,
+                              gint y,
+                              gint device_id);
+
+G_END_DECLS
+
+#endif /* __CUSTOM_CURSORH__ */
diff --git a/attic/gcr/gcr.c b/attic/gcr/gcr.c
new file mode 100644 (file)
index 0000000..68888e3
--- /dev/null
@@ -0,0 +1,206 @@
+/* Minimal screencast recorder for clutter (GL) using GEGL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2008 Øyvind Kolås
+ * Copyright (C) 2008 OpenedHand
+ */
+
+#include <gegl.h>
+#include <clutter/clutter.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <string.h>
+
+/* some basic configuration */
+#define FPS 25
+#define KBITRATE (7000*8)  
+
+/* TODO: Move away from pixbufs, the original code used a pixbuf but
+ * with newer GEGL it should be better to use a linear buffer directly
+ */
+
+static GThread      *encode_thread   = NULL;
+static GStaticMutex  mutex           = G_STATIC_MUTEX_INIT;
+static gint          prev_width      = 0;
+static gint          prev_height     = 0;
+static gint          frames          = 0;
+static guchar       *pixels          = NULL;
+static guchar       *pixels_inverted = NULL;
+static gboolean      got_data        = FALSE;
+static GdkPixbuf    *pixbuf          = NULL;
+static GeglNode     *gegl            = NULL;
+static GeglNode     *load_pixbuf     = NULL;
+static GeglNode     *ff_save;
+static long          prev_stored     = 0;
+
+static gpointer encoder (gpointer data);
+static void save_frame  (gpointer data);
+
+long babl_ticks (void);
+
+void gcr_prepare (const gchar *path)
+{
+  if (!g_thread_supported ()) g_thread_init (NULL);
+
+  gegl_init (NULL, NULL);
+  gegl = gegl_node_new ();
+
+  ff_save = gegl_node_new_child (gegl,
+     "operation", "ff-save",
+     "bitrate",   KBITRATE *1000.0,
+     "fps",       (FPS * 1.0),
+     "path",      path,
+     NULL
+    );
+  load_pixbuf = gegl_node_create_child (gegl, "pixbuf");
+  gegl_node_link (load_pixbuf, ff_save);
+}
+
+void gcr_start (void)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+
+  g_signal_connect_after (stage, "paint", G_CALLBACK (save_frame), NULL);
+
+  encode_thread = g_thread_create (encoder, NULL, FALSE, NULL);
+
+  prev_stored = babl_ticks ();
+}
+
+void gcr_stop (void)
+{
+  /* FIXME: NYI */
+}
+
+/* this is called by clutter each time a stage has been rendered */
+static void save_frame (gpointer data)
+{
+
+  GLint      viewport[4];
+  gint       x, y, width, height;
+  glong      delta;
+
+  /* issue commands that might make sure we're fully rendered ... */
+  glFinish ();
+  glFlush ();
+
+  glGetIntegerv(GL_VIEWPORT, viewport);
+  x         = viewport[0]; 
+  y         = viewport[1]; 
+  width     = viewport[2] - x;
+  height    = viewport[3] - y;
+
+  /* by locking here we wait until the encoder thread is finished encoding */
+  g_static_mutex_lock (&mutex);
+
+  /* we only create the pixbuf on the first frame (hopefully) */
+
+  if (prev_width  != width ||
+      prev_height != height)
+    {
+      if (pixels)
+        g_free (pixels);
+      if (pixels_inverted)
+        g_free (pixels_inverted);
+      if (pixbuf)
+        g_object_unref (pixbuf);
+      pixels_inverted = g_malloc (width * height * 4);
+      pixels = g_malloc (width * height * 4);
+
+      pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
+                                         width, height, width * 4, NULL, NULL);
+
+      prev_width = width;
+      prev_height = height;
+    }
+
+  /* figure out the time elapsed since the previously stored encoded frame */
+  delta = babl_ticks () - prev_stored;
+
+  if (got_data == FALSE && delta >= 1000000.0/FPS)
+    {
+      prev_stored += delta;
+      glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels_inverted);
+      /* we only do the read pixels here, the encoder thread does the
+       * inversion
+       */
+      got_data = TRUE;
+
+      frames = delta / (1000000.0/FPS);
+      /* FIXME: * precision loss, we need to keep a remainder around to produce
+       * the correct framerate */
+    }
+  g_static_mutex_unlock (&mutex);
+}
+
+static gpointer encoder (gpointer data)
+{
+  while (TRUE)
+    {
+      gint rowstride;
+      gint width, height;
+      gint repeats = 0;
+
+      gboolean action = FALSE;
+
+      /* critical section */
+      g_static_mutex_lock (&mutex);
+      if (got_data)
+        {
+          gint y;
+          height = prev_height;
+          width = prev_width;
+          rowstride = prev_width * 4;
+
+          /* flip the image right side up when copying it */
+          for (y=0; y<height; y++)
+            {
+              memcpy (pixels + ((height-y-1) * rowstride),
+                      pixels_inverted + y * rowstride, rowstride);
+            }
+          got_data = FALSE;
+          action = TRUE;  /* store that we've got work to do */
+          repeats = frames;
+        }
+      g_static_mutex_unlock (&mutex);
+
+      if (action)
+        {
+          static     gint dump_no = -1;
+
+          if (dump_no<=0)
+            {
+              dump_no++;
+            }
+          else
+            {
+              /* encode the current frame for the number of frames
+               * that is needed
+               */
+              while (repeats--)
+                {
+                  gegl_node_set (load_pixbuf, "pixbuf", pixbuf, NULL);
+                  gegl_node_process (ff_save);
+                }
+            }
+        }
+      else
+        {
+          g_usleep (100);
+        }
+    }
+}
diff --git a/attic/gcr/gcr.h b/attic/gcr/gcr.h
new file mode 100644 (file)
index 0000000..a0f56e8
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __GCR_H__
+#define __GCR_H__
+#include <clutter/clutter.h>
+
+/* this needs to be called before clutter_main()  */
+void gcr_prepare (const gchar *path);
+void gcr_start   (void);
+void gcr_stop    (void);
+
+#endif
diff --git a/attic/gcr/test.c b/attic/gcr/test.c
new file mode 100644 (file)
index 0000000..95f3490
--- /dev/null
@@ -0,0 +1,27 @@
+#include <clutter/clutter.h>
+
+#include "custom-cursor.h"
+
+#include "gcr.h"
+
+
+gint
+main (int   argc,
+      char *argv[])
+{
+  ClutterActor *stage;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+
+  custom_cursor (0, 0, 0);
+
+  gcr_prepare ("/tmp/test.mpg");
+  clutter_actor_show (stage);
+  gcr_start ();
+  clutter_main ();
+  gcr_stop ();
+
+  return 0;
+}
diff --git a/attic/mallums-magic-browser/Makefile b/attic/mallums-magic-browser/Makefile
new file mode 100644 (file)
index 0000000..875a5dd
--- /dev/null
@@ -0,0 +1,86 @@
+# A generic buildfiles to build single executable directory projects depending
+# only on pkg-config ability to build. It automatically names the project on
+# the toplevel directory you're in.
+#
+# Setting additional CFLAGS like $ export CFLAGS=-Wall -Werror # can help you
+# track issues down better after compilation.
+#
+# 20071008
+# Øyvind Kolås (c) 2007 <pippin@gimp.org>  placed in the Public Domain.
+##
+
+PKGMODULES = tidy-1.0 clutter-0.8 webkit-clutter-1.0
+
+# you only need to change the following if you want to change where the
+# generated tarball gets scp'd to:
+
+SCP_DESTINATION=pug.vpn:tmp
+
+BINARY=$(shell basename `pwd`)#
+PACKAGE=../$(BINARY).tar.bz2 # you can use both .gz and .bz2 as extension here
+
+
+##
+# end of template configuration.
+#
+
+# This makefile uses the current directory as the only target binary, and
+# expects a single of the .c files to contain a main function.
+
+
+
+all: $(BINARY)
+
+# The help available also contains brief information about the different
+# build rules supported.
+help: 
+       @echo ''
+       @echo 'Available targets in this make system'
+       @echo ''
+       @echo '  (none)   builds $(BINARY)'
+       @echo '  dist     create $(PACKAGE)'
+       @echo '  clean    rm *.o *~ and foo and bar'
+       @echo '  run      ./$(BINARY)'
+       @echo '  gdb      gdb ./$(BINARY)'
+       @echo '  gdb2     gdb ./$(BINARY) --g-fatal-warnings'
+       @echo '  scp      scp $(PACKAGE) $(SCP_DESTINATION)'
+       @echo '  help     this help'
+       @echo ''
+
+
+LIBS= $(shell pkg-config --libs $(PKGMODULES) | sed -e 's/-Wl,\-\-export\-dynamic//')
+INCS= $(shell pkg-config --cflags $(PKGMODULES))
+
+
+CFILES  = $(wildcard *.c)
+OBJECTS = $(subst ./,,$(CFILES:.c=.o))
+HFILES  = $(wildcard *.h)
+%.o: %.c $(HFILES)
+       $(CC) -g $(CFLAGS) $(INCS) -c $< -o$@
+$(BINARY): $(OBJECTS)
+       $(CC) -o $@ $(OBJECTS) $(LIBS)
+
+#$(BINARY): $(CFILES)
+#      $(LD) $(CFLAGS) $(INCS) $(CFILES) $(LIBS) -o $@
+test: run
+run: $(BINARY)
+       ./$(BINARY)
+
+../$(BINARY).tar.gz: clean $(CFILES) $(HFILES)
+       cd ..;tar czvhf $(BINARY).tar.gz $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.gz
+../$(BINARY).tar.bz2: clean $(CFILES) $(HFILES)
+       cd ..;tar cjvhf $(BINARY).tar.bz2 $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.bz2
+
+dist: $(PACKAGE) 
+       echo $(PACKAGE) 
+scp: dist
+       scp $(PACKAGE) $(SCP_DESTINATION)
+
+gdb: all
+       gdb --args ./$(BINARY)
+gdb2: all
+       gdb --args ./$(BINARY) -demo --g-fatal-warnings
+clean:
+       rm -fvr *.o $(BINARY) *~ *.patch
diff --git a/attic/mallums-magic-browser/README-mozilla b/attic/mallums-magic-browser/README-mozilla
new file mode 100644 (file)
index 0000000..a033441
--- /dev/null
@@ -0,0 +1,16 @@
+Notes on building the mozilla version:
+
+The mozilla version of mallums-magic-browser requires mozilla built with the
+headless backend and ClutterMozEmbed;
+
+git://git.o-hand.com/mozilla-headless.git
+git://git.clutter-project.org/clutter-mozembed.git
+
+It also builds against clutter 0.9 instead of 0.8.
+
+To build, you'll want a line something along the lines of;
+
+gcc -o web-browser-mallum web-browser-mallum.c -Wall -g `pkg-config --cflags --libs cluttermozembed` -DWITH_MOZILLA
+
+Which should then produce a binary 'web-browser-mallum'. Note that the  port
+to Clutter 0.9 was mmade in a rush, so some animations may not be correct.
diff --git a/attic/mallums-magic-browser/assets/back.png b/attic/mallums-magic-browser/assets/back.png
new file mode 100755 (executable)
index 0000000..a7617db
Binary files /dev/null and b/attic/mallums-magic-browser/assets/back.png differ
diff --git a/attic/mallums-magic-browser/assets/bground.png b/attic/mallums-magic-browser/assets/bground.png
new file mode 100755 (executable)
index 0000000..0d5b4c3
Binary files /dev/null and b/attic/mallums-magic-browser/assets/bground.png differ
diff --git a/attic/mallums-magic-browser/assets/document-new.png b/attic/mallums-magic-browser/assets/document-new.png
new file mode 100644 (file)
index 0000000..e6d64bb
Binary files /dev/null and b/attic/mallums-magic-browser/assets/document-new.png differ
diff --git a/attic/mallums-magic-browser/assets/forward.png b/attic/mallums-magic-browser/assets/forward.png
new file mode 100755 (executable)
index 0000000..266200d
Binary files /dev/null and b/attic/mallums-magic-browser/assets/forward.png differ
diff --git a/attic/mallums-magic-browser/assets/go-next.png b/attic/mallums-magic-browser/assets/go-next.png
new file mode 100644 (file)
index 0000000..036e432
Binary files /dev/null and b/attic/mallums-magic-browser/assets/go-next.png differ
diff --git a/attic/mallums-magic-browser/assets/go-previous.png b/attic/mallums-magic-browser/assets/go-previous.png
new file mode 100644 (file)
index 0000000..895ce33
Binary files /dev/null and b/attic/mallums-magic-browser/assets/go-previous.png differ
diff --git a/attic/mallums-magic-browser/assets/tabs.png b/attic/mallums-magic-browser/assets/tabs.png
new file mode 100755 (executable)
index 0000000..f872e21
Binary files /dev/null and b/attic/mallums-magic-browser/assets/tabs.png differ
diff --git a/attic/mallums-magic-browser/assets/toolbar-bg.png b/attic/mallums-magic-browser/assets/toolbar-bg.png
new file mode 100644 (file)
index 0000000..21fbd7d
Binary files /dev/null and b/attic/mallums-magic-browser/assets/toolbar-bg.png differ
diff --git a/attic/mallums-magic-browser/popup-factory.c b/attic/mallums-magic-browser/popup-factory.c
new file mode 100644 (file)
index 0000000..985416d
--- /dev/null
@@ -0,0 +1,118 @@
+#include <webkit/webkitpopupfactory.h>
+
+#include <clutter/clutter.h>
+#include "popup-factory.h"
+
+static void popup_factory_iface_init (WebKitPopupFactoryInterface *iface);
+
+enum {
+  NAME_COLUMN,
+  LAST_COLUMN
+};
+
+enum {
+  SHOW_MENU,
+  HIDE_MENU,
+  LAST_SIGNAL
+};
+
+G_DEFINE_TYPE_WITH_CODE (PopupFactory, popup_factory, TIDY_TYPE_LIST_VIEW,
+                        G_IMPLEMENT_INTERFACE (WEBKIT_TYPE_POPUP_FACTORY,
+                                               popup_factory_iface_init));
+#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), POPUP_TYPE_FACTORY, PopupFactoryPrivate))
+
+struct _PopupFactoryPrivate
+{
+  ClutterModel *model;
+};
+
+static guint32 signals[LAST_SIGNAL] = {0, };
+
+static void
+popup_factory_class_init (PopupFactoryClass *klass)
+{
+  g_type_class_add_private (klass, sizeof (PopupFactoryPrivate));
+
+  signals[SHOW_MENU] = g_signal_new ("show-menu",
+                                    G_TYPE_FROM_CLASS (klass),
+                                    G_SIGNAL_NO_RECURSE | 
+                                    G_SIGNAL_RUN_LAST,
+                                    G_STRUCT_OFFSET ( PopupFactoryClass,
+                                                     show_menu),
+                                    NULL, NULL,
+                                    g_cclosure_marshal_VOID__VOID,
+                                    G_TYPE_NONE, 0);
+  
+  signals[HIDE_MENU] = g_signal_new ("hide-menu",
+                                    G_TYPE_FROM_CLASS (klass),
+                                    G_SIGNAL_NO_RECURSE | 
+                                    G_SIGNAL_RUN_LAST,
+                                    G_STRUCT_OFFSET ( PopupFactoryClass,
+                                                     hide_menu),
+                                    NULL, NULL,
+                                    g_cclosure_marshal_VOID__VOID,
+                                    G_TYPE_NONE, 0);
+}
+
+static void
+popup_factory_init (PopupFactory *factory)
+{
+  PopupFactoryPrivate *priv = factory->priv = GET_PRIVATE (factory);
+  
+  priv->model = clutter_list_model_new (LAST_COLUMN, G_TYPE_STRING, "name");
+  g_object_set (G_OBJECT (factory),
+               "model", priv->model,
+               NULL);
+}
+       
+static void
+factory_clear (WebKitPopupFactory *factory)
+{
+  PopupFactoryPrivate *priv = POPUP_FACTORY (factory)->priv;
+
+  if (priv->model) {
+    g_object_unref (priv->model);
+  }
+
+  priv->model = clutter_list_model_new (LAST_COLUMN, G_TYPE_STRING, "name");
+}
+
+static void
+factory_append_separator (WebKitPopupFactory *factory)
+{
+}
+
+static void
+factory_append_item (WebKitPopupFactory *factory,
+                    const char         *text)
+{
+  PopupFactoryPrivate *priv = POPUP_FACTORY (factory)->priv;
+
+  clutter_model_append (priv->model, NAME_COLUMN, text, -1);
+}
+
+static void
+factory_show (WebKitPopupFactory *factory, int index)
+{
+  PopupFactoryPrivate *priv = POPUP_FACTORY (factory)->priv;
+  
+  tidy_list_view_set_model (TIDY_LIST_VIEW (factory), priv->model);
+  g_signal_emit (factory, signals[SHOW_MENU], 0);
+}
+
+static void
+factory_hide (WebKitPopupFactory *factory)
+{
+  g_signal_emit (factory, signals[HIDE_MENU], 0);
+  tidy_list_view_set_model (TIDY_LIST_VIEW (factory), NULL);
+}
+
+static void
+popup_factory_iface_init (WebKitPopupFactoryInterface *iface)
+{
+  iface->clear = factory_clear;
+  iface->append_separator = factory_append_separator;
+  iface->append_item = factory_append_item;
+  iface->show = factory_show;
+  iface->hide = factory_hide;
+}
diff --git a/attic/mallums-magic-browser/popup-factory.h b/attic/mallums-magic-browser/popup-factory.h
new file mode 100644 (file)
index 0000000..0ec3d41
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _POPUP_FACTORY
+#define _POPUP_FACTORY
+
+#include <tidy/tidy-list-view.h>
+
+G_BEGIN_DECLS
+
+#define POPUP_TYPE_FACTORY (popup_factory_get_type ())
+
+typedef struct _PopupFactoryPrivate PopupFactoryPrivate;
+
+#define POPUP_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POPUP_TYPE_FACTORY, PopupFactory))
+
+typedef struct {
+  TidyListView parent;
+
+  PopupFactoryPrivate *priv;
+} PopupFactory;
+
+typedef struct {
+  TidyListViewClass parent_class;
+  
+  void (*show_menu) (PopupFactory *factory);
+  void (*hide_menu) (PopupFactory *factory);
+} PopupFactoryClass;
+
+GType popup_factory_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/mallums-magic-browser/scroll-frame.c b/attic/mallums-magic-browser/scroll-frame.c
new file mode 100644 (file)
index 0000000..27ac97a
--- /dev/null
@@ -0,0 +1,362 @@
+#include <tidy/tidy.h>
+
+#include "scroll-frame.h"
+
+static void scrollable_iface_init (TidyScrollableInterface *iface);
+
+static void scrollable_set_adjustments (TidyScrollable *scrollable,
+                                       TidyAdjustment *hadjustment,
+                                       TidyAdjustment *vadjustment);
+static void scrollable_get_adjustments (TidyScrollable  *scrollable,
+                                       TidyAdjustment **hadjustment,
+                                       TidyAdjustment **vadjustment);
+
+enum {
+  PROP_0,
+  PROP_HADJUST,
+  PROP_VADJUST
+};
+
+G_DEFINE_TYPE_WITH_CODE (ScrollFrame, scroll_frame, TIDY_TYPE_FRAME,
+                        G_IMPLEMENT_INTERFACE (TIDY_TYPE_SCROLLABLE,
+                                               scrollable_iface_init));
+#define FRAME_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), SCROLL_TYPE_FRAME, ScrollFramePrivate))
+
+struct _ScrollFramePrivate {
+  TidyAdjustment *hadj;
+  TidyAdjustment *vadj;
+  
+  WebkitAdjustment *wk_hadj;
+  WebkitAdjustment *wk_vadj;
+  
+  guint           hadj_idle;
+  gdouble         hadj_value;
+
+  guint           vadj_idle;
+  gdouble         vadj_value;  
+};
+
+static void
+scroll_frame_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (scroll_frame_parent_class)->finalize (object);
+}
+
+static void
+scroll_frame_dispose (GObject *object)
+{
+  ScrollFramePrivate *priv = SCROLL_FRAME (object)->priv;
+  
+  if (priv->hadj_idle) {
+    g_source_remove (priv->hadj_idle);
+    priv->hadj_idle = 0;
+  }
+
+  if (priv->vadj_idle) {
+    g_source_remove (priv->vadj_idle);
+    priv->vadj_idle = 0;
+  }
+  
+  G_OBJECT_CLASS (scroll_frame_parent_class)->dispose (object);
+}
+
+static void
+scroll_frame_set_property (GObject      *object,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  ScrollFrame *frame = SCROLL_FRAME (object);
+
+  switch (prop_id) {
+  case PROP_HADJUST:
+    scrollable_set_adjustments (TIDY_SCROLLABLE (object),
+                               g_value_get_object (value),
+                               frame->priv->vadj);
+    break;
+
+  case PROP_VADJUST:
+    scrollable_set_adjustments (TIDY_SCROLLABLE (object),
+                               frame->priv->hadj,
+                               g_value_get_object (value));
+    break;
+
+  default:
+    break;
+  }
+}
+
+static void
+scroll_frame_get_property (GObject    *object,
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  ScrollFrame *frame = SCROLL_FRAME (object);
+  TidyAdjustment *adj;
+
+  switch (prop_id) {
+  case PROP_HADJUST:
+    scrollable_get_adjustments (TIDY_SCROLLABLE (object), &adj, NULL);
+    g_value_set_object (value, adj);
+    break;
+
+  case PROP_VADJUST:
+    scrollable_get_adjustments (TIDY_SCROLLABLE (object), NULL, &adj);
+    g_value_set_object (value, adj);
+    break;
+
+  default:
+    break;
+  }
+}
+
+static gboolean
+scroll_frame_button_release_event (ClutterActor       *actor,
+                                  ClutterButtonEvent *event)
+{
+  ClutterActor *child = tidy_frame_get_child (TIDY_FRAME (actor));
+
+  if (child) {
+    return clutter_actor_event (child, (ClutterEvent *) event, FALSE);
+  }
+
+  return FALSE;
+}
+
+static void
+scroll_frame_class_init (ScrollFrameClass *klass)
+{
+  GObjectClass *o_class = (GObjectClass *) klass;
+  ClutterActorClass *a_class = (ClutterActorClass *) klass;
+
+  o_class->finalize = scroll_frame_finalize;
+  o_class->dispose = scroll_frame_dispose;
+  o_class->set_property = scroll_frame_set_property;
+  o_class->get_property = scroll_frame_get_property;
+
+  a_class->button_release_event = scroll_frame_button_release_event;
+
+  g_type_class_add_private (klass, sizeof (ScrollFramePrivate));
+
+  g_object_class_override_property (o_class, PROP_HADJUST, "hadjustment");
+  g_object_class_override_property (o_class, PROP_VADJUST, "vadjustment");
+}
+
+static void
+vadj_wk_changed (WebkitAdjustment *adjustment,
+                ScrollFrame      *frame)
+{
+  ScrollFramePrivate *priv = frame->priv;
+  double value, lower, upper, step, page_inc, page_size;
+
+  webkit_adjustment_get_values (adjustment, &value, &lower, &upper,
+                               &step, &page_inc, &page_size);
+  tidy_adjustment_set_values (priv->vadj, value, lower, upper, step,
+                             page_inc, page_size);
+}
+
+static void
+vadj_wk_value_changed (WebkitAdjustment *adjustment,
+                      GParamSpec       *pspec,
+                      ScrollFrame      *frame)
+{
+  vadj_wk_changed (adjustment, frame);
+}
+
+static void
+hadj_wk_changed (WebkitAdjustment *adjustment,
+                ScrollFrame      *frame)
+{
+  ScrollFramePrivate *priv = frame->priv;
+  double value, lower, upper, step, page_inc, page_size;
+
+  webkit_adjustment_get_values (adjustment, &value, &lower, &upper,
+                               &step, &page_inc, &page_size);
+  tidy_adjustment_set_values (priv->hadj, value, lower, upper, step,
+                             page_inc, page_size);
+}
+
+static void
+hadj_wk_value_changed (WebkitAdjustment *adjustment,
+                      GParamSpec       *pspec,
+                      ScrollFrame      *frame)
+{
+  hadj_wk_changed (adjustment, frame);
+}
+
+static gboolean
+vadj_idle_cb (ScrollFrame *frame)
+{
+  ScrollFramePrivate *priv = frame->priv;
+  
+  webkit_adjustment_set_value (priv->wk_vadj, priv->vadj_value);
+  priv->vadj_idle = 0;
+  
+  return FALSE;
+}
+
+static gboolean
+hadj_idle_cb (ScrollFrame *frame)
+{
+  ScrollFramePrivate *priv = frame->priv;
+  
+  webkit_adjustment_set_value (priv->wk_hadj, priv->hadj_value);
+  priv->hadj_idle = 0;
+  
+  return FALSE;
+}
+
+static void 
+vadj_tidy_changed (TidyAdjustment *adjustment,
+                  GParamSpec     *pspec,
+                  ScrollFrame    *frame)
+{
+  ScrollFramePrivate *priv = frame->priv;
+  double value;
+
+  value = tidy_adjustment_get_value (adjustment);
+  priv->vadj_value = value;
+  if (!priv->vadj_idle)
+    priv->vadj_idle = g_idle_add_full (G_PRIORITY_DEFAULT,
+                                       (GSourceFunc)vadj_idle_cb, frame, NULL);
+}
+
+static void
+hadj_tidy_changed (TidyAdjustment *adjustment,
+                  GParamSpec     *pspec,
+                  ScrollFrame    *frame)
+{
+  ScrollFramePrivate *priv = frame->priv;
+  double value;
+
+  value = tidy_adjustment_get_value (adjustment);
+  priv->hadj_value = value;
+  if (!priv->hadj_idle)
+    priv->hadj_idle = g_idle_add_full (G_PRIORITY_DEFAULT,
+                                       (GSourceFunc)hadj_idle_cb, frame, NULL);
+}
+
+static void
+scrollable_set_adjustments (TidyScrollable *scrollable,
+                           TidyAdjustment *hadjustment,
+                           TidyAdjustment *vadjustment)
+{
+  ScrollFramePrivate *priv = SCROLL_FRAME (scrollable)->priv;
+
+  if (hadjustment != priv->hadj) {
+    if (priv->hadj) {
+      g_signal_handlers_disconnect_by_func (priv->hadj,
+                                           hadj_tidy_changed,
+                                           scrollable);
+      g_object_unref (priv->hadj);
+    }
+
+    if (hadjustment) {
+      g_object_ref (hadjustment);
+      g_signal_connect (hadjustment, "notify::value",
+                       G_CALLBACK (hadj_tidy_changed), scrollable);
+    }
+
+    priv->hadj = hadjustment;
+  }
+
+  if (vadjustment != priv->vadj) {
+    if (priv->vadj) {
+      g_signal_handlers_disconnect_by_func (priv->vadj,
+                                           vadj_tidy_changed,
+                                           scrollable);
+      g_object_unref (priv->vadj);
+    }
+
+    if (vadjustment) {
+      g_object_ref (vadjustment);
+      g_signal_connect (vadjustment, "notify::value",
+                       G_CALLBACK (vadj_tidy_changed), scrollable);
+    }
+
+    priv->vadj = vadjustment;
+  }
+}
+
+static void
+scrollable_get_adjustments (TidyScrollable  *scrollable,
+                           TidyAdjustment **hadjustment,
+                           TidyAdjustment **vadjustment)
+{
+  ScrollFramePrivate *priv = SCROLL_FRAME (scrollable)->priv;
+
+  if (hadjustment) {
+    if (priv->hadj) {
+      *hadjustment = priv->hadj;
+    } else {
+      TidyAdjustment *adjustment = tidy_adjustment_newx (0, 0, 0, 0, 0, 0);
+      double value, lower, upper, step, page_inc, page_size;
+
+      webkit_adjustment_get_values (priv->wk_hadj, &value, &lower, &upper,
+                                   &step, &page_inc, &page_size);
+      tidy_adjustment_set_values (adjustment, value, lower, upper, step,
+                                 page_inc, page_size);
+
+      scrollable_set_adjustments (scrollable, adjustment, priv->vadj);
+      *hadjustment = adjustment;
+    }
+
+    g_signal_connect (priv->wk_hadj, "notify::value",
+                     G_CALLBACK (hadj_wk_value_changed), scrollable);
+    g_signal_connect (priv->wk_hadj, "changed",
+                     G_CALLBACK (hadj_wk_changed), scrollable);
+  }
+
+  if (vadjustment) {
+    if (priv->vadj) {
+      *vadjustment = priv->vadj;
+    } else {
+      TidyAdjustment *adjustment = tidy_adjustment_newx (0, 0, 0, 0, 0, 0);
+      double value, lower, upper, step, page_inc, page_size;
+
+      webkit_adjustment_get_values (priv->wk_vadj, &value, &lower, &upper,
+                                   &step, &page_inc, &page_size);
+      tidy_adjustment_set_values (adjustment, value, lower, upper, step,
+                                 page_inc, page_size);
+
+      scrollable_set_adjustments (scrollable, priv->hadj, adjustment);
+      *vadjustment = adjustment;
+    }
+
+    g_signal_connect (priv->wk_vadj, "notify::value",
+                     G_CALLBACK (vadj_wk_value_changed), scrollable);
+    g_signal_connect (priv->wk_vadj, "changed",
+                     G_CALLBACK (vadj_wk_changed), scrollable);
+  }
+}
+      
+static void
+scrollable_iface_init (TidyScrollableInterface *iface)
+{
+  iface->set_adjustments = scrollable_set_adjustments;
+  iface->get_adjustments = scrollable_get_adjustments;
+}
+
+static void
+scroll_frame_init (ScrollFrame *frame)
+{
+  ScrollFramePrivate *priv;
+  ClutterColor bg = {0x00, 0x00, 0x00, 0x00};
+
+  priv = frame->priv = FRAME_PRIVATE (frame);
+  priv->wk_hadj = webkit_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+  priv->wk_vadj = webkit_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+}
+
+void
+scroll_frame_add_webkit (ScrollFrame   *frame,
+                        WebKitWebView *web_view)
+{
+  webkit_web_view_set_scroll_adjustments (web_view,
+                                         frame->priv->wk_hadj,
+                                         frame->priv->wk_vadj);
+  clutter_container_add_actor (CLUTTER_CONTAINER (frame), 
+                              CLUTTER_ACTOR (web_view));
+}
diff --git a/attic/mallums-magic-browser/scroll-frame.h b/attic/mallums-magic-browser/scroll-frame.h
new file mode 100644 (file)
index 0000000..6577a63
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _SCROLL_FRAME
+#define _SCROLL_FRAME
+
+#include <glib-object.h>
+#include <tidy/tidy.h>
+
+#include <webkit/webkit.h>
+
+G_BEGIN_DECLS
+
+#define SCROLL_TYPE_FRAME scroll_frame_get_type ()
+
+typedef struct _ScrollFramePrivate ScrollFramePrivate;
+
+#define SCROLL_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCROLL_TYPE_FRAME, ScrollFrame))
+
+typedef struct {
+  TidyFrame parent;
+  ScrollFramePrivate *priv;
+} ScrollFrame;
+
+typedef struct {
+  TidyFrameClass parent;
+} ScrollFrameClass;
+
+GType scroll_frame_get_type (void);
+
+void scroll_frame_add_webkit (ScrollFrame   *frame,
+                             WebKitWebView *web_view);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/mallums-magic-browser/web-browser-mozilla.c b/attic/mallums-magic-browser/web-browser-mozilla.c
new file mode 100644 (file)
index 0000000..a4ea56e
--- /dev/null
@@ -0,0 +1,952 @@
+#include <clutter/clutter.h>
+
+#include "web-browser-mozilla.h"
+
+#ifdef WITH_MOZILLA
+#  include "clutter-mozembed.h"
+#else
+#  include <tidy/tidy.h>
+#  include <webkit/webkit.h>
+#  include "scroll-frame.h"
+#  include "popup-factory.h"
+#endif
+
+static void
+tabs_cb (ClutterActor *button,
+         ClutterEvent *event,
+         MmBrowser    *browser);
+
+G_DEFINE_TYPE (MmBrowser, mm_browser, CLUTTER_TYPE_GROUP)
+#define BROWSER_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_BROWSER, MmBrowserPrivate))
+
+typedef struct _MmBrowserPage
+{
+  MmBrowser *browser;
+  ClutterActor *web;
+  ClutterActor *overlay;
+  ClutterActor *scroll;
+  ClutterActor *popup_menu;
+
+#ifndef WITH_MOZILLA
+  PopupFactory *factory;
+
+  WebKitWebView *view;
+  WebkitAdjustment *hadj, *vadj;
+#endif
+
+  char *address;
+
+  gboolean over_link;
+
+  int start_x;
+  int start_y;
+} MmBrowserPage;
+
+struct _MmBrowserPrivate
+{
+  ClutterTimeline *fade_timeline;
+  ClutterTimeline *scale_timeline;
+  ClutterTimeline *scroll_timeline;
+  ClutterTimeline *move_timeline;
+
+  ClutterActor *toolbar, *toolbar_bg;
+  ClutterActor *tab_control;
+  ClutterActor *new_tab;
+  ClutterActor *prev_tab;
+  ClutterActor *next_tab;
+
+  ClutterActor *next_prev_group;
+
+  ClutterActor *back;
+  ClutterActor *forward;
+  ClutterActor *entry;
+  ClutterActor *tabs;
+  ClutterActor *progress;
+
+  ClutterActor *page_group;
+
+  GList *pages;
+  GList *current_page;
+
+  gboolean showing_tabs;
+  gboolean maybe_scroll;
+
+  int popup_x;
+  int popup_y;
+};
+
+#define WEB_WIDTH 800
+#define WEB_HEIGHT 480
+
+#define JITTER 5
+
+static void
+mm_browser_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (mm_browser_parent_class)->finalize (object);
+}
+
+static void
+mm_browser_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (mm_browser_parent_class)->dispose (object);
+}
+
+static void
+mm_browser_class_init (MmBrowserClass *klass)
+{
+  GObjectClass *o_class = (GObjectClass *) klass;
+  ClutterActorClass *a_class = (ClutterActorClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (MmBrowserPrivate));
+
+  o_class->finalize = mm_browser_finalize;
+  o_class->dispose = mm_browser_dispose;
+}
+
+static void
+set_back_and_forward (MmBrowser *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+
+#ifdef WITH_MOZILLA
+  if (clutter_mozembed_can_go_back (CLUTTER_MOZEMBED (page->web))) {
+#else
+  if (webkit_web_view_can_go_back (page->view)) {
+#endif
+    clutter_actor_animate (priv->back, CLUTTER_LINEAR, 500,
+                           "opacity", 0xff, NULL);
+  } else {
+    clutter_actor_animate (priv->back, CLUTTER_LINEAR, 500,
+                           "opacity", 0x55, NULL);
+  }
+
+#ifdef WITH_MOZILLA
+  if (clutter_mozembed_can_go_forward (CLUTTER_MOZEMBED (page->web))) {
+#else
+  if (webkit_web_view_can_go_forward (page->view)) {
+#endif
+    clutter_actor_animate (priv->forward, CLUTTER_LINEAR, 500,
+                           "opacity", 0xff, NULL);
+  } else {
+    clutter_actor_animate (priv->forward, CLUTTER_LINEAR, 500,
+                           "opacity", 0x55, NULL);
+  }
+}
+
+static void
+load_started_cb (MmBrowser      *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  ClutterTimeline *tl;
+
+  clutter_actor_animate (priv->progress, CLUTTER_LINEAR, 500,
+                         "opacity", 0xff, NULL);
+}
+
+#ifdef WITH_MOZILLA
+static void
+load_finished_cb (MmBrowser       *browser,
+                  ClutterMozEmbed *mozembed)
+#else
+static void
+load_finished_cb (MmBrowser      *browser,
+                  WebKitWebFrame *frame,
+                  WebKitWebView  *web_view)
+#endif
+{
+  MmBrowserPrivate *priv = browser->priv;
+  const gchar *location;
+  MmBrowserPage *page;
+  ClutterTimeline *tl;
+
+  clutter_actor_animate (priv->progress, CLUTTER_LINEAR, 500,
+                         "opacity", 0x00, NULL);
+
+#ifdef WITH_MOZILLA
+  location = clutter_mozembed_get_location (mozembed);
+#else
+  location = webkit_web_frame_get_uri (frame);
+#endif
+
+  clutter_text_set_text (CLUTTER_TEXT (priv->entry), location);
+  page = priv->current_page->data;
+
+  g_free (page->address);
+  page->address = g_strdup (location);
+
+  set_back_and_forward (browser);
+}
+
+static gboolean
+web_event_capture_cb (ClutterActor  *actor,
+                      ClutterEvent  *event,
+                      MmBrowserPage *page)
+{
+  MmBrowser *browser = page->browser;
+  MmBrowserPrivate *priv = browser->priv;
+
+  switch (event->type) {
+  case CLUTTER_BUTTON_PRESS:
+    if (priv->showing_tabs == TRUE)
+      {
+        tabs_cb (NULL, NULL, browser);
+        return TRUE;
+      }
+
+    return FALSE;
+
+  case CLUTTER_BUTTON_RELEASE:
+    return FALSE;
+
+  case CLUTTER_MOTION:
+#if 0
+    if (priv->maybe_scroll == TRUE) {
+      ClutterMotionEvent *mev = (ClutterMotionEvent *) event;
+      int dx = mev->x - page->start_x;
+      int dy = mev->y - page->start_y;
+
+      gtk_adjustment_set_value (page->hscroll,
+                                MIN (page->hscroll->value - dx,
+                                     page->hscroll->upper - WEB_WIDTH));
+      gtk_adjustment_set_value (page->vscroll,
+                                MIN (page->vscroll->value - dy,
+                                     page->vscroll->upper - WEB_HEIGHT));
+
+      page->start_x = mev->x;
+      page->start_y = mev->y;
+    } else {
+      return FALSE;
+    }
+#endif
+    return FALSE;
+
+  case CLUTTER_ENTER:
+  case CLUTTER_LEAVE:
+  default:
+    /* Let the actor handle all the other events */
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+#ifndef WITH_MOZILLA
+static void
+hovering_over_link_cb (WebKitWebView *view,
+                       const char    *string1, /* What is this string? */
+                       const char    *url,
+                       MmBrowserPage *page)
+{
+  if (string1 == NULL && url == NULL) {
+    page->over_link = FALSE;
+  } else {
+    page->over_link = TRUE;
+  }
+}
+
+static void
+show_popup_menu (WebKitPopupFactory *factory,
+                 MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  page = priv->current_page->data;
+  clutter_actor_raise_top (page->popup_menu);
+  clutter_actor_show_all (page->popup_menu);
+}
+
+static void
+hide_popup_menu (WebKitPopupFactory *factory,
+                 MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  page = priv->current_page->data;
+  clutter_actor_hide (page->popup_menu);
+}
+
+static gboolean
+popup_button_release_cb (ClutterActor       *actor,
+                         ClutterButtonEvent *event,
+                         MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  page = priv->current_page->data;
+
+  if ((ABS (event->x - priv->popup_x) < JITTER) &&
+      (ABS (event->y - priv->popup_y) < JITTER)) {
+    int row;
+
+    row = tidy_list_view_get_row_at_pos (TIDY_LIST_VIEW (page->factory),
+                                         event->x, event->y);
+    if (row == -1) {
+      return FALSE;
+    }
+
+    webkit_popup_factory_activate (WEBKIT_POPUP_FACTORY (page->factory), row);
+    webkit_popup_factory_close (WEBKIT_POPUP_FACTORY (page->factory));
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+popup_button_press_cb (ClutterActor       *actor,
+                       ClutterButtonEvent *event,
+                       MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+
+  if (event->button != 1) {
+    return FALSE;
+  }
+
+  priv->popup_x = event->x;
+  priv->popup_y = event->y;
+
+  return TRUE;
+}
+
+static void
+create_popup_factory (MmBrowser     *browser,
+                     MmBrowserPage *page)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  ClutterActor *bground, *scroll;
+  ClutterColor black = {0xbb, 0xbb, 0xbb, 0xdd};
+
+  page->popup_menu = clutter_group_new ();
+
+  bground = clutter_rectangle_new_with_color (&black);
+  clutter_container_add_actor (CLUTTER_CONTAINER (page->popup_menu), bground);
+  clutter_actor_set_size (bground, WEB_WIDTH, 125);
+  clutter_actor_show (bground);
+
+  page->factory = g_object_new (POPUP_TYPE_FACTORY,
+                               "rules-hint", FALSE,
+                               "show-headers", FALSE,
+                               NULL);
+  tidy_stylable_set_style (TIDY_STYLABLE (page->factory), tidy_style_new ());
+  tidy_stylable_set (TIDY_STYLABLE (page->factory),
+                    "font-name", "Impact 20", NULL);
+
+  g_signal_connect (page->factory, "show-menu",
+                    G_CALLBACK (show_popup_menu), browser);
+  g_signal_connect (page->factory, "hide-menu",
+                    G_CALLBACK (hide_popup_menu), browser);
+  g_signal_connect (page->factory, "button-press-event",
+                    G_CALLBACK (popup_button_press_cb), browser);
+  g_signal_connect (page->factory, "button-release-event",
+                    G_CALLBACK (popup_button_release_cb), browser);
+  webkit_web_view_set_popup_factory (page->view, WEBKIT_POPUP_FACTORY (page->factory));
+  clutter_actor_set_size (CLUTTER_ACTOR (page->factory), WEB_WIDTH, 125);
+  clutter_actor_show (CLUTTER_ACTOR (page->factory));
+
+  scroll = tidy_finger_scroll_new (TIDY_FINGER_SCROLL_MODE_KINETIC);
+  clutter_container_add_actor (CLUTTER_CONTAINER (page->popup_menu), scroll);
+  clutter_container_add_actor (CLUTTER_CONTAINER (scroll),
+                               CLUTTER_ACTOR (page->factory));
+  clutter_actor_set_size (scroll, WEB_WIDTH, 125);
+
+  clutter_actor_set_position (page->popup_menu, 0, WEB_HEIGHT - 125);
+  clutter_container_add_actor (CLUTTER_CONTAINER (clutter_stage_get_default ()),
+                               page->popup_menu);
+
+  clutter_actor_show_all (scroll);
+}
+
+static void
+page_start_editing_cb (WebkitActor *actor,
+                      MmBrowser   *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+
+  webkit_web_view_zoom_to_selected_node (page->view);
+}
+
+static void
+page_stop_editing_cb (WebkitActor *actor,
+                     MmBrowser   *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+
+  webkit_web_view_zoom_to_default (page->view);
+}
+#endif
+
+static void
+add_new_page (MmBrowser *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+  ClutterActor *frame;
+
+  page = g_new (MmBrowserPage, 1);
+  page->address = NULL;
+  page->browser = browser;
+
+#ifdef WITH_MOZILLA
+  page->scroll = page->web = clutter_mozembed_new ();
+  clutter_actor_set_size (page->web, WEB_WIDTH, WEB_HEIGHT);
+  clutter_mozembed_open (CLUTTER_MOZEMBED (page->web), "about:blank");
+  g_signal_connect_swapped (page->web, "net-start",
+                            G_CALLBACK (load_started_cb), browser);
+  g_signal_connect_swapped (page->web, "net-stop",
+                            G_CALLBACK (load_finished_cb), browser);
+#else
+  page->hadj = webkit_adjustment_new (0,0,0,0,0,0);
+  page->vadj = webkit_adjustment_new (0,0,0,0,0,0);
+
+  page->web = webkit_web_view_new (WEB_WIDTH, WEB_HEIGHT);
+  webkit_web_view_set_scroll_adjustments (WEBKIT_WEB_VIEW (page->web),
+                                         page->hadj, page->vadj);
+
+  clutter_actor_set_reactive (page->web, TRUE);
+  clutter_actor_set_size (page->web, WEB_WIDTH, WEB_HEIGHT);
+  g_signal_connect (page->web, "captured-event",
+                    G_CALLBACK (webkit_event_capture_cb), page);
+  page->view = WEBKIT_WEB_VIEW (page->web);
+  clutter_actor_show (page->web);
+
+  frame = g_object_new (SCROLL_TYPE_FRAME, NULL);
+  /* clutter_actor_set_size (frame, WEB_WIDTH, WEB_HEIGHT); */
+  clutter_actor_show (frame);
+
+  scroll_frame_add_webkit (SCROLL_FRAME (frame), page->view);
+
+  page->scroll = tidy_finger_scroll_new (TIDY_FINGER_SCROLL_MODE_KINETIC);
+  tidy_stylable_set_style (TIDY_STYLABLE (page->scroll), tidy_style_new ());
+  tidy_stylable_set (TIDY_STYLABLE (page->scroll),
+                    "xthickness", 5, "ythickness", 5, NULL);
+  clutter_actor_set_size (page->scroll, WEB_WIDTH, WEB_HEIGHT);
+  clutter_container_add_actor (CLUTTER_CONTAINER (page->scroll), frame);
+
+  webkit_web_view_open (page->view, "about:blank");
+  g_signal_connect_swapped (page->view, "load-started",
+                            G_CALLBACK (load_started_cb), browser);
+  g_signal_connect_swapped (page->view, "load-finished",
+                            G_CALLBACK (load_finished_cb), browser);
+  g_signal_connect (page->view, "hovering-over-link",
+                    G_CALLBACK (hovering_over_link_cb), page);
+  g_signal_connect (page->view, "start-editing",
+                   G_CALLBACK (page_start_editing_cb), browser);
+  g_signal_connect (page->view, "stop-editing",
+                   G_CALLBACK (page_stop_editing_cb), browser);
+
+  create_popup_factory (browser, page);
+#endif
+
+  clutter_actor_set_anchor_point_from_gravity (page->scroll,
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (page->scroll, WEB_WIDTH / 2, WEB_HEIGHT / 2);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->page_group),
+                               page->scroll);
+
+  priv->pages = g_list_append (priv->pages, page);
+
+  /* Fixme...obviously */
+  priv->current_page = g_list_last (priv->pages);
+}
+
+static ClutterActor *
+make_button (const char *image)
+{
+  return clutter_texture_new_from_file (image, NULL);
+}
+
+#if 0
+static void
+key_release_cb (ClutterEntry *entry,
+                ClutterEvent *event,
+                MmBrowser    *browser)
+{
+  if (event->type == CLUTTER_KEY_RELEASE) {
+    ClutterKeyEvent *kev = (ClutterKeyEvent *) event;
+
+    clutter_entry_handle_key_event (CLUTTER_ENTRY (browser->priv->entry), kev);
+  }
+}
+#endif
+static void
+entry_activated_cb (ClutterText  *entry,
+                    MmBrowser    *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+  char *address = g_strdup (clutter_text_get_text (entry));
+  MmBrowserPage *page;
+
+  mm_browser_open (browser, address);
+
+  page = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), page->web);
+  g_free (address);
+}
+
+static gboolean
+entry_clicked_cb (ClutterActor       *actor,
+                 ClutterButtonEvent *event,
+                 MmBrowser          *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), priv->entry);
+  
+  return FALSE;
+}
+
+static void
+back_cb (ClutterActor *button,
+         ClutterEvent *event,
+         MmBrowser    *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  if (priv->showing_tabs == TRUE)
+    return;
+
+  /* Get top page */
+  page = priv->current_page->data;
+#ifdef WITH_MOZILLA
+  clutter_mozembed_back (CLUTTER_MOZEMBED (page->web));
+#else
+  webkit_web_view_go_back (page->view);
+#endif
+  set_back_and_forward (browser);
+}
+
+static void
+forward_cb (ClutterActor *button,
+            ClutterEvent *event,
+            MmBrowser    *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  if (priv->showing_tabs == TRUE)
+    return;
+
+  /* Get top page */
+  page = priv->current_page->data;
+#ifdef WITH_MOZILLA
+  clutter_mozembed_forward (CLUTTER_MOZEMBED (page->web));
+#else
+  webkit_web_view_go_forward (page->view);
+#endif
+  set_back_and_forward (browser);
+}
+
+static void
+hide_on_effect_complete (ClutterActor *actor,
+                        gpointer      userdata)
+{
+  clutter_actor_hide (actor);
+}
+
+static void
+tabs_cb (ClutterActor *button,
+         ClutterEvent *event,
+         MmBrowser    *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page, *prev = NULL, *next = NULL;
+
+  if (priv->showing_tabs == FALSE) {
+    page = priv->current_page->data;
+
+    /* Layout previous page */
+    if (priv->current_page->prev) {
+      prev = priv->current_page->prev->data;
+
+      clutter_actor_set_scale (prev->scroll, 0.4, 0.4);
+      clutter_actor_set_position (prev->scroll, 0, 240);
+      clutter_actor_set_opacity (prev->scroll, 0x00);
+
+      clutter_actor_show (prev->scroll);
+    } else {
+      g_print ("No prev\n");
+    }
+
+    /* Layout next page */
+    if (priv->current_page->next) {
+      next = priv->current_page->next->data;
+
+      clutter_actor_set_scale (next->scroll, 0.4, 0.4);
+      clutter_actor_set_position (next->scroll, 800, 240);
+      clutter_actor_set_opacity (next->scroll, 0x00);
+
+      clutter_actor_show (next->scroll);
+    }
+
+    clutter_actor_animate (page->scroll, CLUTTER_LINEAR, 100,
+                           "scale-x", 0.4, "scale-y", 0.4, NULL);
+    clutter_actor_show (priv->tab_control);
+    clutter_actor_animate (priv->tab_control, CLUTTER_LINEAR, 500,
+                           "opacity", 0xff, NULL);
+    if (prev != NULL) {
+      clutter_actor_show (prev->scroll);
+      clutter_actor_animate (prev->scroll, CLUTTER_LINEAR, 500,
+                             "opacity", 0xff, NULL);
+    }
+
+    if (next != NULL) {
+      clutter_actor_show (next->scroll);
+      clutter_actor_animate (next->scroll, CLUTTER_LINEAR, 500,
+                             "opacity", 0xff, NULL);
+    }
+
+    priv->showing_tabs = TRUE;
+  } else {
+    page = priv->current_page->data;
+
+    if (priv->current_page->prev) {
+      prev = priv->current_page->prev->data;
+
+      g_signal_connect_swapped (clutter_actor_animate (prev->scroll,
+                                                       CLUTTER_LINEAR, 500,
+                                                       "opacity", 0x00, NULL),
+                                "completed",
+                                G_CALLBACK (hide_on_effect_complete),
+                                prev->scroll);
+    }
+
+    if (priv->current_page->next) {
+      next = priv->current_page->next->data;
+
+      g_signal_connect_swapped (clutter_actor_animate (next->scroll,
+                                                       CLUTTER_LINEAR, 500,
+                                                       "opacity", 0x00, NULL),
+                                "completed",
+                                G_CALLBACK (hide_on_effect_complete),
+                                next->scroll);
+    }
+
+    clutter_actor_animate (page->scroll, CLUTTER_LINEAR, 100,
+                           "scale-x", 1.0, "scale-y", 1.0, NULL);
+    g_signal_connect_swapped (clutter_actor_animate (priv->tab_control,
+                                                     CLUTTER_LINEAR, 500,
+                                                     "opacity", 0x00, NULL),
+                              "completed",
+                              G_CALLBACK (hide_on_effect_complete),
+                              priv->tab_control);
+    priv->showing_tabs = FALSE;
+  }
+}
+
+static void
+select_previous_tab (ClutterActor *button,
+                     ClutterEvent *event,
+                     MmBrowser    *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *pages[4], *current;
+  int i;
+
+  pages[2] = priv->current_page->data;
+
+  if (priv->current_page->next) {
+    pages[3] = priv->current_page->next->data;
+  } else {
+    pages[3] = NULL;
+  }
+
+  if (priv->current_page->prev) {
+    pages[1] = priv->current_page->prev->data;
+
+    if (priv->current_page->prev->prev) {
+      pages[0] = priv->current_page->prev->prev->data;
+    } else {
+      pages[0] = NULL;
+    }
+  } else {
+    /* Current page was the first page, so we can't screll */
+    return;
+  }
+
+  /* Scroll all four pages */
+  for (i = 0; i < 4; i++) {
+    int x;
+
+    if (pages[i] == NULL) {
+      continue;
+    }
+
+    clutter_actor_get_position (pages[i]->scroll, &x, NULL);
+    clutter_actor_animate (pages[i]->scroll, CLUTTER_LINEAR, 400,
+                           "x", x + 400, NULL);
+  }
+
+  priv->current_page = priv->current_page->prev;
+  current = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), current->scroll);
+  clutter_text_set_text (CLUTTER_TEXT (priv->entry), 
+                          current->address ? current->address : "");
+}
+
+static void
+select_next_tab (ClutterActor *button,
+                 ClutterEvent *event,
+                 MmBrowser    *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *pages[4], *current;
+  int i;
+
+  pages[1] = priv->current_page->data;
+
+  if (priv->current_page->prev) {
+    pages[0] = priv->current_page->prev->data;
+  } else {
+    pages[0] = NULL;
+  }
+
+  if (priv->current_page->next) {
+    pages[2] = priv->current_page->next->data;
+
+    if (priv->current_page->next->next) {
+      pages[3] = priv->current_page->next->next->data;
+    } else {
+      pages[3] = NULL;
+    }
+  } else {
+    /* Current page was last page, so we can't scroll */
+    return;
+  }
+
+  /* Scroll all four pages */
+  for (i = 0; i < 4; i++) {
+    int x;
+
+    if (pages[i] == NULL) {
+      continue;
+    }
+
+    clutter_actor_get_position (pages[i]->scroll, &x, NULL);
+    clutter_actor_animate (pages[i]->scroll, CLUTTER_LINEAR, 400,
+                           "x", x - 400, NULL);
+  }
+
+  priv->current_page = priv->current_page->next;
+  current = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), current->web);
+  clutter_text_set_text (CLUTTER_TEXT (priv->entry), 
+                          current->address ? current->address : "");
+}
+
+static void
+create_new_tab (ClutterActor *button,
+                ClutterEvent *event,
+                MmBrowser    *browser)
+{
+  g_print ("New tab\n");
+}
+
+static void
+mm_browser_init (MmBrowser *self)
+{
+  MmBrowserPrivate *priv;
+  ClutterColor white = {0x33, 0x33, 0x33, 0xff};
+  ClutterColor progress_color = {0x00, 0x55, 0xdd, 0xff};
+  ClutterActor *stage = clutter_stage_get_default ();
+  ClutterAlpha *alpha;
+  ClutterBehaviour *behave;
+  ClutterKnot progress_knots[] = {{265, 11}, {515, 11}};
+  MmBrowserPage *page;
+
+  priv = self->priv = BROWSER_PRIVATE (self);
+
+  alpha = clutter_alpha_new_full (priv->move_timeline, CLUTTER_EASE_IN_OUT_CUBIC);
+  behave = clutter_behaviour_path_new_with_knots (alpha, progress_knots, 2);
+
+  priv->pages = NULL;
+  priv->showing_tabs = FALSE;
+
+  priv->page_group = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->page_group);
+  clutter_actor_set_position (priv->page_group, 0, 0);
+  clutter_actor_set_reactive (priv->page_group, TRUE);
+
+  add_new_page (self);
+  add_new_page (self);
+  add_new_page (self);
+
+  priv->current_page = priv->current_page->prev;
+  clutter_actor_show (((MmBrowserPage *) priv->current_page->data)->scroll);
+  clutter_actor_raise_top (((MmBrowserPage *) priv->current_page->data)->scroll);
+
+  priv->tab_control = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->page_group), priv->tab_control);
+  clutter_actor_set_position (priv->tab_control, 0, 350);
+  clutter_actor_set_size (priv->tab_control, 800, 34);
+  
+  priv->prev_tab = make_button ("assets/go-previous.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
+                               priv->prev_tab);
+  clutter_actor_set_reactive (priv->prev_tab, TRUE);
+  clutter_actor_set_position (priv->prev_tab, 20, 2);
+  g_signal_connect (priv->prev_tab, "button-release-event",
+                    G_CALLBACK (select_previous_tab), self);
+
+  priv->next_tab = make_button ("assets/go-next.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
+                               priv->next_tab);
+  clutter_actor_set_reactive (priv->next_tab, TRUE);
+  clutter_actor_set_position (priv->next_tab, 748, 2);
+  g_signal_connect (priv->next_tab, "button-release-event",
+                    G_CALLBACK (select_next_tab), self);
+
+#if 0  
+  priv->new_tab = make_button ("assets/document-new.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
+                               priv->new_tab);
+  clutter_actor_set_reactive (priv->new_tab, TRUE);
+  clutter_actor_set_position (priv->new_tab, 384, 2);
+  g_signal_connect (priv->new_tab, "button-release-event",
+                    G_CALLBACK (create_new_tab), self);
+#endif
+  clutter_actor_set_opacity (priv->tab_control, 0x00);
+  clutter_actor_show_all (priv->tab_control);
+
+  clutter_actor_show (priv->page_group);
+
+  priv->toolbar = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->toolbar);
+  clutter_actor_set_position (priv->toolbar, 0, 430);
+
+  priv->toolbar_bg = clutter_texture_new_from_file ("assets/toolbar-bg.png", NULL);
+  clutter_group_add (CLUTTER_GROUP (priv->toolbar), priv->toolbar_bg);
+
+  priv->progress = clutter_rectangle_new_with_color (&progress_color);
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), 
+                               priv->progress);
+  clutter_actor_set_size (priv->progress, 30, 28);
+  clutter_actor_set_position (priv->progress, 265, 11);
+  clutter_actor_set_opacity (priv->progress, 0x00);
+  clutter_behaviour_apply (behave, priv->progress);
+
+
+  priv->back = make_button ("assets/back.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->back);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->back), TRUE);
+  clutter_actor_set_position (priv->back, 140, 2);
+  g_signal_connect (priv->back, "button-release-event",
+                    G_CALLBACK (back_cb), self);
+
+  priv->forward = make_button ("assets/forward.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->forward);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->forward), TRUE);
+  clutter_actor_set_position (priv->forward, 200, 2);
+  g_signal_connect (priv->forward, "button-release-event",
+                    G_CALLBACK (forward_cb), self);
+
+  priv->tabs = make_button ("assets/tabs.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->tabs);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->tabs), TRUE);
+  clutter_actor_set_position (priv->tabs, 8, 2);
+  g_signal_connect (priv->tabs, "button-release-event",
+                    G_CALLBACK (tabs_cb), self);
+
+
+  priv->entry = clutter_text_new_full ("Sans 28px", "", &white);
+  g_object_set (G_OBJECT (priv->entry),
+                "editable", TRUE, "activatable", TRUE, NULL);
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->entry);
+  clutter_actor_set_reactive (priv->entry, TRUE);
+  clutter_actor_set_position (priv->entry, 265, 11);
+  clutter_actor_set_size (priv->entry, 515, 50);
+#if 0
+  g_signal_connect (priv->entry, "key-release-event",
+                    G_CALLBACK (key_release_cb), self);
+#endif
+  g_signal_connect (priv->entry, "activate",
+                    G_CALLBACK (entry_activated_cb), self);
+  g_signal_connect (priv->entry, "button-release-event",
+                   G_CALLBACK (entry_clicked_cb), self);
+
+  set_back_and_forward (self);
+
+  page = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), page->web);
+
+  clutter_actor_show_all (priv->toolbar);
+
+  /* clutter_actor_raise_top (priv->page_group); */
+}
+
+MmBrowser *
+mm_browser_new (void)
+{
+  return g_object_new (MM_TYPE_BROWSER, NULL);
+}
+
+void
+mm_browser_open (MmBrowser  *browser,
+                 const char *address)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+#ifdef WITH_MOZILLA
+  clutter_mozembed_open (CLUTTER_MOZEMBED (page->web), address);
+#else
+  webkit_web_view_open (page->view, address);
+#endif
+}
+
+/***************************************************************************/
+
+int
+main (int    argc,
+      char **argv)
+{
+        ClutterActor *stage;
+        ClutterActor *background;
+        MmBrowser *browser;
+        ClutterColor col = {0x24, 0x29, 0x29, 0xff};
+
+        clutter_init (&argc, &argv);
+
+        stage = clutter_stage_get_default ();
+        clutter_actor_set_size (stage, 800, 480);
+        clutter_stage_set_color (CLUTTER_STAGE(stage), &col);
+
+        browser = mm_browser_new ();
+        clutter_actor_set_position (CLUTTER_ACTOR (browser), 0, 0);
+        clutter_group_add (CLUTTER_GROUP (stage), CLUTTER_ACTOR (browser));
+        clutter_actor_show_all (stage);
+
+        if (argc < 2) {
+          mm_browser_open (browser, "http://news.google.co.uk/");
+        } else {
+          mm_browser_open (browser, argv[1]);
+        }
+
+        clutter_main ();
+        return 0;
+}
diff --git a/attic/mallums-magic-browser/web-browser-mozilla.h b/attic/mallums-magic-browser/web-browser-mozilla.h
new file mode 100644 (file)
index 0000000..9d39ad0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _MM_BROWSER
+#define _MM_BROWSER
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_BROWSER mm_browser_get_type ()
+
+typedef struct _MmBrowserPrivate MmBrowserPrivate;
+
+#define MM_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROWSER, MmBrowser))
+
+typedef struct {
+  ClutterGroup parent;
+  MmBrowserPrivate *priv;
+} MmBrowser;
+
+typedef struct {
+  ClutterGroupClass parent_class;
+} MmBrowserClass;
+
+GType mm_browser_get_type (void);
+
+MmBrowser *mm_browser_new (void);
+void       mm_browser_open (MmBrowser  *browser,
+                            const char *address);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/mallums-magic-browser/web-browser.c b/attic/mallums-magic-browser/web-browser.c
new file mode 100644 (file)
index 0000000..75fbaa4
--- /dev/null
@@ -0,0 +1,901 @@
+#include <clutter/clutter.h>
+#include <webkit/webkit.h>
+#include <tidy/tidy.h>
+
+#include "web-browser.h"
+#include "scroll-frame.h"
+#include "popup-factory.h"
+
+static void
+tabs_cb (ClutterActor *button,
+         ClutterEvent *event,
+         MmBrowser    *browser);
+
+G_DEFINE_TYPE (MmBrowser, mm_browser, CLUTTER_TYPE_GROUP)
+#define BROWSER_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_BROWSER, MmBrowserPrivate))
+
+typedef struct _MmBrowserPage
+{
+  MmBrowser *browser;
+  ClutterActor *webkit;
+  ClutterActor *overlay;
+  ClutterActor *scroll;
+  ClutterActor *popup_menu;
+
+  PopupFactory *factory;
+
+  WebKitWebView *view;
+  WebkitAdjustment *hadj, *vadj;
+
+  char *address;
+
+  gboolean over_link;
+
+  int start_x;
+  int start_y;
+} MmBrowserPage;
+
+struct _MmBrowserPrivate
+{
+  ClutterTimeline *fade_timeline;
+  ClutterTimeline *scale_timeline;
+  ClutterTimeline *scroll_timeline;
+  ClutterTimeline *move_timeline;
+
+  ClutterEffectTemplate *fade_template;
+  ClutterEffectTemplate *scale_template;
+  ClutterEffectTemplate *scroll_template;
+
+  ClutterActor *toolbar, *toolbar_bg;
+  ClutterActor *tab_control;
+  ClutterActor *new_tab;
+  ClutterActor *prev_tab;
+  ClutterActor *next_tab;
+
+  ClutterActor *next_prev_group;
+
+  ClutterActor *back;
+  ClutterActor *forward;
+  ClutterActor *entry;
+  ClutterActor *tabs;
+  ClutterActor *progress;
+
+  ClutterActor *page_group;
+
+  GList *pages;
+  GList *current_page;
+
+  gboolean showing_tabs;
+  gboolean maybe_scroll;
+
+  int popup_x;
+  int popup_y;
+};
+
+#define WEBKIT_WIDTH 800
+#define WEBKIT_HEIGHT 480
+
+#define JITTER 5
+
+static void
+mm_browser_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (mm_browser_parent_class)->finalize (object);
+}
+
+static void
+mm_browser_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (mm_browser_parent_class)->dispose (object);
+}
+
+static void
+mm_browser_class_init (MmBrowserClass *klass)
+{
+  GObjectClass *o_class = (GObjectClass *) klass;
+  ClutterActorClass *a_class = (ClutterActorClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (MmBrowserPrivate));
+
+  o_class->finalize = mm_browser_finalize;
+  o_class->dispose = mm_browser_dispose;
+}
+
+static void
+set_back_and_forward (MmBrowser *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+
+  if (webkit_web_view_can_go_back (page->view)) {
+    clutter_effect_fade (priv->fade_template, priv->back, 0xff, NULL, NULL);
+  } else {
+    clutter_effect_fade (priv->fade_template, priv->back, 0x55, NULL, NULL);
+  }
+
+  if (webkit_web_view_can_go_forward (page->view)) {
+    clutter_effect_fade (priv->fade_template, priv->forward, 0xff, NULL, NULL);
+  } else {
+    clutter_effect_fade (priv->fade_template, priv->forward, 0x55, NULL, NULL);
+  }
+}
+
+static void
+load_started_cb (WebKitWebView  *web_view,
+                 WebKitWebFrame *frame,
+                 MmBrowser      *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  ClutterTimeline *tl;
+
+  clutter_effect_fade (priv->fade_template, priv->progress, 0xff, NULL, NULL);
+  clutter_timeline_start (priv->move_timeline);
+}
+
+static void
+load_finished_cb (WebKitWebView  *web_view,
+                  WebKitWebFrame *frame,
+                  MmBrowser      *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+  ClutterTimeline *tl;
+
+  clutter_effect_fade (priv->fade_template, priv->progress, 0x00, NULL, NULL);
+  clutter_timeline_stop (priv->move_timeline);
+  clutter_timeline_rewind (priv->move_timeline);
+
+  clutter_entry_set_text (CLUTTER_ENTRY (priv->entry),
+                          webkit_web_frame_get_uri (frame));
+  page = priv->current_page->data;
+
+  g_free (page->address);
+  page->address = g_strdup (webkit_web_frame_get_uri (frame));
+
+  set_back_and_forward (browser);
+}
+
+static gboolean
+webkit_event_capture_cb (ClutterActor  *actor,
+                         ClutterEvent  *event,
+                         MmBrowserPage *page)
+{
+  MmBrowser *browser = page->browser;
+  MmBrowserPrivate *priv = browser->priv;
+
+  switch (event->type) {
+  case CLUTTER_BUTTON_PRESS:
+    if (priv->showing_tabs == TRUE)
+      {
+       tabs_cb (NULL, NULL, browser);
+       return TRUE;
+      }
+
+    return FALSE;
+
+  case CLUTTER_BUTTON_RELEASE:
+    return FALSE;
+
+  case CLUTTER_MOTION:
+#if 0
+    if (priv->maybe_scroll == TRUE) {
+      ClutterMotionEvent *mev = (ClutterMotionEvent *) event;
+      int dx = mev->x - page->start_x;
+      int dy = mev->y - page->start_y;
+
+      gtk_adjustment_set_value (page->hscroll,
+                                MIN (page->hscroll->value - dx,
+                                     page->hscroll->upper - WEBKIT_WIDTH));
+      gtk_adjustment_set_value (page->vscroll,
+                                MIN (page->vscroll->value - dy,
+                                     page->vscroll->upper - WEBKIT_HEIGHT));
+
+      page->start_x = mev->x;
+      page->start_y = mev->y;
+    } else {
+      return FALSE;
+    }
+#endif
+    return FALSE;
+
+  case CLUTTER_ENTER:
+  case CLUTTER_LEAVE:
+  default:
+    /* Let the actor handle all the other events */
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+hovering_over_link_cb (WebKitWebView *view,
+                       const char    *string1, /* What is this string? */
+                       const char    *url,
+                       MmBrowserPage *page)
+{
+  if (string1 == NULL && url == NULL) {
+    page->over_link = FALSE;
+  } else {
+    page->over_link = TRUE;
+  }
+}
+
+static void
+show_popup_menu (WebKitPopupFactory *factory,
+                 MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  page = priv->current_page->data;
+  clutter_actor_raise_top (page->popup_menu);
+  clutter_actor_show_all (page->popup_menu);
+}
+
+static void
+hide_popup_menu (WebKitPopupFactory *factory,
+                 MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  page = priv->current_page->data;
+  clutter_actor_hide (page->popup_menu);
+}
+
+static gboolean
+popup_button_release_cb (ClutterActor       *actor,
+                         ClutterButtonEvent *event,
+                         MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  page = priv->current_page->data;
+
+  if ((ABS (event->x - priv->popup_x) < JITTER) &&
+      (ABS (event->y - priv->popup_y) < JITTER)) {
+    int row;
+
+    row = tidy_list_view_get_row_at_pos (TIDY_LIST_VIEW (page->factory),
+                                         event->x, event->y);
+    if (row == -1) {
+      return FALSE;
+    }
+
+    webkit_popup_factory_activate (WEBKIT_POPUP_FACTORY (page->factory), row);
+    webkit_popup_factory_close (WEBKIT_POPUP_FACTORY (page->factory));
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+popup_button_press_cb (ClutterActor       *actor,
+                       ClutterButtonEvent *event,
+                       MmBrowser          *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+
+  if (event->button != 1) {
+    return FALSE;
+  }
+
+  priv->popup_x = event->x;
+  priv->popup_y = event->y;
+
+  return TRUE;
+}
+
+static void
+create_popup_factory (MmBrowser     *browser,
+                     MmBrowserPage *page)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  ClutterActor *bground, *scroll;
+  ClutterColor black = {0xbb, 0xbb, 0xbb, 0xdd};
+
+  page->popup_menu = clutter_group_new ();
+
+  bground = clutter_rectangle_new_with_color (&black);
+  clutter_container_add_actor (CLUTTER_CONTAINER (page->popup_menu), bground);
+  clutter_actor_set_size (bground, WEBKIT_WIDTH, 125);
+  clutter_actor_show (bground);
+
+  page->factory = g_object_new (POPUP_TYPE_FACTORY,
+                               "rules-hint", FALSE,
+                               "show-headers", FALSE,
+                               NULL);
+  tidy_stylable_set_style (TIDY_STYLABLE (page->factory), tidy_style_new ());
+  tidy_stylable_set (TIDY_STYLABLE (page->factory),
+                    "font-name", "Impact 20", NULL);
+
+  g_signal_connect (page->factory, "show-menu",
+                    G_CALLBACK (show_popup_menu), browser);
+  g_signal_connect (page->factory, "hide-menu",
+                    G_CALLBACK (hide_popup_menu), browser);
+  g_signal_connect (page->factory, "button-press-event",
+                    G_CALLBACK (popup_button_press_cb), browser);
+  g_signal_connect (page->factory, "button-release-event",
+                    G_CALLBACK (popup_button_release_cb), browser);
+  webkit_web_view_set_popup_factory (page->view, WEBKIT_POPUP_FACTORY (page->factory));
+  clutter_actor_set_size (CLUTTER_ACTOR (page->factory), WEBKIT_WIDTH, 125);
+  clutter_actor_show (CLUTTER_ACTOR (page->factory));
+
+  scroll = tidy_finger_scroll_new (TIDY_FINGER_SCROLL_MODE_KINETIC);
+  clutter_container_add_actor (CLUTTER_CONTAINER (page->popup_menu), scroll);
+  clutter_container_add_actor (CLUTTER_CONTAINER (scroll),
+                               CLUTTER_ACTOR (page->factory));
+  clutter_actor_set_size (scroll, WEBKIT_WIDTH, 125);
+
+  clutter_actor_set_position (page->popup_menu, 0, WEBKIT_HEIGHT - 125);
+  clutter_container_add_actor (CLUTTER_CONTAINER (clutter_stage_get_default ()),
+                               page->popup_menu);
+
+  clutter_actor_show_all (scroll);
+}
+
+static void
+page_start_editing_cb (WebkitActor *actor,
+                      MmBrowser   *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+
+  webkit_web_view_zoom_to_selected_node (page->view);
+}
+
+static void
+page_stop_editing_cb (WebkitActor *actor,
+                     MmBrowser   *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+
+  webkit_web_view_zoom_to_default (page->view);
+}
+
+static void
+add_new_page (MmBrowser *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+  ClutterActor *frame;
+
+  page = g_new (MmBrowserPage, 1);
+  page->address = NULL;
+  page->browser = browser;
+
+  page->hadj = webkit_adjustment_new (0,0,0,0,0,0);
+  page->vadj = webkit_adjustment_new (0,0,0,0,0,0);
+
+  page->webkit = webkit_web_view_new (WEBKIT_WIDTH, WEBKIT_HEIGHT);
+  webkit_web_view_set_scroll_adjustments (WEBKIT_WEB_VIEW (page->webkit),
+                                         page->hadj, page->vadj);
+
+  clutter_actor_set_reactive (page->webkit, TRUE);
+  clutter_actor_set_size (page->webkit, WEBKIT_WIDTH, WEBKIT_HEIGHT);
+  g_signal_connect (page->webkit, "captured-event",
+                    G_CALLBACK (webkit_event_capture_cb), page);
+  page->view = WEBKIT_WEB_VIEW (page->webkit);
+  clutter_actor_show (page->webkit);
+
+  frame = g_object_new (SCROLL_TYPE_FRAME, NULL);
+  /* clutter_actor_set_size (frame, WEBKIT_WIDTH, WEBKIT_HEIGHT); */
+  clutter_actor_show (frame);
+
+  scroll_frame_add_webkit (SCROLL_FRAME (frame), page->view);
+
+  page->scroll = tidy_finger_scroll_new (TIDY_FINGER_SCROLL_MODE_KINETIC);
+  tidy_stylable_set_style (TIDY_STYLABLE (page->scroll), tidy_style_new ());
+  tidy_stylable_set (TIDY_STYLABLE (page->scroll),
+                    "xthickness", 5, "ythickness", 5, NULL);
+  clutter_actor_set_size (page->scroll, WEBKIT_WIDTH, WEBKIT_HEIGHT);
+  clutter_container_add_actor (CLUTTER_CONTAINER (page->scroll), frame);
+
+  webkit_web_view_open (page->view, "about:blank");
+  g_signal_connect (page->view, "load-started",
+                    G_CALLBACK (load_started_cb), browser);
+  g_signal_connect (page->view, "load-finished",
+                    G_CALLBACK (load_finished_cb), browser);
+  g_signal_connect (page->view, "hovering-over-link",
+                    G_CALLBACK (hovering_over_link_cb), page);
+  g_signal_connect (page->view, "start-editing",
+                   G_CALLBACK (page_start_editing_cb), browser);
+  g_signal_connect (page->view, "stop-editing",
+                   G_CALLBACK (page_stop_editing_cb), browser);
+
+  clutter_actor_set_anchor_point_from_gravity (page->scroll,
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (page->scroll, WEBKIT_WIDTH / 2,
+                              WEBKIT_HEIGHT / 2);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->page_group),
+                               page->scroll);
+  priv->pages = g_list_append (priv->pages, page);
+
+  create_popup_factory (browser, page);
+
+  /* Fixme...obviously */
+  priv->current_page = g_list_last (priv->pages);
+}
+
+static ClutterActor *
+make_button (const char *image)
+{
+  return clutter_texture_new_from_file (image, NULL);
+}
+
+#if 0
+static void
+key_release_cb (ClutterEntry *entry,
+                ClutterEvent *event,
+                MmBrowser    *browser)
+{
+  if (event->type == CLUTTER_KEY_RELEASE) {
+    ClutterKeyEvent *kev = (ClutterKeyEvent *) event;
+
+    clutter_entry_handle_key_event (CLUTTER_ENTRY (browser->priv->entry), kev);
+  }
+}
+#endif
+static void
+entry_activated_cb (ClutterEntry *entry,
+                    MmBrowser    *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+  char *address = g_strdup (clutter_entry_get_text (entry));
+  MmBrowserPage *page;
+
+  mm_browser_open (browser, address);
+
+  page = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), page->webkit);
+  g_free (address);
+}
+
+static void
+entry_clicked_cb (ClutterActor       *actor,
+                 ClutterButtonEvent *event,
+                 MmBrowser          *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), priv->entry);
+}
+
+static void
+back_cb (ClutterActor *button,
+         ClutterEvent *event,
+         MmBrowser    *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  if (priv->showing_tabs == TRUE)
+    return;
+
+  /* Get top page */
+  page = priv->current_page->data;
+  webkit_web_view_go_back (page->view);
+  set_back_and_forward (browser);
+}
+
+static void
+forward_cb (ClutterActor *button,
+            ClutterEvent *event,
+            MmBrowser    *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  if (priv->showing_tabs == TRUE)
+    return;
+
+  /* Get top page */
+  page = priv->current_page->data;
+  webkit_web_view_go_forward (page->view);
+  set_back_and_forward (browser);
+}
+
+static void
+hide_on_effect_complete (ClutterActor *actor,
+                        gpointer      userdata)
+{
+  clutter_actor_hide (actor);
+}
+
+static void
+tabs_cb (ClutterActor *button,
+         ClutterEvent *event,
+         MmBrowser    *browser)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page, *prev = NULL, *next = NULL;
+
+  if (priv->showing_tabs == FALSE) {
+    page = priv->current_page->data;
+
+    /* Layout previous page */
+    if (priv->current_page->prev) {
+      prev = priv->current_page->prev->data;
+
+      clutter_actor_set_scale (prev->scroll, 0.4, 0.4);
+      clutter_actor_set_position (prev->scroll, 0, 240);
+      clutter_actor_set_opacity (prev->scroll, 0x00);
+
+      clutter_actor_show (prev->scroll);
+    } else {
+      g_print ("No prev\n");
+    }
+
+    /* Layout next page */
+    if (priv->current_page->next) {
+      next = priv->current_page->next->data;
+
+      clutter_actor_set_scale (next->scroll, 0.4, 0.4);
+      clutter_actor_set_position (next->scroll, 800, 240);
+      clutter_actor_set_opacity (next->scroll, 0x00);
+
+      clutter_actor_show (next->scroll);
+    }
+
+    clutter_effect_scale (priv->scale_template, page->scroll, 
+                          0.4, 0.4, NULL, NULL);
+    clutter_actor_show (priv->tab_control);
+    clutter_effect_fade (priv->fade_template, priv->tab_control, 
+                         0xff, NULL, NULL);
+    if (prev != NULL) {
+      clutter_actor_show (prev->scroll);
+      clutter_effect_fade (priv->fade_template, prev->scroll, 0xff, NULL, NULL);
+    }
+
+    if (next != NULL) {
+      clutter_actor_show (next->scroll);
+      clutter_effect_fade (priv->fade_template, next->scroll, 0xff, NULL, NULL);
+    }
+
+    priv->showing_tabs = TRUE;
+  } else {
+    page = priv->current_page->data;
+
+    if (priv->current_page->prev) {
+      prev = priv->current_page->prev->data;
+
+      clutter_effect_fade (priv->fade_template, prev->scroll, 0x00, hide_on_effect_complete, NULL);
+    }
+
+    if (priv->current_page->next) {
+      next = priv->current_page->next->data;
+
+      clutter_effect_fade (priv->fade_template, next->scroll, 0x00, hide_on_effect_complete, NULL);
+    }
+
+    clutter_effect_scale (priv->scale_template, page->scroll,
+                          1.0, 1.0, NULL, NULL);
+    clutter_effect_fade (priv->fade_template, priv->tab_control,
+                         0x00, hide_on_effect_complete, NULL);
+    priv->showing_tabs = FALSE;
+  }
+}
+
+static void
+select_previous_tab (ClutterActor *button,
+                     ClutterEvent *event,
+                     MmBrowser    *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *pages[4], *current;
+  int i;
+
+  pages[2] = priv->current_page->data;
+
+  if (priv->current_page->next) {
+    pages[3] = priv->current_page->next->data;
+  } else {
+    pages[3] = NULL;
+  }
+
+  if (priv->current_page->prev) {
+    pages[1] = priv->current_page->prev->data;
+
+    if (priv->current_page->prev->prev) {
+      pages[0] = priv->current_page->prev->prev->data;
+    } else {
+      pages[0] = NULL;
+    }
+  } else {
+    /* Current page was the first page, so we can't screll */
+    return;
+  }
+
+  /* Scroll all four pages */
+  for (i = 0; i < 4; i++) {
+    int x, y;
+
+    if (pages[i] == NULL) {
+      continue;
+    }
+
+    clutter_actor_get_position (pages[i]->scroll, &x, &y);
+    clutter_effect_move (priv->scroll_template, pages[i]->scroll, 
+                         x + 400, y, NULL, NULL);
+  }
+
+  priv->current_page = priv->current_page->prev;
+  current = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), current->scroll);
+  clutter_entry_set_text (CLUTTER_ENTRY (priv->entry), 
+                          current->address ? current->address : "");
+}
+
+static void
+select_next_tab (ClutterActor *button,
+                 ClutterEvent *event,
+                 MmBrowser    *browser)
+{
+  ClutterActor *stage = clutter_stage_get_default ();
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *pages[4], *current;
+  int i;
+
+  pages[1] = priv->current_page->data;
+
+  if (priv->current_page->prev) {
+    pages[0] = priv->current_page->prev->data;
+  } else {
+    pages[0] = NULL;
+  }
+
+  if (priv->current_page->next) {
+    pages[2] = priv->current_page->next->data;
+
+    if (priv->current_page->next->next) {
+      pages[3] = priv->current_page->next->next->data;
+    } else {
+      pages[3] = NULL;
+    }
+  } else {
+    /* Current page was last page, so we can't scroll */
+    return;
+  }
+
+  /* Scroll all four pages */
+  for (i = 0; i < 4; i++) {
+    int x, y;
+
+    if (pages[i] == NULL) {
+      continue;
+    }
+
+    clutter_actor_get_position (pages[i]->scroll, &x, &y);
+    clutter_effect_move (priv->scroll_template, pages[i]->scroll, 
+                         x - 400, y, NULL, NULL);
+  }
+
+  priv->current_page = priv->current_page->next;
+  current = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), current->webkit);
+  clutter_entry_set_text (CLUTTER_ENTRY (priv->entry), 
+                          current->address ? current->address : "");
+}
+
+static void
+create_new_tab (ClutterActor *button,
+                ClutterEvent *event,
+                MmBrowser    *browser)
+{
+  g_print ("New tab\n");
+}
+
+static void
+mm_browser_init (MmBrowser *self)
+{
+  MmBrowserPrivate *priv;
+  ClutterColor white = {0x33, 0x33, 0x33, 0xff};
+  ClutterColor progress_color = {0x00, 0x55, 0xdd, 0xff};
+  ClutterActor *stage = clutter_stage_get_default ();
+  ClutterAlpha *alpha;
+  ClutterBehaviour *behave;
+  ClutterKnot progress_knots[] = {{265, 11}, {515, 11}};
+  MmBrowserPage *page;
+
+  priv = self->priv = BROWSER_PRIVATE (self);
+
+  priv->fade_timeline = clutter_timeline_new_for_duration (500);
+  priv->fade_template = clutter_effect_template_new (priv->fade_timeline,
+                                                     CLUTTER_ALPHA_RAMP_INC);
+
+  priv->scale_timeline = clutter_timeline_new_for_duration (100);
+  priv->scale_template = clutter_effect_template_new (priv->scale_timeline,
+                                                      CLUTTER_ALPHA_RAMP_INC);
+
+  priv->scroll_timeline = clutter_timeline_new_for_duration (250);
+  priv->scroll_template = clutter_effect_template_new (priv->scroll_timeline,
+                                                       CLUTTER_ALPHA_RAMP_INC);
+
+  priv->move_timeline = clutter_timeline_new_for_duration (2000);
+  clutter_timeline_set_loop (priv->move_timeline, TRUE);
+
+  alpha = clutter_alpha_new_full (priv->move_timeline, CLUTTER_ALPHA_RAMP, 
+                                  NULL, NULL);
+  behave = clutter_behaviour_path_new (alpha, progress_knots, 2);
+
+  priv->pages = NULL;
+  priv->showing_tabs = FALSE;
+
+  priv->page_group = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->page_group);
+  clutter_actor_set_position (priv->page_group, 0, 0);
+  clutter_actor_set_size (priv->page_group, WEBKIT_WIDTH, WEBKIT_HEIGHT);
+  clutter_actor_set_reactive (priv->page_group, TRUE);
+
+  add_new_page (self);
+  add_new_page (self);
+  add_new_page (self);
+
+  priv->current_page = priv->current_page->prev;
+  clutter_actor_show (((MmBrowserPage *) priv->current_page->data)->scroll);
+  clutter_actor_raise_top (((MmBrowserPage *) priv->current_page->data)->scroll);
+
+  priv->tab_control = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->page_group), priv->tab_control);
+  clutter_actor_set_position (priv->tab_control, 0, 350);
+  clutter_actor_set_size (priv->tab_control, 800, 34);
+  
+  priv->prev_tab = make_button ("assets/go-previous.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
+                               priv->prev_tab);
+  clutter_actor_set_reactive (priv->prev_tab, TRUE);
+  clutter_actor_set_position (priv->prev_tab, 20, 2);
+  g_signal_connect (priv->prev_tab, "button-release-event",
+                    G_CALLBACK (select_previous_tab), self);
+
+  priv->next_tab = make_button ("assets/go-next.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
+                               priv->next_tab);
+  clutter_actor_set_reactive (priv->next_tab, TRUE);
+  clutter_actor_set_position (priv->next_tab, 748, 2);
+  g_signal_connect (priv->next_tab, "button-release-event",
+                    G_CALLBACK (select_next_tab), self);
+
+#if 0  
+  priv->new_tab = make_button ("assets/document-new.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
+                               priv->new_tab);
+  clutter_actor_set_reactive (priv->new_tab, TRUE);
+  clutter_actor_set_position (priv->new_tab, 384, 2);
+  g_signal_connect (priv->new_tab, "button-release-event",
+                    G_CALLBACK (create_new_tab), self);
+#endif
+  clutter_actor_set_opacity (priv->tab_control, 0x00);
+  clutter_actor_show_all (priv->tab_control);
+
+  clutter_actor_show (priv->page_group);
+
+  priv->toolbar = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->toolbar);
+  clutter_actor_set_position (priv->toolbar, 0, 430);
+
+  priv->toolbar_bg = clutter_texture_new_from_file ("assets/toolbar-bg.png", NULL);
+  clutter_group_add (CLUTTER_GROUP (priv->toolbar), priv->toolbar_bg);
+
+  priv->progress = clutter_rectangle_new_with_color (&progress_color);
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), 
+                               priv->progress);
+  clutter_actor_set_size (priv->progress, 30, 28);
+  clutter_actor_set_position (priv->progress, 265, 11);
+  clutter_actor_set_opacity (priv->progress, 0x00);
+  clutter_behaviour_apply (behave, priv->progress);
+
+
+  priv->back = make_button ("assets/back.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->back);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->back), TRUE);
+  clutter_actor_set_position (priv->back, 140, 2);
+  g_signal_connect (priv->back, "button-release-event",
+                    G_CALLBACK (back_cb), self);
+
+  priv->forward = make_button ("assets/forward.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->forward);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->forward), TRUE);
+  clutter_actor_set_position (priv->forward, 200, 2);
+  g_signal_connect (priv->forward, "button-release-event",
+                    G_CALLBACK (forward_cb), self);
+
+  priv->tabs = make_button ("assets/tabs.png");
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->tabs);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->tabs), TRUE);
+  clutter_actor_set_position (priv->tabs, 8, 2);
+  g_signal_connect (priv->tabs, "button-release-event",
+                    G_CALLBACK (tabs_cb), self);
+
+
+  priv->entry = clutter_entry_new_full ("Sans 28px", "", &white);
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->entry);
+  clutter_actor_set_reactive (priv->entry, TRUE);
+  clutter_actor_set_position (priv->entry, 265, 11);
+  clutter_actor_set_size (priv->entry, 515, 50);
+#if 0
+  g_signal_connect (priv->entry, "key-release-event",
+                    G_CALLBACK (key_release_cb), self);
+#endif
+  g_signal_connect (priv->entry, "activate",
+                    G_CALLBACK (entry_activated_cb), self);
+  g_signal_connect (priv->entry, "button-release-event",
+                   G_CALLBACK (entry_clicked_cb), self);
+
+  set_back_and_forward (self);
+
+  page = priv->current_page->data;
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), page->webkit);
+
+  clutter_actor_show_all (priv->toolbar);
+
+  /* clutter_actor_raise_top (priv->page_group); */
+}
+
+MmBrowser *
+mm_browser_new (void)
+{
+  return g_object_new (MM_TYPE_BROWSER, NULL);
+}
+
+void
+mm_browser_open (MmBrowser  *browser,
+                 const char *address)
+{
+  MmBrowserPrivate *priv = browser->priv;
+  MmBrowserPage *page;
+
+  /* Get top page */
+  page = priv->current_page->data;
+  webkit_web_view_open (page->view, address);
+}
+
+/***************************************************************************/
+
+int
+main (int    argc,
+      char **argv)
+{
+        ClutterActor *stage;
+        ClutterActor *background;
+        MmBrowser *browser;
+        ClutterColor col = {0x24, 0x29, 0x29, 0xff};
+
+        clutter_init (&argc, &argv);
+
+        stage = clutter_stage_get_default ();
+        clutter_actor_set_size (stage, 800, 480);
+        clutter_stage_set_color (CLUTTER_STAGE(stage), &col);
+
+        browser = mm_browser_new ();
+        clutter_actor_set_position (CLUTTER_ACTOR (browser), 0, 0);
+        clutter_group_add (CLUTTER_GROUP (stage), CLUTTER_ACTOR (browser));
+        clutter_actor_show_all (stage);
+
+        if (argc < 2) {
+          mm_browser_open (browser, "http://www.openedhand.com");
+        } else {
+          mm_browser_open (browser, argv[1]);
+        }
+
+        clutter_main ();
+        return 0;
+}
diff --git a/attic/mallums-magic-browser/web-browser.h b/attic/mallums-magic-browser/web-browser.h
new file mode 100644 (file)
index 0000000..9d39ad0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _MM_BROWSER
+#define _MM_BROWSER
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_BROWSER mm_browser_get_type ()
+
+typedef struct _MmBrowserPrivate MmBrowserPrivate;
+
+#define MM_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROWSER, MmBrowser))
+
+typedef struct {
+  ClutterGroup parent;
+  MmBrowserPrivate *priv;
+} MmBrowser;
+
+typedef struct {
+  ClutterGroupClass parent_class;
+} MmBrowserClass;
+
+GType mm_browser_get_type (void);
+
+MmBrowser *mm_browser_new (void);
+void       mm_browser_open (MmBrowser  *browser,
+                            const char *address);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/sqlite-model/Makefile b/attic/sqlite-model/Makefile
new file mode 100644 (file)
index 0000000..9389842
--- /dev/null
@@ -0,0 +1,13 @@
+LIBS=`pkg-config --libs clutter-0.8 sqlite3`
+INCS=`pkg-config --cflags clutter-0.8 sqlite3`
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: test-sqlite-model
+
+test-sqlite-model: test-sqlite-model.o clutter-sqlite-model.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ test-sqlite-model.o clutter-sqlite-model.o $(LIBS)
+
+clean:
+       rm -fr *.o test-sqlite-model
diff --git a/attic/sqlite-model/clutter-sqlite-model.c b/attic/sqlite-model/clutter-sqlite-model.c
new file mode 100644 (file)
index 0000000..0a4c624
--- /dev/null
@@ -0,0 +1,1110 @@
+/*
+ * ClutterSqliteModel
+ *
+ * An sqlite3-backed ClutterModel implementation.
+ *
+ * Authored By Chris Lord  <chris@openedhand.com>
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * NB: Inspiration taken from the 'woohaa' toy by Matthew Allum and 
+ *     GValue conversion code copied from ClutterListModel, by
+ *     Matthew Allum, Neil Jagdish Patel and Emmanuele Bassi.
+ */
+
+#include <string.h>
+#include <glib.h>
+
+#include "clutter-sqlite-model.h"
+
+#define CLUTTER_SQLITE_TYPE_MODEL_ITER            (clutter_sqlite_model_iter_get_type())
+#define CLUTTER_SQLITE_MODEL_ITER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+                                                   CLUTTER_SQLITE_TYPE_MODEL_ITER,   \
+                                                   ClutterSqliteModelIter))
+#define CLUTTER_SQLITE_IS_MODEL_ITER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+                                                   CLUTTER_SQLITE_TYPE_MODEL_ITER))
+#define CLUTTER_SQLITE_MODEL_ITER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                                   CLUTTER_SQLITE_TYPE_MODEL_ITER,   \
+                                                   ClutterSqliteModelIterClass))
+#define CLUTTER_SQLITE_IS_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+                                                   CLUTTER_SQLITE_TYPE_MODEL_ITER))
+#define CLUTTER_SQLITE_MODEL_ITER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                                   CLUTTER_SQLITE_TYPE_MODEL_ITER,   \
+                                                   ClutterSqliteModelIterClass))
+
+typedef struct _ClutterSqliteModelIter      ClutterSqliteModelIter;
+typedef struct _ClutterSqliteModelIterClass ClutterSqliteModelIterClass;
+
+struct _ClutterSqliteModelIter
+{
+  ClutterModelIter  parent_instance;
+  
+  guint             is_parent;
+  gboolean          is_last;
+  gint              row;
+  gint              rowid;
+};
+
+struct _ClutterSqliteModelIterClass
+{
+  ClutterModelIterClass parent_class;
+};
+
+G_DEFINE_TYPE (ClutterSqliteModel, clutter_sqlite_model, CLUTTER_TYPE_MODEL)
+G_DEFINE_TYPE (ClutterSqliteModelIter, clutter_sqlite_model_iter, \
+               CLUTTER_TYPE_MODEL_ITER)
+
+#define MODEL_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLUTTER_SQLITE_TYPE_MODEL, \
+   ClutterSqliteModelPrivate))
+
+enum
+{
+  PROP_0,
+  
+  PROP_DB,
+  PROP_TABLE,
+  PROP_COL_NAMES,
+  PROP_COL_TYPES,
+  PROP_STATEMENT,
+};
+
+enum 
+{
+  SQL_ADD_ROW = 0,
+  SQL_GET_ROW,
+  SQL_DELETE_ROW,
+  N_SQL_STATEMENTS
+};
+
+/* TODO: Optimisation: Do select statements like the update statements and have
+ *       a separate query per column.
+ */
+static const gchar *sql_statements[] =
+  {
+    "insert into %s(\"%s\") values(NULL);",
+    "select *,rowid from %s where rowid=:rowid;",
+    "delete from %s where rowid=:rowid;",
+  };
+
+static const gchar *sql_update_statement =
+  "update %s set %s=:value where rowid=:rowid;";
+
+struct _ClutterSqliteModelPrivate
+{
+  sqlite3            *db;
+  gchar             **col_names;
+  ClutterSqliteIntV  *col_types;
+  gchar              *table;
+  gint                n_columns;
+
+  sqlite3_stmt       *statements[N_SQL_STATEMENTS];
+  sqlite3_stmt      **update_statements;
+
+  gboolean            complete;
+  sqlite3_stmt       *statement;
+  guint               version;
+  GPtrArray          *rowids;
+  GHashTable         *rowid_to_row;
+  
+  gboolean            skip_add;
+  gboolean            skip_change;
+  gboolean            skip_remove;
+};
+
+/* Retries are every half a second */
+#define META_MAX_TRIES 30
+
+/* In case another process/thread is using this db, deal with locking */
+#define DB_RETRY_TIME 2000
+#define DB_RETRY_WAIT 0
+
+static ClutterModelIter *
+clutter_sqlite_model_iter_new (ClutterSqliteModel *db,
+                               gint                row);
+
+static ClutterModelIter *
+clutter_sqlite_model_iter_new_from_rowid (ClutterSqliteModel *db,
+                                          gint                rowid);
+
+
+ClutterSqliteIntV *
+clutter_sqlite_intv_copy (const ClutterSqliteIntV *intv)
+{
+  ClutterSqliteIntV *copy;
+  
+  copy = g_memdup (intv, sizeof (ClutterSqliteIntV));
+  copy->data = g_memdup (intv->data, sizeof (gint) * copy->length);
+  
+  return copy;
+}
+
+void
+clutter_sqlite_intv_free (ClutterSqliteIntV *intv)
+{
+  g_free (intv->data);
+  g_free (intv);
+}
+
+GType
+clutter_sqlite_intv_get_type (void)
+{
+  static GType our_type = 0;
+  
+  if (!our_type)
+    our_type = g_boxed_type_register_static ("ClutterSqliteIntV",
+                                             (GBoxedCopyFunc) clutter_sqlite_intv_copy,
+                                             (GBoxedFreeFunc) clutter_sqlite_intv_free);
+  
+  return our_type;
+}
+
+static void
+reset_statement (ClutterSqliteModel *model)
+{
+  ClutterSqliteModelPrivate *priv  = model->priv;
+
+  priv->version ++;
+  priv->complete = FALSE;
+  if (priv->rowids->len > 0)
+    g_ptr_array_remove_range (priv->rowids, 0, priv->rowids->len);
+  g_hash_table_remove_all (priv->rowid_to_row);
+}
+
+static void
+clutter_sqlite_model_get_property (GObject    *object,
+                                   guint       property_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  ClutterSqliteModelPrivate *priv = CLUTTER_SQLITE_MODEL (object)->priv;
+  
+  switch (property_id)
+    {
+    case PROP_DB:
+      g_value_set_pointer (value, priv->db);
+      break;
+    case PROP_TABLE:
+      g_value_set_string (value, priv->table);
+      break;
+    case PROP_COL_NAMES:
+      g_value_set_boxed (value, priv->col_names);
+      break;
+    case PROP_COL_TYPES:
+      g_value_set_boxed (value, priv->col_types);
+      break;
+    case PROP_STATEMENT:
+      g_value_set_pointer (value, priv->statement);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+clutter_sqlite_model_set_property (GObject      *object,
+                                   guint         property_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterSqliteModelPrivate *priv = CLUTTER_SQLITE_MODEL (object)->priv;
+
+  switch (property_id)
+    {
+    case PROP_DB:
+      priv->db = g_value_get_pointer (value);
+      break;
+    case PROP_TABLE:
+      if (priv->table)
+        g_free (priv->table);
+      priv->table = g_value_dup_string (value);
+      break;
+    case PROP_COL_NAMES:
+      if (priv->col_names)
+        g_strfreev (priv->col_names);
+      priv->col_names = g_value_dup_boxed (value);
+      break;
+    case PROP_COL_TYPES:
+      if (priv->col_types)
+        clutter_sqlite_intv_free (priv->col_types);
+      priv->col_types = g_value_dup_boxed (value);
+      break;
+    case PROP_STATEMENT:
+      reset_statement (CLUTTER_SQLITE_MODEL (object));
+      if (priv->statement)
+        sqlite3_reset (priv->statement);
+      priv->statement = g_value_get_pointer (value);
+      g_signal_emit_by_name (object, "sort-changed");
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+clutter_sqlite_model_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (clutter_sqlite_model_parent_class)->dispose (object);
+}
+
+static void
+clutter_sqlite_model_finalize (GObject *object)
+{
+  gint i;
+  
+  ClutterSqliteModelPrivate *priv = CLUTTER_SQLITE_MODEL (object)->priv;
+
+  /* Remove db change notification */
+  sqlite3_update_hook (priv->db, NULL, NULL);
+
+  g_strfreev (priv->col_names);
+  clutter_sqlite_intv_free (priv->col_types);
+  g_ptr_array_free (priv->rowids, TRUE);
+  g_hash_table_destroy (priv->rowid_to_row);
+
+  /* Finalize statements */
+  for (i = 0; i < N_SQL_STATEMENTS; i++)
+    if (priv->statements[i])
+      sqlite3_finalize (priv->statements[i]);
+  
+  for (i = 0; priv->update_statements[i]; i++)
+    sqlite3_finalize (priv->update_statements[i]);
+  g_free (priv->update_statements);
+  
+  G_OBJECT_CLASS (clutter_sqlite_model_parent_class)->finalize (object);
+}
+
+static glong
+time_val_diff (GTimeVal *val1, GTimeVal *val2)
+{
+  glong diff;
+  
+  diff = (val2->tv_sec - val1->tv_sec) * 1000;
+  diff += (val2->tv_usec - val1->tv_usec) / 1000;
+  
+  return diff;
+}
+
+static int
+sqlite3_step_retry (sqlite3_stmt *stmt)
+{
+  GTimeVal val1, val2;
+  int result = SQLITE_BUSY;
+  
+  g_assert (stmt);
+  
+  g_get_current_time (&val1);
+  
+  while (result == SQLITE_BUSY) {
+    if ((result = sqlite3_step (stmt)) != SQLITE_BUSY)
+      break;
+    
+    g_get_current_time (&val2);
+    
+    if (time_val_diff (&val1, &val2) >= DB_RETRY_TIME)
+      break;
+  }
+  
+  if (result == SQLITE_BUSY)
+    g_warning ("Database busy, could not execute query");
+  
+  return result;
+}
+
+static gboolean
+statement_next (ClutterSqliteModel *model,
+                gboolean            complete,
+                gint                find_rowid,
+                gint                stop_on_row)
+{
+  ClutterSqliteModelPrivate *priv = model->priv;
+  gboolean                   last = FALSE;
+  
+  if (!priv->statement)
+    return TRUE;
+  
+  priv->version ++;
+  
+  if (priv->rowids->len == 0)
+    sqlite3_reset (priv->statement);
+  
+  do
+    {
+      int result = sqlite3_step_retry (priv->statement);
+      gint rowid = sqlite3_column_int (priv->statement, priv->n_columns);
+      
+      if (result == SQLITE_ROW)
+        {
+          g_hash_table_insert (priv->rowid_to_row,
+                               GINT_TO_POINTER (rowid),
+                               GINT_TO_POINTER (priv->rowids->len) + 1);
+          g_ptr_array_add (priv->rowids, GINT_TO_POINTER (rowid));
+          
+          if (rowid == find_rowid)
+            break;
+        }
+      else if ((result == SQLITE_DONE) || (result == SQLITE_OK))
+        {
+          sqlite3_reset (priv->statement);
+          priv->complete = TRUE;
+          last = TRUE;
+          break;
+        }
+      else
+        {
+          g_warning ("Error while stepping main statement: %s",
+                     sqlite3_errmsg (priv->db));
+          break;
+        }
+      
+      if ((priv->rowids->len - 1) == stop_on_row)
+        break;
+    } while (complete);
+  
+  return last;
+}
+
+static void
+clutter_sqlite_update_hook (void          *user_data,
+                            int            type,
+                            const char    *db_name,
+                            const char    *table,
+                            sqlite_int64   rowid)
+{
+  ClutterModelIter          *iter;
+  ClutterSqliteModel        *model = user_data;
+  ClutterSqliteModelPrivate *priv  = model->priv;
+  gboolean                   skip = FALSE;
+  
+  if (strcmp (priv->table, table) != 0)
+    return;
+  
+  /* We need to be able to skip row additions/changes as ClutterModel emits 
+   * these signals itself, where as we want to emit them for all additions/
+   * changes using sqlite hooks.
+   */
+  if ((type == SQLITE_INSERT) && (priv->skip_add))
+    {
+      skip = TRUE;
+      priv->skip_add = FALSE;
+    }
+  else if ((type == SQLITE_UPDATE) && (priv->skip_change))
+    {
+      skip = TRUE;
+      priv->skip_change = FALSE;
+    }
+  else if ((type == SQLITE_DELETE) && (priv->skip_remove))
+    {
+      skip = TRUE;
+      priv->skip_remove = FALSE;
+    }
+  
+  if (!skip)
+    {
+      switch (type)
+        {
+        case SQLITE_INSERT:
+          iter = clutter_sqlite_model_iter_new_from_rowid (model, rowid);
+          g_signal_emit_by_name (model, "row-added", iter);
+          if (iter)
+            g_object_unref (iter);
+          break;
+        case SQLITE_DELETE:
+          g_signal_emit_by_name (model, "row-removed", NULL);
+          break;
+        case SQLITE_UPDATE:
+          iter = clutter_sqlite_model_iter_new_from_rowid (model, rowid);
+          g_signal_emit_by_name (model, "row-changed", iter);
+          if (iter)
+            g_object_unref (iter);
+          break;
+        }
+    }
+  
+  /* Reset our index, it may not be valid anymore */
+  reset_statement (model);
+}
+
+static guint
+clutter_sqlite_model_get_n_rows (ClutterModel *model)
+{
+  ClutterSqliteModel        *sqlite_model = CLUTTER_SQLITE_MODEL (model);
+  ClutterSqliteModelPrivate *priv         = sqlite_model->priv;
+  
+  if (!priv->complete)
+    statement_next (sqlite_model, TRUE, -1, -1);
+  
+  return priv->rowids->len;
+}
+
+static guint
+clutter_sqlite_model_get_n_columns (ClutterModel *model)
+{
+  ClutterSqliteModelPrivate *priv = CLUTTER_SQLITE_MODEL (model)->priv;
+  return priv->n_columns;
+}
+
+static const gchar *
+clutter_sqlite_model_get_column_name (ClutterModel *model, guint column)
+{
+  ClutterSqliteModelPrivate *priv = CLUTTER_SQLITE_MODEL (model)->priv;
+  return priv->col_names[column];
+}
+
+static GType
+clutter_sqlite_model_get_column_type (ClutterModel *model, guint column)
+{
+  ClutterSqliteModelPrivate *priv = CLUTTER_SQLITE_MODEL (model)->priv;
+
+  switch (priv->col_types->data[column])
+    {
+      case SQLITE_INTEGER :
+        return G_TYPE_INT;
+      case SQLITE_FLOAT :
+        return G_TYPE_DOUBLE;
+      case SQLITE_BLOB :
+      case SQLITE_TEXT :
+        return G_TYPE_STRING;
+      case SQLITE_NULL :
+      default :
+        return G_TYPE_INVALID;
+    }
+}
+
+static ClutterModelIter *
+clutter_sqlite_model_insert_row (ClutterModel *model, gint index)
+{
+  /* Note: This ignores index and just 'appends' to the table */
+  gint                       result;
+  ClutterSqliteModel        *sqlite_model = CLUTTER_SQLITE_MODEL (model);
+  ClutterSqliteModelPrivate *priv         = sqlite_model->priv;
+
+  /* Cancel the current iteration through the db,
+   * we'll be reset on add anyway */
+  if (!priv->complete && priv->rowids->len)
+    sqlite3_reset (priv->statement);
+
+  /* Skip the add hook, ClutterModel generates the row-added signal */
+  priv->skip_add = TRUE;
+  result = sqlite3_step_retry (priv->statements[SQL_ADD_ROW]);
+  sqlite3_reset (priv->statements[SQL_ADD_ROW]);
+
+  if (result == SQLITE_DONE)
+    {
+      gint              rowid = sqlite3_last_insert_rowid (priv->db);
+      ClutterModelIter *iter  =
+        clutter_sqlite_model_iter_new_from_rowid (sqlite_model, rowid);
+      if (iter)
+        return iter;
+      else
+        g_warning ("Failed to get iter for newly created row, "
+                   "probably about to assert.");
+    }
+  else
+    g_warning ("Failed to create row, probably about to assert: %s",
+               sqlite3_errmsg (priv->db));
+  
+  return NULL;
+}
+
+static void
+clutter_sqlite_model_remove_row (ClutterModel *model, guint row)
+{
+  ClutterSqliteModel        *sqlite_model = CLUTTER_SQLITE_MODEL (model);
+  ClutterSqliteModelPrivate *priv         = sqlite_model->priv;
+  ClutterModelIter          *iter;
+
+  /* Fire off 'removed' signal. We do this here, so at least for rows 
+   * removed through ClutterModel, we can pass a valid iter.
+   */
+  iter = clutter_sqlite_model_iter_new (sqlite_model, row);
+  if (iter)
+    {
+      priv->skip_remove = TRUE;
+      g_signal_emit_by_name (model, "row-removed", iter);
+      g_object_unref (iter);
+    }
+
+  if (!priv->complete && priv->rowids->len)
+    sqlite3_reset (priv->statement);
+
+  sqlite3_bind_int (priv->statements[SQL_DELETE_ROW],
+                    1,
+                    GPOINTER_TO_INT (priv->rowids->pdata[row]));
+  sqlite3_step_retry (priv->statements[SQL_DELETE_ROW]);
+  sqlite3_reset (priv->statements[SQL_DELETE_ROW]);
+}
+
+static ClutterModelIter *
+clutter_sqlite_model_get_iter_at_row (ClutterModel *model, guint row)
+{
+  return clutter_sqlite_model_iter_new (CLUTTER_SQLITE_MODEL (model), row);
+}
+
+static void
+clutter_sqlite_model_resort (ClutterModel         *model,
+                             ClutterModelSortFunc  func,
+                             gpointer              data)
+{
+}
+
+static GObject *
+clutter_sqlite_model_constructor (GType                  type,
+                                  guint                  n_properties,
+                                  GObjectConstructParam *properties)
+{
+  GObjectClass              *gobject_class;
+  GObject                   *obj;
+  ClutterSqliteModelPrivate *priv;
+  gint                       i;
+  
+  gobject_class = G_OBJECT_CLASS (clutter_sqlite_model_parent_class);
+  obj = gobject_class->constructor (type, n_properties, properties);
+  priv = CLUTTER_SQLITE_MODEL (obj)->priv;
+  
+  /* Set the busy-timeout */
+  sqlite3_busy_timeout (priv->db, DB_RETRY_WAIT);
+  
+  /* Generate and precompile statements */
+  for (i = 0; i < N_SQL_STATEMENTS; i++)
+    {
+      gchar *text =
+        g_strdup_printf (sql_statements[i], priv->table, priv->col_names[0]);
+      
+      if (sqlite3_prepare (priv->db,
+                           text,
+                           -1, 
+                           &priv->statements[i],
+                           NULL) != SQLITE_OK)
+        g_warning ("Failed to prepare '%s': %s", 
+                   text,
+                   sqlite3_errmsg (priv->db));
+      
+      g_free (text);
+    }
+  
+  priv->n_columns = priv->col_types->length;
+  
+  priv->update_statements =
+    g_malloc0 (sizeof (sqlite3_stmt *) * priv->n_columns);
+  for (i = 0; i < priv->n_columns; i++)
+    {
+      gchar *text = g_strdup_printf (sql_update_statement,
+                                     priv->table,
+                                     priv->col_names[i]);
+      if (sqlite3_prepare (priv->db,
+                           text,
+                           -1,
+                           &priv->update_statements[i],
+                           NULL) != SQLITE_OK)
+        g_warning ("Failed to prepare '%s' : %s", 
+                   text,
+                   sqlite3_errmsg (priv->db));
+      
+      g_free (text);
+    }
+  
+  /* Hook onto data change notification */
+  sqlite3_update_hook (priv->db, clutter_sqlite_update_hook, obj);
+  
+  return obj;
+}
+
+static void
+clutter_sqlite_model_class_init (ClutterSqliteModelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ClutterSqliteModelPrivate));
+
+  object_class->constructor  = clutter_sqlite_model_constructor;
+  object_class->get_property = clutter_sqlite_model_get_property;
+  object_class->set_property = clutter_sqlite_model_set_property;
+  object_class->dispose      = clutter_sqlite_model_dispose;
+  object_class->finalize     = clutter_sqlite_model_finalize;
+  
+  model_class->get_n_rows      = clutter_sqlite_model_get_n_rows;
+  model_class->get_n_columns   = clutter_sqlite_model_get_n_columns;
+  model_class->get_column_name = clutter_sqlite_model_get_column_name;
+  model_class->get_column_type = clutter_sqlite_model_get_column_type;
+  model_class->insert_row      = clutter_sqlite_model_insert_row;
+  model_class->remove_row      = clutter_sqlite_model_remove_row;
+  model_class->get_iter_at_row = clutter_sqlite_model_get_iter_at_row;
+  model_class->resort          = clutter_sqlite_model_resort;
+
+  g_object_class_install_property (object_class,
+                                   PROP_DB,
+                                   g_param_spec_pointer ("db",
+                                                         "Database",
+                                                         "Sqlite3 database "
+                                                         "pointer",
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_TABLE,
+                                   g_param_spec_string ("table",
+                                                        "Table name",
+                                                        "Sqlite3 table name",
+                                                        NULL,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_COL_NAMES,
+                                   g_param_spec_boxed ("col-names",
+                                                       "Column names",
+                                                       "Sqlite3 column names",
+                                                       G_TYPE_STRV,
+                                                       G_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_COL_TYPES,
+                                   g_param_spec_boxed ("col-types",
+                                                       "Column types",
+                                                       "Sqlite3 column types",
+                                                       CLUTTER_SQLITE_TYPE_INTV,
+                                                       G_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_STATEMENT,
+                                   g_param_spec_pointer ("statement",
+                                                         "Statement",
+                                                         "Sqlite3 statement "
+                                                         "pointer",
+                                                         G_PARAM_READWRITE));
+}
+
+static void
+clutter_sqlite_model_init (ClutterSqliteModel *self)
+{
+  ClutterSqliteModelPrivate *priv = self->priv = MODEL_PRIVATE (self);
+  
+  priv->rowids = g_ptr_array_new ();
+  priv->rowid_to_row = g_hash_table_new (NULL, NULL);
+}
+
+ClutterModel *
+clutter_sqlite_model_new (sqlite3 *db, const gchar *table, ...)
+{
+  ClutterModel      *model;
+  gint               n_columns;
+  const gchar       *name;
+  GStrv              name_array;
+  ClutterSqliteIntV *type_array;
+  GList             *names = NULL;
+  GList             *types = NULL;
+  
+  va_list args;
+  
+  va_start (args, table);
+  
+  n_columns = 0;
+  name = va_arg (args, const gchar *);
+  for (; name; name = va_arg (args, const gchar *))
+    {
+      names = g_list_prepend (names, g_strdup (name));
+      types = g_list_prepend (types, GINT_TO_POINTER (va_arg (args, gint)));
+      
+      n_columns ++;
+    }
+  
+  va_end (args);
+  
+  name_array = g_malloc0 (sizeof (gchar *) * (n_columns + 1));
+
+  type_array = g_new (ClutterSqliteIntV, 1);
+  type_array->length = n_columns;
+  type_array->data = g_malloc (sizeof (gint) * n_columns);
+  
+  while (names)
+    {
+      n_columns--;
+      name_array[n_columns] = names->data;
+      type_array->data[n_columns] = GPOINTER_TO_INT (types->data);
+      
+      names = g_list_delete_link (names, names);
+      types = g_list_delete_link (types, types);
+    }
+  
+  model = CLUTTER_MODEL (g_object_new (CLUTTER_SQLITE_TYPE_MODEL,
+                                       "db", db,
+                                       "table", table,
+                                       "col-names", name_array,
+                                       "col-types", type_array,
+                                       NULL));
+  
+  g_strfreev (name_array);
+  clutter_sqlite_intv_free (type_array);
+  
+  return model;
+}
+
+static void
+clutter_sqlite_model_iter_get_value (ClutterModelIter *iter,
+                                     guint             column,
+                                     GValue           *value)
+{
+  sqlite3_stmt *statement;
+  GType         column_type;
+  gboolean      converted    = FALSE;
+  GValue        real_value   = { 0, };
+  GValue        column_value = { 0, };
+
+  ClutterModel              *model   = clutter_model_iter_get_model (iter);
+  ClutterSqliteModelPrivate *priv    = CLUTTER_SQLITE_MODEL (model)->priv;
+  ClutterSqliteModelIter    *sqliter = CLUTTER_SQLITE_MODEL_ITER (iter);
+  
+  if (!priv->statement)
+    return;
+
+  column_type = clutter_sqlite_model_get_column_type (model, column);
+  if (column_type == G_TYPE_INVALID)
+    return;
+  
+  if (sqliter->is_parent == priv->version)
+    statement = priv->statement;
+  else
+    {
+      gint rowid = (sqliter->row == -1) ?
+        sqliter->rowid : GPOINTER_TO_INT (priv->rowids->pdata[sqliter->row]);
+      sqlite3_bind_int (priv->statements[SQL_GET_ROW], 1, rowid);
+      if (sqlite3_step_retry (priv->statements[SQL_GET_ROW]) != SQLITE_ROW)
+        {
+          g_warning ("Error getting row: %s", sqlite3_errmsg (priv->db));
+          sqlite3_reset (priv->statements[SQL_GET_ROW]);
+          return;
+        }
+      
+      statement = priv->statements[SQL_GET_ROW];
+    }
+  
+  g_value_init (&column_value, column_type);
+  switch (column_type)
+    {
+      case G_TYPE_STRING :
+        if (priv->col_types->data[column] == SQLITE_TEXT)
+          g_value_set_string (&column_value, (const gchar *)
+                              sqlite3_column_text (statement, column));
+        break;
+      case G_TYPE_INT :
+        g_value_set_int (&column_value,
+                         sqlite3_column_int (statement, column));
+        break;
+      case G_TYPE_BOOLEAN :
+        g_value_set_boolean (&column_value,
+                             sqlite3_column_int (statement, column));
+        break;
+      default :
+        g_value_unset (&column_value);
+        if (sqliter->is_parent != priv->version)
+          sqlite3_reset (priv->statements[SQL_GET_ROW]);
+        return;
+    }
+  
+  if (sqliter->is_parent != priv->version)
+    sqlite3_reset (priv->statements[SQL_GET_ROW]);
+
+  if (!g_type_is_a (G_VALUE_TYPE (value), column_type))
+    {
+      if (!g_value_type_compatible (G_VALUE_TYPE (value), column_type) &&
+          !g_value_type_compatible (column_type, G_VALUE_TYPE (value)))
+        {
+          g_warning ("%s: Unable to convert from %s to %s",
+                     G_STRLOC,
+                     g_type_name (G_VALUE_TYPE (value)),
+                     g_type_name (column_type));
+          return;
+        }
+      
+      if (!g_value_transform (&column_value, &real_value))
+        {
+          g_warning ("%s: Unable to make conversion from %s to %s",
+                     G_STRLOC, 
+                     g_type_name (column_type),
+                     g_type_name (G_VALUE_TYPE (value)));
+          g_value_unset (&real_value);
+        }
+      
+      converted = TRUE;
+    }
+    
+  if (converted)
+    {
+      g_value_copy (&real_value, value);
+      g_value_unset (&real_value);
+    }
+  else
+    g_value_copy (&column_value, value);
+  
+  g_value_unset (&column_value);
+}
+
+static void
+clutter_sqlite_model_iter_set_value (ClutterModelIter *iter,
+                                     guint             column,
+                                     const GValue     *value)
+{
+  gint         res, rowid;
+  GType        column_type;
+  gboolean     converted  = FALSE;
+  GValue       real_value = { 0, };
+    
+  ClutterModel              *model        = clutter_model_iter_get_model (iter);
+  ClutterSqliteModel        *sqlite_model = CLUTTER_SQLITE_MODEL (model);
+  ClutterSqliteModelPrivate *priv         = sqlite_model->priv;
+  ClutterSqliteModelIter    *sqliter      = CLUTTER_SQLITE_MODEL_ITER (iter);
+
+  if (!priv->statement)
+    return;
+  
+  column_type = clutter_sqlite_model_get_column_type (model, column);
+  if (column_type == G_TYPE_INVALID)
+    return;
+
+  g_value_init (&real_value, column_type);
+  
+  if (!g_type_is_a (G_VALUE_TYPE (value), column_type))
+    {
+      if (!g_value_type_compatible (G_VALUE_TYPE (value), column_type) &&
+          !g_value_type_compatible (column_type, G_VALUE_TYPE (value)))
+        {
+          g_warning ("%s: Unable to convert from %s to %s",
+                     G_STRLOC,
+                     g_type_name (G_VALUE_TYPE (value)),
+                     g_type_name (column_type));
+          return;
+        }
+      
+      if (!g_value_transform (value, &real_value))
+        {
+          g_warning ("%s: Unable to make conversion from %s to %s",
+                     G_STRLOC, 
+                     g_type_name (G_VALUE_TYPE (value)),
+                     g_type_name (column_type));
+          g_value_unset (&real_value);
+        }
+      
+      converted = TRUE;
+    }
+  
+  if (!converted)
+    g_value_copy (value, &real_value);
+  
+  if (!priv->complete && priv->rowids->len)
+    statement_next (sqlite_model, TRUE, -1, -1);
+  
+  switch (column_type)
+    {
+      case G_TYPE_STRING :
+        sqlite3_bind_text (priv->update_statements[column],
+                           1, g_value_get_string (&real_value), -1,
+                           SQLITE_TRANSIENT);
+        break;
+      case G_TYPE_INT :
+        sqlite3_bind_int (priv->update_statements[column],
+                          1, g_value_get_int (&real_value));
+        break;
+      case G_TYPE_BOOLEAN :
+        sqlite3_bind_int (priv->update_statements[column],
+                          1, g_value_get_boolean (&real_value));
+        break;
+      case G_TYPE_ENUM :
+        sqlite3_bind_int (priv->update_statements[column],
+                          1, g_value_get_enum (&real_value));
+        break;
+      case G_TYPE_OBJECT :
+        /* TODO: Let's think about this later */
+      default :
+        goto _iter_set_value_skip_write;
+    }
+  
+  rowid = (sqliter->row == -1) ?
+    sqliter->rowid : GPOINTER_TO_INT (priv->rowids->pdata[sqliter->row]);
+  sqlite3_bind_int (priv->update_statements[column], 2, rowid);
+  priv->skip_change = TRUE;
+  sqlite3_step_retry (priv->update_statements[column]);
+  res = sqlite3_reset (priv->update_statements[column]);
+
+  if (res != SQLITE_OK)
+    g_warning ("Unable to write to db (%d): %s",
+               res,
+               sqlite3_errmsg (priv->db));
+
+_iter_set_value_skip_write:
+  
+  g_value_unset (&real_value);
+}
+
+static gboolean
+clutter_sqlite_model_iter_is_first (ClutterModelIter *iter)
+{
+  ClutterSqliteModelIter *sqliter = CLUTTER_SQLITE_MODEL_ITER (iter);
+  return (sqliter->row == 0) ? TRUE : FALSE;
+}
+
+static gboolean
+clutter_sqlite_model_iter_is_last (ClutterModelIter *iter)
+{
+  ClutterSqliteModelIter *sqliter = CLUTTER_SQLITE_MODEL_ITER (iter);
+  return sqliter->is_last;
+}
+
+static ClutterModelIter *
+clutter_sqlite_model_iter_new (ClutterSqliteModel *model,
+                               gint                row)
+{
+  ClutterSqliteModelIter    *iter;
+  ClutterSqliteModelPrivate *priv = model->priv;
+  
+  if (!priv->statement)
+    return NULL;
+  
+  if (row && (row > (gint)priv->rowids->len))
+    {
+      if (!priv->complete)
+        statement_next (model, TRUE, -1, row);
+      
+      if (row > priv->rowids->len)
+        return NULL;
+    }
+  
+  iter = g_object_new (CLUTTER_SQLITE_TYPE_MODEL_ITER,
+                       "model", model,
+                       "row", row,
+                       NULL);
+  iter->row = row;
+  iter->is_last = (row >= priv->rowids->len) ? TRUE : FALSE;
+  
+  if ((row == priv->rowids->len) && (!priv->complete))
+    {
+      iter->is_last = statement_next (model, FALSE, -1, -1);
+      iter->is_parent = priv->version;
+    }
+  
+  return CLUTTER_MODEL_ITER (iter);
+}
+
+static ClutterModelIter *
+clutter_sqlite_model_iter_new_from_rowid (ClutterSqliteModel *model,
+                                          gint                rowid)
+{
+  ClutterSqliteModelPrivate *priv = model->priv;
+  ClutterModelIter          *iter;
+  ClutterSqliteModelIter    *sqlite_iter;
+  
+  if (!priv->statement)
+    return NULL;
+  
+  iter = clutter_sqlite_model_iter_new (model, -1);
+  sqlite_iter = CLUTTER_SQLITE_MODEL_ITER (iter);
+  sqlite_iter->rowid = rowid;
+  
+  return iter;
+}
+
+static ClutterModelIter *
+clutter_sqlite_model_iter_next (ClutterModelIter *iter)
+{
+  ClutterModelIter          *new_iter;
+  ClutterSqliteModelIter    *sqliter = CLUTTER_SQLITE_MODEL_ITER (iter);
+  ClutterSqliteModel        *model;
+  ClutterSqliteModelPrivate *priv;
+  
+  if (sqliter->is_last)
+    return NULL;
+  
+  model = CLUTTER_SQLITE_MODEL (clutter_model_iter_get_model (iter));
+  priv = model->priv;
+
+  /* If we don't yet have a row set, try to get one */
+  if (sqliter->row < 0)
+    {
+      sqliter->row = GPOINTER_TO_INT (
+        g_hash_table_lookup (priv->rowid_to_row,
+                             GINT_TO_POINTER (sqliter->rowid)));
+
+      if (!priv->complete && !sqliter->row)
+        {
+          statement_next (model, TRUE, sqliter->rowid, -1);
+          sqliter->row = GPOINTER_TO_INT (
+            g_hash_table_lookup (priv->rowid_to_row,
+                                 GINT_TO_POINTER (sqliter->rowid)));
+        }
+      
+      if (!sqliter->row)
+        {
+          sqliter->row = -1;
+          return NULL;
+        }
+    }
+  
+  new_iter = clutter_sqlite_model_iter_new (model, sqliter->row + 1);
+  
+  if (sqliter->is_parent == priv->version)
+    {
+      ClutterSqliteModelIter *sqlite_iter =
+        CLUTTER_SQLITE_MODEL_ITER (new_iter);
+      statement_next (model, FALSE, -1, -1);
+      sqlite_iter->is_parent = priv->version;
+    }
+
+  g_object_unref (sqliter);
+
+  return new_iter;
+}
+
+static ClutterModelIter *
+clutter_sqlite_model_iter_prev (ClutterModelIter *iter)
+{
+  ClutterModelIter          *new_iter;
+  ClutterSqliteModelIter    *sqliter = CLUTTER_SQLITE_MODEL_ITER (iter);
+  ClutterSqliteModel        *model;
+  
+  if (sqliter->row == 0)
+    return NULL;
+  
+  model = CLUTTER_SQLITE_MODEL (clutter_model_iter_get_model (iter));
+  new_iter = clutter_sqlite_model_iter_new (model, sqliter->row - 1);
+
+  g_object_unref (sqliter);
+  
+  return new_iter;
+}
+
+static void
+clutter_sqlite_model_iter_class_init (ClutterSqliteModelIterClass *klass)
+{
+  ClutterModelIterClass *iter_class = CLUTTER_MODEL_ITER_CLASS (klass);
+  
+  iter_class->get_value = clutter_sqlite_model_iter_get_value;
+  iter_class->set_value = clutter_sqlite_model_iter_set_value;
+  iter_class->is_first  = clutter_sqlite_model_iter_is_first;
+  iter_class->is_last   = clutter_sqlite_model_iter_is_last;
+  iter_class->next      = clutter_sqlite_model_iter_next;
+  iter_class->prev      = clutter_sqlite_model_iter_prev;
+}
+
+static void
+clutter_sqlite_model_iter_init (ClutterSqliteModelIter *iter)
+{
+}
+
diff --git a/attic/sqlite-model/clutter-sqlite-model.h b/attic/sqlite-model/clutter-sqlite-model.h
new file mode 100644 (file)
index 0000000..815af58
--- /dev/null
@@ -0,0 +1,97 @@
+
+/*
+ * ClutterSqliteModel
+ *
+ * An sqlite3-backed ClutterModel implementation.
+ *
+ * Authored By Chris Lord  <chris@openedhand.com>
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * NB: Inspiration taken from the 'woohaa' toy by Matthew Allum and 
+ *     GValue conversion code copied from ClutterListModel, by
+ *     Matthew Allum, Neil Jagdish Patel and Emmanuele Bassi.
+ */
+
+#ifndef _CLUTTER_SQLITE_MODEL
+#define _CLUTTER_SQLITE_MODEL
+
+#include <glib-object.h>
+#include <sqlite3.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_SQLITE_TYPE_INTV  (clutter_sqlite_intv_get_type())
+
+typedef struct _ClutterSqliteIntV ClutterSqliteIntV;
+
+struct _ClutterSqliteIntV
+{
+  guint  length;
+  gint  *data;
+};
+
+ClutterSqliteIntV *clutter_sqlite_intv_copy (const ClutterSqliteIntV *intv);
+void               clutter_sqlite_intv_free (ClutterSqliteIntV       *intv);
+
+
+#define CLUTTER_SQLITE_TYPE_MODEL (clutter_sqlite_model_get_type())
+
+#define CLUTTER_SQLITE_MODEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_SQLITE_TYPE_MODEL, ClutterSqliteModel))
+
+#define CLUTTER_SQLITE_MODEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_SQLITE_TYPE_MODEL, ClutterSqliteModelClass))
+
+#define CLUTTER_SQLITE_IS_MODEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_SQLITE_TYPE_MODEL))
+
+#define CLUTTER_SQLITE_IS_MODEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_SQLITE_TYPE_MODEL))
+
+#define CLUTTER_SQLITE_MODEL_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_SQLITE_TYPE_MODEL, ClutterSqliteModelClass))
+
+typedef struct _ClutterSqliteModel        ClutterSqliteModel;
+typedef struct _ClutterSqliteModelPrivate ClutterSqliteModelPrivate;
+typedef struct _ClutterSqliteModelClass   ClutterSqliteModelClass;
+
+struct _ClutterSqliteModel {
+  ClutterModel               parent;
+  
+  ClutterSqliteModelPrivate *priv;
+};
+
+struct _ClutterSqliteModelClass {
+  ClutterModelClass parent_class;
+};
+
+GType clutter_sqlite_model_get_type (void);
+
+ClutterModel *clutter_sqlite_model_new (sqlite3 *db, const gchar *table, ...);
+
+G_END_DECLS
+
+#endif
+
diff --git a/attic/sqlite-model/test-sqlite-model.c b/attic/sqlite-model/test-sqlite-model.c
new file mode 100644 (file)
index 0000000..0cc2750
--- /dev/null
@@ -0,0 +1,248 @@
+#include <clutter/clutter.h>
+#include <sqlite3.h>
+#include "clutter-sqlite-model.h"
+#include <string.h>
+#include <glib/gstdio.h>
+
+/* Test taken from Clutter and modified to use ClutterSqliteModel */
+
+/* gcc -o test-sqlite-model *.c `pkg-config --cflags --libs clutter-0.8 sqlite3` -Wall -g */
+
+#define N_ROWS 1000
+
+enum
+{
+  COLUMN_FOO,
+  COLUMN_BAR,
+
+  N_COLUMNS
+};
+
+static sqlite3_stmt *statement = NULL;
+
+static void
+set_query (ClutterModel *model, const gchar *query)
+{
+  sqlite3_stmt *old_stmt;
+  sqlite3 *db;
+  
+  old_stmt = statement;
+
+  g_object_get (G_OBJECT (model), "db", &db, NULL);
+  if (sqlite3_prepare (db, query, -1, &statement, NULL) != SQLITE_OK)
+    g_error ("Error preparing query: %s", sqlite3_errmsg (db));
+  g_object_set (G_OBJECT (model), "statement", statement, NULL);
+
+  if (old_stmt)
+    sqlite3_finalize (old_stmt);
+}
+
+static void
+print_iter (ClutterModelIter *iter,
+            const gchar      *text)
+{
+  ClutterModel *model;
+  gint i;
+  gchar *string;
+
+  model = clutter_model_iter_get_model (iter);
+
+  clutter_model_iter_get (iter, COLUMN_FOO, &i, COLUMN_BAR, &string, -1);
+
+  g_print ("[row:%02d]: %s: (%s: %d), (%s: %s)\n",
+           clutter_model_iter_get_row (iter),
+           text,
+           clutter_model_get_column_name (model, COLUMN_FOO), i,
+           clutter_model_get_column_name (model, COLUMN_BAR), string);
+
+  g_free (string);
+}
+
+static gboolean
+foreach_func (ClutterModel     *model,
+              ClutterModelIter *iter,
+              gpointer          dummy)
+{
+  gint i;
+  gchar *string;
+
+  clutter_model_iter_get (iter, COLUMN_FOO, &i, COLUMN_BAR, &string, -1);
+
+  g_print ("[row:%02d]: Foreach: %d, %s\n",
+           clutter_model_iter_get_row (iter),
+           i, string);
+  
+  g_free (string);
+
+  return TRUE;
+}
+
+static void
+on_row_changed (ClutterModel     *model,
+                ClutterModelIter *iter)
+{
+  print_iter (iter, "Changed");
+}
+
+static void
+filter_model (ClutterModel *model)
+{
+  ClutterModelIter *iter;
+
+  g_print ("\n* Changing Query: reverse alpha\n");
+  set_query (model, "select *,rowid from mytable order by bar desc;");
+
+  g_signal_connect (model, "row-changed", G_CALLBACK (on_row_changed), NULL);
+  
+  iter = clutter_model_get_iter_at_row (model, 0);
+  clutter_model_iter_set (iter, COLUMN_BAR, "Changed string of 0th row, "
+                                            "automatically gets sorted",
+                                -1);
+  g_object_unref (iter);
+
+  clutter_model_foreach (model, foreach_func, NULL);
+
+  g_print ("\n* Unset filter\n");
+  clutter_model_set_filter (model, NULL, NULL, NULL);
+
+  while (clutter_model_get_n_rows (model))
+    clutter_model_remove (model, 0);
+  
+  clutter_main_quit ();
+}
+
+static void
+iterate (ClutterModel *model)
+{
+  ClutterModelIter *iter;
+  
+  iter = clutter_model_get_first_iter (model);
+
+  while (!clutter_model_iter_is_last (iter))
+    {
+      print_iter (iter, "Forward Iteration");
+      iter = clutter_model_iter_next (iter);
+    }
+  g_object_unref (iter);
+
+  iter = clutter_model_get_last_iter (model);  
+  do
+    {
+      print_iter (iter, "Reverse Iteration");
+      iter = clutter_model_iter_prev (iter);
+    }
+  while (!clutter_model_iter_is_first (iter));
+  
+  print_iter (iter, "Reverse Iteration");
+  g_object_unref (iter);
+
+  filter_model (model);
+}
+
+
+static gboolean
+populate_model (ClutterModel *model)
+{
+  gint i;
+
+  for (i = 0; i < N_ROWS; i++)
+    {
+      gchar *string = g_strdup_printf ("String %d", i);
+
+      clutter_model_append (model,
+                            COLUMN_FOO, i,
+                            COLUMN_BAR, string,
+                            -1);
+      g_free (string);
+    }
+
+  clutter_model_foreach (model, foreach_func, NULL);
+  iterate (model);
+
+  return FALSE;
+}
+
+static void
+on_row_added (ClutterModel     *model,
+              ClutterModelIter *iter,
+              gpointer          dummy)
+{
+  gint i;
+  gchar *string;
+
+  clutter_model_iter_get (iter, COLUMN_FOO, &i, COLUMN_BAR, &string, -1);
+
+  g_print ("[row:%02d]: Added: %d, %s\n",
+           clutter_model_iter_get_row (iter),
+           i, string);
+
+  g_free (string);
+}
+
+static void
+on_row_removed (ClutterModel     *model,
+                ClutterModelIter *iter,
+                gpointer          dummy)
+{
+  print_iter (iter, "Removed");
+}
+
+static void
+on_sort_changed (ClutterModel *model)
+{
+  g_print ("*** Sort Changed   ***\n\n");
+  clutter_model_foreach (model, foreach_func, NULL);
+}
+
+static void
+on_filter_changed (ClutterModel *model)
+{
+  g_print ("*** Filter Changed ***\n\n");
+}
+int
+main (int argc, char *argv[])
+{
+  sqlite3         *db;
+  ClutterModel    *model;
+  const gchar     *file = "test-sqlite-db.db";
+
+  clutter_init (&argc, &argv);
+
+  if (sqlite3_open (file, &db))
+    g_error ("Error creating database: %s", sqlite3_errmsg (db));
+  
+  if (sqlite3_exec (db,
+                    "CREATE TABLE IF NOT EXISTS mytable(foo int, bar text);",
+                    NULL,
+                    NULL,
+                    NULL))
+    g_error ("Can't create table: %s", sqlite3_errmsg (db));
+  
+  model = clutter_sqlite_model_new (db, "mytable",
+                                    "foo", SQLITE_INTEGER,
+                                    "bar", SQLITE_TEXT,
+                                    NULL);
+
+  set_query (model, "select *,rowid from mytable order by bar;");
+
+  g_timeout_add (1000, (GSourceFunc) populate_model, model);
+
+  g_signal_connect (model, "row-added",
+                    G_CALLBACK (on_row_added), NULL);
+  g_signal_connect (model, "row-removed",
+                    G_CALLBACK (on_row_removed), NULL);
+  g_signal_connect (model, "sort-changed",
+                    G_CALLBACK (on_sort_changed), NULL);
+  g_signal_connect (model, "filter-changed",
+                    G_CALLBACK (on_filter_changed), NULL);
+
+  clutter_main();
+  
+  g_object_unref (model);
+  
+  g_remove (file);
+  
+  return 0;
+}
+
diff --git a/attic/table/Makefile b/attic/table/Makefile
new file mode 100644 (file)
index 0000000..385061e
--- /dev/null
@@ -0,0 +1,14 @@
+LIBS=`pkg-config --libs clutter-0.6 gnome-vfs-2.0 clutter-gst-0.6`
+INCS=`pkg-config --cflags clutter-0.6 gnome-vfs-2.0 clutter-gst-0.6`
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: table
+
+
+table: table.o clutter-dominatrix.o clutter-video-player.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ table.o clutter-dominatrix.o clutter-video-player.o $(LIBS)
+
+clean:
+       rm -fr *.o table
diff --git a/attic/table/clutter-dominatrix.c b/attic/table/clutter-dominatrix.c
new file mode 100644 (file)
index 0000000..79e2991
--- /dev/null
@@ -0,0 +1,1008 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Tomas Frydrych tf@openedhand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:clutter-dominatrix
+ * @short_description: An actor manipulation proxy.
+ * 
+ * #ClutterDominatrix is a proxy object for manipulation for actors via a
+ * pointer: the slave actor can be rotated by dragging one of it's corners,
+ * moved by dragging it's center and resizes by dragging the rest of it.
+ */
+
+#include "clutter-dominatrix.h"
+#include <clutter/clutter.h>
+#include <stdlib.h>
+
+#ifndef CLUTTER_PARAM_READWRITE
+#define CLUTTER_PARAM_READWRITE \
+        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+#endif
+
+G_DEFINE_TYPE (ClutterDominatrix,
+              clutter_dominatrix,
+              G_TYPE_OBJECT);
+
+#define CLUTTER_DOMINATRIX_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_DOMINATRIX, ClutterDominatrixPrivate))
+
+typedef enum {
+  DRAG_NONE = 0,
+  DRAG_ROTATE,
+  DRAG_MOVE,
+  DRAG_RESIZE_TL,
+  DRAG_RESIZE_TR,
+  DRAG_RESIZE_BL,
+  DRAG_RESIZE_BR,
+  DRAG_SCALE,
+} DragType;
+
+struct _ClutterDominatrixPrivate
+{
+  ClutterActor * slave;
+
+  guint rhandle_width;
+  guint rhandle_height;
+  
+  guint mhandle_width;
+  guint mhandle_height;
+
+  DragType  dragging;
+  gint      prev_x;
+  gint      prev_y;
+  gint      center_x;
+  gint      center_y;
+  
+  gboolean  scale : 1;
+  gboolean  dont_rotate : 1;
+  gboolean  dont_resize : 1;
+  gboolean  dont_move : 1;
+
+  ClutterGravity gravity;
+
+  ClutterActorBox orig_box;
+  ClutterFixed    orig_scale_x;
+  ClutterFixed    orig_scale_y;
+  ClutterFixed    orig_zang;
+  gint            orig_rot_x;
+  gint            orig_rot_y;
+
+  guint8          old_opacity;
+};
+
+enum
+{
+  MANIPULATION_STARTED,
+  MANIPULATION_ENDED,
+  
+  LAST_SIGNAL
+};
+
+static guint dmx_signals[LAST_SIGNAL] = { 0, };
+
+enum
+{
+  PROP_0,
+  PROP_ROTATE_HANDLE_WIDTH,
+  PROP_ROTATE_HANDLE_HEIGHT,
+  PROP_MOVE_HANDLE_WIDTH,
+  PROP_MOVE_HANDLE_HEIGHT,
+  PROP_SLAVE,
+  PROP_SCALE,
+  PROP_DISABLE_ROTATION,
+  PROP_DISABLE_RESIZING,
+  PROP_DISABLE_MOVEMENT,
+  PROP_GRAVITY,
+};
+
+
+static void 
+clutter_dominatrix_set_property (GObject      *object, 
+                                 guint         prop_id,
+                                 const GValue *value, 
+                                 GParamSpec   *pspec)
+{
+
+  ClutterDominatrix        *dominatrix;
+  ClutterDominatrixPrivate *priv;
+
+  dominatrix = CLUTTER_DOMINATRIX(object);
+  priv = dominatrix->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_ROTATE_HANDLE_WIDTH:
+      priv->rhandle_width = g_value_get_int (value);
+      break;
+    case PROP_ROTATE_HANDLE_HEIGHT:
+      priv->rhandle_height = g_value_get_int (value);
+      break;
+    case PROP_MOVE_HANDLE_WIDTH:
+      priv->mhandle_width = g_value_get_int (value);
+      break;
+    case PROP_MOVE_HANDLE_HEIGHT:
+      priv->mhandle_height = g_value_get_int (value);
+      break;
+    case PROP_SLAVE:
+      clutter_dominatrix_set_slave (dominatrix,
+                               CLUTTER_ACTOR (g_value_get_pointer (value)));
+      break;
+    case PROP_SCALE:
+      priv->scale = g_value_get_boolean (value);
+      break;
+    case PROP_DISABLE_ROTATION:
+      priv->dont_rotate = g_value_get_boolean (value);
+      break;
+    case PROP_DISABLE_RESIZING:
+      priv->dont_resize = g_value_get_boolean (value);
+      break;
+    case PROP_DISABLE_MOVEMENT:
+      priv->dont_move = g_value_get_boolean (value);
+      break;
+    case PROP_GRAVITY:
+      priv->gravity = g_value_get_enum (value);
+      clutter_actor_move_anchor_point_from_gravity (priv->slave,
+                                                    priv->gravity);
+      break;
+      
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void 
+clutter_dominatrix_get_property (GObject    *object, 
+                                 guint       prop_id,
+                                 GValue     *value, 
+                                 GParamSpec *pspec)
+{
+  ClutterDominatrix        *dominatrix;
+  ClutterDominatrixPrivate *priv;
+
+  dominatrix = CLUTTER_DOMINATRIX(object);
+  priv = dominatrix->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_ROTATE_HANDLE_WIDTH:
+      g_value_set_int (value, priv->rhandle_width);
+      break;
+    case PROP_ROTATE_HANDLE_HEIGHT:
+      g_value_set_int (value, priv->rhandle_height);
+      break;
+    case PROP_MOVE_HANDLE_WIDTH:
+      g_value_set_int (value, priv->mhandle_width);
+      break;
+    case PROP_MOVE_HANDLE_HEIGHT:
+      g_value_set_int (value, priv->mhandle_height);
+      break;
+    case PROP_SLAVE:
+      g_value_set_pointer (value, priv->slave);
+      break;
+    case PROP_SCALE:
+      g_value_set_boolean (value, priv->scale);
+      break;
+    case PROP_DISABLE_ROTATION:
+      g_value_set_boolean (value, priv->dont_rotate);
+      break;
+    case PROP_DISABLE_RESIZING:
+      g_value_set_boolean (value, priv->dont_resize);
+      break;
+    case PROP_DISABLE_MOVEMENT:
+      g_value_set_boolean (value, priv->dont_move);
+      break;
+    case PROP_GRAVITY:
+      g_value_set_enum (value, priv->gravity);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_dominatrix_release_slave (ClutterDominatrixPrivate * priv)
+{
+  priv->dragging = DRAG_NONE;
+  
+  if (priv->slave)
+    {
+      g_object_unref (priv->slave);
+      g_object_set_data (G_OBJECT (priv->slave), "dominatrix", NULL);
+      priv->slave = NULL;
+    }
+}
+
+static void 
+clutter_dominatrix_finalize (GObject *object)
+{
+  ClutterDominatrix *dmx = CLUTTER_DOMINATRIX (object);
+
+  clutter_dominatrix_release_slave (dmx->priv);
+  
+  G_OBJECT_CLASS (clutter_dominatrix_parent_class)->finalize (object);
+}
+
+static void
+clutter_dominatrix_store_original_settings (ClutterDominatrixPrivate *priv)
+{
+  clutter_actor_move_anchor_point_from_gravity (priv->slave,
+                                                CLUTTER_GRAVITY_NONE);
+  clutter_actor_query_coords (priv->slave, &priv->orig_box);
+  
+  clutter_actor_get_scalex (priv->slave,
+                           &priv->orig_scale_x,
+                           &priv->orig_scale_y);
+
+  priv->orig_zang = clutter_actor_get_rotationx (priv->slave,
+                                                 CLUTTER_Z_AXIS,
+                                                 &priv->orig_rot_x,
+                                                 &priv->orig_rot_y,
+                                                 NULL);
+  clutter_actor_move_anchor_point_from_gravity (priv->slave,
+                                                priv->gravity);
+}
+
+static GObject *
+clutter_dominatrix_constructor (GType                  gtype,
+                               guint                  n_params,
+                               GObjectConstructParam *params)
+{
+  GObjectClass       * parent_class;
+  GObject            * retval;
+  ClutterDominatrix  * dmx;
+  ClutterActor       * stage;
+  
+  parent_class = G_OBJECT_CLASS (clutter_dominatrix_parent_class);
+  retval = parent_class->constructor (gtype, n_params, params);
+
+  dmx = CLUTTER_DOMINATRIX (retval);
+
+  stage = clutter_stage_get_default ();
+  
+  clutter_dominatrix_store_original_settings (dmx->priv);
+  
+  g_object_set_data (G_OBJECT (dmx->priv->slave), "dominatrix", retval);
+  
+  return retval;
+}
+
+static void
+clutter_dominatrix_class_init (ClutterDominatrixClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructor = clutter_dominatrix_constructor;
+  object_class->set_property = clutter_dominatrix_set_property;
+  object_class->get_property = clutter_dominatrix_get_property;
+  object_class->finalize     = clutter_dominatrix_finalize;
+
+  g_type_class_add_private (klass, sizeof (ClutterDominatrixPrivate));
+
+  /**
+   * ClutterDominatrix:rotate-handle-width:
+   *
+   * Width of the rotation handle.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_ROTATE_HANDLE_WIDTH,
+                                   g_param_spec_int ("rotate-handle-width",
+                                                "width of rotation handle",
+                                                "width of rotation handle",
+                                                0, G_MAXINT,
+                                                0,
+                                                CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterDominatrix:rotate-handle-height:
+   *
+   * Height of the rotation handle.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_ROTATE_HANDLE_HEIGHT,
+                                   g_param_spec_int ("rotate-handle-height",
+                                                "height of rotation handle",
+                                                "height of rotation handle",
+                                                0, G_MAXINT,
+                                                0,
+                                                CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterDominatrix:move-handle-width:
+   *
+   * Width of the move handle.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_MOVE_HANDLE_WIDTH,
+                                   g_param_spec_int ("move-handle-width",
+                                                "width of move handle",
+                                                "width of move handle",
+                                                0, G_MAXINT,
+                                                0,
+                                                CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterDominatrix:move-handle-height:
+   *
+   * Height of the move handle.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_MOVE_HANDLE_HEIGHT,
+                                   g_param_spec_int ("move-handle-height",
+                                                "height of move handle",
+                                                "height of move handle",
+                                                0, G_MAXINT,
+                                                0,
+                                                CLUTTER_PARAM_READWRITE));
+
+  
+  /**
+   * ClutterDominatrix:slave:
+   *
+   * Slave we are manipulating.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_SLAVE,
+                                   g_param_spec_pointer ("slave",
+                                                "slave",
+                                                "slave",
+                                               G_PARAM_CONSTRUCT |
+                                               CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterDominatrix:scale:
+   *
+   * Whether dragging in the no-mans land should be translated to scaling
+   * or resizing. Deafult TRUE
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_SCALE,
+                                   g_param_spec_boolean ("scale",
+                                                "whether to scale or resize",
+                                                "whether to scale or resize",
+                                               TRUE,
+                                                CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterDominatrix:disable-rotation:
+   *
+   * Whether rotation should be disabled; default FALSE
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_DISABLE_ROTATION,
+                                   g_param_spec_boolean ("disable-rotation",
+                                                "whether to rotate",
+                                                "whether to rotate",
+                                               FALSE,
+                                                CLUTTER_PARAM_READWRITE));
+  
+
+  /**
+   * ClutterDominatrix:disable-resizing:
+   *
+   * Whether resizing should be disabled; default FALSE
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_DISABLE_RESIZING,
+                                   g_param_spec_boolean ("disable-resizing",
+                                                "whether to resize",
+                                                "whether to resize",
+                                               FALSE,
+                                                CLUTTER_PARAM_READWRITE));
+  
+  /**
+   * ClutterDominatrix:disable-movement:
+   *
+   * Whether moving should be disabled; default FALSE
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_DISABLE_MOVEMENT,
+                                   g_param_spec_boolean ("disable-movement",
+                                                "whether to move",
+                                                "whether to move",
+                                               FALSE,
+                                                CLUTTER_PARAM_READWRITE));
+  
+  /**
+   * ClutterDominatrix:gravity:
+   *
+   * Gravity to use when scaling; default CLUTTER_GRAVITY_CENTER
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_GRAVITY,
+                                   g_param_spec_enum ("gravity",
+                                            "which gravity to use for scaling",
+                                            "which gravity to use for scaling",
+                                           CLUTTER_TYPE_GRAVITY,
+                                           CLUTTER_GRAVITY_CENTER,
+                                           G_PARAM_CONSTRUCT |
+                                            CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterDominatrix::manipulation-started:
+   * @dmx: the object which received the signal
+   *
+   * This signal is emitted each time the users starts to manipulate the
+   * actor.
+   *
+   */
+  dmx_signals[MANIPULATION_STARTED] =
+    g_signal_new ("manipulation-started",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterDominatrixClass,
+                                  manipulation_started),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  
+  /**
+   * ClutterDominatrix::manipulation-ended:
+   * @dmx: the object which received the signal
+   *
+   * This signal is emitted each time the users starts to manipulate the
+   * actor.
+   *
+   */
+  dmx_signals[MANIPULATION_ENDED] =
+    g_signal_new ("manipulation-ended",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterDominatrixClass,
+                                  manipulation_ended),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+static void
+clutter_dominatrix_init (ClutterDominatrix *self)
+{
+  self->priv = CLUTTER_DOMINATRIX_GET_PRIVATE (self);
+
+  self->priv->rhandle_width  = 30;
+  self->priv->rhandle_height = 30;
+  self->priv->mhandle_width  = 30;
+  self->priv->mhandle_height = 30;
+  self->priv->scale = TRUE;
+  self->priv->gravity = CLUTTER_GRAVITY_CENTER;
+  self->priv->old_opacity = 0xff;
+}
+
+void 
+clutter_dominatrix_handle_event (ClutterDominatrix        *dominatrix,
+                                ClutterEvent             *event)
+{
+  ClutterDominatrixPrivate * priv = dominatrix->priv;
+  
+  switch (event->type)
+    {
+    case CLUTTER_BUTTON_PRESS:
+      {
+       gint x, y;
+       ClutterActor   * actor = priv->slave;
+       ClutterVertex    v[4];
+       ClutterVertex    v1, v2;
+       ClutterFixed     xp, yp;
+       ClutterFixed     zang;
+       gint32           xmin, xmax, ymin, ymax;
+       gint i;
+       gint width, height;
+       gint mhandle_width  = priv->mhandle_width;
+       gint mhandle_height = priv->mhandle_height;
+       gint rhandle_width  = priv->rhandle_width;
+       gint rhandle_height = priv->rhandle_height;
+       
+       if (((ClutterButtonEvent *)event)->click_count == 2)
+         {
+           clutter_dominatrix_restore (dominatrix);
+           break;
+         }
+       
+        clutter_event_get_coords (event, &x, &y);
+
+       clutter_actor_raise_top (priv->slave);
+
+       priv->old_opacity = clutter_actor_get_opacity (priv->slave);
+           
+
+       g_signal_emit (dominatrix, dmx_signals[MANIPULATION_STARTED], 0);
+
+       priv->prev_x = x;
+       priv->prev_y = y;
+       
+       /* Check that the handle size are sensible in relationship to the
+        * projected size of our slave, otherwise if the user reduces the size
+        * of the slave too much, s/he will not be able to expand it again
+        * -- we practice safe bondage only in this house ;).
+        *
+        * Allow the movement handle to be at most half of the width/height
+        * and the rotation handles to be at most a quarter of width/height.
+        */
+       clutter_actor_get_vertices (actor, v);
+
+       xmin = xmax = v[0].x;
+       ymin = ymax = v[0].y;
+
+       for (i = 1; i < 4; ++i)
+         {
+           if (xmin > v[i].x)
+             xmin = v[i].x;
+           if (xmax < v[i].x)
+             xmax = v[i].x;
+           
+           if (ymin > v[i].y)
+             ymin = v[i].y;
+           if (ymax < v[i].y)
+             ymax = v[i].y;
+         }
+       
+       width  = CLUTTER_FIXED_INT (xmax - xmin);
+       height = CLUTTER_FIXED_INT (ymax - ymin);
+
+       /* FIXME -- make this work when the actor is rotated */
+       if (width < 2 * mhandle_width)
+         {
+           mhandle_width = width >> 1;
+           g_debug ("Adjusted mhandle width to %d", mhandle_width);
+         }
+
+       if (height < 2 * mhandle_height)
+         {
+           mhandle_height = height >> 1;
+           g_debug ("Adjusted mhandle height to %d", mhandle_height);
+         }
+       
+       if (width < 4 * rhandle_width)
+         {
+           rhandle_width = width >> 2;
+           g_debug ("Adjusted rhandle width to %d", rhandle_width);
+         }
+       
+       if (height < 4 * rhandle_height)
+         {
+           rhandle_height = height >> 2;
+           g_debug ("Adjusted rhandle height to %d", rhandle_height);
+         }
+       
+       /*
+        * work out drag type
+        *
+        * First, check for movement
+        */
+       v1.x = CLUTTER_INT_TO_FIXED (clutter_actor_get_width  (actor) / 2);
+       v1.y = CLUTTER_INT_TO_FIXED (clutter_actor_get_height (actor) / 2);
+       v1.z = 0;
+  
+       clutter_actor_apply_transform_to_point (actor, &v1, &v2);
+
+       xp = CLUTTER_FIXED_INT (v2.x);
+       yp = CLUTTER_FIXED_INT (v2.y);
+
+       /* Store these for later */
+       priv->center_x = xp;
+       priv->center_y = yp;
+
+       if (abs (xp - x) < mhandle_width &&
+           abs (yp - y) < mhandle_height)
+         {
+           priv->dragging = DRAG_MOVE;
+           clutter_actor_set_opacity (priv->slave, priv->old_opacity / 2);
+           return;
+         }
+
+       /*
+        * Next, we check for rotation
+        */
+       for (i = 0; i < 4; ++i)
+         if (abs (CLUTTER_FIXED_INT (v[i].x) - x) < rhandle_width &&
+             abs (CLUTTER_FIXED_INT (v[i].y) - y) < rhandle_height)
+           {
+             priv->dragging = DRAG_ROTATE;
+             return;
+           }
+
+       
+       /*
+        *  Neither move or rotation, so we are resizing or scaling.
+         */
+       if (priv->scale)
+         {
+           priv->dragging = DRAG_SCALE;
+           return;
+         }
+       else
+         {
+           /*
+            * We notionally divide the projected area into 2 x 2 grid,
+            * representing 4 types of resize.
+            *
+            * If the object is rotated, we need to unrotate the screen
+            * coords first.
+            */
+           zang = clutter_actor_get_rotationx (actor, CLUTTER_Z_AXIS,
+                                               NULL, NULL, NULL);
+
+           if (zang)
+             {
+               gint x2 = x - xp;
+               gint y2 = y - yp;
+               ClutterFixed zang_rad = -CFX_MUL (zang, CFX_PI) / 180;
+           
+               x = CLUTTER_FIXED_INT (x2 * clutter_cosx (zang_rad) -
+                                      y2 * clutter_sinx (zang_rad)) + xp;
+
+               y = CLUTTER_FIXED_INT (y2 * clutter_cosx (zang_rad) +
+                                      x2 * clutter_sinx (zang_rad)) + yp;
+             }
+       
+           if (x < xp && y < yp)
+             {
+               priv->dragging = DRAG_RESIZE_TL;
+               return;
+             }
+
+           if (x < xp && y >= yp)
+             {
+               priv->dragging = DRAG_RESIZE_BL;
+               return;
+             }
+
+           if (x >= xp && y < yp)
+             {
+               priv->dragging = DRAG_RESIZE_TR;
+               return;
+             }
+
+           if (x >= xp && y >= yp)
+             {
+               priv->dragging = DRAG_RESIZE_BR;
+               return;
+             }
+         }
+       
+       g_warning ("Error calculating drag type");
+       priv->dragging = DRAG_NONE;
+      }
+      break;
+
+    case CLUTTER_MOTION:
+      {
+       gint x, y;
+       ClutterFixed zang;
+       ClutterActorBox box;
+
+       if (priv->dragging == DRAG_NONE)
+         return;
+       
+        clutter_event_get_coords (event, &x, &y);
+       
+       /* We intentionally do not test here if the pointer is within
+        * our slave since we want to be able to manipulate the objects with
+        * the point outwith the object (i.e., for greater precission when
+        * rotating)
+        */
+       clutter_actor_query_coords (priv->slave, &box);
+
+  zang = clutter_actor_get_rotationx (priv->slave, CLUTTER_Z_AXIS,
+                                      NULL, NULL, NULL);
+
+       if (priv->dragging == DRAG_MOVE)
+         {
+           if (priv->dont_move)
+             return;
+
+           clutter_actor_move_by (priv->slave,
+                                  x - priv->prev_x,
+                                  y - priv->prev_y);
+         }
+       else if (priv->dragging >= DRAG_RESIZE_TL &&
+                priv->dragging <= DRAG_RESIZE_BR)
+         {
+           ClutterFixed xp, yp;
+
+           if (priv->dont_resize)
+             return;
+           
+           
+           xp = CLUTTER_INT_TO_FIXED (x - priv->prev_x);
+           yp = CLUTTER_INT_TO_FIXED (y - priv->prev_y);
+
+           if (zang)
+             {
+               gint x2 = x - priv->prev_x;
+               gint y2 = y - priv->prev_y;
+               
+               ClutterFixed zang_rad = -CFX_MUL (zang, CFX_PI) / 180;
+           
+               xp = x2 * clutter_cosx (zang_rad) -
+                 y2 * clutter_sinx (zang_rad);
+
+               yp = y2 * clutter_cosx (zang_rad) +
+                 x2 * clutter_sinx (zang_rad);
+             }
+           
+           switch (priv->dragging)
+             {
+             case DRAG_RESIZE_TL:
+               box.x1 += xp;
+               box.y1 += yp;
+               break;
+             case DRAG_RESIZE_TR:
+               box.x2 += xp;
+               box.y1 += yp;
+               break;
+             case DRAG_RESIZE_BL:
+               box.x1 += xp;
+               box.y2 += yp;
+               break;
+             case DRAG_RESIZE_BR:
+               box.x2 += xp;
+               box.y2 += yp;
+               break;
+             default:
+               break;
+             }
+           
+           clutter_actor_request_coords (priv->slave, &box);
+         }
+       else if (priv->dragging == DRAG_ROTATE)
+         {
+           ClutterFixed a;
+           gint x1, x2, y1, y2, div;
+           
+           if (priv->dont_rotate)
+             return;
+           
+           x1 = priv->prev_x;
+           y1 = priv->prev_y;
+           x2 = x;
+           y2 = y;
+           
+           /*
+            * For the incremental angle a,
+            * 
+            * sin(a) = (x1*y2 - x2*y1) / (x1^2 + y1^2)
+            *
+            * where x1,y1 and x2,y2 are coords relative to the center of
+            * rotation.
+            * 
+            * For very small a, we can assume sin(a) == a,
+            * and after converting from rad to deg and to ClutterFixed,
+            * we get,
+            *
+            * a = 0x394bb8 * (x1*y2 - x2*y1) / (x1^2 + y1^2),
+            *
+            */
+
+           /* We work out the rotation on screen, not in the actor space.
+            * This is not entirely acurate, but considerably easier, and
+            * since the angles are very small should be generally enough for
+            * the rotatated actor not to get out of sync with the position
+            * of the pointer even if it is somewhat rotated around x and/or y
+            * axes.
+            *
+            * FIXME: if the actor has been rotated around the Z axis prior to
+            * start of our dragging, and the center of rotation was not the
+            * center of the actor, the actor will move from it's current
+            * position, since we will preserve the rotation angle, but change
+            * the pivot point. This is probably not a great deal for the
+            * kinds of application the dominatrix is intended for.
+            *
+            * First, project the center of the actor, which will be our
+            * reference point.
+            */
+           x1 -= priv->center_x;
+           y1 -= priv->center_y;
+           x2 -= priv->center_x;
+           y2 -= priv->center_y;
+
+           div = x1 * x1 + y1 * y1;
+
+           if (div)
+             a = (((x1 * y2 - x2 * y1) * 0x32000) / div) << 4;
+           else
+             a = CFX_ONE;
+
+           /*
+            * For anything above 0.7 rad, we tweak the value a bit
+            */
+           if (a >= 0xb333)
+             a = CFX_MUL (a, 0x14000);
+
+            clutter_actor_set_rotationx (priv->slave, CLUTTER_Z_AXIS, zang + a,
+                                         0, 0, 0);
+         }
+       else if (priv->dragging == DRAG_SCALE)
+         {
+           /*
+            * for each pixel of movement from the center increase scale by
+            * some sensible step, proportionate to the actor width.
+            */
+#define SCALE_STEP 40
+           ClutterFixed sx, sy;
+           gint d1, d2, diff, x1, y1, x2, y2;
+
+           if (priv->dont_resize)
+             return;
+           
+           x1 = abs (priv->prev_x - priv->center_x);
+           y1 = abs (priv->prev_y - priv->center_y);
+           x2 = abs (x - priv->center_x);
+           y2 = abs (y - priv->center_y);
+           
+           clutter_actor_get_scalex (priv->slave, &sx, &sy);
+
+           d1 = x1*x1 + y1*y1;
+           d2 = x2*x2 + y2*y2;
+
+           /* What we should do now is to sqrt d1 and d2 and substract the
+            * results but d1 and d2 can be quite big and sqrti does not
+            * handle very big numbers well, while ClutterFixed range is
+            * limited, ruling out sqrtx. We do not want to use sqrt for
+            * performance reasons, and all we need is reasonable speed of
+            * scaling and semblance of constancy. So, we substract the
+            * numbers first, then sqrti the difference, give it appropriate
+            * sign and choose a suitable step to go with what that produces.
+            */
+           diff = (clutter_sqrti (abs (d2 - d1)) *
+                   clutter_actor_get_width (priv->slave)) / 25;
+
+           if (d1 > d2)
+             diff = -diff;
+           
+           sx += SCALE_STEP * diff;
+           sy += SCALE_STEP * diff;
+           
+           clutter_actor_set_scalex (priv->slave, sx, sy);
+#undef SCALE_STEP
+         }
+
+       priv->prev_x = x;
+       priv->prev_y = y;
+
+      }
+      break;
+      
+    case CLUTTER_BUTTON_RELEASE:
+      {
+       if (priv->dragging != DRAG_NONE)
+         {
+           clutter_actor_set_opacity (priv->slave, priv->old_opacity);
+           g_signal_emit (dominatrix, dmx_signals[MANIPULATION_ENDED], 0);
+           priv->dragging = DRAG_NONE;
+         }
+      }
+      break;
+      
+    default:
+      break;
+    }
+  clutter_actor_move_anchor_point_from_gravity (priv->slave,
+                                                priv->gravity);
+}
+
+
+/**
+ * clutter_dominatrix_new:
+ * @slave: a #ClutterActor to manipulate
+ *
+ * Creates a ClutterDominatrix proxy for the given actor that allows
+ * the user to be manipulated via a pointer.
+ * 
+ * When you are done with the proxy, release the references to it.
+ */
+ClutterDominatrix *
+clutter_dominatrix_new (ClutterActor *slave)
+{
+  return g_object_new (CLUTTER_TYPE_DOMINATRIX, "slave", slave, NULL);
+}
+
+/**
+ * clutter_dominatrix_new_with_gravity:
+ * @slave: a #ClutterActor to manipulate
+ * @gravity: a #ClutterGravity to use when the actor is being scaled.
+ * 
+ * Creates a ClutterDominatrix proxy for the given actor that allows
+ * the user to be manipulated via a pointer, and sets the gravity for scaling
+ * to the provided value.
+ * 
+ * When you are done with the proxy, release the references to it.
+ */
+ClutterDominatrix *
+clutter_dominatrix_new_with_gravity (ClutterActor   * slave,
+                                    ClutterGravity   gravity)
+{
+  return g_object_new (CLUTTER_TYPE_DOMINATRIX,
+                      "slave", slave,
+                      "gravity", gravity,
+                      NULL);
+}
+
+/**
+ * clutter_dominatrix_set_slave:
+ * @dmx: a #ClutterDominatrix
+ * @slave: a #ClutterActor that the proxy should operate on.
+ * 
+ */
+void
+clutter_dominatrix_set_slave (ClutterDominatrix *dmx, ClutterActor *slave)
+{
+  clutter_dominatrix_release_slave (dmx->priv);
+
+  g_object_ref (slave);
+  dmx->priv->slave = slave;
+
+  clutter_dominatrix_store_original_settings (dmx->priv);
+  clutter_actor_move_anchor_point_from_gravity (slave,
+                                                dmx->priv->gravity);
+}
+
+/**
+ * clutter_dominatrix_get_slave:
+ * @dmx: a #ClutterDominatrix
+ *
+ * Returns the #ClutterActor that the proxy currently operates on. When you
+ * are done with it, you have to unref the slave.
+ */
+ClutterActor *
+clutter_dominatrix_get_slave (ClutterDominatrix *dmx)
+{
+  g_return_val_if_fail (CLUTTER_IS_DOMINATRIX (dmx), NULL);
+  
+  if (dmx->priv->slave)
+    g_object_ref (dmx->priv->slave);
+
+  return dmx->priv->slave;
+}
+
+/**
+ * clutter_dominatrix_restore:
+ * @dmx: a #ClutterDominatrix
+ *
+ * Restores the slave the proxy manipulates to it's original state.
+ */
+void
+clutter_dominatrix_restore (ClutterDominatrix *dmx)
+{
+  ClutterDominatrixPrivate * priv;
+  g_return_if_fail (CLUTTER_IS_DOMINATRIX (dmx));
+
+  priv = dmx->priv;
+  
+  clutter_actor_move_anchor_point_from_gravity (priv->slave,
+                                                CLUTTER_GRAVITY_NONE);
+  clutter_actor_set_rotationx (priv->slave, CLUTTER_Z_AXIS, priv->orig_zang,
+                               priv->orig_rot_x, priv->orig_rot_y, 0);
+  
+  clutter_actor_set_scalex (priv->slave,
+                           priv->orig_scale_x, priv->orig_scale_y);
+  
+  clutter_actor_request_coords (priv->slave, &priv->orig_box);
+  clutter_actor_move_anchor_point_from_gravity (priv->slave,
+                                                priv->gravity);
+}
diff --git a/attic/table/clutter-dominatrix.h b/attic/table/clutter-dominatrix.h
new file mode 100644 (file)
index 0000000..d99e510
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Tomas Frydrych tf@openedhand.com>
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_DOMINATRIX_H
+#define _HAVE_CLUTTER_DOMINATRIX_H
+
+/* clutter-dominatrix.h */
+
+#include <glib-object.h>
+#include <clutter/clutter-fixed.h>
+#include <clutter/clutter-actor.h>
+#include <clutter/clutter-event.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DOMINATRIX clutter_dominatrix_get_type()
+
+#define CLUTTER_DOMINATRIX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DOMINATRIX, ClutterDominatrix))
+#define CLUTTER_DOMINATRIX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DOMINATRIX, ClutterDominatrixClass))
+#define CLUTTER_IS_DOMINATRIX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DOMINATRIX))
+#define CLUTTER_IS_DOMINATRIX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DOMINATRIX))
+#define CLUTTER_DOMINATRIX_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DOMINATRIX, ClutterDominatrixClass))
+
+typedef struct _ClutterDominatrix         ClutterDominatrix;
+typedef struct _ClutterDominatrixClass    ClutterDominatrixClass;
+typedef struct _ClutterDominatrixPrivate  ClutterDominatrixPrivate;
+
+struct _ClutterDominatrix
+{
+  /*< public >*/
+  GObject parent_instance;
+
+  /*< private >*/
+  ClutterDominatrixPrivate *priv;
+};
+
+struct _ClutterDominatrixClass
+{
+  GObjectClass parent_class;
+
+  void (* manipulation_started)  (ClutterDominatrix *dmx);
+  void (* manipulation_ended)    (ClutterDominatrix *dmx);
+};
+
+GType                 clutter_dominatrix_get_type         (void) G_GNUC_CONST;
+
+ClutterDominatrix *   clutter_dominatrix_new              (ClutterActor *actor);
+ClutterDominatrix *   clutter_dominatrix_new_with_gravity (ClutterActor   *actor,
+                                                          ClutterGravity  gravity);
+
+void                  clutter_dominatrix_set_slave        (ClutterDominatrix *dmx,
+                                                          ClutterActor      *slave);
+ClutterActor *        clutter_dominatrix_get_slave        (ClutterDominatrix *dmx);
+void                  clutter_dominatrix_restore          (ClutterDominatrix *dmx);
+
+void 
+clutter_dominatrix_handle_event (ClutterDominatrix        *dominatrix,
+                                ClutterEvent             *event);
+
+G_END_DECLS
+
+#endif /* _HAVE_CLUTTER_DOMINATRIX_H */
diff --git a/attic/table/clutter-video-player.c b/attic/table/clutter-video-player.c
new file mode 100644 (file)
index 0000000..2f62e0a
--- /dev/null
@@ -0,0 +1,374 @@
+
+#include <clutter-gst/clutter-gst.h>
+#include "clutter-video-player.h"
+#include "play_png.h"
+#include "pause_png.h"
+
+#define CTRL_SIZE 10
+
+#ifndef CLUTTER_PARAM_READWRITE
+#define CLUTTER_PARAM_READWRITE \
+        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+#endif
+
+G_DEFINE_TYPE (ClutterVideoPlayer, clutter_video_player, CLUTTER_TYPE_GROUP);
+
+#define CLUTTER_VIDEO_PLAYER_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_VIDEO_PLAYER, ClutterVideoPlayerPrivate))
+
+struct _ClutterVideoPlayerPrivate
+{
+  ClutterActor    * vtexture;
+
+  ClutterActor    * control;
+  ClutterActor    * control_play;
+  ClutterActor    * control_pause;
+  
+  gboolean          paused;
+
+  gint              width;
+  gint              height;
+  
+  gchar           * uri;
+};
+
+static void
+toggle_pause_state (ClutterVideoPlayer *player);
+
+static void 
+input_cb (ClutterStage * stage, ClutterEvent * event, gpointer data);
+
+static gboolean
+autostop_playback (gpointer data)
+{
+  ClutterVideoPlayer        * player = data;
+  ClutterVideoPlayerPrivate * priv = player->priv;
+
+  clutter_actor_show (priv->vtexture);
+
+  toggle_pause_state (player);
+  clutter_media_set_position (CLUTTER_MEDIA (priv->vtexture), 0);
+  return FALSE;
+}
+
+static void
+eos_cb (ClutterMedia * media, gpointer data)
+{
+  ClutterVideoPlayer * player = data;
+
+  if (!player->priv->paused)
+    toggle_pause_state (player);
+
+  clutter_media_set_position (media, 0);
+}
+
+static GdkPixbuf *
+pixbuf_from_data (const guchar * data, gint length)
+{
+  GdkPixbuf *pixbuf;
+  GdkPixbufLoader * ldr = gdk_pixbuf_loader_new_with_type ("png", NULL);
+
+  if (!ldr)
+    {
+      g_warning ("Could not create loader");
+      return NULL;
+    }
+  
+  if (!gdk_pixbuf_loader_write (ldr, data, length, NULL))
+    {
+      g_warning ("Failed to write to loader.");
+      return NULL;
+    }
+  
+  pixbuf = gdk_pixbuf_loader_get_pixbuf (ldr);
+
+  return pixbuf;
+}
+
+void
+size_change (ClutterTexture *texture, 
+            gint            width,
+            gint            height,
+            gpointer        data)
+{
+  ClutterVideoPlayer *player = data;
+  gint h = player->priv->width * height / width;
+  
+  clutter_actor_set_size (CLUTTER_ACTOR (player), player->priv->width, h);
+}
+
+static void
+construct_controls (ClutterVideoPlayer *player)
+{
+  ClutterVideoPlayerPrivate *priv = player->priv;
+  GdkPixbuf           *pixb;
+
+  priv->vtexture = clutter_gst_video_texture_new ();
+
+  if (priv->vtexture == NULL)
+    g_error("failed to create vtexture");
+  
+  /* Dont let the underlying pixbuf dictate size */
+  g_object_set (G_OBJECT(priv->vtexture), "sync-size", FALSE, NULL);
+
+  g_signal_connect (CLUTTER_TEXTURE(priv->vtexture), 
+                   "size-change",
+                   G_CALLBACK (size_change), player);
+  
+  clutter_media_set_filename(CLUTTER_MEDIA(priv->vtexture), priv->uri);
+  clutter_media_set_playing (CLUTTER_MEDIA(priv->vtexture), TRUE);
+  priv->paused = FALSE;
+  g_signal_connect (priv->vtexture, "eos", G_CALLBACK (eos_cb), player);
+  g_timeout_add (100, autostop_playback, player);
+  
+  priv->control = clutter_group_new ();
+  
+  pixb = pixbuf_from_data (&play_png[0], sizeof (play_png));
+
+  if (pixb == NULL)
+    g_error("Unable to load play button image");
+
+  priv->control_play = clutter_texture_new_from_pixbuf (pixb);
+  clutter_actor_set_size (priv->control_play, CTRL_SIZE, CTRL_SIZE);
+  clutter_actor_show (priv->control_play);
+  
+  pixb = pixbuf_from_data (&pause_png[0], sizeof (pause_png));
+
+  if (pixb == NULL)
+    g_error("Unable to load pause button image");
+
+  priv->control_pause = clutter_texture_new_from_pixbuf (pixb);
+  clutter_actor_set_size (priv->control_pause, CTRL_SIZE, CTRL_SIZE);
+  
+  clutter_group_add_many (CLUTTER_GROUP (priv->control), 
+                         priv->control_play, 
+                         priv->control_pause,
+                         NULL);
+
+  clutter_actor_set_opacity (priv->control, 0xee);
+
+  clutter_actor_set_position (priv->control_play, 0, 0);
+  clutter_actor_set_position (priv->control_pause, 0, 0);
+
+  clutter_group_add_many (CLUTTER_GROUP (player), 
+                         priv->vtexture, priv->control, NULL);
+
+  g_signal_connect (clutter_stage_get_default(), "event",
+                   G_CALLBACK (input_cb), 
+                   player);
+}
+
+enum
+{
+  PROP_0,
+  PROP_URI,
+};
+
+static void 
+clutter_video_player_set_property (GObject      *object, 
+                                 guint         prop_id,
+                                 const GValue *value, 
+                                 GParamSpec   *pspec)
+{
+  ClutterVideoPlayer        *player;
+  ClutterVideoPlayerPrivate *priv;
+
+  player = CLUTTER_VIDEO_PLAYER(object);
+  priv = player->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_URI:
+      g_free (priv->uri);
+      priv->uri = g_strdup (g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void 
+clutter_video_player_get_property (GObject    *object, 
+                                  guint       prop_id,
+                                  GValue     *value, 
+                                  GParamSpec *pspec)
+{
+  ClutterVideoPlayer        *player;
+  ClutterVideoPlayerPrivate *priv;
+
+  player = CLUTTER_VIDEO_PLAYER(object);
+  priv = player->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_URI:
+      g_value_set_string (value, priv->uri);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static GObject *
+clutter_video_player_constructor (GType                  gtype,
+                                 guint                  n_params,
+                                 GObjectConstructParam *params)
+{
+  GObjectClass       * parent_class;
+  GObject            * retval;
+
+  parent_class = G_OBJECT_CLASS (clutter_video_player_parent_class);
+  retval = parent_class->constructor (gtype, n_params, params);
+
+  construct_controls (CLUTTER_VIDEO_PLAYER (retval));
+  
+  return retval;
+}
+
+static void 
+clutter_video_player_finalize (GObject *object)
+{
+  ClutterVideoPlayer *player = CLUTTER_VIDEO_PLAYER (object);
+
+  g_free (player->priv->uri);
+  
+  G_OBJECT_CLASS (clutter_video_player_parent_class)->finalize (object);
+}
+
+static void
+clutter_video_player_request_coords (ClutterActor        *self,
+                                    ClutterActorBox     *box)
+{
+  ClutterVideoPlayer * player = CLUTTER_VIDEO_PLAYER (self);
+  ClutterVideoPlayerPrivate *priv = player->priv;
+  ClutterActorBox cbox;
+
+  cbox.x1 = 0;
+  cbox.y1 = 0;
+  cbox.x2 = box->x2 - box->x1;
+  cbox.y2 = box->y2 - box->y1;
+
+  priv->width  = CLUTTER_FIXED_INT (cbox.x2);
+  priv->height = CLUTTER_FIXED_INT (cbox.y2);
+
+  g_debug ("coords request %d x %d",
+          CLUTTER_FIXED_INT (cbox.x2),
+          CLUTTER_FIXED_INT (cbox.y2));
+  
+  clutter_actor_request_coords (priv->vtexture, &cbox);
+
+  clutter_actor_set_position (priv->control, 0, 0);
+  
+  CLUTTER_ACTOR_CLASS (clutter_video_player_parent_class)->request_coords (self, box);
+
+  g_object_notify (G_OBJECT (self), "height");
+  g_object_notify (G_OBJECT (self), "width");
+  
+  clutter_actor_set_position (priv->control,
+                             (clutter_actor_get_width (priv->vtexture) -
+                              CTRL_SIZE) / 2,
+                             clutter_actor_get_height (priv->vtexture) -
+                             (CTRL_SIZE + CTRL_SIZE/2));
+  
+  clutter_actor_show (priv->control);
+  clutter_actor_queue_redraw (priv->vtexture);
+}
+
+static void
+clutter_video_player_class_init (ClutterVideoPlayerClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  gobject_class->constructor  = clutter_video_player_constructor;
+  gobject_class->set_property = clutter_video_player_set_property;
+  gobject_class->get_property = clutter_video_player_get_property;
+  gobject_class->finalize     = clutter_video_player_finalize;
+
+  actor_class->request_coords  = clutter_video_player_request_coords;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_URI,
+                                   g_param_spec_string ("uri",
+                                                       "uri",
+                                                       "uri",
+                                                       "test.avi",
+                                                       G_PARAM_CONSTRUCT |
+                                                       CLUTTER_PARAM_READWRITE));
+   
+  g_type_class_add_private (gobject_class, sizeof (ClutterVideoPlayerPrivate));
+}
+
+static void
+clutter_video_player_init (ClutterVideoPlayer *self)
+{
+  ClutterVideoPlayerPrivate *priv;
+
+  self->priv = priv = CLUTTER_VIDEO_PLAYER_GET_PRIVATE (self);
+
+  priv->paused = TRUE;
+}
+
+ClutterActor *
+clutter_video_player_new (const gchar * uri)
+{
+  return g_object_new (CLUTTER_TYPE_VIDEO_PLAYER, "uri", uri, NULL);
+}
+
+static void
+toggle_pause_state (ClutterVideoPlayer *player)
+{
+  if (player->priv->paused)
+    {
+      clutter_media_set_playing (CLUTTER_MEDIA(player->priv->vtexture), 
+                                TRUE);
+      player->priv->paused = FALSE;
+      clutter_actor_hide (player->priv->control_play);
+      clutter_actor_show (player->priv->control_pause);
+    }
+  else
+    {
+      clutter_media_set_playing (CLUTTER_MEDIA(player->priv->vtexture), 
+                                    FALSE);
+      player->priv->paused = TRUE;
+      clutter_actor_hide (player->priv->control_pause);
+      clutter_actor_show (player->priv->control_play);
+    }
+}
+
+static void 
+input_cb (ClutterStage *stage, 
+         ClutterEvent *event,
+         gpointer      user_data)
+{
+  ClutterVideoPlayer *player = (ClutterVideoPlayer*)user_data;
+  ClutterVideoPlayerPrivate *priv = player->priv;
+  
+  switch (event->type)
+    {
+    case CLUTTER_BUTTON_PRESS:
+       {
+         ClutterActor       *actor;
+         ClutterButtonEvent *bev = (ClutterButtonEvent *) event;
+
+         actor 
+           = clutter_stage_get_actor_at_pos 
+                                (CLUTTER_STAGE(clutter_stage_get_default()),
+                                 bev->x, bev->y);
+
+         printf("got actor %p at pos %ix%i\n", actor, bev->x, bev->y);
+
+         if (actor == priv->control_pause || actor == priv->control_play)
+           {
+             toggle_pause_state (player);
+             return;
+           }
+
+       }
+      break;
+    default:
+      break;
+    }
+}
diff --git a/attic/table/clutter-video-player.h b/attic/table/clutter-video-player.h
new file mode 100644 (file)
index 0000000..f2ec2e2
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CLUTTER_VIDEO_PLAYER_H__
+#define __CLUTTER_VIDEO_PLAYER_H__
+
+#include <clutter/clutter-group.h>
+#include <clutter/clutter-color.h>
+#include <clutter/clutter-event.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_VIDEO_PLAYER (clutter_video_player_get_type())
+
+#define CLUTTER_VIDEO_PLAYER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_VIDEO_PLAYER, ClutterVideoPlayer))
+
+#define CLUTTER_VIDEO_PLAYER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_TYPE_VIDEO_PLAYER, ClutterVideoPlayerClass))
+
+#define CLUTTER_IS_VIDEO_PLAYER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_VIDEO_PLAYER))
+
+#define CLUTTER_IS_VIDEO_PLAYER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_TYPE_VIDEO_PLAYER))
+
+#define CLUTTER_VIDEO_PLAYER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_TYPE_VIDEO_PLAYER, ClutterVideoPlayerClass))
+
+typedef struct _ClutterVideoPlayer        ClutterVideoPlayer;
+typedef struct _ClutterVideoPlayerClass   ClutterVideoPlayerClass;
+typedef struct _ClutterVideoPlayerPrivate ClutterVideoPlayerPrivate;
+
+struct _ClutterVideoPlayer
+{
+  ClutterGroup parent_instance;
+  
+  /*< private >*/
+  ClutterVideoPlayerPrivate *priv;
+}; 
+
+struct _ClutterVideoPlayerClass 
+{
+  ClutterGroupClass parent_class;
+};
+
+GType         clutter_video_player_get_type         (void) G_GNUC_CONST;
+
+ClutterActor *clutter_video_player_new              (const gchar * uri);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_VIDEO_PLAYER_H__ */
diff --git a/attic/table/hand0.png b/attic/table/hand0.png
new file mode 100644 (file)
index 0000000..5b71eeb
Binary files /dev/null and b/attic/table/hand0.png differ
diff --git a/attic/table/hand1.png b/attic/table/hand1.png
new file mode 100644 (file)
index 0000000..2cf1b78
Binary files /dev/null and b/attic/table/hand1.png differ
diff --git a/attic/table/hand2.png b/attic/table/hand2.png
new file mode 100644 (file)
index 0000000..ac5243a
Binary files /dev/null and b/attic/table/hand2.png differ
diff --git a/attic/table/hand3.png b/attic/table/hand3.png
new file mode 100644 (file)
index 0000000..83c7c07
Binary files /dev/null and b/attic/table/hand3.png differ
diff --git a/attic/table/hand4.png b/attic/table/hand4.png
new file mode 100644 (file)
index 0000000..2d289ee
Binary files /dev/null and b/attic/table/hand4.png differ
diff --git a/attic/table/hand5.png b/attic/table/hand5.png
new file mode 100644 (file)
index 0000000..f0fb783
Binary files /dev/null and b/attic/table/hand5.png differ
diff --git a/attic/table/hand6.png b/attic/table/hand6.png
new file mode 100644 (file)
index 0000000..7a50ab7
Binary files /dev/null and b/attic/table/hand6.png differ
diff --git a/attic/table/hand7.png b/attic/table/hand7.png
new file mode 100644 (file)
index 0000000..d0dfd4f
Binary files /dev/null and b/attic/table/hand7.png differ
diff --git a/attic/table/hand8.png b/attic/table/hand8.png
new file mode 100644 (file)
index 0000000..21236ce
Binary files /dev/null and b/attic/table/hand8.png differ
diff --git a/attic/table/pause_png.h b/attic/table/pause_png.h
new file mode 100644 (file)
index 0000000..7971cf9
--- /dev/null
@@ -0,0 +1,431 @@
+static unsigned char pause_png [] = {
+0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,
+0x52,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x84,0x08,0x06,0x00,0x00,0x00,0x5c,
+0x5a,0xf3,0xe0,0x00,0x00,0x00,0x04,0x73,0x42,0x49,0x54,0x08,0x08,0x08,0x08,
+0x7c,0x08,0x64,0x88,0x00,0x00,0x00,0x19,0x74,0x45,0x58,0x74,0x53,0x6f,0x66,
+0x74,0x77,0x61,0x72,0x65,0x00,0x77,0x77,0x77,0x2e,0x69,0x6e,0x6b,0x73,0x63,
+0x61,0x70,0x65,0x2e,0x6f,0x72,0x67,0x9b,0xee,0x3c,0x1a,0x00,0x00,0x18,0xb4,
+0x49,0x44,0x41,0x54,0x78,0x9c,0xe5,0x5d,0xcf,0x8f,0x25,0xc9,0x51,0x8e,0xa8,
+0xd7,0xdd,0xef,0x47,0xf7,0x74,0xcf,0xec,0x0c,0x06,0x76,0x61,0x77,0xc6,0xbb,
+0xd8,0xbb,0x7b,0x40,0x2c,0x86,0x03,0x12,0x48,0x20,0x2c,0x21,0xc4,0x09,0x63,
+0xa1,0xe5,0x80,0xe4,0x83,0x25,0x0c,0x47,0x2e,0x9c,0xf9,0x07,0x10,0x37,0x8c,
+0xb9,0x21,0x0e,0x7b,0x47,0xb2,0x40,0x32,0x57,0x30,0xa7,0x35,0x02,0x2f,0x12,
+0x07,0x66,0x90,0x58,0x2d,0xf6,0xee,0x7a,0xd7,0xeb,0xf1,0xcc,0x74,0xbf,0x7e,
+0x15,0x1c,0xea,0x57,0x66,0xc6,0x17,0x59,0x99,0x2f,0xdf,0x7b,0xfd,0xba,0x37,
+0xa4,0x99,0xae,0xca,0xaa,0xcc,0x8a,0xf8,0x32,0x32,0x22,0x32,0x32,0xab,0x1e,
+0x8b,0x08,0x11,0x11,0x31,0x33,0x13,0xd1,0x31,0x11,0xdd,0x22,0xa2,0x13,0x22,
+0x62,0xba,0xde,0x74,0x49,0x44,0x3f,0x24,0xa2,0x1f,0x48,0x27,0xe4,0x9a,0xc4,
+0xcc,0x15,0x35,0x98,0xdc,0x22,0xa2,0x05,0x5d,0x7f,0x6c,0x96,0xd4,0xe0,0xf2,
+0xc3,0xae,0x80,0x45,0x84,0x98,0xf9,0x88,0x88,0x5e,0x24,0xa2,0xea,0xca,0x58,
+0xdb,0x1e,0x5d,0x10,0xd1,0xff,0x89,0xc8,0xb3,0x75,0x2a,0x33,0xf3,0x31,0x11,
+0x3d,0x4f,0xd7,0xbf,0xf3,0x11,0x3d,0x25,0xa2,0xef,0x89,0xc8,0x45,0xd7,0xf1,
+0x3f,0x49,0x37,0x53,0x09,0x88,0x88,0x8e,0x88,0xe8,0x45,0x66,0x3e,0xc8,0xad,
+0xd8,0x5a,0x82,0xcf,0xd0,0xcd,0x54,0x02,0x22,0xa2,0x39,0x35,0xd8,0x70,0xc5,
+0xcc,0x67,0x6d,0xc1,0x4d,0xa7,0x5b,0x6b,0xd4,0xb9,0x4b,0x44,0x87,0x9b,0x66,
+0x64,0xcf,0xa8,0x22,0xa2,0xe3,0x8a,0x88,0x9e,0xbb,0x6a,0x4e,0x76,0x44,0x59,
+0x8a,0xd0,0xc6,0x4c,0x77,0xb6,0xc4,0xcb,0xbe,0xd1,0xad,0x83,0xaa,0xaa,0x4c,
+0x93,0x79,0xfb,0xf6,0xd9,0xec,0xce,0x73,0x77,0x4e,0x76,0xc9,0x51,0x09,0x7d,
+0xf2,0xc9,0x8f,0x9e,0x7c,0xf0,0xfe,0x07,0x4f,0x8c,0xcb,0x33,0x66,0x9e,0x88,
+0xc8,0x2a,0xb1,0xb9,0x49,0x55,0xd9,0xde,0xf2,0xee,0xbd,0xbb,0x8b,0xd3,0xd3,
+0x5b,0x8b,0x6c,0x26,0xaf,0x88,0x7e,0xf0,0xe1,0x47,0x8f,0x3f,0xfe,0xf8,0x63,
+0x2b,0x4e,0x3a,0x39,0xa8,0xaa,0x4a,0xf9,0xbf,0x97,0xee,0xbf,0x78,0xf7,0xb5,
+0xd7,0x5f,0xfb,0xe3,0xd9,0x6c,0xfa,0xa5,0x36,0x58,0xba,0x16,0x24,0x22,0xcb,
+0xe5,0x72,0xf9,0xad,0x47,0x0f,0xff,0xe7,0x2f,0xff,0xe3,0xdf,0xbf,0xfb,0x28,
+0xbc,0xbe,0x5a,0xad,0x2a,0x22,0x4a,0x52,0x84,0xd9,0x6c,0xc6,0x97,0x97,0x97,
+0xaa,0xfc,0xb5,0xd7,0x5f,0x7d,0xf1,0xc1,0x67,0xef,0xff,0xc9,0xd1,0xd1,0xd1,
+0xef,0xb4,0x41,0xf6,0xb5,0x20,0x11,0x79,0x7a,0x71,0x7e,0xf1,0xcd,0x77,0xde,
+0xf9,0xcf,0xbf,0x78,0xf8,0xdf,0x8f,0x3e,0x08,0x2e,0x73,0x55,0x55,0x95,0x84,
+0xff,0x5e,0x7b,0xfd,0xd5,0xaf,0xce,0xe7,0xb3,0x3f,0xbc,0x4e,0x4a,0x40,0x44,
+0xc4,0xcc,0x87,0x47,0x47,0x47,0xbf,0x7d,0xff,0xc1,0x4b,0x7f,0x8a,0xe4,0x9a,
+0xcd,0x66,0x59,0xed,0xa1,0x36,0x5e,0x7e,0xe5,0xb3,0x7f,0x36,0x9d,0x4e,0x7f,
+0xf7,0x3a,0x29,0x01,0x11,0x11,0x33,0xcf,0xa7,0xb3,0xe9,0xef,0xbd,0xfa,0xea,
+0xe7,0xbf,0x82,0xe4,0xaa,0xaa,0xaa,0xa2,0xf0,0xdf,0x6c,0x36,0xfb,0xd2,0x55,
+0x33,0x5e,0x42,0x87,0x87,0x87,0x5f,0xbc,0xff,0xe0,0xa5,0xbb,0xa1,0x5c,0xb9,
+0x14,0xd6,0xbf,0xff,0xe0,0xa5,0xbb,0x07,0x07,0x07,0xbf,0xb1,0x05,0x96,0x77,
+0x46,0xb3,0xf9,0xec,0xcb,0xa8,0xcf,0x0f,0x10,0x40,0xcc,0x7c,0xfb,0x0a,0x78,
+0xdc,0x18,0x31,0xf3,0xe4,0xf4,0xf4,0xf4,0xac,0xaa,0xaa,0x0f,0xdd,0xf2,0xdc,
+0xbc,0x52,0x88,0xcd,0xe9,0xe9,0xe9,0x19,0x33,0x4f,0xca,0x39,0xbc,0x3a,0x62,
+0xe6,0x3b,0xa8,0xcf,0xa1,0x22,0xdc,0x04,0xaa,0x2a,0xa6,0xc9,0xc4,0xef,0x33,
+0xe4,0xf3,0xe3,0x6d,0xf8,0xd8,0xf0,0x0d,0xc9,0x26,0x84,0xb8,0x10,0x65,0x28,
+0xc2,0x9b,0x6f,0xbe,0x49,0x6f,0xfc,0xc2,0x1b,0x9b,0xe6,0xa9,0x98,0x1e,0x3e,
+0x7c,0x48,0x5f,0xff,0xeb,0xaf,0xeb,0x0b,0xcc,0xaa,0x23,0x73,0x62,0x84,0xd9,
+0x6c,0x46,0x75,0x5d,0xab,0x36,0x11,0x7d,0xed,0x8f,0xbe,0x46,0x0f,0x1e,0x3c,
+0x48,0x6e,0x7b,0x57,0xf4,0xf6,0x77,0xde,0xa6,0xb7,0xde,0x7a,0x4b,0x95,0x17,
+0x59,0x84,0x57,0x5e,0xf9,0x39,0x7a,0x70,0xff,0xe5,0x62,0xe6,0x36,0x4d,0x87,
+0x87,0x38,0x66,0x63,0xd2,0x8a,0x90,0x4b,0xca,0x22,0x18,0x09,0xc6,0xcf,0x7d,
+0xee,0xf3,0xf4,0x33,0x2f,0xfc,0x6c,0xd1,0xb3,0xb6,0x41,0x3f,0x7a,0xfc,0x18,
+0x96,0x7f,0xaa,0x5c,0x03,0x03,0x8b,0xa0,0x46,0xf8,0x08,0x69,0xd7,0x70,0x33,
+0x7c,0x83,0xa5,0x08,0x45,0x2b,0x73,0xfb,0x4a,0x5c,0xb1,0x84,0xb2,0xad,0xa1,
+0x08,0x5e,0x7d,0xae,0xf8,0x46,0x60,0x85,0xfa,0xfc,0xe6,0x5a,0x04,0xe0,0x1a,
+0x16,0x8b,0x45,0x72,0x47,0x2e,0x16,0x0b,0x09,0x83,0x4b,0xcb,0x35,0x5c,0x37,
+0x82,0x16,0x01,0x45,0x90,0xa9,0x24,0x22,0xf4,0xf4,0x99,0x95,0xd1,0xdd,0x3c,
+0x4d,0x8f,0xa6,0x34,0x99,0xa4,0x2d,0x22,0x22,0xd7,0x90,0x4b,0x21,0x36,0x20,
+0x09,0x6b,0x52,0x5d,0xaf,0xe8,0xd9,0x79,0x7c,0xe5,0xbb,0xdd,0x02,0xe0,0x1c,
+0x57,0xc4,0x44,0x24,0x84,0xf5,0xb5,0xbb,0x5f,0xa4,0x59,0x0e,0x6d,0x8e,0x9b,
+0x93,0xf9,0x6c,0x91,0xec,0xba,0x36,0xae,0x08,0x97,0x97,0x4b,0x7a,0xff,0x83,
+0xef,0xed,0xcc,0x77,0xde,0xbd,0x73,0x8f,0x8e,0x8f,0xd3,0xd6,0x8e,0xb6,0xa1,
+0x08,0xcd,0xaa,0x74,0x1a,0x3d,0x7d,0xfa,0x84,0x3e,0xfc,0x28,0xcc,0xe4,0x6e,
+0x8f,0x7e,0xea,0x33,0xcf,0xd3,0xd1,0xd1,0x34,0xe9,0x5e,0xa8,0x08,0xe5,0x9d,
+0xb8,0x9f,0xe6,0x72,0x13,0xc1,0x62,0x09,0x36,0x85,0x9b,0xa2,0xb6,0x4a,0x9f,
+0xae,0x60,0x11,0x28,0xc2,0xd1,0x51,0xfa,0xf2,0xc0,0x6c,0x36,0xa3,0xd5,0x6a,
+0xe5,0x61,0x93,0xe3,0x1a,0xf6,0x99,0x3e,0x8d,0xd3,0xc7,0x22,0x25,0x57,0xd8,
+0xdc,0x9c,0xe9,0x63,0xc1,0xac,0x41,0xf6,0xdb,0xdc,0x85,0xc4,0xac,0x53,0xcc,
+0xa5,0x6b,0x0d,0xf6,0xac,0x41,0x54,0xdb,0xfb,0x8c,0x54,0x51,0x8a,0x19,0x45,
+0xb2,0xbb,0x16,0x56,0x08,0x75,0x26,0xe6,0xa2,0x34,0x46,0x40,0xf5,0xad,0x98,
+0x61,0x5f,0x3a,0x5d,0x61,0x63,0x30,0x76,0x23,0x5d,0x83,0xd5,0x09,0x3b,0xcd,
+0x2c,0xee,0x81,0x26,0x20,0x16,0xac,0x69,0x68,0xd9,0xac,0x41,0xc0,0xe3,0xf6,
+0xc1,0x55,0x98,0x9a,0xa0,0x3b,0x6e,0x3e,0x4f,0xdf,0xa3,0x3b,0x9f,0xcf,0xf5,
+0x6a,0x65,0x14,0xaa,0x3d,0xc0,0x22,0x91,0x50,0x9f,0x67,0xe4,0x11,0x64,0x2f,
+0xfa,0x3d,0x15,0xf0,0x8a,0x2b,0xe8,0x0b,0x73,0x48,0x25,0x94,0x8c,0x3c,0x82,
+0x20,0x6c,0x76,0x0d,0x96,0x08,0xe9,0x81,0x8a,0x6f,0xb5,0x62,0x84,0x24,0x8e,
+0xf7,0x43,0x07,0x34,0xe0,0x96,0xf9,0x63,0xd6,0x6b,0x0d,0x6b,0x04,0x8b,0xfe,
+0x5a,0x03,0x1b,0x6b,0x0d,0xa0,0xf4,0x2a,0xf0,0xd2,0xe2,0x99,0xae,0x41,0xcf,
+0x1a,0x8a,0x52,0xcc,0x6b,0xd7,0xdc,0xe0,0xf3,0x0c,0x26,0x98,0xb5,0x2f,0x5c,
+0xad,0x52,0x37,0x30,0x37,0xa4,0x33,0x8b,0xd7,0x6b,0xfa,0x68,0xf5,0x4f,0x59,
+0xb0,0x88,0x4c,0xcf,0x7e,0xd8,0x09,0x4c,0x85,0x09,0xa5,0xf9,0x7c,0xae,0x14,
+0xc7,0x9e,0x35,0x20,0x6c,0x76,0x4b,0x39,0x4f,0x2f,0x0a,0x16,0x9b,0xa9,0x5b,
+0xc1,0xd3,0x37,0x46,0xe1,0x7c,0xdd,0x70,0x0d,0x1b,0xd8,0x98,0x92,0x63,0x01,
+0x52,0xcd,0xf2,0xf6,0x08,0xc5,0x08,0x19,0xb3,0x86,0xd2,0x80,0x6a,0xd7,0x94,
+0xea,0xe6,0xd1,0xf4,0x31,0x47,0x31,0xaa,0xaa,0x52,0x8a,0x60,0xa6,0x98,0xf7,
+0x21,0x8a,0x16,0xcd,0xc6,0x96,0x5c,0x83,0x6e,0x7a,0x0f,0xc4,0x37,0x3b,0x61,
+0x13,0xab,0x8f,0xa9,0x29,0x66,0x71,0xfe,0x1f,0x61,0x6b,0x2f,0x68,0x0b,0x8b,
+0x4e,0xbb,0x95,0x56,0x32,0x94,0x11,0xa5,0x98,0x73,0x83,0x45,0x35,0x6b,0xd8,
+0xd3,0x95,0x56,0x22,0xac,0x8c,0x59,0xd3,0xc7,0xf4,0x18,0x01,0xcd,0x95,0x93,
+0xaa,0x6e,0x94,0x84,0xd2,0x16,0xbe,0xd1,0xf4,0x31,0x37,0x58,0x5c,0x2e,0x97,
+0xaa,0x4d,0xcc,0xd4,0x1e,0xe4,0x58,0x32,0x18,0xd8,0xf8,0xf4,0xf1,0x4a,0x48,
+0x02,0xfd,0xdb,0xa2,0x6b,0xb8,0x6e,0xd3,0xc7,0xd4,0x1c,0x4b,0x61,0x8a,0xf9,
+0xea,0xa7,0x48,0x59,0xcf,0x07,0x29,0xe6,0x5c,0x52,0xf5,0xa3,0x4b,0x0d,0x57,
+0x8d,0x4d,0x3a,0x15,0xa5,0x98,0x73,0x16,0x35,0xb6,0x4b,0x69,0x31,0x02,0x4a,
+0x31,0xe7,0x2e,0x3a,0xa5,0xa6,0x98,0x11,0x5d,0x8d,0xab,0x48,0x9b,0x3e,0x16,
+0x2d,0x43,0x47,0xda,0xdd,0x1d,0x49,0x4e,0x8c,0x90,0x37,0x5d,0x0c,0x09,0xbd,
+0x38,0x6b,0x1a,0x98,0x3d,0x88,0x11,0x72,0x06,0xa5,0x95,0x47,0x48,0x6b,0x21,
+0x63,0x51,0x63,0xab,0x94,0x18,0x23,0x10,0x08,0x16,0x73,0x2c,0xc2,0x62,0xb1,
+0xa0,0xe5,0x72,0x19,0xac,0x35,0xe0,0x19,0x16,0x76,0x0d,0xbb,0x07,0x27,0x23,
+0x8f,0xa0,0x83,0xc5,0xeb,0xb5,0x1f,0x41,0x2b,0xa3,0xbd,0x0a,0x0d,0xdf,0x6b,
+0xc8,0x7a,0x5a,0xfa,0x4b,0xb0,0x57,0x6d,0x2a,0x3b,0x16,0x76,0x90,0x59,0xec,
+0xba,0x80,0xbd,0xb2,0x3d,0x00,0x20,0x63,0x87,0x52,0x2e,0x25,0x6f,0x67,0xdf,
+0x07,0x18,0x32,0xa8,0x68,0xd6,0xd0,0xdd,0x75,0xd5,0x32,0x77,0xcf,0x1f,0xe3,
+0x7a,0x13,0x8a,0x90,0xb5,0xd6,0x30,0x5a,0xb0,0x5d,0x92,0x76,0x58,0xa6,0x70,
+0x5c,0x94,0x62,0x6e,0x2c,0x8f,0x96,0xae,0xc1,0x2a,0xf6,0xf8,0xcd,0x21,0x22,
+0xe0,0xd8,0x0e,0x11,0x58,0x75,0x64,0xf1,0xe6,0xd5,0x98,0x62,0x84,0x6d,0x8f,
+0xe2,0x42,0xb4,0x0d,0x6d,0x41,0x18,0x85,0x04,0xa7,0x8f,0xe5,0x31,0x02,0xb7,
+0xaf,0x69,0xd9,0xd7,0x31,0xad,0x09,0x42,0x62,0x67,0x32,0x33,0x1d,0x1c,0xf8,
+0xaf,0xc7,0x85,0xe7,0x31,0x42,0x5b,0xd5,0xb2,0xf2,0x12,0x92,0x62,0x45,0xb7,
+0x8c,0x8d,0x81,0x15,0xc2,0x21,0x73,0x3f,0x82,0x41,0xcc,0xc4,0x16,0xf3,0xe2,
+0xfd,0x71,0x2b,0x59,0x0f,0x8a,0x31,0x91,0x7c,0x7f,0xe3,0x1a,0xca,0x12,0x4a,
+0xa9,0xc1,0x22,0xe4,0x80,0x87,0x0a,0x10,0x1b,0x81,0x87,0x4e,0xe5,0xa4,0xa7,
+0x24,0x5f,0x76,0x29,0x63,0xd1,0x09,0x4f,0xb3,0xd0,0xb3,0x06,0x70,0x0c,0x94,
+0xb8,0xa9,0xa9,0xae,0x26,0x2b,0x88,0x3d,0x4b,0x60,0x8b,0xa9,0x86,0x2f,0xe1,
+0x40,0xb6,0x9c,0x74,0x7a,0x7b,0xaf,0xdf,0x3a,0xd7,0x26,0xdc,0xf1,0x7e,0x00,
+0xd8,0xf4,0x45,0xa9,0xd8,0xc4,0x95,0xa3,0x8b,0x11,0xdc,0x3b,0x8b,0xa7,0x8f,
+0x35,0x52,0x04,0x93,0x8f,0x31,0xd7,0x60,0x54,0x46,0x0a,0x92,0x04,0x80,0x78,
+0x47,0xe6,0x73,0x99,0xb3,0x32,0x81,0x88,0xd4,0x76,0x78,0xeb,0x89,0x96,0x32,
+0xc6,0x2f,0x07,0x77,0x85,0x45,0xeb,0x63,0xd3,0xdf,0x93,0x33,0x7d,0x84,0x8a,
+0x90,0x93,0x89,0x6d,0x83,0xa2,0x81,0xa5,0x30,0xe3,0x93,0xe1,0x23,0x0d,0x00,
+0xe2,0xc3,0xd0,0x70,0x0d,0x20,0x8f,0x50,0x1a,0x2c,0x4a,0x5d,0xc3,0x29,0xb3,
+0xe9,0x80,0x7a,0xd7,0xd0,0xb7,0xb0,0x53,0x6c,0x22,0x16,0x41,0x95,0xe1,0x18,
+0x01,0x29,0x82,0x02,0xbd,0x13,0x32,0x84,0x81,0xb1,0x0c,0x44,0x4a,0x43,0xad,
+0x2e,0xd4,0xcd,0xc5,0x1c,0x2a,0xee,0x06,0x34,0x7d,0x5c,0x63,0x3f,0x82,0x77,
+0x5e,0x0b,0xc3,0x41,0xe6,0xef,0x59,0x8c,0xc5,0x25,0x16,0x36,0xa9,0x0a,0x92,
+0x87,0x8d,0x15,0xd3,0x94,0xbf,0xe9,0xe4,0xe7,0x76,0xf3,0x13,0x4a,0x01,0x67,
+0x08,0x84,0x24,0x00,0x3c,0x36,0xac,0x60,0xb1,0x7c,0x17,0xb3,0x0a,0x16,0x6b,
+0x93,0x41,0xd7,0x1e,0x0f,0xf7,0x47,0x6e,0xf7,0x29,0x4d,0x41,0xf2,0xb1,0xc1,
+0xc5,0xdb,0x79,0xe5,0x8d,0x5b,0xab,0x10,0x28,0xc9,0x08,0x2f,0x61,0x03,0xee,
+0x99,0xd7,0xb9,0xa3,0xb8,0x9b,0xcd,0x96,0xa5,0x98,0x17,0x8b,0x85,0x56,0x9c,
+0xdc,0x65,0x6d,0x66,0xd2,0x5b,0x59,0x4a,0xb0,0x49,0x51,0x0c,0x27,0xc7,0x62,
+0x5c,0x2f,0x5a,0x74,0xb2,0x3d,0x31,0x77,0x87,0x5e,0x79,0x7f,0xb4,0x8e,0x82,
+0x38,0x80,0xa7,0x2a,0x46,0x48,0x15,0xb3,0x24,0x2f,0xa8,0x19,0x14,0xd6,0xaf,
+0x2e,0x39,0xf9,0xd3,0xee,0x3d,0x29,0xdd,0x29,0xc1,0x26,0x32,0x68,0x40,0x4c,
+0x60,0xa9,0x2d,0xc2,0xa5,0xc8,0x22,0x24,0x8d,0x8f,0x51,0x05,0x49,0x00,0x20,
+0x32,0x12,0x63,0xa0,0x85,0x09,0xa0,0x9c,0xe9,0xe3,0xc1,0xc1,0x41,0xf2,0x07,
+0x37,0xad,0xe7,0xe7,0xdd,0x62,0x63,0x93,0x34,0x68,0xc0,0xe3,0xac,0x7a,0x1b,
+0xc9,0x2c,0x8a,0x77,0xdc,0x45,0xb1,0xd6,0xee,0xde,0x88,0x08,0x20,0xff,0x90,
+0x06,0x40,0xa2,0xd7,0x2d,0xdc,0x8f,0x40,0x94,0xfe,0x7d,0x04,0x6c,0x8a,0x25,
+0xba,0xd9,0x35,0x07,0x1b,0x64,0x39,0xb0,0xc7,0x09,0x23,0xce,0xc2,0xe9,0xa3,
+0x45,0xb0,0xd9,0x48,0xba,0x0d,0x03,0x11,0x81,0xc0,0x04,0x20,0xa8,0x23,0xc6,
+0x71,0xc0,0xd7,0xa6,0xa7,0x8f,0xb1,0xd7,0xe2,0x31,0x36,0x46,0xc3,0xb9,0xd8,
+0x84,0x96,0x43,0xfc,0x29,0xa9,0x97,0xdd,0xd0,0x13,0x3b,0x45,0x1b,0x78,0xaf,
+0xc1,0x22,0x10,0x1f,0x8f,0x24,0xa0,0xfc,0xe2,0x91,0x8c,0x0c,0x39,0x41,0x57,
+0x24,0xf8,0xf2,0xab,0x6e,0x7e,0xfa,0x68,0x7a,0x06,0x58,0xce,0x64,0xce,0x1b,
+0x4a,0xb1,0x09,0x14,0x83,0x3b,0xc5,0x48,0xd4,0xf3,0x42,0x8b,0x30,0x36,0x79,
+0xd1,0xd2,0x29,0x23,0x66,0x00,0x10,0x8a,0x3f,0x2e,0xfc,0x38,0x31,0xf8,0x3a,
+0x7b,0x8e,0x22,0x2c,0x16,0x0b,0xf0,0x7d,0x04,0xdb,0x22,0x40,0x1e,0x9c,0xff,
+0x71,0x95,0xcd,0x61,0x03,0x59,0x30,0xf8,0x4a,0x7e,0xaf,0xc1,0x5e,0x65,0x43,
+0x4c,0xb0,0x79,0x19,0x01,0x31,0x0a,0x40,0xaa,0xf0,0x4e,0x2b,0x96,0x0c,0x61,
+0x79,0xee,0x0e,0xa5,0xb0,0x3e,0x6a,0xb3,0xb9,0xe0,0x72,0x13,0x96,0x07,0xcc,
+0x7a,0x97,0xb6,0x83,0x4d,0x5f,0x62,0xf0,0x0b,0x83,0xc5,0x83,0x83,0x03,0xd5,
+0x52,0x9e,0x72,0xb8,0xf3,0x19,0x43,0x05,0x95,0x6c,0x1c,0x5c,0x4a,0x15,0x1e,
+0xad,0xe3,0x61,0x61,0xab,0xaa,0x92,0x50,0xb6,0xdc,0x18,0x21,0xac,0x5f,0x55,
+0x95,0xe4,0x6d,0x91,0x1f,0xc1,0x66,0x44,0x39,0x72,0x15,0x03,0xa9,0x84,0xd1,
+0xe9,0x7a,0xfa,0x98,0xd7,0xe9,0x9a,0x50,0xae,0x50,0x31,0x15,0x82,0xb0,0xb6,
+0x62,0x84,0xfc,0x37,0xe7,0xa9,0x16,0x21,0x47,0x11,0x0e,0x0f,0x0f,0xe1,0x6b,
+0xf1,0x10,0x9b,0xb1,0x10,0x27,0x38,0x1b,0x46,0x6c,0x5c,0x39,0x62,0xd8,0x48,
+0x2d,0xb4,0xaa,0x57,0x24,0x52,0xd3,0xaa,0x5e,0xd1,0x29,0x9f,0xc1,0x86,0x92,
+0x2d,0x02,0x8a,0x11,0xd0,0x8d,0xb9,0x99,0x19,0x04,0x82,0x09,0x40,0x54,0x78,
+0x14,0x06,0xfb,0xf5,0xa1,0x45,0x60,0xbd,0x1d,0x3d,0xf7,0xad,0x2e,0xf5,0x36,
+0x35,0xeb,0x37,0xa4,0x03,0x76,0xe3,0x65,0xea,0x92,0xad,0x1c,0x52,0x0b,0xd5,
+0x52,0x93,0xd4,0x4d,0x47,0xaf,0x56,0xab,0xe6,0x5c,0xea,0x5e,0x41,0xb1,0x62,
+0x27,0x60,0x93,0x1a,0x2c,0x9a,0x5a,0x84,0x9e,0xab,0xee,0x15,0xef,0x8f,0x77,
+0x6b,0x70,0x94,0xa6,0x18,0x46,0xfb,0x4e,0x53,0x16,0xbf,0xdb,0x98,0x3e,0x26,
+0x7f,0x59,0x4d,0x28,0x8a,0x8d,0x48,0x4d,0x75,0xdb,0xd9,0x75,0x5d,0x53,0x2d,
+0xab,0xe6,0xef,0xaa,0xf9,0x2b,0x61,0x9d,0x5e,0x06,0xa2,0x6e,0x36,0xa2,0x79,
+0x09,0x99,0x30,0xdd,0xa6,0x2a,0x83,0xbb,0x98,0xb1,0xf9,0x1b,0x9b,0x35,0x0c,
+0x25,0xa2,0x2e,0x60,0xe5,0x48,0x52,0x8c,0xb1,0xbe,0x13,0x4b,0xeb,0xcb,0xa7,
+0x8f,0xe8,0xeb,0xec,0xa9,0xae,0x81,0xab,0xe6,0x0b,0xed,0xab,0x55,0x63,0xbe,
+0x3b,0x53,0xde,0x75,0xbc,0xaa,0xec,0xe6,0x22,0xbc,0x1d,0x5f,0xec,0x5d,0x1b,
+0xde,0xc3,0x75,0x57,0x42,0xed,0xbe,0xc9,0xb1,0x08,0xe9,0xc1,0x22,0xb6,0xcc,
+0x90,0x81,0xb0,0x04,0x2a,0x47,0x44,0x31,0xa2,0x7e,0x14,0xf1,0xa6,0x0b,0xed,
+0xb7,0x97,0x13,0xe8,0xf8,0xf8,0x18,0xbd,0xe0,0x92,0x8c,0x0d,0x13,0xd1,0x93,
+0x27,0x8f,0xdd,0x22,0xff,0x7e,0x71,0x3a,0xb4,0xad,0xe0,0x0d,0x07,0x71,0x31,
+0x70,0x10,0x71,0xca,0x5d,0xa5,0x40,0x24,0x64,0xf6,0xa5,0x0e,0x16,0xb3,0x62,
+0x84,0x31,0xd7,0x10,0xd1,0x50,0x6d,0xc4,0x1c,0xf0,0x80,0xc5,0x80,0x4a,0xa1,
+0x18,0x8a,0x68,0x3d,0x70,0x0d,0xc7,0xc7,0x79,0xbf,0x67,0xaa,0x5c,0x83,0x65,
+0x11,0x80,0x52,0x37,0x15,0x9c,0x88,0x27,0xc0,0x46,0xc2,0x85,0x35,0xa2,0x56,
+0x39,0x80,0x62,0xb4,0x05,0x43,0x39,0x50,0x96,0x80,0x9d,0xee,0xf1,0x1b,0x8f,
+0x11,0x2c,0xe2,0xe0,0x44,0xc2,0x52,0x43,0x39,0xc2,0x60,0xd2,0xb7,0x18,0x62,
+0x28,0x85,0x6a,0x26,0xa2,0xf5,0xeb,0xfd,0xe8,0xa7,0x4b,0x3a,0x58,0x8c,0xc4,
+0x08,0x9a,0x03,0x3f,0xbe,0x61,0xf1,0xb0,0x09,0x95,0xa3,0x91,0xdf,0xbd,0xd6,
+0xcd,0x11,0x86,0x01,0xa3,0x14,0xc0,0x55,0x0a,0xaf,0xbd,0xe1,0x7c,0xf3,0xc1,
+0xa2,0x19,0x06,0xb3,0xc7,0x81,0xba,0x2b,0x54,0x8e,0x04,0xc5,0x50,0xd6,0x22,
+0x66,0xe0,0x4d,0xad,0xd7,0x99,0xc5,0x5c,0xd2,0xc1,0xa2,0x31,0x6b,0x30,0xb0,
+0x61,0x66,0x72,0xb7,0x94,0x2a,0x83,0xec,0x28,0xc7,0xa0,0x18,0xbe,0xc5,0xb0,
+0xad,0xc5,0x88,0x55,0xe8,0xda,0x05,0xfc,0x26,0xbf,0x0d,0x9d,0x95,0x34,0xe1,
+0x86,0x19,0x4d,0x86,0x72,0x40,0xc5,0x48,0x51,0x0a,0xb0,0xdb,0x97,0x6c,0xd7,
+0xc0,0x95,0x7e,0x2d,0x3e,0xe7,0x33,0x41,0x87,0x87,0x87,0x12,0x2e,0x43,0xdb,
+0xae,0xc1,0x20,0x26,0x62,0x17,0x9b,0x5e,0x64,0xac,0x1c,0xc2,0xd2,0xdf,0xe4,
+0x2a,0x06,0xb6,0x16,0x86,0x55,0x70,0x1f,0x6f,0x0c,0x92,0x74,0x45,0x40,0xef,
+0x03,0x18,0xf2,0xb3,0x73,0xcd,0x63,0x47,0x29,0x07,0x56,0x0c,0x51,0x0d,0x68,
+0xa5,0x68,0xa6,0x57,0x35,0xd5,0xc1,0x35,0x69,0xff,0x21,0x7e,0xd1,0x6b,0xed,
+0xb9,0x84,0xbe,0xca,0x06,0xb1,0x31,0x88,0x1d,0xcb,0xe6,0xe6,0x43,0x42,0xe5,
+0xf0,0xec,0x82,0xeb,0x2e,0xb8,0x2f,0x8d,0x2a,0x05,0x1a,0x22,0xbd,0xaa,0x19,
+0xd8,0x84,0x04,0x15,0xa1,0x82,0xae,0x41,0x53,0xc3,0xe2,0x10,0x2e,0xe3,0x91,
+0xdf,0x5d,0xc6,0x8a,0xd1,0x74,0xb4,0x90,0xc8,0x8a,0x56,0x6d,0x87,0x4b,0xdd,
+0xce,0xad,0xdb,0xf3,0x8e,0x4e,0x16,0x27,0x4e,0xcd,0xf6,0x48,0x30,0xbf,0x28,
+0x58,0x2c,0xfd,0x3a,0x7b,0xc5,0x9c,0x8c,0x4d,0x73,0x81,0x7b,0x1e,0xfd,0x78,
+0xa1,0x77,0x00,0xcd,0xa9,0x83,0x8d,0x30,0xb2,0x16,0x71,0xa5,0xf0,0x2d,0xa8,
+0x7f,0x04,0xb1,0x29,0x99,0x3e,0x22,0x8a,0x85,0x7f,0xae,0x62,0x34,0x1d,0x5d,
+0xd3,0xca,0xe9,0x64,0xe9,0x3a,0x5d,0x9c,0x4d,0xb0,0x61,0xf0,0x44,0x9d,0xe8,
+0x9d,0xdf,0xf4,0x9f,0x24,0xc4,0xa6,0xf9,0x43,0x1f,0xd3,0x2a,0xfe,0xdd,0x47,
+0x66,0xbc,0xd6,0x60,0xe0,0xd5,0x8f,0x5b,0x15,0x3b,0x4b,0xdb,0xc9,0x83,0x40,
+0x43,0x39,0xb2,0x16,0x86,0x52,0xb8,0x0a,0xe1,0x3d,0x73,0x70,0xa9,0xd6,0x3a,
+0x4c,0x58,0x56,0x14,0x23,0xf4,0x0f,0x95,0x21,0x1d,0x3a,0xfc,0x6d,0x3a,0xbf,
+0xe9,0x68,0x52,0x09,0x29,0x6f,0x44,0x78,0x80,0xf8,0x82,0xfb,0x7e,0x93,0x9d,
+0x5a,0x71,0x7e,0x19,0x24,0x94,0x72,0xa6,0x8f,0x6d,0x1e,0x41,0xb5,0x09,0xa7,
+0xd6,0xf0,0xe5,0xe0,0xe1,0x5e,0x71,0xfe,0x0b,0x95,0xa3,0xc3,0xc6,0x2d,0xef,
+0xb1,0x71,0x2c,0x09,0xb2,0x14,0x1d,0x36,0xd8,0x22,0x50,0xde,0xac,0x21,0x39,
+0xb3,0x08,0x48,0x88,0xe8,0xc9,0xd3,0x1f,0x23,0x16,0x3c,0x77,0xdf,0x28,0xb0,
+0xdb,0x89,0xce,0x88,0x18,0x11,0x7c,0x18,0x21,0x4d,0x44,0x10,0x9a,0x3e,0x8b,
+0xdf,0x6d,0x7d,0xa6,0x1f,0x5b,0x1f,0x5d,0x77,0x48,0x05,0xb7,0xc1,0x9c,0x13,
+0x0b,0x29,0xc5,0x48,0xc0,0x06,0xb9,0x0f,0x1f,0x1b,0xed,0x16,0xac,0x94,0x38,
+0x0c,0x16,0x93,0x15,0xc1,0xf0,0x8d,0x43,0x71,0x2b,0x4c,0xdf,0xf9,0x58,0x78,
+0x6e,0x47,0xbc,0x2f,0x24,0x39,0x65,0x81,0x90,0x8e,0x95,0xa0,0x60,0xaa,0x1a,
+0xe3,0x17,0x59,0x84,0x5c,0x02,0xb3,0x8e,0xe4,0xe9,0x63,0xe3,0xb2,0xfc,0xeb,
+0x26,0x36,0xc0,0x5a,0x60,0x4b,0xe1,0x63,0x23,0x83,0x69,0x68,0x9f,0x93,0x86,
+0x0d,0xb4,0x08,0x40,0x2a,0x23,0x8f,0x80,0x6e,0x6c,0xee,0x75,0x2d,0xa3,0x97,
+0x0b,0x77,0x78,0x73,0x85,0x37,0xcd,0xa1,0x0c,0x1b,0x3e,0xa5,0x8b,0x8a,0xbc,
+0x40,0x6b,0x70,0x13,0x63,0x16,0xa1,0x74,0x19,0x7a,0x3a,0x9d,0xd2,0xc5,0xc5,
+0x05,0x94,0x37,0x95,0xc2,0x77,0xc4,0x31,0x36,0xd2,0x2a,0x8c,0x3b,0x60,0x80,
+0xa5,0x00,0xd8,0x70,0x18,0x34,0x65,0x60,0x13,0x92,0x61,0x11,0xd0,0x48,0x42,
+0xf6,0xaf,0x29,0x1f,0xda,0x6d,0xe7,0xb7,0x9e,0x4b,0x70,0x84,0xf7,0x94,0x02,
+0x8c,0x06,0xee,0x80,0x03,0x56,0xc2,0x0d,0xae,0xc2,0x30,0x15,0xf0,0x8b,0x96,
+0xa1,0x73,0xbe,0x8f,0x40,0x84,0x5c,0xc3,0xc4,0xc0,0xc6,0x20,0x0e,0xa3,0x1a,
+0x84,0x0d,0xb2,0x16,0x11,0x6c,0x9c,0x01,0xe4,0x0e,0x96,0x81,0x12,0xb0,0x29,
+0x5a,0x74,0x52,0x25,0xd4,0x8e,0x10,0x72,0x98,0x6e,0x59,0xec,0x18,0x24,0x22,
+0x71,0x7c,0x9b,0x5e,0x39,0x1b,0x46,0x03,0x76,0x1d,0x8e,0x45,0xf0,0x94,0xcd,
+0x67,0x62,0x8b,0x29,0xe6,0xb4,0x59,0x83,0x41,0xc3,0xec,0x91,0xfd,0xb2,0x08,
+0x36,0x32,0x98,0xc7,0x00,0x1b,0x7b,0xb0,0x48,0x26,0x36,0x45,0x29,0x66,0x68,
+0x54,0x55,0xe7,0xb7,0x85,0x8e,0xf0,0x71,0xc1,0x43,0x2b,0x11,0x00,0xa1,0x2c,
+0x02,0x66,0x22,0x75,0xfa,0x98,0x4b,0xa9,0x8b,0x4e,0xf6,0xc0,0x61,0xf2,0x74,
+0x38,0x01,0x1b,0xd7,0x52,0x84,0x56,0xc2,0x1a,0x2c,0xf6,0x1a,0x2b,0xc6,0xa6,
+0x68,0xfa,0x68,0xed,0xcc,0x61,0xdf,0x24,0x90,0x78,0xc2,0x27,0x08,0x1e,0x8c,
+0x04,0x2f,0x96,0x08,0x14,0x02,0x93,0xad,0xf5,0x1b,0xf8,0x3a,0xbb,0x7f,0x6e,
+0xae,0x35,0x20,0xb6,0x78,0x73,0xd8,0xf4,0x4a,0x82,0x07,0x8b,0x99,0xe1,0xcf,
+0x99,0x35,0xac,0xb5,0x67,0xb1,0x77,0xd5,0xdc,0x06,0x44,0x83,0x5f,0x1b,0x0c,
+0x83,0x24,0x09,0x1e,0x15,0x32,0x38,0xb7,0x78,0x49,0x0d,0x16,0x73,0x29,0x79,
+0x17,0xb3,0xc3,0x4b,0x4f,0x42,0x18,0x9b,0x56,0x96,0x38,0x36,0x39,0x0a,0x81,
+0xd7,0x60,0xba,0xc2,0xb2,0x60,0x71,0x6c,0xad,0x41,0x9c,0x03,0x6e,0x7d,0xb8,
+0x53,0xd6,0x78,0x8c,0x30,0x1d,0xea,0x08,0x2e,0x4e,0x76,0xdd,0x52,0x08,0x24,
+0xb4,0x41,0x38,0x9f,0xae,0x57,0x1f,0xa7,0xd3,0xa9,0xd9,0x46,0x48,0xc7,0xc7,
+0xc7,0xea,0xbd,0x86,0xaa,0xe2,0xf8,0x5a,0x83,0x37,0x45,0x20,0x85,0x8d,0x38,
+0xd6,0xae,0xc3,0xa1,0x29,0x0f,0xb1,0x31,0x06,0x0b,0x54,0x08,0xfc,0xcd,0x86,
+0xe6,0x7e,0xcc,0x6f,0xd1,0xea,0x23,0xbb,0x91,0x61,0x2f,0xd9,0xb0,0xe6,0xee,
+0x65,0xbe,0xda,0x5b,0x90,0xe0,0x9e,0x92,0x90,0xf4,0x41,0x66,0x5c,0x68,0xe9,
+0x70,0x05,0x7c,0x19,0xfc,0x6e,0x61,0xd1,0x89,0xcd,0x3c,0x02,0x69,0x6c,0x88,
+0x14,0x36,0x5a,0x29,0x5c,0x4b,0x51,0x80,0x8d,0xa5,0x9b,0x62,0xc6,0x08,0xaa,
+0x0c,0xbe,0x16,0x1f,0xdd,0xa9,0xeb,0x06,0x88,0xbd,0x30,0x02,0x35,0x1f,0x09,
+0x6e,0x5b,0x84,0x98,0xd0,0x40,0xeb,0x9d,0x73,0x2b,0x58,0x0c,0x65,0x0b,0x53,
+0xc6,0x31,0xba,0xbc,0xbc,0xa4,0xc3,0xc3,0xc3,0xc4,0x59,0x43,0x17,0x0b,0x0c,
+0xc7,0x6e,0x5c,0xe3,0xe1,0xa0,0x94,0x22,0xb4,0xa0,0x01,0x36,0xde,0x39,0x72,
+0x19,0x36,0x36,0x91,0xcc,0xa2,0x0e,0x16,0xad,0x6d,0x5e,0x4a,0xd4,0x61,0xc0,
+0x7b,0x0f,0x74,0x23,0x83,0x3e,0xd1,0x81,0x04,0xef,0xb2,0x61,0x31,0x85,0x08,
+0x85,0xee,0xfd,0x66,0x17,0x2f,0xb8,0x0c,0x0d,0x02,0x5b,0xab,0x8f,0xa1,0x6c,
+0x27,0x27,0x27,0xea,0x3e,0x8b,0x4e,0x4e,0x4e,0x54,0x42,0xc9,0x5a,0x7d,0x1c,
+0x90,0xf7,0x4b,0xbc,0x97,0x4f,0x54,0x5a,0x98,0x86,0xb5,0x82,0xd8,0x60,0xf1,
+0xce,0x07,0x05,0xf0,0x77,0x33,0x07,0xec,0x8c,0x60,0x53,0xf4,0x5e,0x83,0xe5,
+0xa2,0x19,0x25,0x81,0x08,0x28,0x40,0x30,0x12,0x6c,0xa1,0x1d,0x21,0x99,0xda,
+0x73,0xd7,0x67,0x52,0xa0,0x11,0x76,0x40,0xb4,0x71,0xd7,0x60,0x8c,0x30,0x73,
+0xfa,0xe8,0x30,0x3c,0xe0,0xd0,0x9c,0x13,0x01,0x6c,0x62,0x83,0x25,0xc0,0x26,
+0xb4,0x9c,0x3d,0x05,0x03,0x76,0x0b,0x7b,0x16,0x23,0xc1,0x5a,0xfb,0x3f,0x4a,
+0x0b,0x63,0x21,0xbb,0x73,0xac,0xf5,0xc8,0x3a,0x34,0xbf,0x12,0xc0,0xc3,0x03,
+0x7b,0x65,0x30,0x3a,0x67,0x03,0x6b,0x0d,0xe9,0x9b,0x57,0x01,0xb1,0x8b,0x18,
+0x3b,0x69,0xe1,0xf6,0x22,0x45,0x06,0x4b,0x88,0x4d,0x37,0x70,0x62,0xd8,0x38,
+0xcf,0x25,0x21,0xcf,0x3d,0x8c,0xc9,0x45,0x94,0x33,0x7d,0xe4,0x00,0x7f,0xe7,
+0xde,0x5e,0x09,0xdb,0x2d,0x54,0x83,0x67,0x10,0x5b,0xeb,0x1d,0xb3,0x28,0x03,
+0xd7,0xc4,0xe6,0x08,0x10,0xcc,0x00,0x99,0x09,0xa5,0x9d,0x4d,0x1f,0xbb,0x40,
+0x36,0x0b,0x1b,0x6f,0xed,0x60,0x04,0x9b,0x3e,0xde,0x8a,0x60,0x43,0x90,0x81,
+0xf4,0xe9,0xe3,0xe1,0xe1,0x61,0xd2,0x8d,0x1d,0xd3,0x5e,0x88,0xc0,0xdc,0x5e,
+0x19,0x3a,0x72,0x10,0xb2,0xb9,0x3b,0x5c,0x20,0x71,0x85,0x0e,0x83,0xca,0xde,
+0x24,0xc2,0x11,0x80,0xac,0x41,0x07,0x04,0x8a,0x11,0xca,0x7f,0xca,0x27,0xc4,
+0x66,0x52,0x4d,0xe0,0xb3,0x50,0xf8,0xd4,0xa9,0x87,0x89,0x8d,0x77,0xde,0xed,
+0x3f,0x1c,0xac,0xa9,0x69,0x39,0xa1,0x35,0x30,0xb0,0x11,0xdc,0x97,0xc9,0xbf,
+0x16,0x3f,0x36,0x92,0xc4,0x39,0x6a,0x6e,0x75,0xb3,0x80,0x5a,0xe8,0x66,0x9e,
+0xec,0x0a,0xd9,0x08,0x8d,0xdc,0x85,0xab,0x1c,0xfd,0x6a,0x61,0x0b,0xc0,0xc0,
+0xa0,0x2f,0x70,0x6a,0x66,0x71,0x5b,0x3b,0x94,0xbc,0xa0,0x90,0x7a,0xc3,0xaf,
+0x12,0x62,0x10,0x9b,0x6e,0xd6,0xd5,0x76,0xe8,0xb8,0x75,0x68,0xf7,0x6c,0x89,
+0x3f,0x50,0x1c,0x66,0x1c,0xb7,0x90,0xa1,0x08,0xeb,0x64,0x16,0x9d,0x10,0xa8,
+0x3f,0xf3,0xa7,0x32,0xbe,0xd0,0x9d,0x59,0x0c,0xfd,0xa4,0x18,0x23,0xa0,0xd7,
+0x79,0xf6,0xcd,0x61,0xfb,0xd0,0x9e,0xfa,0x91,0x88,0x5d,0x99,0xa0,0x37,0x7a,
+0x52,0x69,0x3e,0x9f,0x2b,0xc5,0xb1,0x5c,0x03,0xd8,0xa8,0x4c,0x83,0x45,0x20,
+0x22,0x80,0x4d,0xbf,0x5d,0x5d,0x61,0x13,0xb7,0x0e,0x2e,0x36,0xee,0x40,0x69,
+0x18,0x71,0x78,0x6a,0xff,0x59,0x53,0xeb,0xb0,0x2c,0x73,0xab,0x9a,0xf6,0x84,
+0x3d,0x0f,0xce,0xdc,0x36,0x1c,0x05,0xd2,0x76,0x28,0xb4,0x0e,0xc8,0x55,0x38,
+0x02,0xfb,0xe6,0x50,0x73,0x63,0xf1,0x8b,0x96,0xa1,0xe7,0xf3,0xb9,0x21,0x17,
+0xa6,0xe4,0x59,0x43,0xff,0xbf,0x78,0x65,0xfd,0x94,0x17,0x60,0xd3,0xcf,0xb5,
+0x00,0x36,0xc8,0x3a,0x8c,0x2a,0x03,0x74,0x4c,0xb6,0xb5,0x0c,0x69,0x8d,0x45,
+0xa7,0xc1,0x1e,0x78,0x30,0x74,0x2f,0x6b,0x48,0x6b,0xfc,0x7b,0xb3,0x18,0xb1,
+0x0e,0xbd,0x7f,0x04,0xae,0x01,0x28,0x43,0xf7,0xb8,0xf0,0xe5,0x4f,0x6b,0xd6,
+0x50,0x1a,0x2c,0xe6,0xcf,0x1a,0x34,0x36,0x9d,0x45,0x88,0x61,0xa3,0xad,0x43,
+0xc4,0x1a,0x98,0xca,0xd0,0xb8,0x8d,0x24,0x6c,0x92,0xf3,0x08,0xa3,0x7b,0xf7,
+0xbb,0x70,0xa5,0xd5,0xfa,0x2e,0x7a,0xed,0x84,0x76,0x72,0xe1,0x32,0x0c,0x0b,
+0x6d,0x1d,0xfa,0xe3,0x34,0x65,0xe8,0x1e,0xcd,0x2e,0x07,0x8c,0xf9,0xad,0xaa,
+0x4a,0x6d,0x44,0x51,0xdf,0x44,0x1a,0xa1,0xf5,0xde,0x6b,0x70,0x94,0x37,0x11,
+0x1b,0x6d,0x1d,0xf2,0x06,0x4a,0x1f,0xa3,0x24,0x62,0x03,0x7f,0xb8,0xc3,0xda,
+0xd4,0x11,0x27,0x57,0xf3,0x51,0x9a,0x18,0x8c,0x00,0x67,0xcd,0x60,0x6d,0x65,
+0xf0,0x38,0x70,0x76,0x32,0x02,0x7e,0x91,0x19,0xcf,0xcd,0x2c,0x9e,0x9f,0x9f,
+0x83,0x36,0xc7,0x2c,0xa8,0x7f,0x3c,0x86,0x4d,0x03,0x4b,0x21,0x36,0x41,0x17,
+0x7a,0x2a,0x32,0xca,0x6f,0x43,0x19,0x9b,0x57,0x09,0x85,0x08,0xbe,0xd6,0x3b,
+0xd3,0x19,0x25,0x64,0x54,0x19,0xc8,0x37,0x85,0x44,0x58,0xf8,0x96,0x06,0x7b,
+0x14,0x33,0x7f,0x9b,0xdf,0xc5,0x6c,0xbf,0xfb,0x48,0x18,0x1b,0x87,0x57,0x0b,
+0x9b,0x71,0x65,0xa0,0x11,0x6c,0xd4,0x8c,0x91,0xc6,0xb0,0xb1,0x66,0x0d,0x6a,
+0xb8,0x45,0xa7,0x48,0xa1,0x1b,0xa4,0xce,0x04,0x76,0xd6,0x61,0x1d,0x65,0x18,
+0xfc,0x22,0x94,0x2e,0x42,0x22,0x96,0x22,0x94,0xcd,0x1a,0x9a,0x36,0xfc,0xfa,
+0x6d,0x9b,0xe8,0x4e,0xef,0xcf,0xb0,0xb5,0x48,0x27,0x7e,0x52,0x94,0x41,0xb5,
+0x1d,0xc5,0x06,0xd5,0x19,0xae,0x24,0xcf,0x1a,0x90,0x76,0xe0,0x85,0x95,0x4e,
+0xc8,0xf0,0x51,0x7d,0xe3,0x49,0xca,0x40,0x23,0x02,0xfb,0x32,0x87,0x89,0x95,
+0xee,0xce,0xc1,0x3e,0x30,0x5b,0x8b,0x4e,0xdb,0x79,0xaf,0x01,0xbf,0xf2,0xa6,
+0x3b,0xc7,0xe5,0x36,0x65,0xa0,0x0c,0xc7,0x14,0x0c,0x92,0x7e,0xd8,0x0c,0x5d,
+0x9e,0x88,0x4d,0xc3,0x73,0xa2,0x45,0x98,0x4c,0x26,0x70,0xbe,0xac,0xc9,0xd1,
+0x7a,0x67,0xc2,0xe0,0x99,0xac,0x98,0x32,0x90,0x73,0x6c,0x0a,0x4c,0x64,0xd4,
+0xe8,0xb9,0x08,0x4d,0x9f,0xc5,0x2f,0x8a,0x11,0x72,0x82,0xc5,0xd5,0x6a,0xa5,
+0x82,0x2a,0x33,0x8f,0xd0,0x06,0x66,0x0e,0x83,0x5a,0x8e,0x98,0x0b,0xed,0xef,
+0x0f,0x3a,0x7d,0xc4,0x45,0x68,0x3e,0x86,0x56,0x5c,0x9e,0x43,0x82,0x31,0x02,
+0xb3,0xde,0xc9,0x33,0x9a,0x4f,0xef,0x0e,0xda,0x68,0xcd,0x9f,0xce,0x18,0x02,
+0x3b,0x8b,0x23,0x81,0x7e,0xfb,0x4f,0x71,0x4d,0x5f,0xa0,0x74,0xae,0xb8,0x6e,
+0x9d,0xd4,0xcc,0x62,0x4e,0x1e,0xe1,0xd6,0xad,0x5b,0x7a,0x19,0xda,0xd8,0x98,
+0x02,0xb1,0x69,0x8f,0x07,0x6c,0x02,0xf5,0x76,0xd3,0xc3,0x2c,0x69,0x16,0xd3,
+0xd7,0x32,0x10,0x2c,0xea,0x20,0x25,0x39,0x46,0xc8,0x0a,0x16,0xa3,0x02,0x23,
+0x8d,0x8c,0x08,0x34,0x62,0x15,0x62,0xbe,0xcf,0x25,0x21,0x7b,0xd1,0x69,0xd3,
+0x6f,0x3a,0x99,0x79,0x84,0xb0,0x88,0x9d,0x42,0x0f,0x8e,0x7e,0x94,0xa8,0xdb,
+0x91,0xfd,0x73,0xb1,0xf1,0x6f,0x4c,0xc3,0x26,0x36,0x48,0x42,0x2a,0xff,0x50,
+0x86,0xf3,0xd0,0x21,0x52,0xf5,0xe2,0x25,0x68,0x15,0xc2,0x3a,0x61,0x19,0x74,
+0x15,0x3a,0x3c,0x36,0x03,0x22,0x64,0x11,0x72,0x29,0x79,0x17,0x73,0xd8,0x4f,
+0x01,0x8d,0xbb,0x88,0xa0,0x32,0x68,0x68,0x6c,0x78,0x75,0xd6,0x39,0xe4,0x67,
+0xf3,0x16,0xc1,0x61,0xc1,0x0b,0x5a,0xc8,0x31,0x4f,0xe2,0xdf,0x17,0xa3,0x54,
+0x9d,0x56,0x95,0x9c,0xe3,0x41,0xd9,0xd2,0x62,0x84,0x5c,0x4a,0xb6,0x08,0x3d,
+0x73,0x3e,0x36,0xa1,0xf5,0x73,0xef,0x0b,0xeb,0x6a,0xcf,0x9f,0xe0,0x1e,0x8c,
+0x9a,0x1d,0x36,0x42,0x79,0x31,0x82,0xea,0x0f,0x6b,0xfa,0xd8,0x3f,0xd0,0xe8,
+0xc1,0xb5,0x3a,0x17,0xd5,0x1b,0x55,0xff,0xa0,0xbe,0x21,0xec,0x64,0x32,0xf1,
+0x3e,0x7f,0x93,0xfb,0xc1,0x4d,0x35,0x7d,0x34,0x4c,0x2d,0x31,0x01,0x6c,0x70,
+0x14,0x94,0xf4,0xdc,0x35,0xeb,0xa1,0x76,0xac,0x3d,0x8b,0xe1,0x04,0x61,0xbd,
+0xed,0xec,0xd1,0x47,0xa7,0xf9,0x2e,0x6d,0xfb,0xb0,0xff,0x54,0xe4,0xc5,0x4b,
+0xad,0xb9,0x05,0xfc,0x76,0xa3,0xd7,0x95,0x2f,0x37,0xc5,0x0c,0x2d,0x42,0xea,
+0xa7,0x73,0x22,0xa6,0x7d,0x6b,0x24,0xc1,0x09,0x1b,0xd8,0x80,0x09,0x42,0xc1,
+0x47,0xb9,0x4b,0xc4,0x5a,0xb7,0xae,0x80,0xda,0xf6,0x2e,0x9c,0x50,0xd8,0x1c,
+0x45,0x38,0x39,0x39,0xd1,0x1f,0xca,0x48,0x76,0x37,0x5a,0xbe,0x6d,0x2b,0x41,
+0xbb,0xc9,0x4f,0x3b,0x93,0xd4,0x18,0xa1,0x28,0x58,0x94,0xf0,0x74,0x3d,0x71,
+0x85,0xc8,0xb7,0x06,0x20,0x28,0x1c,0x0e,0xc3,0x67,0xd8,0x7b,0xf7,0x43,0xd9,
+0x72,0xd6,0x1a,0xba,0x36,0xc2,0xf3,0x9c,0xb8,0xa3,0x4c,0xdd,0xd7,0xa9,0x17,
+0x76,0x48,0xc6,0xac,0x21,0xfb,0x8b,0x29,0x81,0xf9,0xc1,0x9d,0x9f,0x32,0xed,
+0x5b,0x83,0x04,0xd7,0x4b,0xb5,0x08,0xb9,0x84,0xf2,0x2b,0xd1,0x64,0x1b,0x0c,
+0xe5,0xc3,0x72,0x8c,0xd7,0xba,0x36,0x24,0x3a,0xf8,0x72,0xf2,0x08,0xa9,0xc1,
+0xa2,0xcf,0x1b,0x78,0xb8,0x33,0xa2,0xbd,0xc1,0xed,0xd4,0x49,0x13,0x16,0xdd,
+0x85,0x9e,0x37,0x1c,0xa6,0xae,0x35,0x14,0x07,0x8b,0xe6,0x5a,0x83,0x44,0xb1,
+0xf1,0x32,0xa3,0x2e,0x1e,0x86,0xe5,0xb3,0x09,0xdb,0x44,0xe3,0x36,0xb2,0xac,
+0x25,0x5c,0x6b,0xe8,0xd2,0xa8,0x6e,0x14,0x19,0x37,0x7f,0xa2,0x8f,0x04,0x96,
+0x92,0x62,0x59,0x9c,0x32,0xef,0x36,0x2d,0x60,0x4e,0x97,0x59,0xab,0x8f,0xa5,
+0x5f,0x67,0x0f,0x7f,0xfb,0xd1,0x5c,0x7d,0x04,0x4a,0x80,0x67,0x58,0x63,0x52,
+0x89,0x86,0xc8,0xc5,0x26,0x3a,0x10,0x09,0x06,0xf4,0xc9,0xae,0xa1,0xbb,0xd1,
+0x35,0x17,0x96,0x22,0x58,0xd3,0xc7,0x71,0x8d,0x17,0xd0,0xc9,0x86,0x76,0x63,
+0xed,0x6a,0x4f,0x01,0xd0,0x06,0xbf,0x9b,0xc8,0x23,0x84,0xee,0x25,0x96,0x47,
+0x80,0xd8,0x84,0x3c,0x5b,0xd8,0xd8,0x20,0xd8,0x65,0xe2,0x3f,0xb3,0x0b,0x16,
+0x3d,0x5e,0x28,0x23,0x8f,0x90,0xfa,0xc1,0x4d,0xc8,0x8f,0xf8,0xe6,0x56,0xa0,
+0x7b,0x70,0xb5,0x7c,0x44,0xe3,0x81,0x72,0x78,0x2a,0xd4,0x1d,0x06,0x81,0xa5,
+0xf5,0x51,0xc9,0x70,0xd1,0x28,0xe7,0xc7,0xbd,0x4e,0x4f,0x4f,0xc1,0x2b,0x6f,
+0x78,0xf5,0xd1,0x79,0x67,0xcd,0xe3,0xcb,0x57,0x82,0x9e,0x79,0x63,0x80,0xa4,
+0x59,0x83,0xd1,0x80,0xdc,0xc1,0x86,0x09,0x63,0x93,0xb1,0x43,0x29,0xe6,0x07,
+0xb1,0x01,0xf7,0x94,0x60,0xd4,0x25,0x18,0x1a,0x1f,0xb1,0x06,0x6e,0x7d,0xdf,
+0x71,0x6f,0xd7,0x22,0x24,0xb5,0x29,0x3a,0x07,0xe2,0x7b,0xbe,0x88,0x12,0x8c,
+0x60,0x03,0x07,0x08,0xb0,0x06,0xc3,0xb1,0x5b,0x37,0xe3,0x05,0x17,0xa4,0x1d,
+0xf6,0xc7,0xb4,0x7c,0x86,0xba,0x33,0xdb,0xcc,0x75,0xe7,0xed,0x9d,0xee,0xf1,
+0x50,0x60,0x6a,0xbc,0x5e,0x7e,0xd6,0x16,0x42,0x0c,0x7e,0xd1,0x2e,0xe6,0x9c,
+0xf7,0x1a,0xea,0xba,0x56,0x23,0xa7,0x99,0x3e,0xea,0x67,0xe1,0xa1,0xd1,0x72,
+0x1b,0x73,0x95,0x09,0xd8,0x44,0x07,0x88,0xe2,0xc3,0xc7,0xa6,0xc9,0x2c,0x26,
+0x7e,0x4c,0x2b,0xd9,0x22,0xa0,0x19,0x92,0x94,0x0b,0xea,0x1f,0x5b,0x5a,0x8e,
+0x2d,0x48,0xd7,0xa4,0xb5,0x8b,0xb9,0xf3,0xef,0xb9,0x2f,0xb6,0xf4,0x6d,0x24,
+0x5a,0x04,0x76,0xe5,0xea,0xd9,0xdb,0x14,0x36,0x5e,0x2d,0xff,0xd8,0xc3,0x49,
+0x9a,0xec,0xac,0x73,0x87,0x00,0x19,0x88,0x08,0xe2,0x82,0xdf,0x74,0x42,0x69,
+0x54,0x4f,0x31,0xc3,0x2a,0x05,0x82,0xa6,0x9a,0x3d,0x72,0x8f,0x9d,0xbd,0x0d,
+0x76,0x1a,0xb5,0xff,0x98,0x56,0x37,0x02,0xd6,0xd8,0xc5,0xec,0x7b,0x21,0x66,
+0x41,0xcf,0xea,0x40,0x6f,0x4e,0x7c,0xa9,0x7c,0x6b,0x3f,0x82,0x53,0x58,0x3f,
+0x63,0x80,0x08,0xd1,0x10,0x2a,0x76,0xd8,0x10,0xc6,0x26,0xc4,0x85,0x28,0x37,
+0xb3,0x18,0x2a,0x00,0x33,0x4d,0xa7,0x33,0x87,0x15,0x72,0x84,0xa6,0x80,0x4d,
+0xbf,0x0d,0x6d,0x4e,0x05,0x14,0x06,0xdb,0xae,0xaa,0x0a,0x9a,0xc6,0x6d,0xed,
+0x47,0xc8,0xfb,0x95,0x37,0x9f,0xb1,0xaa,0x62,0x9a,0x4e,0xbb,0x8d,0x30,0x25,
+0xd8,0xe8,0xba,0xc8,0x4a,0x32,0x33,0xf4,0x1c,0xd9,0xd3,0xc7,0xb1,0xca,0xea,
+0xd1,0xed,0xc9,0x10,0x95,0xb2,0xf7,0xa7,0xd1,0x50,0x21,0x50,0x18,0x5c,0x1b,
+0xda,0x13,0x6b,0xaf,0xa9,0x78,0xb6,0x40,0xf1,0x94,0x1a,0x2c,0x9e,0x9d,0x85,
+0x3f,0x92,0x69,0xd3,0xd9,0xd9,0x19,0x3d,0x7b,0xf6,0x6c,0xb4,0xcd,0x96,0x75,
+0x80,0x0d,0xd3,0x30,0x18,0x47,0xb0,0xf1,0x0e,0xc1,0xd7,0xa2,0xd6,0xc2,0x86,
+0xa2,0x81,0x74,0x48,0x46,0xb0,0x68,0xc4,0x08,0x20,0x33,0x87,0x35,0x1b,0x1e,
+0x9a,0x25,0x76,0x1c,0x40,0x9e,0xa0,0x61,0xa5,0xe1,0x05,0x1f,0x1c,0x23,0x94,
+0x5a,0x04,0x1c,0x2c,0x1a,0x31,0xc2,0x3e,0x62,0x43,0x19,0x16,0x21,0xd9,0x35,
+0xb8,0x9f,0x7c,0x09,0x39,0x35,0x0f,0xf5,0xa8,0x37,0xaf,0x21,0x4a,0x10,0x94,
+0xd8,0x58,0x74,0x62,0x9d,0x47,0xc8,0xa5,0x54,0xd7,0xe0,0x8e,0xe1,0xbd,0xc2,
+0xc6,0x18,0x24,0x45,0x79,0x04,0x7f,0x79,0x09,0x0b,0x31,0x1c,0x62,0xcd,0xee,
+0xda,0x81,0x34,0xa2,0xf9,0x43,0xfe,0x54,0xbb,0xa8,0x54,0xd7,0x20,0x19,0x8b,
+0x0d,0x22,0xa2,0xd6,0x15,0xec,0x3c,0x82,0x81,0x0d,0x84,0x69,0xd3,0xd8,0xf8,
+0x27,0x29,0x31,0x82,0x95,0x59,0x54,0x4f,0x40,0x37,0x2e,0x97,0x17,0xb4,0xba,
+0x5c,0xea,0x67,0xbb,0xfc,0x80,0xd9,0x04,0x8a,0x75,0x3c,0x96,0x25,0xb8,0xea,
+0x05,0x3c,0xa1,0x60,0x7e,0x34,0x24,0x42,0x74,0x7e,0x71,0x6e,0x2e,0xac,0xec,
+0xea,0x17,0x5c,0x2e,0x5a,0x6c,0x2c,0x2d,0xdb,0x3e,0x36,0xba,0x21,0x11,0xa2,
+0xf3,0x25,0xc6,0xa6,0xe8,0x13,0xbc,0xdf,0xf9,0xb7,0xb7,0xe9,0x9d,0x77,0xbe,
+0x1b,0x8a,0x62,0x50,0xf2,0xc0,0x8b,0x53,0xc2,0x88,0x5a,0xad,0x56,0xc9,0xb3,
+0x86,0xd2,0xdf,0x74,0xb2,0x2c,0xc2,0xb7,0xff,0xf5,0x9f,0xe9,0x60,0xe2,0x9b,
+0xdb,0x5d,0x62,0x63,0x59,0xea,0xcb,0xe5,0xe5,0xe6,0x63,0x84,0xe5,0x72,0x99,
+0xf5,0x9d,0xc2,0x5d,0xd2,0x55,0x4f,0x1f,0xcf,0xcf,0xcf,0xe9,0x9c,0xce,0x55,
+0xf9,0x3e,0x50,0xb2,0x22,0xa0,0xc0,0x21,0xba,0xe8,0x74,0x4d,0x68,0x52,0x55,
+0x52,0xa2,0x08,0xb7,0x6f,0xdf,0x56,0x8b,0x4e,0x93,0xc9,0x44,0x6e,0x02,0x36,
+0xc9,0x16,0x61,0x32,0x99,0xfc,0x4b,0x5d,0xd7,0xbf,0xb2,0x0b,0xa6,0xb6,0x44,
+0xef,0x7d,0xe1,0x17,0x7f,0xf9,0x91,0xab,0xe4,0x75,0x5d,0xd3,0xed,0xdb,0xb7,
+0xb3,0x1a,0x09,0xb1,0xf9,0xc2,0x1b,0xbf,0xf4,0xe8,0xbd,0xf7,0xde,0x7d,0x97,
+0x88,0x5e,0xd8,0x04,0x93,0x57,0x41,0x55,0x55,0x7d,0x3b,0xc4,0x85,0xc8,0x50,
+0x84,0xe3,0xe3,0xe3,0xbf,0x79,0xfc,0xf8,0xf1,0x75,0x55,0x04,0x99,0x4e,0xa7,
+0x7f,0x75,0xe7,0xce,0x73,0x5e,0x3e,0x79,0x1d,0xeb,0x10,0xd6,0xb9,0x7b,0xf7,
+0xde,0xe5,0x6c,0x36,0xff,0xc6,0xf9,0xf9,0xb3,0x3f,0x2f,0x63,0xf1,0xca,0x68,
+0x75,0xbc,0x38,0xfe,0x86,0x5b,0xd0,0xc9,0xc8,0x22,0xf2,0x1c,0xaa,0xf1,0xad,
+0x7f,0xfa,0xc7,0x97,0xbf,0xff,0xfe,0xf7,0xff,0xa0,0xae,0x57,0x3f,0xbd,0x03,
+0x06,0x37,0x42,0x15,0x57,0x1f,0xde,0xbb,0xf7,0x13,0x7f,0xf7,0xc5,0xdf,0xfc,
+0xad,0xff,0x82,0xd7,0xab,0xea,0x63,0x22,0x4a,0x8d,0x18,0x2b,0x22,0x82,0x26,
+0xe4,0x9b,0xff,0xf0,0xf7,0x3f,0xff,0xf1,0x47,0x1f,0xfd,0x7e,0x2d,0xf5,0x9d,
+0x35,0x59,0xdd,0x39,0x55,0xd5,0xe4,0xdd,0x17,0x9e,0x7f,0xe1,0x6f,0x7f,0xed,
+0x57,0x7f,0xfd,0x7f,0xd1,0x75,0x16,0x91,0x13,0x22,0x3a,0xda,0x31,0x5f,0x57,
+0x45,0x1f,0x51,0x5e,0xd8,0x7e,0x46,0x44,0x65,0x3b,0x60,0xaf,0x07,0xd5,0x15,
+0x11,0x5d,0x8c,0xde,0x76,0x33,0xe8,0x19,0xe5,0xcf,0xdd,0xf6,0x73,0x2a,0xb0,
+0x79,0x7a,0x5a,0x11,0xd1,0x92,0x36,0x36,0xb9,0xdd,0x5b,0xaa,0x89,0xe8,0xe9,
+0x1a,0xf5,0x3e,0x0d,0x83,0xe4,0x92,0x88,0xce,0x2b,0x6a,0x94,0xe0,0x93,0xb6,
+0xe0,0xa6,0xd2,0x8f,0x69,0x3d,0x65,0xaf,0xa9,0xc1,0x26,0x6f,0xfb,0xf3,0xf5,
+0x21,0xa1,0x06,0x1b,0xe2,0x20,0xfd,0x3e,0x25,0xa2,0x39,0x35,0x81,0xd2,0x75,
+0xa7,0x25,0x35,0x23,0xfa,0x82,0x36,0x63,0xf1,0xe6,0x44,0x34,0x23,0xb8,0x69,
+0xfc,0xda,0x51,0x87,0x4b,0xef,0x0d,0xfe,0x1f,0x25,0x02,0xa9,0x06,0xfd,0x19,
+0xc9,0xa6,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,
+};
diff --git a/attic/table/play_png.h b/attic/table/play_png.h
new file mode 100644 (file)
index 0000000..e76dd0b
--- /dev/null
@@ -0,0 +1,540 @@
+static unsigned char play_png [] = {
+0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,
+0x52,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x82,0x08,0x06,0x00,0x00,0x00,0x9e,
+0xba,0x4c,0x59,0x00,0x00,0x00,0x04,0x73,0x42,0x49,0x54,0x08,0x08,0x08,0x08,
+0x7c,0x08,0x64,0x88,0x00,0x00,0x00,0x19,0x74,0x45,0x58,0x74,0x53,0x6f,0x66,
+0x74,0x77,0x61,0x72,0x65,0x00,0x77,0x77,0x77,0x2e,0x69,0x6e,0x6b,0x73,0x63,
+0x61,0x70,0x65,0x2e,0x6f,0x72,0x67,0x9b,0xee,0x3c,0x1a,0x00,0x00,0x1f,0x07,
+0x49,0x44,0x41,0x54,0x78,0x9c,0xed,0x5d,0x79,0x9c,0x14,0xd5,0x9d,0xff,0xbe,
+0x3a,0xba,0xbb,0xfa,0x1a,0x06,0x66,0x98,0x01,0x86,0x73,0x18,0x6e,0x10,0xe5,
+0x46,0x8e,0x19,0x30,0x1a,0x24,0x11,0x5d,0xb3,0x2e,0xc9,0x1a,0x4d,0x62,0x44,
+0xa2,0xc6,0xb8,0xc1,0xcd,0x6e,0x92,0xcd,0x1a,0x3f,0x2b,0x72,0x1f,0x8a,0x5c,
+0x2a,0x87,0x20,0xc2,0x20,0x51,0x50,0x23,0x2a,0x31,0x86,0x78,0xc5,0x80,0x89,
+0x37,0xa7,0x9a,0x21,0x20,0xcc,0xd1,0xdd,0xd3,0x73,0xf4,0xcc,0xf4,0x51,0x6f,
+0xff,0xa8,0xee,0x9e,0xaa,0xae,0x57,0xd5,0xc7,0x0c,0xcc,0x00,0xfd,0xe5,0xd3,
+0x43,0xd5,0xbb,0xab,0xbe,0xfd,0xfb,0xfd,0xde,0xfb,0xbd,0xa3,0x09,0xa5,0x14,
+0x84,0x10,0x02,0x20,0x17,0x80,0x1b,0x40,0x10,0x40,0x08,0x40,0x1d,0xa5,0xb4,
+0x05,0x59,0x74,0x6a,0x10,0x00,0x02,0x80,0x9e,0x00,0x6c,0x8c,0x78,0x3f,0x80,
+0x1a,0x4a,0x69,0xe4,0x82,0xb6,0x2a,0x8b,0x94,0x41,0x00,0xe4,0x01,0xe8,0x6a,
+0x92,0x46,0x06,0xe0,0x01,0x50,0x4b,0x29,0xa5,0x17,0xa4,0x55,0x59,0xa4,0x0c,
+0x02,0xa0,0x1f,0x00,0x4b,0x0a,0x69,0x43,0x00,0xaa,0x29,0xa5,0x0d,0xe7,0xb5,
+0x45,0x59,0xa4,0x05,0x0e,0xa9,0x91,0x07,0x00,0x22,0x80,0x9e,0x84,0x90,0x22,
+0x42,0x88,0xf5,0x3c,0xb6,0x29,0x8b,0x34,0xc0,0x65,0x90,0xc7,0x0e,0xa0,0x2f,
+0x21,0xa4,0x80,0x10,0xc2,0xb7,0x77,0x83,0xb2,0x48,0x0f,0x42,0x62,0xc0,0x90,
+0x21,0x83,0x4b,0x7a,0x15,0xf5,0x5c,0x42,0x29,0x9a,0x9b,0x9a,0x9a,0x5e,0x3a,
+0x7c,0xe8,0x83,0xdd,0xa1,0x50,0x88,0xd5,0x89,0xc9,0x01,0xe0,0x22,0x84,0x78,
+0x01,0xf8,0xb2,0xf6,0xb1,0x63,0x40,0x00,0x0c,0x52,0x07,0x5c,0xf3,0x8d,0x19,
+0x07,0x39,0x8e,0x2b,0x8c,0xdd,0x47,0x22,0x91,0x63,0x1e,0x8f,0x77,0xe1,0x87,
+0x7f,0xff,0xe8,0x7d,0x93,0x72,0xb2,0xf6,0xb1,0x83,0xa0,0x53,0xa1,0x6a,0xf2,
+0x00,0x80,0xe7,0xf9,0xc1,0xdd,0xbb,0xe7,0x6f,0x2b,0x9b,0x31,0x7d,0xcd,0x80,
+0xe2,0xfe,0x45,0x06,0xe5,0xc4,0xec,0x63,0xef,0xac,0x7d,0xbc,0xb0,0x48,0xd9,
+0x06,0x8a,0xa2,0x78,0x6d,0x71,0xf1,0x80,0x57,0xa6,0x4e,0xbb,0xfa,0x3f,0xba,
+0x74,0xc9,0x91,0x0c,0x92,0x49,0x50,0xec,0x63,0x21,0x21,0x44,0xa7,0x9e,0xb3,
+0x68,0x7f,0xa4,0xd5,0x89,0x21,0x84,0x58,0x25,0x49,0x9a,0x3f,0x76,0xdc,0x98,
+0xd7,0x27,0x4c,0x1c,0x37,0x27,0xea,0xc1,0x61,0xc1,0x0d,0xa0,0x1f,0x21,0xa4,
+0xab,0x49,0x9a,0x2c,0xda,0x01,0xa6,0x04,0x0a,0x82,0x80,0x69,0xd3,0xa6,0xe9,
+0x33,0x71,0x5c,0xf7,0x9c,0x9c,0x9c,0xa5,0x33,0x66,0x96,0xee,0x1a,0x39,0x72,
+0xf8,0x28,0x93,0xb2,0xf3,0xa0,0x10,0xe9,0x6a,0x7b,0x53,0xb3,0x60,0x21,0x29,
+0x81,0xbf,0xfa,0xe5,0xff,0xe0,0xf1,0xb5,0x6b,0xd1,0xa7,0x4f,0x1f,0x5d,0x3c,
+0xcf,0xf3,0xa3,0x0b,0x7b,0x14,0xee,0x2e,0x2d,0x9b,0xb6,0xb8,0x77,0xef,0xa2,
+0x7c,0x83,0x62,0x44,0x00,0x3d,0xa2,0xf6,0x91,0xe5,0xae,0xcb,0xa2,0x0d,0x48,
+0xaa,0x42,0x09,0x21,0x28,0x29,0x1e,0x84,0x0d,0xeb,0x9f,0xc0,0xaf,0x7e,0xf5,
+0x2b,0xd8,0x6c,0xb6,0xc4,0x78,0x62,0xb1,0x58,0x6e,0x1a,0x32,0x74,0xf0,0xeb,
+0x57,0x4f,0x99,0x3c,0xcf,0xe1,0xb0,0x1b,0x39,0x06,0x24,0x00,0x7d,0xb2,0xf6,
+0xb1,0x7d,0x91,0xb2,0x0d,0xe4,0x79,0x1e,0xd3,0xa7,0x95,0x61,0xd7,0xce,0x72,
+0xcc,0xfd,0xee,0x5c,0x5d,0x3c,0x21,0xc4,0xee,0x70,0xd8,0x17,0x4c,0x9a,0x3c,
+0xf1,0x95,0xb1,0xe3,0xc6,0x5c,0x63,0x52,0x54,0xcc,0x3e,0x76,0xcb,0xda,0xc7,
+0xb6,0x23,0x6d,0x4f,0x8c,0x24,0xd9,0xf1,0xc3,0xdb,0xef,0xc0,0xf6,0xed,0xcf,
+0x60,0xcc,0xd8,0x31,0xfa,0x02,0x39,0xae,0x77,0xd7,0xae,0xb9,0x6b,0x67,0xcc,
+0x2c,0xdd,0x3a,0x64,0xe8,0xe0,0x12,0x93,0x7a,0xbb,0x01,0xe8,0x9f,0xb5,0x8f,
+0x6d,0x43,0x26,0xae,0x34,0x00,0x40,0xf7,0xfc,0x02,0x2c,0xfc,0xbf,0x45,0x58,
+0xb1,0x62,0x25,0xba,0x77,0xef,0xae,0x8b,0x17,0x04,0x61,0x52,0xef,0xde,0x45,
+0xfb,0xa6,0x97,0x4e,0xfd,0xdf,0x82,0x82,0xee,0x39,0x06,0xc5,0x08,0x50,0xec,
+0x63,0x9f,0xac,0x7d,0xcc,0x0c,0x19,0x13,0x08,0x28,0xf6,0x71,0xc4,0xf0,0x91,
+0xd8,0xb2,0x79,0x2b,0xee,0xbf,0xff,0x7e,0x08,0x82,0x90,0x18,0xcf,0x5b,0xad,
+0xd6,0x7f,0x1f,0x75,0xc5,0xc8,0x03,0x93,0xaf,0x9e,0x78,0xab,0xc5,0x62,0x31,
+0xf2,0x9d,0xda,0x90,0xb5,0x8f,0x19,0x21,0x2d,0x02,0x29,0xa5,0x68,0x6e,0x69,
+0xd2,0x85,0x0b,0x82,0x88,0x59,0xdf,0x9c,0x8d,0xf2,0x5d,0xbb,0xf1,0xad,0x6f,
+0x7f,0x4b,0x17,0x4f,0x08,0xc9,0x71,0x3a,0x9d,0xbf,0x99,0x3a,0x6d,0xca,0xbe,
+0x2b,0xaf,0x1a,0x3d,0xd9,0xa4,0x0a,0x37,0x14,0xb5,0x9a,0xb5,0x8f,0x29,0x22,
+0x6d,0x02,0xfd,0x75,0xb5,0xf0,0xd6,0xd6,0x20,0x1c,0x0e,0xe9,0xe2,0x9d,0x4e,
+0x17,0x7e,0x7a,0xcf,0xcf,0xb0,0x69,0xd3,0x66,0x0c,0x1b,0x36,0x54,0x17,0xcf,
+0xf3,0x5c,0x49,0x7e,0x7e,0xde,0x96,0xb2,0x19,0xd3,0xd7,0x0d,0x1c,0x58,0xac,
+0x1f,0x97,0x28,0x20,0x68,0xb5,0x8f,0xee,0x74,0xda,0x77,0x39,0x22,0x23,0x15,
+0x1a,0x0a,0x85,0xe0,0xad,0xf5,0xc0,0x5f,0xe7,0x83,0x4c,0x65,0x5d,0x7c,0x51,
+0xaf,0xde,0x58,0xb1,0x7c,0x35,0x16,0x2e,0x5c,0x88,0x9c,0x1c,0xbd,0xf9,0x13,
+0x45,0x71,0x66,0xff,0x01,0xfd,0x7e,0x3f,0x75,0xda,0x94,0x07,0xba,0x76,0xed,
+0xea,0x30,0xa8,0x46,0x00,0x50,0x98,0xb5,0x8f,0xe6,0xc8,0xd8,0x06,0x2a,0xea,
+0xb4,0x19,0x1e,0x6f,0x35,0x1a,0x1a,0xf5,0x93,0x10,0x1c,0xc7,0x61,0xec,0x98,
+0xf1,0x78,0x66,0xfb,0x0e,0xcc,0xbb,0xeb,0x2e,0x24,0x6a,0x44,0x42,0x88,0x45,
+0x92,0x6c,0x77,0x5e,0x35,0x66,0xf4,0xeb,0x13,0x27,0x8e,0xff,0x17,0x13,0x95,
+0x19,0xb3,0x8f,0x3d,0xb2,0xf6,0x51,0x8f,0x36,0x75,0x62,0x00,0x40,0x96,0x65,
+0x34,0x06,0xea,0xe1,0xf1,0x56,0xa3,0xa5,0x45,0xbf,0x88,0xcd,0x62,0xb1,0xe2,
+0xe6,0x9b,0xbe,0x83,0x5d,0xbb,0xca,0x51,0x56,0x56,0xa6,0x6f,0x00,0xc7,0xe5,
+0xb9,0x73,0xdc,0x8b,0x66,0xcc,0x2c,0x7d,0x6e,0xd4,0xa8,0x11,0x57,0x9a,0x54,
+0xe5,0x82,0xa2,0x56,0xf3,0x08,0x21,0x6d,0x6e,0xf7,0xa5,0x82,0x76,0x7b,0x11,
+0xe1,0x48,0x18,0xb5,0x75,0x5e,0x78,0x6b,0x3d,0x88,0x44,0xc2,0xba,0xf8,0x2e,
+0x39,0xb9,0xf8,0xaf,0x5f,0xfc,0x12,0xeb,0xd7,0xaf,0x47,0xbf,0x7e,0xfd,0x74,
+0xf1,0x3c,0xcf,0x8f,0x2c,0x28,0x2c,0xd8,0x59,0x5a,0x36,0x6d,0x79,0xdf,0xbe,
+0x7d,0x0a,0x0c,0xaa,0x21,0x50,0x16,0x60,0xf5,0xcb,0xda,0x47,0x05,0xed,0xfe,
+0x4d,0x0e,0x85,0x82,0xf0,0xf8,0x6a,0x50,0x57,0xef,0x47,0xe2,0x24,0x3d,0x21,
+0x04,0x03,0xfa,0x0f,0xc4,0xba,0xb5,0x1b,0xf0,0x9b,0xdf,0xfc,0x06,0x92,0x24,
+0x25,0xc6,0x13,0x8b,0xc5,0xf2,0xed,0x41,0x83,0x4b,0x5e,0x9b,0x32,0x75,0xf2,
+0x4f,0x9c,0x4e,0xa7,0xd1,0xdc,0xa2,0xda,0x3e,0x1a,0x4d,0x6d,0x5d,0x16,0x38,
+0x2f,0xaa,0x88,0x52,0x8a,0xa6,0xe6,0x00,0x6a,0xbc,0xd5,0x08,0x34,0x35,0xea,
+0xe2,0x79,0x9e,0xc7,0x94,0xab,0xa7,0x61,0xd7,0xce,0x72,0xdc,0x7a,0xeb,0xad,
+0xba,0x78,0x42,0x88,0x64,0xb7,0xdb,0xef,0x9f,0x38,0x69,0xfc,0xfe,0x71,0xe3,
+0xc7,0x5c,0x67,0x52,0x95,0x0d,0x40,0xef,0xa8,0x7d,0x14,0xdb,0xef,0x09,0x2e,
+0x1e,0x9c,0x57,0x5b,0x22,0xcb,0x11,0xd4,0x37,0xd4,0xc1,0xeb,0xab,0x41,0x30,
+0xa8,0xb7,0x8f,0x36,0x9b,0x84,0xef,0xdf,0x7a,0x3b,0x9e,0x79,0x66,0x07,0x26,
+0x8c,0x1f,0xaf,0x6f,0x1c,0xc7,0xf5,0xca,0xcd,0xcd,0x7d,0x6c,0xc6,0xcc,0xd2,
+0xed,0x43,0x87,0x0d,0x19,0x6c,0x52,0x95,0x0b,0x8a,0x5a,0xbd,0xec,0xec,0xe3,
+0x05,0x79,0xd8,0x50,0x38,0x84,0xda,0x3a,0x1f,0x6a,0xfd,0x5e,0x44,0x64,0xfd,
+0xfa,0xa8,0xfc,0xbc,0xee,0x78,0xe8,0xa1,0x87,0xb1,0x6a,0xf5,0x6a,0x14,0x16,
+0xf6,0xd0,0xc5,0x0b,0x82,0x30,0xbe,0xa8,0xa8,0xd7,0x0b,0xd3,0x4b,0xa7,0xfe,
+0xb6,0x47,0x8f,0xc2,0x5c,0x83,0x6a,0xd4,0xf6,0xd1,0xc8,0x75,0x77,0xc9,0xe1,
+0x82,0x7d,0x5b,0x29,0xa5,0x68,0x09,0xb6,0xc0,0xeb,0xab,0x41,0x7d,0x43,0x1d,
+0xd3,0x3e,0x0e,0x1b,0x32,0x1c,0x9b,0x9e,0xda,0x8c,0x05,0x0f,0x3c,0x00,0x51,
+0x14,0x13,0xe3,0x79,0xab,0xd5,0xfa,0xdd,0x11,0x23,0x87,0xbf,0x3e,0xf9,0xea,
+0x89,0xb7,0x99,0xb8,0xe5,0x04,0x00,0x05,0x84,0x90,0xbe,0x97,0x83,0x7d,0xbc,
+0xe0,0xea,0x46,0x96,0x65,0x04,0x9a,0x1a,0xe1,0xf1,0x55,0xa3,0xa9,0x39,0xa0,
+0x8b,0x17,0x04,0x01,0xd7,0x5e,0x73,0x1d,0xca,0x77,0xed,0xc6,0x8d,0x37,0xdd,
+0xa8,0x8b,0x27,0x84,0xb8,0x9d,0x4e,0xe7,0xaf,0xa7,0x4d,0x9f,0xf2,0xd2,0x55,
+0x63,0xae,0x9c,0x62,0x52,0x95,0x15,0x8a,0x7d,0xec,0x79,0x29,0xdb,0xc7,0x0e,
+0xb3,0x17,0x91,0x48,0x04,0x75,0xf5,0x7e,0x78,0x7d,0x35,0x08,0x31,0xdc,0x72,
+0x0e,0x87,0x13,0x3f,0xb9,0xeb,0x1e,0x6c,0xd9,0xb2,0x15,0x23,0x47,0x8e,0xd0,
+0xc5,0x73,0x1c,0x57,0x9c,0x97,0xd7,0x6d,0x53,0xd9,0x8c,0xe9,0x1b,0x4a,0x4a,
+0x06,0xf6,0x35,0xa9,0xca,0x89,0x4b,0xd8,0x3e,0x76,0xf8,0x03,0x85,0xc2,0x21,
+0xf8,0x6a,0x3d,0xf0,0xd7,0xd5,0x42,0x96,0xf5,0x6e,0xb9,0x9e,0x3d,0x7a,0x61,
+0xe9,0x92,0x15,0x58,0xbc,0x78,0x09,0x72,0x73,0xf5,0x7b,0x70,0x44,0x51,0x2c,
+0xeb,0xd7,0xbf,0xef,0xef,0xa7,0x4d,0x9f,0xf2,0x8b,0x6e,0xdd,0xba,0x39,0x0d,
+0xaa,0x89,0xd9,0xc7,0xfe,0x97,0x9a,0x7d,0xec,0x70,0x02,0x81,0xd6,0x59,0x0e,
+0x8f,0xaf,0x1a,0x8d,0x81,0x7a,0x5d,0x3c,0xc7,0x71,0xb8,0x72,0xf4,0x55,0xd8,
+0xb6,0x6d,0x3b,0xee,0xbe,0xfb,0x6e,0x96,0x5b,0x4e,0xb4,0xd9,0x6c,0x77,0x5c,
+0x79,0xd5,0xe8,0xd7,0x26,0x4e,0x9a,0xf0,0x1d,0x9e,0xe7,0x8d,0x9e,0x8b,0x47,
+0xab,0x7d,0xb4,0xb7,0xff,0x93,0x5c,0x78,0x74,0x0a,0x02,0x63,0x90,0x65,0x19,
+0x0d,0x8d,0x0d,0x51,0xb7,0x5c,0xb3,0x2e,0xde,0x22,0x5a,0x30,0xe7,0x86,0x9b,
+0x50,0x5e,0xfe,0x1c,0xae,0xf9,0x86,0x7e,0xd5,0x06,0xc7,0x91,0x3c,0xb7,0xdb,
+0xb5,0xb0,0xb4,0x6c,0xda,0x9e,0x2b,0xae,0x18,0xa9,0x5f,0x2e,0xd0,0x0a,0x2b,
+0x80,0xa2,0x4b,0xc1,0x3e,0x76,0x2a,0x02,0x63,0x50,0xdc,0x72,0x3e,0xf8,0x6a,
+0x3d,0x08,0x33,0xdc,0x72,0x39,0xee,0x1c,0xfc,0xe7,0x82,0xff,0xc2,0x86,0x0d,
+0x1b,0x51,0x5c,0x5c,0xac,0x8b,0xe7,0x79,0x7e,0x78,0x41,0x61,0xc1,0xb3,0xa5,
+0x65,0xd3,0x57,0xf6,0xeb,0xd7,0x57,0x3f,0x2e,0x69,0x45,0xcc,0x3e,0xe6,0x5f,
+0xac,0xf6,0xb1,0x53,0x37,0x3a,0x18,0x0a,0xc2,0xeb,0xf3,0x30,0xdd,0x72,0x00,
+0xd0,0xbf,0xdf,0x00,0x3c,0xbe,0x66,0x2d,0x1e,0xfc,0xed,0x83,0x70,0x38,0xf4,
+0x1a,0xd1,0x62,0x11,0x67,0x97,0x0c,0x1a,0xb8,0x7f,0xca,0xd4,0xab,0xef,0x75,
+0xb9,0x5d,0x46,0x53,0x52,0xb1,0xed,0xe5,0x17,0xa5,0x7d,0xec,0xd4,0x04,0x02,
+0x00,0xa5,0x32,0x9a,0x9a,0x03,0xf0,0x18,0xb8,0xe5,0x38,0x8e,0xc7,0xe4,0x89,
+0x53,0xf0,0xec,0xb3,0xe5,0xb8,0xfd,0xf6,0xdb,0x75,0xf1,0x8a,0x5b,0x4e,0xfa,
+0xe9,0x84,0x09,0xe3,0xf6,0x8f,0x9f,0x30,0xf6,0x7a,0x93,0xaa,0x2e,0x4a,0xfb,
+0x48,0x04,0x41,0xd0,0xec,0x4e,0x9a,0x31,0xb3,0xf4,0x58,0xec,0xda,0x66,0xb3,
+0x61,0xdf,0xde,0x97,0xe2,0x71,0xb2,0x2c,0xa3,0xda,0x53,0x79,0x01,0x9b,0xa7,
+0x87,0x28,0x88,0x70,0x38,0x5c,0xb0,0x5a,0xd8,0x7e,0x6e,0x8f,0xb7,0x06,0x6b,
+0x1e,0x5f,0x83,0xf7,0xde,0x7d,0x97,0x19,0x1f,0x09,0x47,0x0e,0x57,0x56,0x56,
+0x2e,0x3c,0x72,0xe4,0xd8,0xe7,0x49,0xaa,0x6a,0x8c,0x44,0x22,0xd5,0x94,0xd2,
+0x60,0x1b,0x9b,0x7c,0x5e,0x41,0x6c,0x36,0x9b,0x86,0xc0,0x69,0xd3,0xa7,0x74,
+0x6a,0x02,0x01,0x80,0x80,0xc0,0x62,0xb1,0xc2,0xe5,0x74,0x83,0xe7,0xf5,0x0e,
+0x19,0x4a,0x29,0x8e,0x9f,0x38,0x8a,0x25,0x4b,0x97,0xe0,0xcc,0xe9,0x33,0xac,
+0x78,0x39,0x14,0x0a,0xed,0xf9,0xea,0xcb,0x7f,0xac,0x3e,0x77,0xae,0xd2,0x63,
+0x52,0x15,0x05,0x50,0xdb,0xd2,0xd2,0xe2,0xa1,0x94,0xb1,0xf4,0xa0,0x13,0x80,
+0xb8,0x5c,0x2e,0x0d,0x81,0x93,0x26,0x4f,0xe8,0xf4,0x04,0xc6,0xc0,0x71,0x1c,
+0x6c,0x56,0x09,0x4e,0x87,0x4b,0x37,0xb4,0x00,0x94,0xce,0xd0,0xc1,0x83,0x6f,
+0x62,0xf5,0xea,0xd5,0x08,0x06,0xf5,0x82,0x44,0x29,0xad,0x6f,0x6a,0x6a,0x5e,
+0xfb,0xf9,0x67,0x47,0xb6,0x07,0x83,0x41,0x7d,0x6f,0xa9,0x15,0x11,0x00,0x9e,
+0xfa,0xfa,0xfa,0xda,0xf6,0x6b,0x7d,0xfb,0x80,0xe4,0xe6,0xe6,0x6a,0x08,0x1c,
+0x37,0x7e,0xcc,0x45,0x43,0x60,0x0c,0x3c,0xcf,0xc3,0x21,0xb9,0x74,0xf3,0x8b,
+0x31,0x04,0x02,0x8d,0x78,0xe6,0xd9,0x67,0xf0,0xbb,0x3d,0x7b,0x98,0xf1,0xb2,
+0x2c,0xff,0xa3,0xbe,0xbe,0xe1,0x91,0x63,0x47,0x8f,0x1f,0x4c,0x52,0x55,0x90,
+0x52,0x5a,0x55,0x5b,0x5b,0xab,0xf7,0x01,0x76,0x10,0x48,0x7e,0x7e,0xbe,0x86,
+0xc0,0x2b,0xaf,0xba,0xe2,0xa2,0x23,0x30,0x06,0x51,0x10,0xe1,0x72,0xba,0x21,
+0x8a,0xec,0xed,0x19,0xe7,0x2a,0xcf,0x62,0xe5,0xaa,0x95,0xf8,0xe8,0xc3,0x0f,
+0x99,0xf1,0x91,0x48,0xe4,0xcf,0x35,0x35,0x9e,0x47,0xbe,0x3e,0x73,0xf6,0x2b,
+0x56,0xbc,0xaa,0x27,0xdc,0x48,0x29,0xad,0xae,0xa9,0xa9,0xe9,0x70,0xfb,0x48,
+0x7a,0xf6,0xec,0xa9,0x21,0x70,0xc4,0xc8,0x61,0x17,0x2d,0x81,0x80,0x32,0xab,
+0x61,0xb5,0xd8,0xe0,0x72,0xba,0xc1,0x71,0xfa,0x4e,0x36,0xa5,0x14,0x1f,0x7f,
+0xf2,0x11,0x96,0x2e,0x5d,0x82,0x9a,0x9a,0x1a,0x56,0x7c,0x38,0x1c,0x0e,0x3f,
+0x73,0xe6,0xf4,0xd7,0x8f,0xd7,0xd7,0x37,0xe8,0xdd,0x42,0xaa,0xa4,0x00,0xfc,
+0xa2,0x28,0x7a,0x2a,0x2a,0x2a,0x3a,0xec,0x20,0x24,0xd2,0xa7,0x4f,0x1f,0x0d,
+0x81,0x43,0x86,0x0e,0xca,0x80,0x40,0x02,0xa2,0xfc,0xd7,0x69,0xc0,0x11,0x0e,
+0x36,0x9b,0x1d,0x4e,0x07,0xdb,0x3d,0x1a,0x0a,0x05,0xf1,0xda,0xeb,0xaf,0x62,
+0xdd,0xba,0x75,0x88,0x44,0xf4,0xef,0x9f,0x52,0xea,0x6d,0x69,0x69,0x59,0x5d,
+0xf1,0x8f,0x53,0xcf,0xc9,0xac,0xb5,0x93,0xad,0x88,0x50,0x4a,0x3d,0xa7,0x4f,
+0x9f,0xf6,0x77,0xc4,0x41,0x0f,0xa4,0xb8,0xb8,0x58,0x43,0x60,0xf1,0xc0,0xfe,
+0xa6,0x04,0xd6,0x78,0xab,0xda,0xa3,0xda,0x76,0x28,0x23,0x06,0xf3,0x77,0x26,
+0xf0,0x02,0x1c,0x76,0x27,0xac,0x56,0xf6,0x38,0xbe,0xbe,0xbe,0x0e,0x9b,0x36,
+0x3f,0x89,0xfd,0xfb,0x5f,0x65,0xc6,0xcb,0xb2,0x7c,0x24,0x10,0x68,0x5a,0x78,
+0xee,0x6c,0xe5,0xa1,0x24,0x0d,0x09,0x12,0x42,0xaa,0x4f,0x9e,0x3c,0xa9,0x1f,
+0xac,0x9e,0x47,0x90,0xc1,0x83,0x07,0x6b,0x08,0xec,0xdb,0xaf,0x77,0x9a,0x04,
+0x12,0xd5,0x5f,0x5d,0x70,0xc7,0x42,0xc5,0xad,0x28,0x8a,0x70,0x3a,0xdc,0xba,
+0xfd,0x1b,0x31,0x9c,0xfa,0x67,0x05,0x96,0x2f,0x5f,0x8a,0x63,0xc7,0x8e,0x33,
+0xe3,0x23,0x91,0xc8,0xab,0x75,0xfe,0xfa,0x25,0x7e,0x7f,0xdd,0xd7,0x49,0x6a,
+0x6d,0x94,0x65,0xb9,0xfa,0xc4,0x89,0x13,0x17,0xc4,0x3e,0x92,0x11,0x23,0x46,
+0x68,0x08,0xec,0xd9,0xab,0xb0,0x95,0x40,0xc9,0x86,0x7d,0x2f,0x68,0x09,0xf4,
+0xf8,0xaa,0x33,0xad,0x2a,0xa3,0xd4,0xe9,0xeb,0x24,0xe3,0x1c,0x84,0x10,0x58,
+0x2c,0x36,0xb8,0x0c,0x86,0x1d,0xb2,0x2c,0xe3,0xd0,0x07,0x7f,0xc5,0xb2,0xa5,
+0xcb,0x50,0x5f,0x5f,0xa7,0x2f,0x99,0xd2,0xe6,0x48,0x24,0xb2,0xd9,0xeb,0xad,
+0x7d,0x22,0x14,0x0c,0xe9,0x37,0x89,0x20,0xde,0xd1,0xa1,0x94,0x52,0x3f,0xa5,
+0xd4,0x73,0xe4,0xc8,0x91,0xf3,0x6a,0x1f,0xc9,0xe8,0xd1,0xa3,0x35,0x04,0x76,
+0x2f,0xc8,0x4b,0x83,0xc0,0x84,0x69,0x1d,0x66,0x0d,0xed,0xd2,0xce,0xf4,0xc1,
+0xe0,0x31,0x16,0xc4,0x73,0x8a,0x7d,0xb4,0x4b,0x6c,0x8f,0x59,0x4b,0xb0,0x05,
+0xfb,0xf6,0xbd,0x80,0x4d,0x9b,0x36,0xb1,0x8b,0xa6,0xf4,0x5c,0x38,0x14,0x5e,
+0xee,0xf5,0xd6,0xbe,0xc4,0x4c,0xd0,0x8a,0x08,0x21,0xc4,0xcb,0xf3,0x7c,0xed,
+0xe1,0xc3,0x87,0xcf,0x8b,0x7d,0xe4,0x04,0x41,0x80,0xfa,0x63,0x0a,0xa2,0x74,
+0x57,0x08,0x08,0x08,0x21,0x20,0x04,0x9a,0x0f,0x74,0x1f,0x66,0xa0,0xee,0x93,
+0xee,0xbf,0x54,0xca,0x54,0x1a,0xc5,0x08,0x22,0x80,0x4c,0x65,0x04,0x9a,0x1a,
+0x50,0xeb,0xf7,0x31,0x07,0xf8,0x56,0x8b,0x15,0xb7,0xfc,0xeb,0x5c,0xec,0xda,
+0x55,0xce,0x3c,0xe4,0x81,0x10,0x52,0x28,0x5a,0xc4,0xe5,0xdd,0x0b,0xf2,0x76,
+0x75,0xe9,0xe2,0x1e,0x91,0xf8,0x0e,0x55,0x1f,0x9e,0xe7,0xf9,0x7c,0x00,0x7d,
+0xc7,0x8c,0x19,0x63,0xb4,0x07,0xa4,0x4d,0x20,0x93,0x26,0x4d,0xd2,0x48,0xa0,
+0xcb,0xed,0x88,0x4b,0xa0,0x24,0xd9,0xb0,0x57,0x2d,0x81,0x54,0x86,0xd7,0x17,
+0xeb,0x7a,0xeb,0x45,0x2b,0xa9,0xb0,0x5d,0x28,0x69,0x34,0xf9,0xae,0xb3,0xa2,
+0x2c,0xa2,0x08,0x87,0xdd,0x65,0xe8,0x96,0xfb,0xe2,0xcb,0x93,0x58,0xb2,0x74,
+0x31,0x4e,0x55,0x9c,0x62,0xc5,0x53,0x4a,0xe9,0xf3,0x2d,0x2d,0xc1,0x95,0xa1,
+0x60,0x58,0x3f,0x2e,0xd1,0x22,0xc0,0x71,0x5c,0xf5,0x3b,0xef,0xbc,0xd3,0x6e,
+0x07,0xe9,0x92,0xa9,0x53,0xa7,0x6a,0x08,0x94,0xec,0x56,0x53,0x02,0x7d,0x3e,
+0x86,0xeb,0xb0,0x8d,0xba,0x33,0x53,0x5e,0xd3,0xd3,0x49,0x26,0x3a,0x15,0xd1,
+0xf1,0xa3,0xd5,0x06,0xbb,0xe4,0x60,0xda,0xc7,0x48,0x24,0x82,0xb7,0xdf,0x7d,
+0x0b,0xab,0x56,0xae,0x44,0x53,0x93,0xde,0xfc,0x51,0x4a,0x1b,0x29,0xa5,0xeb,
+0x5a,0x9a,0x43,0x4f,0x53,0x4a,0xf5,0x8b,0x7c,0x54,0x20,0x84,0xf8,0x79,0x9e,
+0xaf,0x79,0xf3,0xcd,0x37,0xdb,0x6c,0x1f,0xc9,0x8c,0x19,0x33,0x34,0x04,0x0a,
+0x22,0xa7,0x22,0x50,0xc2,0xde,0x17,0x5e,0x8c,0xc7,0xc9,0x54,0x86,0xaf,0x36,
+0x46,0x20,0xfb,0xb5,0xa7,0x4c,0x46,0xbb,0x74,0x5b,0x29,0xf3,0x32,0x8d,0x5c,
+0xba,0x18,0x9e,0xe3,0x61,0xb3,0xda,0x75,0xa7,0x71,0xc4,0xd0,0xd4,0xdc,0x84,
+0xf2,0xf2,0x9d,0xd8,0xb9,0x73,0x27,0xbb,0x04,0x4a,0x2b,0x28,0xc5,0xe2,0x48,
+0x58,0xfe,0xa3,0x69,0x1b,0x14,0xe7,0xb8,0x27,0x3f,0x3f,0xbf,0x76,0xf7,0xee,
+0xdd,0x19,0xdb,0x47,0x72,0xed,0xb5,0xd7,0x0e,0xd2,0x86,0xc8,0x86,0x04,0x52,
+0x2a,0xc3,0x5b,0xeb,0x35,0x7e,0xd5,0x44,0x77,0x61,0x5e,0x79,0x1a,0x0d,0x4d,
+0x86,0xb4,0xa5,0x31,0x89,0x9a,0x15,0x05,0x11,0x92,0xcd,0xae,0x5b,0x9f,0x1a,
+0x43,0x75,0x4d,0x15,0x56,0x3f,0xba,0x0a,0x87,0x0f,0x1d,0x66,0x97,0x41,0xf1,
+0x36,0x80,0x45,0xa0,0xe4,0x64,0x92,0xc6,0x84,0x28,0xa5,0xd5,0x07,0x0e,0x1c,
+0xc8,0xe8,0xa0,0x40,0x32,0x7b,0xf6,0x6c,0x0d,0x81,0xa1,0x70,0x8b,0x29,0x81,
+0xbe,0x5a,0x2f,0xcc,0xdc,0x2e,0x19,0x2b,0xce,0x76,0xd1,0xa3,0xa9,0xd3,0x68,
+0x26,0x85,0xf1,0x48,0x42,0x60,0x11,0x2d,0xb0,0x4b,0x0e,0x43,0xb7,0xdc,0xe7,
+0x47,0x3f,0xc3,0xe2,0x45,0x8b,0x50,0x55,0xc5,0x74,0x70,0x44,0x00,0xec,0xe0,
+0x08,0xbf,0x86,0x10,0x4e,0x3f,0x2e,0xd1,0x22,0x40,0x29,0xad,0xde,0xbf,0x7f,
+0x7f,0x5a,0xf6,0x91,0xcc,0x99,0x33,0x47,0x43,0x60,0x53,0x73,0xa3,0x39,0x81,
+0x7e,0x9f,0x92,0xd1,0xb8,0xc8,0x94,0xc9,0x68,0xef,0x3e,0x4d,0xca,0xf4,0x51,
+0xf3,0xd4,0x89,0x31,0x1c,0xe1,0x60,0xb5,0x5a,0x20,0xd9,0xd8,0x1d,0xc9,0x70,
+0x38,0x8c,0x37,0xfe,0x78,0x00,0x8f,0x3d,0xf6,0x18,0xc2,0x61,0xe6,0xac,0x54,
+0x2d,0x21,0x64,0xb5,0x45,0xb4,0xed,0x26,0x84,0x24,0xb3,0x7b,0x7e,0x9e,0xe7,
+0x6b,0x9e,0x7f,0xfe,0xf9,0x94,0xec,0x23,0xb9,0xf9,0xe6,0x9b,0x35,0x04,0xd6,
+0x37,0xf8,0x4d,0x08,0xa4,0xa8,0xf5,0x7b,0x63,0x59,0x0d,0x19,0x30,0x27,0xa6,
+0x1d,0xd8,0x4d,0x8f,0xa9,0xf4,0x62,0x4c,0xc8,0xe5,0x78,0x1e,0x92,0x55,0x82,
+0xc5,0x60,0x35,0x40,0x63,0x63,0x03,0xb6,0x3c,0xbd,0x05,0x2f,0xbd,0xf8,0x22,
+0x33,0x1e,0xc0,0x71,0x9e,0x17,0x1e,0x96,0x6c,0x76,0xb3,0xb3,0x57,0x41,0x29,
+0x95,0xa3,0xe3,0x47,0x5f,0x32,0xfb,0xc8,0x89,0xa2,0x08,0xf5,0x27,0x29,0xe2,
+0x03,0x3f,0xe3,0x11,0x1d,0x73,0xf0,0xa5,0xca,0x67,0x18,0xc5,0x4e,0xc6,0x1c,
+0x5e,0x9a,0x7d,0x4c,0x13,0xea,0xc6,0x9e,0xac,0xa1,0x2b,0x3b,0x9f,0x1c,0x89,
+0xa0,0x31,0xd0,0x80,0xfa,0x86,0x3a,0xe6,0x6a,0x39,0x87,0xc3,0x89,0x7b,0xef,
+0xfe,0x29,0xb6,0x6c,0xde,0x8a,0x61,0xc3,0x87,0xb1,0xde,0xde,0xa0,0x48,0x24,
+0xbc,0xad,0x31,0x50,0xbf,0x26,0x1c,0x09,0x15,0x25,0xbe,0xfb,0xd8,0xc7,0x62,
+0xb1,0x70,0xa2,0x28,0xe6,0x71,0x1c,0xd7,0x6f,0xee,0xdc,0xb9,0x46,0x8b,0x95,
+0x15,0x3a,0x6e,0xbd,0xf5,0x56,0x8d,0x04,0x56,0x55,0x9f,0x33,0x95,0x40,0x7f,
+0x9d,0x2f,0x96,0x55,0x55,0x0a,0xa3,0x60,0x76,0x75,0x66,0x6d,0x39,0xcf,0xd0,
+0x7f,0x91,0x75,0x21,0x26,0xf6,0x54,0x7d,0x47,0xa9,0x0c,0x59,0x96,0x21,0x8a,
+0x56,0xb8,0x9d,0x6e,0x43,0xb7,0xdc,0x87,0x1f,0xfd,0x1d,0x8b,0x17,0x2f,0x82,
+0xdf,0xef,0x67,0x35,0x28,0xc8,0x71,0xdc,0x66,0xb7,0x2b,0x67,0x83,0x28,0x5a,
+0x98,0x6e,0xb9,0x18,0x08,0x21,0x4d,0xb2,0x2c,0x57,0xed,0xd8,0xb1,0x43,0x67,
+0x1f,0xc9,0x0f,0x7e,0xf0,0x03,0x0d,0x81,0x5f,0x9f,0x3d,0x6d,0x4e,0x60,0xc2,
+0xaa,0x02,0x62,0x72,0x97,0x2c,0xaa,0x6d,0xaa,0xd6,0x5c,0x8f,0x32,0x63,0xcd,
+0xf5,0xa6,0xfe,0x8e,0x52,0x44,0xe4,0x08,0x22,0x91,0xe8,0x47,0x96,0x21,0x47,
+0xc2,0xa0,0xd1,0x8e,0x0e,0x05,0x20,0x08,0x3c,0xba,0x76,0xc9,0x83,0x5d,0x62,
+0xdb,0xc7,0x50,0x28,0x88,0x97,0x7f,0xff,0x32,0x36,0x6e,0xdc,0xc0,0x5c,0x1a,
+0x09,0xa0,0x4a,0x14,0xc4,0xe5,0xdd,0xba,0xe5,0xbf,0x48,0x08,0x49,0x66,0x1c,
+0xfc,0x84,0x10,0xcf,0x96,0x2d,0x5b,0xe2,0xe2,0x4f,0xee,0xbc,0xf3,0x4e,0x0d,
+0x81,0x15,0xa7,0xbe,0x32,0x25,0xb0,0x2e,0x4e,0x60,0x72,0x46,0x88,0x51,0x44,
+0x87,0x82,0xea,0xaf,0xa8,0xb2,0x19,0x35,0x22,0x47,0x20,0x47,0x22,0x08,0xcb,
+0x32,0x64,0x39,0x02,0x4a,0xe5,0x78,0x22,0x4d,0x2e,0x4d,0x98,0xf2,0xd7,0x66,
+0x91,0x90,0x9b,0xdb,0x0d,0x16,0x83,0xd5,0x00,0x75,0x75,0x7e,0x6c,0x78,0x62,
+0x3d,0xde,0xf8,0xc3,0x1b,0xcc,0x78,0x42,0xc8,0x47,0x92,0x64,0x7f,0x38,0xaf,
+0x5b,0xfe,0xc7,0xcc,0x56,0xb7,0x92,0x2f,0x13,0x42,0xbc,0x45,0x45,0x45,0xbe,
+0x07,0x1f,0x7c,0x90,0xa6,0xe7,0x0b,0x55,0xaa,0x42,0xa2,0x01,0x6c,0xb5,0x5b,
+0x46,0x3e,0x4b,0x7d,0x76,0xb6,0x0d,0x24,0x6d,0xfc,0x18,0xd9,0xc2,0xd6,0xea,
+0x65,0x99,0x22,0x1c,0x0e,0x23,0x18,0x0c,0xa2,0xb9,0xb9,0x09,0x8d,0x81,0x46,
+0x34,0x34,0xd6,0x23,0xd0,0x14,0x40,0x4b,0x4b,0x33,0x42,0xe1,0x10,0xe4,0xe8,
+0x26,0x54,0x42,0xb8,0xd4,0xea,0x05,0x41,0x4b,0xb0,0x19,0x67,0x2b,0xcf,0xc0,
+0xeb,0xab,0x61,0x6e,0x62,0x75,0x47,0x57,0x93,0x6f,0xdc,0xf8,0x04,0xfa,0x0f,
+0xe8,0xcf,0x22,0xe8,0x8a,0x40,0xa0,0x71,0xf7,0xe9,0x33,0xa7,0x96,0x34,0x06,
+0x1a,0xf2,0x13,0x79,0x51,0xd9,0x48,0x4e,0x10,0x84,0xbc,0xca,0xca,0xca,0x02,
+0x00,0x20,0xf7,0xdd,0x77,0x9f,0x46,0x02,0x8f,0x1e,0xfb,0xdc,0x5c,0x02,0x1b,
+0xfc,0xc9,0x25,0x8b,0x24,0xc6,0x5e,0x58,0x09,0x94,0x65,0x59,0xb1,0x53,0x51,
+0x5b,0x25,0xcb,0x14,0x54,0x96,0x55,0x87,0x12,0xa9,0x65,0x47,0x7f,0xa1,0xbd,
+0x4d,0x0c,0x4b,0xb8,0x57,0xa9,0xd3,0xd8,0x3d,0x47,0x38,0xe4,0xb8,0x73,0x0d,
+0x57,0xcb,0xc9,0xb2,0x8c,0xbf,0xbc,0xff,0x1e,0x96,0x2e,0x5b,0x82,0xa6,0x00,
+0xd3,0xfc,0x05,0x44,0x51,0xdc,0xd0,0xab,0x67,0xef,0xcd,0x16,0x8b,0xc5,0xd0,
+0x2d,0x47,0x08,0xa9,0x11,0x52,0x93,0x3a,0x55,0x26,0x03,0xd5,0x99,0x11,0x59,
+0xf1,0x7c,0xa9,0xe7,0xa1,0x94,0x82,0x52,0x0a,0x99,0xca,0xa0,0x32,0x8d,0x13,
+0x45,0x65,0xaa,0x3b,0x35,0x8a,0x26,0xe8,0xbf,0xd6,0x97,0x49,0xa0,0xd1,0x83,
+0xf1,0xea,0x8d,0xc2,0x91,0x62,0x18,0x05,0x28,0x01,0xa5,0x14,0x3e,0xbf,0x17,
+0x0d,0x8d,0x75,0xc8,0xcd,0xe9,0x06,0x9b,0x4d,0xbb,0x5a,0x8e,0xe3,0x38,0x4c,
+0x9e,0x74,0x35,0xca,0x77,0x3e,0x87,0x3d,0xbf,0xdb,0x8d,0x6d,0xdb,0xb6,0x25,
+0x3e,0xa6,0x3d,0x14,0x0a,0xfd,0xfc,0xd4,0x3f,0x2b,0x86,0x0f,0x1d,0x32,0xec,
+0x3e,0x93,0xd7,0x21,0x09,0x29,0x0d,0x1d,0x12,0x91,0xce,0x8b,0x27,0x06,0xa4,
+0xeb,0x40,0x41,0x69,0x2b,0x41,0x14,0xb4,0xf5,0xda,0x80,0x20,0x5d,0x55,0x89,
+0xdb,0xce,0xa0,0xbc,0x4c,0x63,0x67,0x7b,0x1b,0xa7,0xe8,0x12,0x09,0x8d,0xde,
+0xc7,0x82,0xc3,0xe1,0x30,0xaa,0x3d,0x95,0x70,0x38,0x5c,0xe8,0xda,0xa5,0x9b,
+0x2e,0xbb,0xd5,0x6a,0xc5,0xbf,0x7f,0xef,0xfb,0x28,0x2d,0x2d,0xc3,0x9d,0xf3,
+0x7e,0x8c,0x48,0x58,0xab,0x7a,0x65,0x39,0x52,0x1a,0x0e,0x87,0x2d,0x36,0x9b,
+0x8d,0x39,0xbb,0x4f,0x29,0xe5,0xd2,0x97,0x40,0xa2,0xbc,0x14,0x4a,0x10,0x57,
+0x27,0xb1,0x97,0xaf,0x7d,0x27,0x54,0x33,0x26,0x8e,0x11,0x02,0x0d,0x41,0xd1,
+0x32,0x52,0x14,0xc0,0xcc,0x0e,0x30,0x34,0x21,0x8a,0x25,0x51,0xba,0x70,0x02,
+0x0a,0x0a,0xa2,0x0a,0x33,0xe0,0x2d,0xa1,0x0c,0x0a,0x10,0x02,0x97,0x33,0x07,
+0x2e,0x27,0xfb,0x4c,0x22,0x4a,0x29,0x8e,0x1e,0x3b,0x82,0x47,0x1e,0x59,0xa8,
+0x23,0x8f,0x10,0x80,0xe3,0xb8,0x8f,0xec,0x76,0x7b,0x98,0x35,0xcd,0x15,0x85,
+0x9c,0x36,0x81,0xca,0x06,0xcc,0x56,0x23,0x97,0x28,0x5d,0xac,0x97,0x4c,0x0c,
+0xbd,0x36,0xa4,0x35,0xfd,0xf9,0x30,0x93,0xca,0x3b,0x04,0x35,0x24,0x91,0x15,
+0x9e,0xa2,0x64,0x26,0x91,0x3e,0xc9,0x66,0x87,0xdb,0xd5,0xc5,0xb0,0x63,0xe8,
+0xf1,0xd4,0x60,0xf5,0xa3,0xab,0x70,0xe8,0x90,0xb2,0x56,0x2a,0xf1,0xbd,0x71,
+0x1c,0xff,0x76,0xef,0xa2,0xde,0xbf,0xb4,0x5a,0xad,0x46,0x6a,0x27,0x1c,0x0e,
+0x87,0x2b,0x75,0x2a,0x54,0x5d,0x10,0xf3,0x1b,0x4f,0x48,0x52,0xd2,0xf4,0xf9,
+0x8c,0x96,0x1d,0x32,0x14,0xb1,0xa1,0xba,0x33,0x83,0xc1,0x5c,0x9f,0xae,0x60,
+0xed,0xf4,0x13,0x21,0x06,0x83,0xf9,0x64,0xb6,0x2f,0x51,0x1a,0x55,0xf7,0x82,
+0x20,0x22,0xc7,0xd5,0xc5,0x70,0xf3,0x4d,0x4b,0x4b,0x33,0x76,0x3f,0x57,0x8e,
+0x67,0x9f,0x7d,0x56,0x69,0x95,0xfe,0xdd,0x55,0xb8,0x5d,0xee,0xc5,0x23,0x46,
+0x8c,0x8a,0x4f,0x47,0x31,0xc6,0x8f,0x32,0x80,0xb3,0x0f,0x3d,0xf4,0x50,0x58,
+0x27,0x81,0xc9,0x08,0x8c,0x91,0xa7,0x8d,0x53,0xba,0xf0,0xba,0x54,0x9a,0xce,
+0x81,0xee,0x56,0x1f,0x6e,0x10,0x9f,0x1c,0xb1,0x74,0xc9,0x24,0x47,0x4b,0x22,
+0x8d,0xb7,0xb4,0xb5,0xe3,0x42,0x13,0x95,0x45,0x02,0x79,0x51,0xcd,0xa8,0x8b,
+0x27,0x84,0x83,0xcb,0xe9,0x82,0x64,0xb3,0x1b,0xf6,0x3c,0xdf,0xfb,0xcb,0xbb,
+0x58,0xb9,0x72,0x05,0x9a,0x9a,0x9a,0x58,0x69,0x1a,0x24,0x49,0x5a,0x3f,0x62,
+0xf8,0xa8,0xa7,0x25,0x49,0x32,0x9b,0x10,0xae,0x13,0x04,0xa1,0xfa,0x81,0x07,
+0x1e,0x88,0x00,0x40,0xda,0x12,0x68,0x14,0xaf,0x57,0x93,0x7a,0x12,0xf5,0x92,
+0x66,0xd2,0x15,0xca,0xd8,0xde,0x21,0xb9,0x5d,0x35,0xb2,0x7d,0x8c,0x74,0x3a,
+0x42,0xd5,0xd1,0xca,0xef,0x0f,0xc3,0x2e,0x39,0xe0,0xb0,0x3b,0x0d,0xa7,0x9c,
+0x2a,0x4e,0xfd,0x03,0x4b,0x97,0x2e,0x41,0x45,0x45,0x85,0xd2,0x4a,0xed,0xb3,
+0xc9,0xa2,0x28,0xbe,0x30,0xa0,0x7f,0xf1,0xca,0x9e,0x3d,0x7b,0x99,0x2d,0xc9,
+0x68,0x21,0x84,0x54,0x2d,0x58,0xb0,0x40,0x33,0xee,0x60,0x48,0x20,0xfb,0x3a,
+0x1e,0xa6,0x21,0xca,0x80,0x24,0xa2,0xba,0x56,0xdd,0x6b,0x92,0x26,0x54,0x90,
+0xd8,0x7f,0x64,0x04,0xa6,0x06,0x1a,0x2b,0xb7,0x55,0xd2,0xcc,0xee,0xb4,0xf9,
+0x52,0x29,0xbb,0xf5,0xd6,0x22,0x5a,0x4c,0xd7,0x9a,0xd6,0xd5,0xd7,0x61,0xe3,
+0xc6,0xf5,0x38,0x78,0xf0,0xa0,0x52,0xb3,0xde,0xce,0xfd,0xad,0xa0,0xa0,0xe0,
+0xe1,0x11,0xc3,0x47,0x7e,0x66,0x52,0xab,0x4c,0x29,0xf5,0xf8,0xfd,0xfe,0xda,
+0x07,0x1f,0x7c,0x50,0xd7,0x70,0xfd,0x30,0x22,0x39,0x83,0xd0,0xaa,0x4c,0x73,
+0xd2,0x5a,0xef,0x59,0x64,0x11,0x03,0xae,0x12,0xea,0x4d,0x95,0x48,0xa3,0x31,
+0x9d,0x61,0x1a,0x93,0xb4,0x0c,0xbb,0x17,0x93,0x46,0x9e,0xe3,0x61,0xb7,0x3b,
+0x0d,0xed,0x5c,0x28,0x14,0xc2,0x2b,0xfb,0x5f,0xc6,0x53,0x4f,0x3d,0xa9,0x94,
+0x9e,0xf8,0x38,0x84,0x9c,0x73,0xbb,0x73,0x96,0x4d,0x9a,0x78,0xf5,0xcb,0x49,
+0x9e,0xa8,0x5e,0x14,0xc5,0xea,0x79,0xf3,0xe6,0x19,0x6e,0x7d,0xd3,0x4b,0xa0,
+0xe6,0xf5,0x9a,0xa9,0x50,0x06,0x71,0x06,0xa4,0x19,0x13,0xa6,0x65,0xcf,0x48,
+0x1e,0x8d,0x82,0x34,0x48,0x95,0x18,0x56,0x78,0x42,0x0f,0x52,0x7b,0xdf,0xca,
+0x1c,0x21,0x04,0x92,0x4d,0x82,0xcd,0x2a,0x31,0xcd,0x0b,0xa5,0x14,0x1f,0x7d,
+0xfc,0x21,0x96,0x2d,0x5f,0x8a,0xba,0xba,0x3a,0x1d,0x73,0x04,0x68,0x96,0x24,
+0xfb,0xa6,0xab,0xae,0x1c,0xfb,0x64,0x6e,0x6e,0xae,0xd9,0x0c,0x44,0x50,0x96,
+0xe5,0xaa,0xf9,0xf3,0xe7,0x27,0xdd,0xc6,0x96,0x76,0x27,0x26,0x55,0xe2,0x12,
+0x49,0x4b,0x24,0x4c,0xa7,0x50,0x59,0x61,0xfa,0xaa,0x33,0x80,0xb6,0x93,0xa2,
+0x2b,0x23,0x99,0xea,0x8c,0xc6,0x5b,0x2c,0x56,0x48,0x36,0x3b,0xd3,0xce,0x01,
+0xc0,0xb9,0x73,0x67,0xb1,0x72,0xd5,0x0a,0x1c,0x3d,0x7a,0x34,0x4e,0xb6,0x1a,
+0xa2,0x28,0xee,0x2f,0x19,0x38,0x68,0xe9,0xa0,0x92,0xc1,0x66,0x4b,0xf3,0xe5,
+0xe8,0x46,0x19,0xa6,0xba,0x64,0x21,0x83,0x4e,0x0c,0x60,0x48,0x16,0x31,0x92,
+0xbe,0x74,0x48,0xcc,0x88,0xa5,0xcc,0x24,0xd4,0x24,0x2c,0x16,0xc5,0xf3,0x02,
+0x24,0xc9,0x0e,0x81,0x67,0xdb,0xb9,0xa6,0xa6,0x00,0xb6,0x6d,0x7f,0x1a,0xaf,
+0xbc,0xf2,0x8a,0xd2,0x0c,0x9d,0x9d,0xe3,0x8e,0x14,0x16,0xf6,0x58,0x38,0x79,
+0xd2,0xd5,0xa6,0x9b,0x63,0x28,0xa5,0xf5,0x00,0xaa,0x6f,0xbb,0xed,0x36,0xb3,
+0x9d,0xc2,0x3a,0xb4,0x93,0x04,0xaa,0xa8,0x30,0x23,0x8e,0x49,0xa2,0x99,0x9a,
+0x66,0x41,0x9f,0x83,0x31,0x41,0xa4,0xcb,0x93,0x6c,0x88,0x91,0x38,0x9e,0x23,
+0x84,0xc0,0x66,0x95,0x0c,0xa7,0x87,0x22,0x91,0x08,0xfe,0x74,0xf0,0x4d,0xac,
+0x5b,0xb7,0x16,0x91,0x48,0x84,0x35,0x9e,0xf3,0xe6,0xb8,0x73,0x56,0xcd,0x98,
+0x71,0xcd,0x1e,0x51,0x14,0xcd,0x7c,0x80,0x41,0x42,0x48,0xd5,0xdc,0xb9,0x73,
+0x33,0xda,0xf5,0x9b,0xc1,0x38,0x10,0x06,0x52,0x67,0x42,0x56,0x02,0x51,0xc9,
+0x06,0xfe,0x66,0x9e,0x9b,0xd6,0xbf,0xda,0x50,0x9a,0x70,0xa5,0x01,0x43,0xd2,
+0x8c,0xc6,0x73,0x80,0xa2,0x2e,0x2d,0xa2,0xd5,0xd0,0xce,0x9d,0x38,0x79,0x1c,
+0xcb,0x96,0x2d,0x8d,0x6f,0x10,0x4d,0x48,0x17,0x96,0x24,0xfb,0xf6,0x09,0xe3,
+0x27,0xac,0xed,0xd5,0xab,0x48,0xb7,0x41,0x54,0x3d,0xaf,0x07,0xc0,0xeb,0xf3,
+0xf9,0x7c,0xf3,0xe6,0xcd,0xcb,0xd8,0x29,0xcb,0x50,0xa1,0xec,0x6b,0x75,0x60,
+0x32,0xf2,0x62,0x6a,0xb6,0xb5,0x8c,0xd8,0xb5,0x11,0x89,0xc9,0x1c,0x01,0xaa,
+0x32,0x0c,0x1e,0x24,0x29,0x89,0x26,0x52,0x18,0x1b,0xcf,0x09,0xbc,0x00,0x8b,
+0xc5,0x6a,0x68,0xe7,0x7c,0x3e,0x2f,0x1e,0x5f,0xbb,0x06,0x7f,0xff,0xfb,0xdf,
+0xa2,0xcf,0xa0,0x8d,0x17,0x45,0xf1,0x60,0x49,0xc9,0xe0,0x45,0x63,0xc7,0x8c,
+0xfb,0xca,0xa0,0x99,0x31,0x34,0x10,0x42,0xaa,0xe6,0xcc,0x99,0x93,0x96,0xba,
+0x64,0x21,0x03,0x15,0x1a,0x8f,0xd4,0x4b,0x98,0x91,0xd4,0xa9,0xae,0x8d,0x07,
+0xff,0xa9,0x79,0x73,0xb4,0x57,0x86,0x8d,0x83,0x59,0xc7,0x45,0x23,0x7d,0x14,
+0xe0,0x78,0x0e,0x16,0xd1,0xca,0xdc,0x1b,0x01,0x00,0xc1,0x60,0x10,0xbf,0x7b,
+0x7e,0x0f,0xf6,0xec,0xd9,0xad,0x7b,0x06,0x00,0xe0,0x38,0xee,0xab,0x82,0x82,
+0xc2,0x45,0xdf,0xbc,0xee,0xfa,0x83,0x49,0x1a,0x16,0x24,0x84,0x54,0xcf,0x9e,
+0x3d,0xbb,0xdd,0x36,0x81,0xa6,0x3d,0x0e,0xd4,0xaa,0x50,0x35,0x69,0x6c,0xf2,
+0x92,0x4b,0xa0,0xf1,0x98,0x52,0x7b,0x99,0x9c,0x40,0xad,0x8c,0xb5,0xde,0x25,
+0x4e,0xd9,0x41,0x45,0x9e,0x68,0xb1,0x80,0xe7,0x79,0x43,0xf7,0xd7,0xa1,0xc3,
+0x7f,0xc5,0xa3,0x8f,0xad,0x56,0x7e,0x13,0x43,0x9f,0xa6,0xbe,0x4b,0x4e,0x97,
+0xb5,0xd7,0xcf,0x9a,0xbd,0xdd,0xe9,0x74,0x19,0x4a,0x13,0x21,0x84,0xca,0xb2,
+0xec,0xa1,0x94,0xfa,0x66,0xcd,0x9a,0xd5,0xc6,0x39,0x2c,0x2d,0x32,0x97,0x40,
+0x40,0x27,0x71,0x2a,0x25,0x1a,0x8f,0xd7,0x93,0xd7,0x4a,0x18,0x51,0xe5,0x53,
+0x13,0xa5,0xbb,0x6e,0x6d,0x50,0x6b,0xb1,0xa9,0xc0,0x70,0x30,0x4e,0xc1,0xf3,
+0x22,0x04,0x5e,0x30,0xb4,0x73,0xa7,0xcf,0xfc,0x13,0xcb,0x57,0x2c,0xc3,0x99,
+0x33,0x67,0x12,0xda,0x0f,0x00,0x90,0x25,0x49,0xda,0x33,0x71,0xc2,0xa4,0x55,
+0x43,0x06,0x0f,0xf5,0xea,0x0a,0xd0,0xa2,0x81,0xe7,0xf9,0xea,0xd2,0xd2,0x52,
+0xd3,0x0d,0x2f,0x99,0x22,0xc3,0xd9,0x08,0x40,0xf3,0x66,0xb4,0x9a,0x50,0x15,
+0xcc,0x92,0x3c,0x55,0x9c,0x21,0x79,0xe6,0x63,0xca,0x84,0x6a,0xd8,0xd0,0x91,
+0xa7,0xe8,0x4d,0x8e,0x70,0x10,0x04,0x1e,0x46,0x87,0x13,0x36,0x34,0x36,0xe0,
+0xa9,0xa7,0x9e,0xc0,0x3b,0xef,0xbc,0xa3,0x79,0x86,0x18,0x04,0x51,0x3c,0x34,
+0xa8,0x64,0xd0,0xc2,0x99,0x33,0xae,0x39,0xa2,0xab,0x52,0x3b,0x6b,0x10,0x92,
+0x65,0xb9,0xaa,0xac,0xac,0xec,0xbc,0xee,0x99,0x4f,0xdb,0x13,0xa3,0x07,0x61,
+0xdf,0xb1,0xb8,0x57,0x2b,0x5b,0x9d,0x90,0x26,0x90,0x97,0x30,0x34,0x49,0x24,
+0x51,0xaf,0x50,0x0d,0x3a,0x28,0x40,0x7c,0x78,0xc0,0xf3,0x82,0x61,0x07,0x25,
+0x1c,0x0e,0xe3,0xd5,0xd7,0x5e,0xc5,0xb6,0x6d,0x5b,0x95,0x52,0xf5,0x76,0xee,
+0xeb,0x82,0x82,0x82,0xa5,0xff,0x76,0xcb,0x77,0xf7,0x33,0x0b,0xd0,0x56,0xe9,
+0x0d,0x06,0x83,0xde,0xb2,0xb2,0xb2,0x76,0x55,0x97,0x2c,0xb4,0x4d,0x85,0x6a,
+0x73,0x9a,0xdc,0x69,0x03,0xf5,0x12,0xc5,0x90,0x3c,0x24,0x92,0xa7,0x26,0x2e,
+0xe1,0x3a,0xfe,0xbf,0xb6,0xe3,0x12,0x23,0x8f,0xe3,0x09,0x62,0x2b,0xcc,0x12,
+0x41,0x29,0xc5,0xa7,0x9f,0x7d,0x8a,0xd5,0xab,0x57,0xa0,0xa1,0xa1,0x81,0x61,
+0xe6,0x48,0x53,0x4e,0x4e,0xce,0x93,0xdf,0xfe,0xd6,0x0d,0x9b,0x0a,0x0a,0x0a,
+0xf5,0xa7,0xd0,0x6a,0xd1,0xc8,0x71,0x5c,0xd5,0xd8,0xb1,0x63,0xcf,0x8b,0xba,
+0x64,0x21,0xfd,0x61,0x84,0x21,0x52,0x9d,0xa3,0x49,0x01,0x06,0x4e,0x74,0x76,
+0x27,0x29,0x21,0x6d,0x9c,0x3c,0x0a,0x0e,0x1c,0x08,0x47,0x0c,0xbf,0x88,0x55,
+0xd5,0x55,0x78,0xf4,0xd1,0x55,0xf8,0xe2,0x8b,0x93,0xcc,0xb2,0x6c,0x36,0xe9,
+0xe5,0x49,0x13,0x27,0x2d,0x1b,0x3f,0x7e,0xe2,0xb9,0x24,0x2d,0x0e,0x11,0x42,
+0xaa,0x47,0x8f,0x1e,0x9d,0xd1,0x16,0xb1,0xb6,0x20,0x7d,0x09,0xa4,0x14,0x94,
+0x10,0x90,0x38,0x61,0xda,0x49,0xb3,0x78,0x68,0xe2,0x40,0x59,0x15,0x69,0xd8,
+0x2b,0x8c,0x27,0x60,0x64,0x4e,0xe9,0xfb,0x41,0x14,0x91,0xa3,0xca,0x8e,0x22,
+0x23,0xe2,0x5a,0x5a,0x9a,0xb1,0x63,0xc7,0x76,0x1c,0xf8,0xc3,0x01,0xe6,0x73,
+0x0a,0x82,0xf0,0xd9,0xc0,0x81,0x25,0x0f,0xff,0xcb,0x4d,0xdf,0xf9,0x5b,0x92,
+0x0a,0x29,0x00,0x5f,0x43,0x43,0x83,0x67,0xd2,0xa4,0x49,0xe7,0x5d,0x5d,0xb2,
+0x90,0x7e,0x27,0xc6,0x00,0x89,0x9e,0x7c,0x4d,0x5c,0x74,0xa0,0x4c,0x41,0x41,
+0x34,0xa4,0xb7,0x7e,0x09,0x28,0x88,0xf2,0xee,0x49,0x42,0x76,0xd5,0x17,0x86,
+0x52,0x02,0x12,0x4d,0x44,0x41,0x41,0xa2,0x5c,0x27,0xb6,0x9f,0x70,0xec,0x76,
+0xcb,0xb2,0x8c,0xb7,0xde,0xfa,0x33,0x36,0x3e,0xb9,0x01,0x88,0xb6,0x29,0x21,
+0x6f,0x4d,0x41,0x41,0xc1,0xca,0xdb,0x6f,0xfb,0xd1,0x0b,0x26,0x6b,0x51,0x62,
+0x68,0xa4,0x94,0x56,0x0f,0x1d,0x3a,0xb4,0x43,0xcf,0x4b,0xcb,0xcc,0x06,0xc6,
+0x5e,0xaa,0x5a,0x1a,0x55,0x84,0xc4,0x88,0xa2,0x8c,0x97,0x14,0x13,0x2e,0x65,
+0xa5,0x17,0x01,0x25,0xca,0xff,0x20,0x31,0x12,0x55,0x65,0x2b,0x8d,0xd0,0xd4,
+0x13,0x27,0x4c,0x65,0xf2,0x62,0x6d,0x8d,0x7d,0xf4,0xcd,0xa5,0xf8,0xf2,0xcb,
+0x2f,0xb0,0x72,0xf5,0x4a,0xf8,0x7c,0xde,0x58,0x06,0x75,0x92,0x90,0xdb,0xed,
+0x7e,0x7a,0xce,0x0d,0x37,0xae,0x2f,0x19,0x38,0x28,0x99,0x1a,0x0c,0x53,0x4a,
+0xab,0x4a,0x4a,0x4a,0x2e,0xb8,0xba,0x64,0x21,0xed,0x81,0xbc,0x4e,0xc0,0x54,
+0x63,0xab,0x28,0x6d,0x5a,0x32,0x63,0xd2,0x17,0x27,0x33,0x26,0x49,0x5a,0x12,
+0x11,0x95,0xae,0x56,0x12,0x01,0xa8,0x08,0xd5,0x30,0x47,0x68,0x4c,0x53,0x82,
+0x10,0x02,0x8e,0x33,0x56,0x97,0xb5,0xfe,0x5a,0x6c,0xd8,0xb0,0x0e,0x9f,0x7c,
+0xfa,0x49,0xf4,0x91,0x12,0xec,0x9c,0xd5,0xf6,0xc7,0xf1,0xe3,0x27,0x2c,0xfe,
+0xe6,0x75,0xb3,0x2a,0x92,0xbc,0x2b,0x4a,0x08,0xf1,0x59,0xad,0x56,0x6f,0x41,
+0x41,0x41,0xa7,0x39,0xfc,0xd5,0x54,0x02,0x99,0x30,0x90,0x3e,0x85,0x33,0xad,
+0xba,0x03,0xd1,0x4a,0x62,0x6c,0x9c,0x14,0xe3,0x23,0xa6,0x56,0xe3,0xe4,0x45,
+0x97,0xb2,0xd0,0xe8,0x1f,0x82,0xd8,0xfa,0x53,0x95,0xc0,0xc5,0xee,0x09,0x01,
+0xc7,0xf1,0x86,0xc3,0x82,0x50,0x28,0x84,0xbd,0x7b,0x9f,0xc7,0xbe,0x17,0xf7,
+0x22,0x96,0x4d,0xfd,0x85,0xe4,0x79,0xfe,0x8b,0xe2,0xe2,0x81,0x8f,0xdc,0xf1,
+0xc3,0x1f,0xbf,0x9d,0xc2,0x7b,0x0a,0x70,0x1c,0x57,0xd5,0xa3,0x47,0x8f,0x0e,
+0x3f,0x5e,0x32,0x11,0xe6,0x2a,0x94,0xd1,0x6b,0x50,0xba,0xe6,0x49,0x48,0x84,
+0xca,0x56,0x69,0x48,0x54,0x4a,0xd5,0x12,0xaa,0x26,0x2f,0x26,0x8d,0x6a,0x22,
+0x19,0x8d,0x8e,0x8e,0xe7,0x8c,0xdc,0x5f,0x1f,0x7c,0x70,0x08,0xeb,0x37,0xac,
+0x43,0x28,0x14,0x62,0xd9,0xb9,0xba,0xee,0xf9,0xdd,0xd7,0xcc,0x9f,0x7f,0xcf,
+0x0e,0xb7,0xdb,0x6d,0xb8,0x8d,0x39,0xfa,0x65,0x0b,0x03,0xa8,0x2e,0x28,0x28,
+0x30,0x3b,0x76,0xb2,0x43,0xa1,0xef,0xc4,0xc4,0xff,0x18,0x0d,0x23,0x8c,0x6c,
+0x55,0xb4,0x03,0x98,0x28,0x81,0x9a,0x0e,0x87,0xc2,0x08,0x4b,0x1a,0xe3,0x95,
+0x53,0xcd,0x85,0x06,0xbc,0x20,0x24,0x71,0x7f,0x9d,0xc6,0x63,0x8f,0xad,0x46,
+0x65,0xe5,0xb9,0x68,0xd9,0x9a,0x74,0x11,0x97,0xcb,0xb5,0xfb,0x86,0x1b,0x6e,
+0x7c,0x74,0xdc,0xd8,0xf1,0x3e,0x5d,0x01,0x89,0x0f,0x09,0xd4,0x46,0x22,0x11,
+0x4f,0x7e,0x7e,0x7e,0xa7,0x51,0x97,0x2c,0x98,0xab,0x50,0xe6,0x8b,0x82,0xa9,
+0xad,0x8a,0x49,0xa0,0xda,0x4e,0xa9,0xc5,0x49,0x4d,0x98,0x96,0xc8,0xd6,0x6b,
+0xc4,0xf3,0x28,0x97,0x3c,0xc7,0x43,0x14,0x45,0x43,0x75,0xd9,0xd0,0xd0,0x80,
+0x2d,0x5b,0x37,0xe1,0xf0,0x61,0xf6,0x2a,0x67,0xab,0xd5,0xfa,0xfe,0xd8,0x31,
+0xe3,0x16,0xce,0x9d,0xfb,0xbd,0x63,0xac,0xfc,0x09,0xcf,0x1f,0x20,0x84,0x54,
+0x39,0x9d,0xce,0x4e,0xa7,0x2e,0x59,0x30,0x1f,0x46,0x30,0x07,0x5e,0xd1,0x4e,
+0x48,0xdc,0x3e,0xc5,0xae,0xd9,0xd2,0x08,0x24,0x27,0x52,0xdf,0xa3,0x8c,0x7d,
+0x51,0x38,0x58,0x2d,0x16,0xf0,0x06,0xcb,0x19,0xc2,0xe1,0x30,0x5e,0x7b,0xfd,
+0x55,0xec,0x7e,0xae,0x5c,0xd7,0x76,0x00,0xe0,0x79,0xfe,0x4c,0xbf,0x7e,0xfd,
+0x97,0x3c,0xb0,0xe0,0x17,0xaf,0xa5,0xf0,0x2e,0xc2,0x84,0x90,0x6a,0x9b,0xcd,
+0xd6,0x69,0xd5,0x25,0x0b,0x69,0x0f,0x23,0x28,0xa5,0xda,0x8e,0x46,0x92,0x9e,
+0x63,0x94,0x2e,0x86,0x44,0xaa,0xea,0x54,0xdf,0x46,0x6f,0xac,0x16,0x2b,0x04,
+0x41,0x34,0x76,0x7f,0x7d,0xfa,0x09,0xd6,0x6d,0x58,0xcb,0x5c,0xe5,0x4c,0x08,
+0x69,0xca,0xcb,0xcb,0xdb,0x78,0xf7,0xfc,0x7b,0x36,0x17,0x15,0xf5,0x4e,0xe5,
+0xdc,0x15,0x9f,0x28,0x8a,0x1e,0x28,0xb3,0xe4,0x17,0x15,0x92,0x10,0xc8,0xce,
+0x94,0x49,0xcf,0x51,0x21,0x4f,0x4d,0x64,0x62,0x22,0x05,0x16,0xd1,0x02,0xab,
+0xc5,0x66,0x48,0x5c,0x55,0x55,0x25,0xd6,0x6d,0x58,0x8b,0x53,0xa7,0x2a,0xa0,
+0x74,0x80,0xb4,0x83,0x1a,0xa7,0xd3,0xf9,0xd2,0x0d,0xdf,0x9e,0xb3,0xec,0x1b,
+0xd7,0x5c,0x9b,0xca,0xd1,0xc2,0x4d,0x00,0xaa,0x00,0xb4,0xdb,0xe1,0x73,0x17,
+0x1a,0x7a,0xdd,0xa4,0x72,0x28,0x1b,0xbd,0xc4,0x68,0xb2,0xa8,0x0a,0x6c,0x75,
+0x5f,0x21,0x7a,0x1b,0x27,0x32,0x56,0x9e,0x4a,0xb5,0x6a,0xfa,0x26,0x2a,0x62,
+0x05,0x9e,0x87,0xcd,0x26,0x19,0xce,0x8a,0x07,0x9a,0x02,0x28,0x2f,0x7f,0x16,
+0x6f,0xbd,0xfd,0x16,0xb3,0x6d,0x16,0x8b,0xe5,0xe3,0xd1,0xa3,0xaf,0x5c,0x38,
+0x7f,0xde,0xdd,0xec,0x23,0xe9,0xb5,0x88,0x00,0xa8,0x06,0x90,0xec,0xf4,0xa4,
+0x4e,0x0f,0x1d,0x81,0xc9,0x3b,0x31,0x46,0xbd,0xc8,0x56,0x89,0x6c,0xcd,0x8f,
+0x04,0x62,0xf5,0x1d,0x4d,0x8e,0xe3,0xa2,0x67,0x92,0x19,0xaf,0xfe,0xfa,0xf3,
+0x5b,0x07,0xb1,0x63,0xc7,0xf6,0x68,0x6f,0x56,0xdb,0x26,0x8e,0xe3,0xaa,0x7b,
+0xf7,0xee,0xb3,0xe2,0x97,0xff,0xfd,0xeb,0xbd,0xa2,0x20,0xa6,0xe2,0x8f,0xac,
+0x05,0x50,0x83,0x8b,0x50,0x5d,0xb2,0xc0,0x20,0x90,0x7d,0xad,0x06,0xab,0xe7,
+0xa8,0xe9,0x5d,0x02,0x5a,0x35,0xca,0x90,0x3c,0x50,0x65,0x0f,0x9d,0xcd,0x6a,
+0xac,0x2e,0x4f,0x9c,0x38,0x8e,0x0d,0x1b,0xd7,0x29,0xab,0x9c,0xa1,0xeb,0x54,
+0x05,0xbb,0x76,0xed,0xba,0xf5,0x8e,0x1f,0xdd,0xb9,0x7e,0xf0,0xe0,0x21,0xa9,
+0x2c,0xc9,0x6b,0x06,0x50,0x89,0x8b,0x58,0x5d,0xb2,0x60,0x2a,0x81,0xa9,0xa9,
+0xd0,0xc4,0x21,0x80,0x5a,0xa5,0xb2,0xc7,0x73,0x56,0x8b,0xcd,0xf0,0x00,0x39,
+0x40,0xd9,0xfc,0xb8,0x79,0xcb,0x53,0x38,0x7e,0xfc,0x38,0xb3,0x1d,0x92,0x64,
+0xff,0xc3,0xcc,0x19,0x33,0x17,0xcf,0x99,0x73,0xd3,0x3f,0x93,0x3c,0x1f,0xa0,
+0xa8,0xcb,0x1a,0x00,0xcc,0xd3,0x76,0x2e,0x76,0x64,0x46,0xa0,0x4e,0xc4,0xd4,
+0xf9,0xd9,0x92,0x08,0x28,0x47,0x38,0x3a,0x1d,0x4e,0x08,0x02,0x7b,0x5f,0x7e,
+0x73,0x4b,0x33,0xf6,0xed,0xdb,0x8b,0x37,0xde,0x30,0x9c,0xe6,0x39,0x31,0x74,
+0xe8,0xb0,0x85,0x3f,0xbd,0xf7,0x67,0xef,0xa5,0xf8,0x7c,0x7e,0x28,0xe4,0x75,
+0xd8,0x0f,0x73,0x9c,0x6f,0xa4,0x4f,0xa0,0x7a,0x5c,0x07,0xf6,0x10,0x00,0x09,
+0xf7,0x1c,0xc7,0xc1,0xe9,0x70,0xc1,0x66,0x65,0xff,0xb6,0x51,0x44,0x8e,0xe0,
+0xd0,0xa1,0xf7,0xf1,0xf4,0xb6,0xad,0xca,0x8f,0x70,0x24,0x54,0x4b,0x08,0xf1,
+0xf7,0x2c,0xec,0xf9,0xe8,0x82,0x05,0xbf,0xd8,0xe5,0x74,0x3a,0x53,0x21,0xa3,
+0x19,0x4a,0xef,0x32,0xd9,0x0c,0xfa,0x45,0x0f,0x3d,0x81,0x48,0x4d,0x85,0x46,
+0x13,0x6b,0x98,0x54,0x13,0x1b,0x8b,0x73,0xd8,0x9d,0x70,0xd8,0x9d,0x86,0x65,
+0x55,0x54,0x7c,0x85,0x27,0x9e,0xda,0x08,0x8f,0xc7,0xc3,0xaa,0x33,0x92,0xe3,
+0xce,0xd9,0x79,0xcb,0x2d,0x73,0x1f,0x1b,0x3b,0x66,0x5c,0x2a,0x2a,0xf0,0x92,
+0x56,0x97,0x2c,0x98,0x4b,0x20,0xcb,0x13,0xa3,0x73,0x95,0xb1,0xed,0x9c,0x64,
+0x95,0xa2,0xbf,0xef,0xc7,0xf6,0xa2,0xf8,0xfd,0xb5,0xd8,0xbe,0x63,0x1b,0x3e,
+0x35,0x98,0xe6,0xb1,0x5a,0xad,0xef,0x4e,0x9a,0x38,0xf9,0x91,0xb9,0xff,0xf6,
+0xbd,0x13,0x29,0x3e,0xcb,0x25,0xaf,0x2e,0x59,0x68,0x83,0x0d,0x54,0x67,0x52,
+0x8d,0xe7,0x04,0x01,0x39,0x6e,0xe3,0x4d,0xfe,0xc1,0x60,0x0b,0x5e,0x3b,0xf0,
+0x2a,0x5e,0x79,0xe5,0xf7,0xcc,0x3a,0x78,0x9e,0x3f,0x35,0xa0,0xff,0x80,0x25,
+0x3f,0xff,0x8f,0xff,0xfc,0x43,0x8a,0xcf,0xd0,0x02,0xa5,0x77,0x79,0xc9,0xab,
+0x4b,0x16,0x18,0x03,0xf9,0x56,0xc9,0x33,0xb2,0x81,0x46,0xe3,0x39,0xb7,0xab,
+0x8b,0xe1,0xa9,0xef,0xb2,0x2c,0xe3,0xa3,0x8f,0x3f,0xc4,0xd3,0xdb,0xb6,0x20,
+0x18,0x0c,0xb2,0xdc,0x5f,0x81,0xbc,0xbc,0xbc,0xf5,0x3f,0xb9,0xeb,0x9e,0xad,
+0x85,0x85,0x29,0xcd,0xbb,0xc9,0x50,0x24,0xae,0xd3,0xfd,0x28,0xe3,0x85,0x44,
+0x92,0x81,0xbc,0x3e,0x03,0xcb,0x06,0xba,0x1c,0x2e,0xb8,0x5d,0x5d,0x0c,0x37,
+0xf9,0x7f,0xfd,0xf5,0x69,0x6c,0xd9,0xba,0x19,0x67,0xcf,0x9e,0x8d,0x66,0xd3,
+0xb9,0xbf,0xf6,0x5e,0x3f,0x6b,0xf6,0x8a,0xe9,0xd3,0xcb,0x52,0xfd,0x5d,0x9f,
+0x3a,0x28,0x9e,0x94,0xcb,0x4a,0x5d,0xb2,0x90,0x81,0x0a,0x45,0xdc,0xdf,0x69,
+0xb3,0x48,0xc8,0xcd,0xe9,0x66,0x78,0xd2,0x6f,0x7d,0x43,0x3d,0xf6,0xec,0x29,
+0xc7,0x07,0x1f,0x1c,0x8e,0x96,0x17,0x2f,0x19,0x00,0x20,0x8a,0x96,0x0f,0x47,
+0x8f,0x1e,0xfd,0xf0,0xed,0xb7,0xfd,0xf0,0x93,0x14,0xdb,0xdb,0x02,0xa5,0x77,
+0x69,0x7a,0x40,0xea,0xe5,0x84,0x8c,0x6c,0xa0,0x20,0x88,0xe8,0xda,0xa5,0x1b,
+0x24,0x83,0xdf,0x1e,0x0a,0x85,0x82,0x38,0xf8,0xd6,0x9f,0xb0,0x77,0xef,0x0b,
+0xb1,0x82,0x34,0xf1,0x1c,0xc7,0x55,0x16,0x15,0xf5,0x5e,0xfe,0xf3,0xfb,0x1f,
+0x78,0x49,0x10,0x84,0x54,0xdc,0x5f,0x59,0x75,0x69,0x80,0xb4,0x09,0xcc,0xcd,
+0xe9,0x0a,0xb7,0x2b,0xc7,0xd0,0xce,0x1d,0x3d,0xfa,0x39,0x9e,0xde,0xbe,0x15,
+0x81,0x40,0x80,0x95,0xa6,0x25,0x37,0xb7,0xeb,0xe6,0xdb,0x6f,0xfb,0xe1,0xc6,
+0xe2,0x01,0xc5,0xa9,0x4a,0x51,0x1d,0x14,0xf2,0xda,0xbc,0x97,0xee,0x52,0x44,
+0x5a,0x04,0x12,0x42,0x90,0xe3,0xee,0xc2,0x2c,0xa8,0xb2,0xea,0x1c,0x9e,0xd9,
+0xb1,0xcd,0xe8,0x30,0x1b,0x48,0x92,0xf4,0x5a,0x59,0xe9,0x8c,0x25,0xdf,0xbc,
+0xee,0x7a,0xfd,0xef,0x82,0xb3,0x91,0x55,0x97,0x29,0x20,0xed,0x4e,0x4c,0x22,
+0x02,0x81,0x46,0xbc,0xf8,0xf2,0x3e,0xbc,0xf7,0xde,0xbb,0xfa,0xfc,0x00,0x04,
+0x41,0x38,0x36,0x64,0xc8,0xd0,0x87,0xef,0xbc,0xe3,0xae,0xbf,0xa6,0xd8,0x26,
+0x19,0x80,0x07,0x8a,0xba,0x4c,0x45,0xbd,0x5e,0xd6,0x60,0x78,0x62,0xd8,0xd7,
+0x89,0x08,0x87,0xc3,0xf8,0xcb,0x5f,0xdf,0xc3,0xf3,0xcf,0xef,0x81,0x2c,0xcb,
+0x2c,0x69,0xf5,0x15,0x16,0xf6,0x78,0xf4,0xde,0xbb,0xef,0xdb,0xed,0x70,0x38,
+0x52,0xed,0x2d,0xd6,0x43,0xe9,0x5d,0x66,0xd5,0x65,0x8a,0x48,0xdb,0x13,0x43,
+0x29,0xc5,0xc9,0x2f,0x4f,0x60,0xc7,0x8e,0xed,0xf0,0xfb,0x6b,0x75,0x79,0x00,
+0x44,0xdc,0xee,0x9c,0x1d,0xdf,0xb9,0xf9,0x5f,0xd7,0x8c,0x1c,0x31,0x2a,0xd5,
+0x09,0xd3,0x20,0x14,0x75,0xd9,0x69,0x7e,0x9f,0xfd,0x62,0x01,0x73,0x46,0x9e,
+0x79,0x0d,0xc0,0xe3,0xad,0x46,0x79,0xf9,0x2e,0x9c,0x3c,0xa9,0x78,0xb7,0x34,
+0x04,0x13,0xc0,0x6a,0xb5,0xbe,0x3d,0x61,0xfc,0xc4,0x47,0x6e,0x9c,0x73,0xf3,
+0x17,0x29,0xd6,0x2f,0x03,0xf0,0x02,0xf0,0x21,0xab,0x2e,0x33,0x42,0x4a,0x9d,
+0x98,0xa6,0xe6,0x26,0xbc,0x7e,0xe0,0x55,0x1c,0x3c,0xf8,0x27,0x10,0xe8,0xed,
+0x1c,0xcf,0xf3,0x15,0xfd,0xfb,0x0f,0x58,0xf4,0x93,0xf9,0xf7,0xbe,0x99,0x46,
+0xdd,0x59,0x75,0xd9,0x0e,0x30,0x25,0x90,0x52,0x8a,0x43,0x1f,0xbc,0x8f,0x3d,
+0x7b,0x9e,0x43,0x38,0x1c,0x66,0xd9,0xb9,0x86,0xbc,0xbc,0xbc,0x75,0x3f,0xfe,
+0xd1,0xbc,0x6d,0x79,0x79,0xf9,0xa9,0x6e,0x6a,0xcc,0xaa,0xcb,0x76,0x84,0x29,
+0x81,0x91,0x48,0x04,0xe5,0xe5,0xbb,0x74,0xe1,0x00,0x64,0x87,0xc3,0xf9,0xc2,
+0xac,0xeb,0x66,0xad,0x9c,0x38,0x71,0x72,0xb2,0x9f,0x1d,0x8d,0x81,0x42,0xe9,
+0x5d,0x66,0xd5,0x65,0x3b,0xc2,0x7c,0x18,0xc1,0x80,0x28,0x5a,0xfe,0x36,0x6a,
+0xd4,0x15,0x0f,0xcf,0xbd,0xe5,0xbb,0x66,0x67,0x5c,0x26,0xa2,0x01,0x8a,0xba,
+0xbc,0x60,0x5b,0x8f,0x2f,0x17,0xa4,0x4c,0x20,0xc7,0x71,0x67,0x8b,0x7a,0x15,
+0x2d,0xbf,0xf7,0x9e,0x9f,0x25,0x3b,0xe3,0x52,0x8d,0x10,0x14,0x75,0x79,0x5e,
+0x4f,0x6a,0xb8,0x9c,0xa1,0x23,0x90,0xe7,0xb9,0xaf,0x65,0x59,0xee,0xa9,0x0a,
+0x6a,0xce,0xcd,0xcd,0xdd,0xf4,0xbd,0xb9,0xdf,0x7f,0xb2,0x4f,0x9f,0xbe,0xa9,
+0x7a,0x45,0x28,0x94,0xde,0xa5,0x17,0x59,0x75,0x79,0x5e,0xa1,0x23,0xb0,0xb0,
+0xa0,0x70,0xfd,0xd9,0x73,0x67,0x7f,0x0d,0xc0,0x26,0x49,0xd2,0xfe,0x69,0x53,
+0x4b,0x97,0x96,0x95,0xce,0x34,0x3b,0xe3,0x32,0x11,0x8d,0x50,0xa4,0x2e,0xab,
+0x2e,0x2f,0x00,0x08,0xa5,0x74,0x50,0x62,0xe0,0x99,0x33,0xa7,0x6d,0x27,0xbf,
+0x38,0x91,0x3b,0x7d,0x5a,0xd9,0xd9,0x34,0xca,0xca,0xaa,0xcb,0x0e,0x00,0x93,
+0xc0,0x34,0x91,0x55,0x97,0x1d,0x88,0xf4,0x7e,0xb6,0x45,0x8f,0xac,0xba,0xec,
+0x60,0x64,0x4a,0x60,0x18,0x0a,0x71,0x9d,0xe2,0xa4,0x86,0xcb,0x19,0xe9,0x12,
+0x48,0xa1,0x0c,0xc4,0x3d,0xc8,0xaa,0xcb,0x4e,0x01,0x01,0xca,0xc4,0x29,0x7b,
+0x0d,0xa0,0x16,0x01,0x28,0x52,0x77,0x51,0x6c,0x3d,0xbe,0x5c,0x20,0x40,0x59,
+0x10,0xdb,0xdd,0x24,0x4d,0x18,0x8a,0x17,0xe5,0xa2,0xda,0x7a,0x7c,0xb9,0x40,
+0x80,0x42,0x4c,0x57,0xe8,0xd5,0x29,0x85,0x32,0x2b,0x7e,0x51,0x6e,0x3d,0xbe,
+0x5c,0x40,0x68,0x7c,0x9b,0x2d,0x72,0x00,0xe4,0x42,0x91,0xb8,0x26,0x28,0x8b,
+0x89,0xb2,0xea,0xb2,0x93,0xe3,0xff,0x01,0xb0,0xa7,0x7e,0xbb,0x8d,0xcf,0x0a,
+0x8d,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,
+};
+
diff --git a/attic/table/table.c b/attic/table/table.c
new file mode 100644 (file)
index 0000000..69f7d16
--- /dev/null
@@ -0,0 +1,446 @@
+#include <clutter/clutter.h>
+#include <clutter/clutter-event.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+#include <gst/gst.h>
+#include <unistd.h>
+#include "clutter-dominatrix.h"
+#include "clutter-video-player.h"
+
+#define SIZE_X 80
+#define MARG 4
+
+ClutterDominatrix  *ActiveDMX = NULL;
+
+/* rand() is not that random, and tends to generate clustered values;
+ * this function attempts to ensure that the images we load are spread more
+ * evenly around the stage
+ *
+ * We divide the stage into n x m squares with size corresponsing to the
+ * thumb width, and maintain a bit matrix indicating if an image has been
+ * placed at a position in each square; then, for first n*m/2 number of thumbs,
+ * we do not allow two thumbs in the same square.
+ */
+static void
+get_xy_coords (ClutterActor * stage, gint * x, gint * y)
+{
+  static unsigned char * map = NULL;
+  static gint            count = 0;
+  static gint            size = 0;
+  static gint            sw, sh;
+  static gint            xdim, ydim;
+  
+  if (!map)
+    {
+      gint w, h;
+
+      sw = clutter_actor_get_width  (stage) - SIZE_X;
+      sh = clutter_actor_get_height (stage) - SIZE_X;
+      
+      w = sw + 2 * SIZE_X - 1;
+      h = sh + 2 * SIZE_X - 1;
+
+      xdim = w / (SIZE_X);
+      ydim = h / (SIZE_X);
+
+      size = xdim * ydim;
+      
+      map = g_malloc0 (size / 8);
+    }
+
+  *x = rand () % sw;
+  *y = rand () % sh;
+  
+  if (count >= size / 2)
+    return;
+  
+  do {
+    gint          off;
+    gint          indx;
+    unsigned char mask;
+    
+    off  = *y/(SIZE_X) * xdim + *x/(SIZE_X);
+    indx = off / 8;
+    mask = 1 << (off % 8);
+
+    if (!(map[indx] & mask))
+      {
+       map[indx] |= mask;
+       count++;
+       return;
+      }
+
+    *x = rand () % sw;
+    *y = rand () % sh;
+    }
+  while (count < size / 2);
+}
+
+struct notify_data
+{
+  ClutterActor * bckg;
+  ClutterActor * shdw;
+};
+
+static void
+notify_cb (GObject           *object,
+           GParamSpec        *param_spec,
+           gpointer           data)
+{
+  ClutterVideoPlayer * player;
+  struct notify_data * d = data;
+
+  if (!CLUTTER_IS_VIDEO_PLAYER (object))
+    return;
+
+  player = CLUTTER_VIDEO_PLAYER (object);
+  
+  gint w = clutter_actor_get_width  (CLUTTER_ACTOR (player)) + MARG;
+  gint h = clutter_actor_get_height (CLUTTER_ACTOR (player)) + MARG;
+
+  if (w == clutter_actor_get_width (d->bckg) &&
+      h == clutter_actor_get_width (d->bckg))
+    return;
+  
+  clutter_actor_set_size (d->bckg, w, h);
+  clutter_actor_set_size (d->shdw, w, h);
+}
+
+static ClutterDominatrix *
+make_item (ClutterActor * stage, ClutterActor *actor)
+{
+  ClutterActor      * rect, * group, * shaddow;
+  ClutterDominatrix * dmx;
+  ClutterColor        bckg_clr = { 0xff, 0xff, 0xff, 0xff };
+  ClutterColor        shdw_clr = { 0x44, 0x44, 0x44, 0x44 };
+  gdouble             scale;
+  gint                w, h, sw, sh, x, y;
+  ClutterFixed        zang;
+  struct notify_data * ndata = g_malloc0(sizeof (struct notify_data));
+  
+  scale = (double) SIZE_X / (double) clutter_actor_get_width (actor);
+  w = SIZE_X;
+  h = (gint)(scale * (double) clutter_actor_get_height (actor));
+
+  sw = clutter_actor_get_width  (stage) - w;
+  sh = clutter_actor_get_height (stage) - h;
+
+  get_xy_coords (stage, &x, &y);
+  
+  group = clutter_group_new ();
+  clutter_actor_set_position (group, x, y);
+  clutter_actor_set_size (group, w + MARG, h + MARG);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+  clutter_actor_show (group);
+  
+  rect = clutter_rectangle_new ();
+  clutter_actor_set_position (rect, 0, 0);
+  clutter_actor_set_size (rect, w + MARG, h + MARG);
+  
+  clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect),
+                               &bckg_clr);
+  clutter_actor_show (rect);
+  ndata->bckg = rect;
+  
+  shaddow = clutter_rectangle_new ();
+  clutter_actor_set_position (shaddow, 2, 2);
+  clutter_actor_set_size (shaddow, w + MARG, h + MARG);
+  clutter_rectangle_set_color (CLUTTER_RECTANGLE (shaddow), &shdw_clr);
+  clutter_actor_show (shaddow);
+  ndata->shdw = shaddow;
+  
+  clutter_actor_set_position (actor, 2, 2);
+  clutter_actor_set_size (actor, w, h);
+  clutter_actor_show (actor);
+
+  if (CLUTTER_IS_VIDEO_PLAYER (actor))
+    {
+      g_signal_connect (actor, "notify::width", G_CALLBACK(notify_cb), ndata);
+      g_signal_connect (actor, "notify::height", G_CALLBACK(notify_cb), ndata);
+    }
+  
+  clutter_container_add (CLUTTER_CONTAINER (group),
+                        shaddow, rect, actor, NULL);
+
+  zang = CLUTTER_INT_TO_FIXED (rand()%360);
+  clutter_actor_set_rotationx (group,
+                               CLUTTER_Z_AXIS,
+                               zang,
+                               0,
+                               0,
+                               0);
+  
+  dmx = clutter_dominatrix_new (group);
+
+  return dmx;
+}
+
+static ClutterDominatrix *
+make_img_item (ClutterActor * stage, const gchar * name)
+{
+  ClutterActor      * img;
+  GdkPixbuf         * pixbuf;
+  
+  pixbuf = gdk_pixbuf_new_from_file_at_size (name, 400, 400, NULL);
+
+  if (!pixbuf)
+    return NULL;
+
+  img = clutter_texture_new_from_pixbuf (pixbuf);
+  clutter_actor_show (img);
+  
+  return make_item (stage, img);
+}
+
+static ClutterDominatrix *
+make_vid_item (ClutterActor * stage, const gchar * name)
+{
+  ClutterActor      * vid;
+
+  vid = clutter_video_player_new (name);
+  return make_item (stage, vid);
+}
+
+static gboolean
+is_supported_img (const gchar * name)
+{
+  GdkPixbufFormat * fmt = gdk_pixbuf_get_file_info (name, NULL, NULL);
+
+  if (fmt)
+    return (gdk_pixbuf_format_is_disabled (fmt) != TRUE);
+  
+  return FALSE;
+}
+
+static void
+process_directory (const gchar * name,
+                  ClutterActor * stage, ClutterActor * notice)
+{
+  GDir              * dir;
+  const gchar       * fname;
+  struct stat         sbuf;
+  
+  dir = g_dir_open (name, 0, NULL);
+
+  if (!dir)
+    return;
+
+  g_chdir (name);
+  
+  while ((fname = g_dir_read_name (dir)))
+    {
+      while (g_main_context_pending (NULL))
+       g_main_context_iteration (NULL, FALSE);
+
+      if (is_supported_img (fname))
+       {
+         make_img_item (stage, fname);
+         clutter_actor_raise_top (notice);
+       }
+      else if (g_str_has_suffix (fname, ".flv")
+              || g_str_has_suffix (fname, ".avi")
+              || g_str_has_suffix (fname, ".mpg")
+              || g_str_has_suffix (fname, ".mp4")
+              || g_str_has_suffix (fname, ".mov")
+              || g_str_has_suffix (fname, ".ogg"))
+       {
+         make_vid_item (stage, fname);
+         clutter_actor_raise_top (notice);
+       }
+              
+      if (g_stat (fname, &sbuf) > -1 && S_ISDIR (sbuf.st_mode))
+       process_directory (fname, stage, notice);
+    }
+
+  g_chdir ("..");
+  
+  g_dir_close (dir);
+}
+
+static ClutterActor *
+make_busy_notice (ClutterActor * stage)
+{
+  ClutterActor     * label;
+  ClutterActor     * rect;
+  ClutterActor     * group;
+  ClutterColor       text_clr = { 0xff, 0xff, 0xff, 0xff };
+  ClutterColor       bckg_clr = { 0x5c, 0x54, 0x57, 0x9f };
+  
+  label = clutter_label_new_with_text ("Sans 54",
+                                      "Please wait, loading images ...");
+  
+  clutter_label_set_color (CLUTTER_LABEL (label), &text_clr);
+  clutter_actor_set_position (label, 10, 10);
+  clutter_actor_show (label);
+
+  group = clutter_group_new ();
+  clutter_actor_show (group);
+  
+  rect = clutter_rectangle_new ();
+  clutter_actor_set_position (rect, 0, 0);
+  clutter_actor_set_size (rect,
+                         clutter_actor_get_width (label) + 20,
+                         clutter_actor_get_height (label) + 20);
+  
+  clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect),
+                               &bckg_clr);
+  clutter_actor_show (rect);
+
+  clutter_container_add (CLUTTER_CONTAINER (group), rect, label, NULL);
+  
+  return group;
+}
+
+struct timeout_cb_data
+{
+  ClutterActor * stage;
+  ClutterActor * notice;
+  const gchar  * name;
+};
+
+static void
+tmln_completed_cb (ClutterActor *actor, gpointer data)
+{
+  ClutterGroup * stage = data;
+
+  clutter_group_remove (stage, actor);
+}
+
+static gboolean
+timeout_cb (gpointer data)
+{
+  ClutterTimeline * tmln;
+  ClutterEffectTemplate * tmpl;
+  
+  struct timeout_cb_data * d = data;
+  
+  process_directory (d->name, d->stage, d->notice);
+
+  tmpl = clutter_effect_template_new (clutter_timeline_new (60, 60),
+                                     CLUTTER_ALPHA_SINE_DEC);
+  
+  clutter_actor_set_opacity (d->notice, 0);
+  tmln = clutter_effect_fade (tmpl, d->notice, 0xff, tmln_completed_cb,
+                             d->stage);
+
+  g_object_unref (tmpl);
+  
+  clutter_actor_show_all (d->stage);
+  clutter_actor_queue_redraw (d->stage);
+  
+  return FALSE;
+}
+
+static void 
+on_event (ClutterStage *stage,
+         ClutterEvent *event,
+         gpointer      data)
+{
+  gint            x,y;
+  ClutterActor   *actor;
+  ClutterDominatrix *dmx;
+
+  switch (event->type)
+    {
+    case CLUTTER_KEY_PRESS:
+      {
+       guint sym = clutter_key_event_symbol ((ClutterKeyEvent*)event);
+
+       switch (sym)
+         {
+         case CLUTTER_Escape:
+         case CLUTTER_q:
+         case CLUTTER_Q:
+            clutter_main_quit ();
+            break;
+            
+         default:
+           break;
+         }
+      }
+      break;
+    case CLUTTER_BUTTON_PRESS:
+      clutter_event_get_coords (event, &x, &y);
+
+      actor = clutter_stage_get_actor_at_pos (stage, x, y);
+       
+      while (actor &&
+            clutter_actor_get_parent (actor) != CLUTTER_ACTOR(stage) &&
+            (actor = clutter_actor_get_parent (actor)));
+       
+      if (!actor)
+       return;
+      
+      dmx = g_object_get_data (G_OBJECT (actor), "dominatrix");
+      
+      if (!dmx)
+       return;
+
+      ActiveDMX = g_object_ref (dmx);
+      break;
+    case CLUTTER_BUTTON_RELEASE:
+      if (ActiveDMX)
+       {
+         clutter_dominatrix_handle_event (ActiveDMX, event);
+         g_object_unref (ActiveDMX);
+         ActiveDMX = NULL;
+       }
+      break;
+    default:
+      break;
+    }
+
+  if (ActiveDMX)
+    clutter_dominatrix_handle_event (ActiveDMX, event);
+
+  return;
+}
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor      * stage, * notice;
+  ClutterColor        stage_clr = { 0xed, 0xe8, 0xe1, 0xff };
+  struct timeout_cb_data tcbd;
+  
+  if (argc != 2)
+    {
+      g_print ("\n    usage: %s image_directory\n\n", argv[0]);
+      exit (1);
+    }
+  
+  srand (time(NULL) + getpid());
+  
+  clutter_init (&argc, &argv);
+  gst_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
+
+  g_object_set (stage, "fullscreen", TRUE, NULL);
+
+  notice = make_busy_notice (stage);
+  clutter_actor_set_position (notice,
+                             (clutter_actor_get_width (stage) -
+                              clutter_actor_get_width (notice))/2,
+                             (clutter_actor_get_height (stage) -
+                              clutter_actor_get_height (notice))/2);
+  
+  clutter_group_add (CLUTTER_GROUP(stage), notice);
+  clutter_actor_show_all (stage);
+
+  tcbd.stage  = stage;
+  tcbd.notice = notice;
+  tcbd.name   = argv[1];
+
+  g_timeout_add (100, timeout_cb, &tcbd);
+
+  g_signal_connect (stage, "event", G_CALLBACK (on_event), NULL);
+  
+  clutter_main();
+
+  return EXIT_SUCCESS;
+}
diff --git a/attic/widgets/Makefile b/attic/widgets/Makefile
new file mode 100644 (file)
index 0000000..d52c9f1
--- /dev/null
@@ -0,0 +1,14 @@
+LIBS=`pkg-config --libs clutter-0.6 gnome-vfs-2.0 clutter-gst-0.6`
+INCS=`pkg-config --cflags clutter-0.6 gnome-vfs-2.0 clutter-gst-0.6`
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: test
+
+
+test: test.o clutter-reflect-texture.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ test.o clutter-reflect-texture.o $(LIBS)
+
+clean:
+       rm -fr *.o test
diff --git a/attic/widgets/clutter-reflect-texture.c b/attic/widgets/clutter-reflect-texture.c
new file mode 100644 (file)
index 0000000..9fd86a1
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define CLUTTER_PARAM_READWRITE \
+        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+
+
+/**
+ * SECTION:clutter-reflect-texture
+ * @short_description: Actor for cloning existing textures in an 
+ * efficient way.
+ *
+ * #ClutterReflectTexture allows the cloning of existing #ClutterTexture with 
+ * a refelction like effect.
+ */
+
+#include <GL/gl.h>
+#include <clutter/cogl.h>
+
+#include "clutter-reflect-texture.h"
+
+enum
+{
+  PROP_0,
+  PROP_REFLECTION_HEIGHT
+};
+
+G_DEFINE_TYPE (ClutterReflectTexture,
+              clutter_reflect_texture,
+              CLUTTER_TYPE_CLONE_TEXTURE);
+
+#define CLUTTER_REFLECT_TEXTURE_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexturePrivate))
+
+struct _ClutterReflectTexturePrivate
+{
+  gint                 reflection_height;
+};
+
+static void
+reflect_texture_render_to_gl_quad (ClutterReflectTexture *ctexture, 
+                                int             x1, 
+                                int             y1, 
+                                int             x2, 
+                                int             y2)
+{
+  gint   qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0;
+  gint   qwidth = 0, qheight = 0;
+  gint   x, y, i =0, lastx = 0, lasty = 0;
+  gint   n_x_tiles, n_y_tiles; 
+  gint   pwidth, pheight, rheight;
+  float tx, ty, ty2 = 0.0;
+
+  ClutterReflectTexturePrivate *priv = ctexture->priv;
+  ClutterActor *parent_texture = CLUTTER_ACTOR(clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(ctexture)));
+
+  priv = ctexture->priv;
+
+  qwidth  = x2 - x1;
+  qheight = y2 - y1;
+
+  rheight = priv->reflection_height;
+
+  if (rheight > qheight)
+    rheight = qheight;
+
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+      clutter_actor_realize (parent_texture);
+
+  /* Only paint if parent is in a state to do so */
+  if (!clutter_texture_has_generated_tiles (CLUTTER_TEXTURE(parent_texture)))
+    return;
+  
+  clutter_texture_get_base_size (CLUTTER_TEXTURE(parent_texture), 
+                                &pwidth, &pheight); 
+
+  if (!clutter_texture_is_tiled (CLUTTER_TEXTURE(parent_texture)))
+    {
+      clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), 0);
+
+      /* NPOTS textures *always* used if extension available
+       */
+      if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+       {
+         tx = (float) pwidth;
+         ty = (float) pheight;
+         ty2 = (float)(clutter_actor_get_height (CLUTTER_ACTOR(ctexture)) * rheight) 
+                                             / pheight;
+         ty2 = pheight - ty2;
+
+       }
+      else
+       {
+         tx = (float) pwidth / clutter_util_next_p2 (pwidth);  
+         ty = (float) pheight / clutter_util_next_p2 (pheight);
+       }
+
+      qx1 = x1; qx2 = x2;
+      qy1 = y1; qy2 = y1 + rheight;
+
+      glBegin (GL_QUADS);
+
+      glColor4ub (255, 255, 255, 
+                 clutter_actor_get_opacity (CLUTTER_ACTOR(ctexture)));
+
+      glTexCoord2f (0, ty);   
+      glVertex2i   (qx1, qy1);
+
+      glTexCoord2f (tx,  ty);   
+      glVertex2i   (qx2, qy1);
+
+      glColor4ub (255, 255, 255, 0);
+
+      glTexCoord2f (tx,  ty2);    
+      glVertex2i   (qx2, qy2);
+      
+      glTexCoord2f (0, ty2);    
+      glVertex2i   (qx1, qy2);
+
+      glEnd ();        
+      
+      return;
+    }
+
+  clutter_texture_get_n_tiles (CLUTTER_TEXTURE(parent_texture), 
+                              &n_x_tiles, &n_y_tiles); 
+
+  for (x = 0; x < n_x_tiles; x++)
+    {
+      lasty = 0;
+
+      for (y = 0; y < n_y_tiles; y++)
+       {
+         gint actual_w, actual_h;
+         gint xpos, ypos, xsize, ysize, ywaste, xwaste;
+         
+         clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), i);
+        
+         clutter_texture_get_x_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            x, &xpos, &xsize, &xwaste);
+
+         clutter_texture_get_y_tile_detail (CLUTTER_TEXTURE(parent_texture), 
+                                            y, &ypos, &ysize, &ywaste);
+
+         actual_w = xsize - xwaste;
+         actual_h = ysize - ywaste;
+
+         tx = (float) actual_w / xsize;
+         ty = (float) actual_h / ysize;
+
+         qx1 = x1 + lastx;
+         qx2 = qx1 + ((qwidth * actual_w ) / pwidth );
+         
+         qy1 = y1 + lasty;
+         qy2 = qy1 + ((qheight * actual_h) / pheight );
+
+         glBegin (GL_QUADS);
+         glTexCoord2f (tx, ty);   glVertex2i   (qx2, qy2);
+         glTexCoord2f (0,  ty);   glVertex2i   (qx1, qy2);
+         glTexCoord2f (0,  0);    glVertex2i   (qx1, qy1);
+         glTexCoord2f (tx, 0);    glVertex2i   (qx2, qy1);
+         glEnd ();     
+
+         lasty += qy2 - qy1;     
+
+         i++;
+       }
+      lastx += qx2 - qx1;
+    }
+}
+
+static void
+clutter_reflect_texture_paint (ClutterActor *self)
+{
+  ClutterReflectTexturePrivate  *priv;
+  ClutterActor                *parent_texture;
+  gint                         x1, y1, x2, y2;
+  GLenum                       target_type;
+
+  priv = CLUTTER_REFLECT_TEXTURE (self)->priv;
+
+  /* no need to paint stuff if we don't have a texture to reflect */
+  if (!clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)))
+    return;
+
+  /* parent texture may have been hidden, there for need to make sure its 
+   * realised with resources available.  
+  */
+  parent_texture = CLUTTER_ACTOR (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self)));
+  if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
+    clutter_actor_realize (parent_texture);
+
+  /* FIXME: figure out nicer way of getting at this info...  
+   */  
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE) &&
+      clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture)) == FALSE)
+    {
+      target_type = CGL_TEXTURE_RECTANGLE_ARB;
+      cogl_enable (CGL_ENABLE_TEXTURE_RECT | CGL_ENABLE_BLEND);
+    }
+  else
+    {
+      target_type = CGL_TEXTURE_2D;
+      cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
+    }
+  
+  cogl_push_matrix ();
+
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glColor4ub (255, 255, 255, clutter_actor_get_opacity (self));
+
+  clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
+
+  /* Parent paint translated us into position */
+  reflect_texture_render_to_gl_quad (CLUTTER_REFLECT_TEXTURE (self), 
+                                  0, 0, x2 - x1, y2 - y1);
+
+  cogl_pop_matrix ();
+}
+
+
+
+static void
+clutter_reflect_texture_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterReflectTexture         *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      priv->reflection_height = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  ClutterReflectTexture *ctexture = CLUTTER_REFLECT_TEXTURE (object);
+  ClutterReflectTexturePrivate  *priv = ctexture->priv;  
+
+  switch (prop_id)
+    {
+    case PROP_REFLECTION_HEIGHT:
+      g_value_set_int (value, priv->reflection_height);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_reflect_texture_class_init (ClutterReflectTextureClass *klass)
+{
+  GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  actor_class->paint = clutter_reflect_texture_paint;
+
+  gobject_class->set_property = clutter_reflect_texture_set_property;
+  gobject_class->get_property = clutter_reflect_texture_get_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_REFLECTION_HEIGHT,
+                                   g_param_spec_int ("reflection-height",
+                                                     "Reflection Height",
+                                                     "",
+                                                     0, G_MAXINT,
+                                                     0,
+                                                     (G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)));
+
+  g_type_class_add_private (gobject_class, sizeof (ClutterReflectTexturePrivate));
+}
+
+static void
+clutter_reflect_texture_init (ClutterReflectTexture *self)
+{
+  ClutterReflectTexturePrivate *priv;
+
+  self->priv = priv = CLUTTER_REFLECT_TEXTURE_GET_PRIVATE (self);
+  priv->reflection_height = 100; 
+}
+
+/**
+ * clutter_reflect_texture_new:
+ * @texture: a #ClutterTexture or %NULL
+ *
+ * Creates an efficient 'reflect' of a pre-existing texture if which it 
+ * shares the underlying pixbuf data.
+ *
+ * You can use clutter_reflect_texture_set_parent_texture() to change the
+ * parent texture to be reflectd.
+ *
+ * Return value: the newly created #ClutterReflectTexture
+ */
+ClutterActor *
+clutter_reflect_texture_new (ClutterTexture *texture, gint reflection_height)
+{
+  g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
+
+  return g_object_new (CLUTTER_TYPE_REFLECT_TEXTURE,
+                      "parent-texture", texture,
+                      "reflection-height", reflection_height,
+                      NULL);
+}
+
diff --git a/attic/widgets/clutter-reflect-texture.h b/attic/widgets/clutter-reflect-texture.h
new file mode 100644 (file)
index 0000000..9ba7353
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_REFLECT_TEXTURE_H
+#define _HAVE_CLUTTER_REFLECT_TEXTURE_H
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_REFLECT_TEXTURE (clutter_reflect_texture_get_type ())
+
+#define CLUTTER_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTexture))
+
+#define CLUTTER_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+#define CLUTTER_IS_REFLECT_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_IS_REFLECT_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_TYPE_REFLECT_TEXTURE))
+
+#define CLUTTER_REFLECT_TEXTURE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_TYPE_REFLECT_TEXTURE, ClutterReflectTextureClass))
+
+typedef struct _ClutterReflectTexture        ClutterReflectTexture;
+typedef struct _ClutterReflectTexturePrivate ClutterReflectTexturePrivate;
+typedef struct _ClutterReflectTextureClass   ClutterReflectTextureClass;
+
+struct _ClutterReflectTexture
+{
+  ClutterCloneTexture              parent;
+  
+  /*< priv >*/
+  ClutterReflectTexturePrivate    *priv;
+};
+
+struct _ClutterReflectTextureClass 
+{
+  ClutterCloneTextureClass parent_class;
+
+  /* padding for future expansion */
+  void (*_clutter_reflect_1) (void);
+  void (*_clutter_reflect_2) (void);
+  void (*_clutter_reflect_3) (void);
+  void (*_clutter_reflect_4) (void);
+}; 
+
+GType           clutter_reflect_texture_get_type           (void) G_GNUC_CONST;
+
+ClutterActor *  clutter_reflect_texture_new                (ClutterTexture      *texture, gint reflection_height);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/widgets/test.c b/attic/widgets/test.c
new file mode 100644 (file)
index 0000000..362b35a
--- /dev/null
@@ -0,0 +1,45 @@
+#include <clutter/clutter.h>
+#include "clutter-reflect-texture.h"
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor  *stage, *tex, *reflect;
+  GdkPixbuf     *pixbuf;
+  ClutterColor   stage_color = { 0x0, 0x0, 0x0, 0xff };
+  gint           x;
+
+  clutter_init (&argc, &argv);
+
+  if (argc < 2)
+    {
+      g_error ("No image argument supplied");
+    }
+
+  stage = clutter_stage_get_default ();
+
+  clutter_stage_set_color (CLUTTER_STAGE (stage),
+                          &stage_color);
+
+  pixbuf = gdk_pixbuf_new_from_file (argv[1], NULL);
+
+  tex = clutter_texture_new_from_pixbuf (pixbuf);
+
+  reflect = clutter_reflect_texture_new (CLUTTER_TEXTURE(tex), 100);
+  clutter_actor_set_opacity (reflect, 100);
+
+  x = (CLUTTER_STAGE_WIDTH() - clutter_actor_get_width(tex))/2;
+
+  clutter_group_add (CLUTTER_GROUP(stage), tex);
+  clutter_group_add (CLUTTER_GROUP(stage), reflect);
+  clutter_actor_set_position (tex, x, 20);
+  clutter_actor_set_position (reflect, x, clutter_actor_get_height(tex) + 20);
+
+  /* clutter_actor_rotate_y (stage, 60.0, CLUTTER_STAGE_WIDTH()/2, 0); */
+
+  clutter_actor_show_all (stage);
+
+  clutter_main();
+
+  return 1;
+}
diff --git a/attic/woohaa/AUTHORS b/attic/woohaa/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/woohaa/ChangeLog b/attic/woohaa/ChangeLog
new file mode 100644 (file)
index 0000000..1663d7f
--- /dev/null
@@ -0,0 +1,271 @@
+2008-02-18  Chris Lord  <chris@openedhand.com>
+
+       * configure.ac:
+       Bump clutter requirement to 0.6
+
+2008-02-13  Chris Lord  <chris@openedhand.com>
+
+       * wh-db.c: (wh_db_dispose), (wh_db_init), (wh_db_monitor_add_idle),
+       (wh_db_media_file_found_idle), (wh_db_import_uri_private),
+       (wh_db_walk_directory), (wh_db_import_uri_func),
+       (on_vfs_monitor_event), (wh_db_import_uri):
+       Do importing in a thread, using a thread pool
+
+2007-09-04  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile.am:
+       * totem-resources.c:
+       * totem-resources.h:
+       * wh-db.c:
+       * wh-screen-video.c:
+       * wh-video-thumbnailer.c:
+       * woohaa.c: 
+       Big Patch from Sir Bastien Nocera:
+        
+       - Use totem-resources.[ch] to avoid the thumbnailer running
+          amok (avoids signals, use threads and monitor memory usage
+          as well).
+       - Put the woohaa db in ~/.local/share/woohaa, as per XDG-ish
+       - Don't use GNOME_VFS_PERM_ACCESS_READABLE, it's only
+          implemented by the file method in gnome-vfs (so doesn't work
+          remotely)
+        - Make sure URIs and not local file paths are getting passed around
+        - Get a list from GConf so that we can use ":" (as in "smb://blah") in
+          the URI
+        - Don't leak the GConfClient (it's not a singleton)
+
+2007-08-07  Matthew Allum  <mallum@openedhand.com>
+
+       * configure.ac:
+       Update for 0.4
+
+2007-07-13  Matthew Allum  <mallum@openedhand.com>
+
+       * woohaa.c: (browse_input_cb):
+       Escape also exit app.
+
+2007-07-13  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-screen-video.c:
+       Escape also quit video.
+       * woohaa.c: 
+       Really hide startup screen.
+
+2007-07-12  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-screen-video.c:
+       * wh-video-view.c:
+       Improve video controls look.
+       Clean up a couple of compiler warnings.
+
+2007-07-11  Matthew Allum  <mallum@openedhand.com>
+
+       * data/arrow-next.svg:
+       * data/arrow-prev.svg:
+       * wh-screen-video.c:
+       * wh-slider-menu.c:
+       * wh-video-view.c:
+       Improve look of arrows (a little).
+       Change keys so enter also pauses, q exits video playback
+
+2007-07-11  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-screen-video.c:
+       * wh-slider-menu.c: 
+       * wh-video-view.c:
+       * woohaa.c:
+       Various minor tweaks to look.
+
+2007-07-09  Neil J. Patel  <njp@o-hand.com>
+
+       * woohaa.c: (main):
+       Look for bg.png in PKGDATADIR
+
+2007-07-09  Matthew Allum  <mallum@openedhand.com>
+
+       * clutter-simple-layout.c:
+       * configure.ac:
+       * data/Makefile.am:
+       * data/arrow-down.svg:
+       * data/arrow-next.svg:
+       * data/arrow-prev.svg:
+       * data/arrow-up.svg:
+       * data/header.svg:
+       * data/play.svg:
+       * data/selected.svg:
+       * data/spinner.svg:
+       * util.c:
+       * wh-busy.c:
+       * wh-slider-menu.c:
+       * wh-video-row-renderer.c:
+       * wh-video-thumbnailer.c:
+       * woohaa.c:
+       Update for 0.3 API, along with a new look. 
+
+2007-04-06  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-screen-video.c:
+       Re-add cheesy easter egg effect (via 'e' key).
+
+       * wh-slider-menu.c:
+       * wh-slider-menu.h:
+       * woohaa.c:
+       * wh-video-view.c:
+       Improve layout/scalability on various sized displays.
+
+       * wh-video-row-renderer.c:
+       Simple glow effect on selected video.
+
+       * wh-video-thumbnailer.c:
+       Clean up a couple of warnings.
+
+2007-04-03  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-slider-menu.c:
+       Fix dissapearing mystery slider menu entrys when Sans font
+       was used.
+
+2007-04-01  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-screen-video.c:
+       Fix Audio/Picture sync on movie playback startup
+
+2007-03-30  Matthew Allum  <mallum@openedhand.com>
+
+       * woohaa.c: (main):
+       Importing -> Syncing copy change.
+
+2007-03-30  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-screen-video.c:
+       Hack to prevent bad video files causing crazed looping. 
+       * woohaa.c:
+       Set stage hidden cursor property.
+
+2007-03-29  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-db.c:
+       Fix space in regexp
+
+       * wh-screen-video.c:
+       Disable thumbnail generation on video stop.
+       Add volume control via up/down arrows
+
+       * wh-theme.c:
+       * wh-video-model.c:
+       * wh-video-thumbnailer.c:
+       * wh-video-view.c:
+       Clean up warnings.      
+
+2007-03-29  Matthew Allum  <mallum@openedhand.com>
+
+       * data/Makefile.am:
+       Add defualt thumbnail image.
+
+       * configure.ac:
+       Pull in gconf.
+
+       * wh-video-model.c:
+       * wh-video-model.h:
+       * wh-screen-video.c:
+       * wh-screen-video.h:
+       * wh-video-model-row.c:
+       * wh-video-row-renderer.c:
+       Various thumbnail related tweaks.
+
+       * wh-video-view.c:
+       Speed up painting via only paint on screen rows.
+
+       * wh-video-thumbnailer.c:
+       * woohaa.c:
+       Add a seperate thumbnailer process and handle it.
+
+       * Makefile.am:
+       * wh-theme.c:
+       * wh-theme.h:
+       Add a *very* simple initial theme 'framework'.
+
+2007-03-20  Matthew Allum  <mallum@openedhand.com>
+
+       * wh-db.c: (wh_db_parse_video_uri_info):
+       Improve filename parsing for video title including parent directory 
+       name if deemed useful. (via patch from Iain). 
+       * wh-screen-video.c:
+       Improve layout of video controls.
+
+2007-03-18  Matthew Allum  <mallum@openedhand.com>
+
+       * clutter-slider-menu.c:
+       * clutter-slider-menu.h:
+       * selector.svg:
+       Remove old uneeded files.
+
+2007-03-18  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile.am:
+       * clutter-simple-layout.c:
+       * clutter-simple-layout.h:
+       * clutter-slider-menu.c:
+       * configure.ac:
+       * data/Makefile.am:
+       * selector.svg:
+       * util.c:
+       * util.h:
+       * wh-busy.c:
+       * wh-busy.h:
+       * wh-db.c:
+       * wh-db.h:
+       * wh-screen-video.c:
+       * wh-screen-video.h:
+       * wh-slider-menu.c:
+       * wh-slider-menu.h:
+       * wh-video-model-row.c:
+       * wh-video-model-row.h:
+       * wh-video-model.c:
+       * wh-video-model.h:
+       * wh-video-row-renderer.c:
+       * wh-video-row-renderer.h:
+       * wh-video-view.c:
+       * woohaa.c:
+       Lots and lots. Far too long without a commit..
+
+2007-02-22  Matthew Allum  <mallum@openedhand.com>
+
+
+       * wh-video-model.c:
+       * wh-video-model.h:
+       * wh-video-view.c: 
+       * wh-video-view.h:
+       * woohaa.c: 
+       Various model/view tweaks
+
+2007-02-20  Matthew Allum  <mallum@openedhand.com>
+
+       * clutter-disk.c:
+       * clutter-disk.h:
+       * clutter-video-model.c:
+       * clutter-video-model.h:
+       * clutter-video-view.c:
+       * clutter-video-view.h:
+       Remove old files
+
+2007-02-20  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile.am:
+       * autogen.sh:
+       * clutter-video-model.h:
+       * configure.ac:
+       * eggsequence.c:
+       * eggsequence.h:
+       * wh-db.c:
+       * wh-db.h:
+       * wh-video-model-row.c:
+       * wh-video-model-row.h:
+       * wh-video-model.c:
+       * wh-video-model.h:
+       * wh-video-row-renderer.c:
+       * wh-video-row-renderer.h:
+       * wh-video-view.c:
+       * wh-video-view.h:
+       * woohaa.c:
+       Overhaul and refactor lots. 
diff --git a/attic/woohaa/Makefile.am b/attic/woohaa/Makefile.am
new file mode 100644 (file)
index 0000000..b275de1
--- /dev/null
@@ -0,0 +1,41 @@
+SUBDIRS=data
+
+bin_PROGRAMS=woohaa wh-video-thumbnailer
+
+PKGDATADIR = $(datadir)/woohaa
+
+AM_CFLAGS = $(DEPS_CFLAGS) $(CLUTTER_HELIX_CFLAGS) $(GCC_FLAGS) -D_GNU_SOURCE -DPKGDATADIR=\"$(PKGDATADIR)\"
+
+woohaa_LDADD  = $(DEPS_LIBS) $(CLUTTER_HELIX_LIBS)
+woohaa_SOURCES = woohaa.c               \
+               wh-busy.c               \
+               wh-busy.h               \
+               wh-slider-menu.c        \
+               wh-slider-menu.h        \
+               wh-screen-video.c       \
+               wh-screen-video.h       \
+               wh-video-model.c        \
+               wh-video-model.h        \
+               wh-video-view.c         \
+               wh-video-view.h         \
+               wh-video-model-row.c    \
+               wh-video-model-row.h    \
+               wh-video-row-renderer.c \
+               wh-video-row-renderer.h \
+               wh-db.c                 \
+               wh-db.h                 \
+               wh-theme.c              \
+               wh-theme.h              \
+               eggsequence.c           \
+               eggsequence.h           \
+               util.c                  \
+               util.h
+
+wh_video_thumbnailer_LDADD = $(DEPS_LIBS) $(CLUTTER_HELIX_LIBS)
+wh_video_thumbnailer_SOURCES = wh-video-thumbnailer.c totem-resources.c totem-resources.h
+
+MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub configure depcomp install-sh ltmain.sh Makefile.in missing
+
+snapshot:
+       $(MAKE) dist distdir=$(PACKAGE)-snap`date +"%Y%m%d"`
+
diff --git a/attic/woohaa/NEWS b/attic/woohaa/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/woohaa/README b/attic/woohaa/README
new file mode 100644 (file)
index 0000000..406a3ba
--- /dev/null
@@ -0,0 +1,25 @@
+Woohaa README
+=============
+
+Woohaa is hacky prototype movie viewing toy. *YMMV*.
+
+To run, 'Woohaa <path to movie files>'
+
+Keys:
+  up/down    - navigate list
+  left/right - check list view (not implemnted as yet) 
+  Enter      - Play movie
+  q          - Quit
+
+  With movie playing:
+  left/right - advance movie forward/back.
+  p          - pause
+  Enter      - toggle on screen display
+  Esc        - exit back to list
+  r          - rotate the screen 180 degrees
+
+Remember its a prototype.
+
+  -- Matthew Allum
+
diff --git a/attic/woohaa/autogen.sh b/attic/woohaa/autogen.sh
new file mode 100755 (executable)
index 0000000..b1376df
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/attic/woohaa/configure.ac b/attic/woohaa/configure.ac
new file mode 100644 (file)
index 0000000..963e010
--- /dev/null
@@ -0,0 +1,43 @@
+AC_PREREQ(2.53)
+AC_INIT(woohaa, 0.0, [http://bugzilla.o-hand.com/enter_bug.cgi?product=woohaa])
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(woohaa.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+
+PKG_CHECK_MODULES(DEPS, clutter-0.8 gnome-vfs-2.0 clutter-gst-0.8 sqlite3 gdk-2.0 gdk-pixbuf-2.0 gconf-2.0)
+AC_SUBST(DEPS_CFLAGS)
+AC_SUBST(DEPS_LIBS)
+
+AC_ARG_ENABLE([helix],
+             AS_HELP_STRING([--enable-helix],[enable helix]),
+             [enable_helix=$enableval],
+             [enable_helix=no])
+
+if test "x$GCC" = "xyes"; then
+        GCC_FLAGS="-g -Wall"
+fi
+
+if test "x$enable_helix" = "xyes"; then
+       PKG_CHECK_MODULES(CLUTTER_HELIX, [clutter-helix-0.8],
+                                        [has_helix=yes],
+                                        [has_helix=no])
+       if test "x$has_helix" = "xno"; then
+            AC_MSG_ERROR([Clutter-Helix libraries are not available.])
+       fi
+
+       GCC_FLAGS+=" -DUSE_HELIX"
+        AC_SUBST(CLUTTER_HELIX_CFLAGS)
+        AC_SUBST(CLUTTER_HELIX_LDFAGS)
+fi
+
+AC_SUBST(GCC_FLAGS)
+
+AC_OUTPUT([
+Makefile
+data/Makefile
+])
diff --git a/attic/woohaa/data/Makefile.am b/attic/woohaa/data/Makefile.am
new file mode 100644 (file)
index 0000000..f41e49e
--- /dev/null
@@ -0,0 +1,4 @@
+resdir = $(datadir)/woohaa
+res_DATA = bg.png busy.png default-thumb.png arrow-next.svg arrow-prev.svg arrow-up.svg arrow-down.svg play.svg selected.svg spinner.svg header.svg
+
+EXTRA_DIST = bg.png busy.png default-thumb.png arrow-next.svg arrow-prev.svg arrow-up.svg arrow-down.svg play.svg selected.svg spinner.svg header.svg
diff --git a/attic/woohaa/data/arrow-down.svg b/attic/woohaa/data/arrow-down.svg
new file mode 100644 (file)
index 0000000..a65cfc2
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="80"
+   height="40"
+   id="svg3200"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docname="arrow-down.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="/home/mallum/Projects/clutter-trunk/toys/woohaa"
+   sodipodi:modified="true">
+  <defs
+     id="defs3202" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.1917808"
+     inkscape:cx="34"
+     inkscape:cy="36.5"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     width="80px"
+     height="40px"
+     inkscape:window-width="772"
+     inkscape:window-height="581"
+     inkscape:window-x="10"
+     inkscape:window-y="71" />
+  <metadata
+     id="metadata3205">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:15;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 70.041194,8.266253 L 40.065885,32.010668 L 9.958806,7.989332"
+       id="path3210" />
+  </g>
+</svg>
diff --git a/attic/woohaa/data/arrow-next.svg b/attic/woohaa/data/arrow-next.svg
new file mode 100644 (file)
index 0000000..1c18c0e
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="480"
+   height="960"
+   id="svg3200"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/home/mallum/Projects/clutter-trunk/toys/woohaa/data"
+   sodipodi:docname="arrow-prev.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs3202" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.5921875"
+     inkscape:cx="160"
+     inkscape:cy="671.24011"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     width="480px"
+     height="960px"
+     inkscape:window-width="772"
+     inkscape:window-height="581"
+     inkscape:window-x="10"
+     inkscape:window-y="70" />
+  <metadata
+     id="metadata3205">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#cccccc;stroke-width:180;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 99.195029,840.49434 L 384.12801,480.79062 L 95.871989,119.50566"
+       id="path3210" />
+  </g>
+</svg>
diff --git a/attic/woohaa/data/arrow-prev.svg b/attic/woohaa/data/arrow-prev.svg
new file mode 100644 (file)
index 0000000..4e8869b
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="480"
+   height="960"
+   id="svg3200"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/home/mallum/Projects/clutter-trunk/toys/woohaa/data"
+   sodipodi:docname="arrow-prev.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs3202" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.5921875"
+     inkscape:cx="160"
+     inkscape:cy="671.24011"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     width="480px"
+     height="960px"
+     inkscape:window-width="772"
+     inkscape:window-height="581"
+     inkscape:window-x="10"
+     inkscape:window-y="70" />
+  <metadata
+     id="metadata3205">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#cccccc;stroke-width:180;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 380.80497,840.49434 L 95.871989,480.79062 L 384.12801,119.50566"
+       id="path3210" />
+  </g>
+</svg>
diff --git a/attic/woohaa/data/arrow-up.svg b/attic/woohaa/data/arrow-up.svg
new file mode 100644 (file)
index 0000000..c30f43f
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="80"
+   height="40"
+   id="svg3200"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docname="arrow-up.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="/home/mallum/Projects/clutter-trunk/toys/woohaa"
+   sodipodi:modified="true">
+  <defs
+     id="defs3202" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.1917808"
+     inkscape:cx="34"
+     inkscape:cy="36.5"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     width="80px"
+     height="40px"
+     inkscape:window-width="772"
+     inkscape:window-height="581"
+     inkscape:window-x="10"
+     inkscape:window-y="71" />
+  <metadata
+     id="metadata3205">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:15;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 9.958806,31.733747 L 39.934115,7.989332 L 70.041194,32.010668"
+       id="path3210" />
+  </g>
+</svg>
diff --git a/attic/woohaa/data/bg.png b/attic/woohaa/data/bg.png
new file mode 100644 (file)
index 0000000..5a5a55f
Binary files /dev/null and b/attic/woohaa/data/bg.png differ
diff --git a/attic/woohaa/data/busy.png b/attic/woohaa/data/busy.png
new file mode 100644 (file)
index 0000000..41765de
Binary files /dev/null and b/attic/woohaa/data/busy.png differ
diff --git a/attic/woohaa/data/default-thumb.png b/attic/woohaa/data/default-thumb.png
new file mode 100644 (file)
index 0000000..2e59381
Binary files /dev/null and b/attic/woohaa/data/default-thumb.png differ
diff --git a/attic/woohaa/data/header.svg b/attic/woohaa/data/header.svg
new file mode 100644 (file)
index 0000000..13c8133
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="995"
+   height="150"
+   id="svg3184"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/tmp"
+   sodipodi:docname="header.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs3186">
+    <filter
+       inkscape:collect="always"
+       id="filter3162">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="2.8275"
+         id="feGaussianBlur3164" />
+    </filter>
+    <linearGradient
+       id="linearGradient3156">
+      <stop
+         style="stop-color:#f3f3f3;stop-opacity:1;"
+         offset="0"
+         id="stop3158" />
+      <stop
+         style="stop-color:#f1f1f1;stop-opacity:1;"
+         offset="1"
+         id="stop3160" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3156"
+       id="linearGradient4643"
+       x1="331"
+       y1="159"
+       x2="331"
+       y2="29"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.9e-6,-7.1e-6)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.68888889"
+     inkscape:cx="325.64057"
+     inkscape:cy="72.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="995px"
+     height="150px"
+     inkscape:window-width="1014"
+     inkscape:window-height="690"
+     inkscape:window-x="0"
+     inkscape:window-y="25" />
+  <metadata
+     id="metadata3189">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:0.42857145;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.2;stroke-opacity:1;filter:url(#filter3162)"
+       d="M 26,4.9999989 C 13.812,4.9999989 4,14.811999 4,26.999999 L 4,94.999999 C 4,107.188 13.812,117 26,117 L 256.87098,115.54839 L 283.87097,142.54839 L 310.87097,115.54839 L 970,117 C 982.188,117 992,107.188 992,94.999999 L 992,26.999999 C 992,14.811999 982.188,4.9999989 970,4.9999989 L 26,4.9999989 z "
+       id="path3171"
+       sodipodi:nodetypes="cccccccccccc" />
+    <path
+       style="opacity:1;fill:url(#linearGradient4643);fill-opacity:1;stroke:#22424f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.2;stroke-opacity:0.30980392"
+       d="M 26,2.9262229 C 13.812,2.9262229 4,12.738227 4,24.926227 L 4,92.926229 C 4,105.11423 13.812,114.92623 26,114.92623 L 255.41937,114.92623 L 282.41936,141.92623 L 309.41936,114.92623 L 970,114.92623 C 982.188,114.92623 992,105.11423 992,92.926229 L 992,24.926227 C 992,12.738227 982.188,2.9262229 970,2.9262229 L 26,2.9262229 z "
+       id="rect2170"
+       sodipodi:nodetypes="cccccccccccc" />
+  </g>
+</svg>
diff --git a/attic/woohaa/data/play.svg b/attic/woohaa/data/play.svg
new file mode 100644 (file)
index 0000000..9c86f4b
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   width="283.465"
+   height="283.465"
+   viewBox="0 0 283.465 283.465"
+   overflow="visible"
+   enable-background="new 0 0 283.465 283.465"
+   xml:space="preserve"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   sodipodi:docname="play.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="/home/mallum/Projects/sato/icons-original"
+   sodipodi:modified="true"><metadata
+   id="metadata8"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+   id="defs6" /><sodipodi:namedview
+   inkscape:window-height="581"
+   inkscape:window-width="772"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   inkscape:zoom="1.3370258"
+   inkscape:cx="141.7325"
+   inkscape:cy="141.7325"
+   inkscape:window-x="102"
+   inkscape:window-y="43"
+   inkscape:current-layer="Layer_1" />
+<path
+   d="M271.465,0H12C5.373,0,0,5.373,0,12v259.465c0,6.627,5.373,12,12,12h259.465c6.627,0,12-5.373,12-12V12  C283.465,5.373,278.092,0,271.465,0z M193.301,154.301l-77.495,74.718c-7.412,7.146-13.476,4.57-13.476-5.725V59.318  c0-10.294,6.064-12.87,13.476-5.723l77.495,74.72C200.715,135.46,200.715,147.152,193.301,154.301z"
+   id="path3"
+   style="fill:#cccccc;fill-opacity:0.80000001" />
+</svg>
\ No newline at end of file
diff --git a/attic/woohaa/data/selected.svg b/attic/woohaa/data/selected.svg
new file mode 100644 (file)
index 0000000..bfc3156
--- /dev/null
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="995"
+   height="140"
+   id="svg3184"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docbase="/home/mallum/Projects/clutter-trunk/toys/woohaa"
+   sodipodi:docname="selected.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <defs
+     id="defs3186">
+    <linearGradient
+       id="linearGradient3135">
+      <stop
+         style="stop-color:#729fcf;stop-opacity:1;"
+         offset="0"
+         id="stop3137" />
+      <stop
+         style="stop-color:#729fcf;stop-opacity:0.80000001;"
+         offset="1"
+         id="stop3139" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3212">
+      <stop
+         style="stop-color:#729fc0;stop-opacity:0;"
+         offset="0"
+         id="stop3214" />
+      <stop
+         style="stop-color:#75f3d2;stop-opacity:1;"
+         offset="1"
+         id="stop3216" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3156">
+      <stop
+         style="stop-color:#f3f3f3;stop-opacity:1;"
+         offset="0"
+         id="stop3158" />
+      <stop
+         style="stop-color:#f1f1f1;stop-opacity:1;"
+         offset="1"
+         id="stop3160" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3212"
+       id="linearGradient3230"
+       x1="995.91223"
+       y1="89.919357"
+       x2="-0.23549497"
+       y2="89.919357"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3135"
+       id="linearGradient3141"
+       x1="497.17743"
+       y1="0.046080098"
+       x2="497.17743"
+       y2="140.59908"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.48711801"
+     inkscape:cx="344.96658"
+     inkscape:cy="72.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="995px"
+     height="140px"
+     inkscape:window-width="1014"
+     inkscape:window-height="690"
+     inkscape:window-x="0"
+     inkscape:window-y="25" />
+  <metadata
+     id="metadata3189">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;fill:url(#linearGradient3141);fill-opacity:1;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.2;stroke-opacity:0.1030303"
+       id="rect1872"
+       width="995.82947"
+       height="140.55299"
+       x="-0.73731583"
+       y="0.046080098"
+       rx="6.1586719"
+       ry="8.2115612" />
+  </g>
+</svg>
diff --git a/attic/woohaa/data/spinner.svg b/attic/woohaa/data/spinner.svg
new file mode 100644 (file)
index 0000000..57c5b96
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="457"
+   height="457"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   version="1.0"
+   sodipodi:docname="spinner.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="/home/mallum/Projects/clutter-trunk/toys/woohaa"
+   sodipodi:modified="true">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.35"
+     inkscape:cx="375"
+     inkscape:cy="508.81"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="457px"
+     height="457px"
+     inkscape:window-width="772"
+     inkscape:window-height="581"
+     inkscape:window-x="0"
+     inkscape:window-y="25" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:0.8;stroke:#cccccc;stroke-width:100;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.2;stroke-opacity:1"
+       id="path2160"
+       sodipodi:cx="401.42856"
+       sodipodi:cy="450.93362"
+       sodipodi:rx="178.57143"
+       sodipodi:ry="178.57143"
+       d="M 579.99998 450.93362 A 178.57143 178.57143 0 1 1  222.85713,450.93362 A 178.57143 178.57143 0 1 1  579.99998 450.93362 z"
+       transform="translate(-172.85713,-221.50505)" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#cccccc;stroke-width:100;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 231.42857,72.076472 L 231.42857,206.36218"
+       id="path3333" />
+  </g>
+</svg>
diff --git a/attic/woohaa/eggsequence.c b/attic/woohaa/eggsequence.c
new file mode 100644 (file)
index 0000000..979a512
--- /dev/null
@@ -0,0 +1,1709 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#include "eggsequence.h"
+
+typedef struct _EggSequenceNode EggSequenceNode;
+
+struct _EggSequence
+{
+    EggSequenceNode *   end_node;
+    GDestroyNotify      data_destroy_notify;
+    gboolean            access_prohibited;
+};
+
+struct _EggSequenceNode
+{
+    gint n_nodes;
+    EggSequenceNode *parent;    
+    EggSequenceNode *left;
+    EggSequenceNode *right;
+    gpointer data;             /* For the end node, this field points
+                                * to the sequence
+                                */
+};
+
+static EggSequenceNode *node_new           (gpointer           data);
+static EggSequenceNode *node_get_first     (EggSequenceNode   *node);
+static EggSequenceNode *node_get_last      (EggSequenceNode   *node);
+static EggSequenceNode *node_get_prev      (EggSequenceNode   *node);
+static EggSequenceNode *node_get_next      (EggSequenceNode   *node);
+static gint             node_get_pos       (EggSequenceNode   *node);
+static EggSequenceNode *node_get_by_pos    (EggSequenceNode   *node,
+                                           gint               pos);
+static EggSequenceNode *node_find_closest  (EggSequenceNode   *haystack,
+                                           EggSequenceNode   *needle,
+                                           EggSequenceNode   *end,
+                                           EggSequenceIterCompareFunc cmp,
+                                           gpointer           user_data);
+static gint             node_get_length    (EggSequenceNode   *node);
+static void             node_free          (EggSequenceNode   *node,
+                                           EggSequence       *seq);
+static void             node_cut           (EggSequenceNode   *split);
+static void             node_insert_after  (EggSequenceNode   *node,
+                                           EggSequenceNode   *second);
+static void             node_insert_before (EggSequenceNode   *node,
+                                           EggSequenceNode   *new);
+static void             node_unlink        (EggSequenceNode   *node);
+static void             node_insert_sorted (EggSequenceNode   *node,
+                                           EggSequenceNode   *new,
+                                           EggSequenceNode   *end,
+                                           EggSequenceIterCompareFunc cmp_func,
+                                           gpointer           cmp_data);
+
+static EggSequence *
+get_sequence (EggSequenceNode *node)
+{
+    return (EggSequence *)node_get_last (node)->data;
+}
+
+static void
+check_seq_access (EggSequence *seq)
+{
+    if (G_UNLIKELY (seq->access_prohibited))
+    {
+       g_warning ("Accessing a sequence while it is "
+                  "being sorted or searched is not allowed");
+    }
+}
+
+static void
+check_iter_access (EggSequenceIter *iter)
+{
+    check_seq_access (get_sequence (iter));
+}
+
+static gboolean
+is_end (EggSequenceIter *iter)
+{
+    EggSequence *seq = get_sequence (iter);
+    
+    return seq->end_node == iter;
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * egg_sequence_new:
+ * @data_destroy: A #GDestroyNotify function, or %NULL
+ * 
+ * Creates a new EggSequence. The @data_destroy function will be called
+ * on all items when the sequence is destroyed and on items that are
+ * removed from the sequence.
+ * 
+ * Return value: A new #EggSequence
+ * 
+ * Since: 2.14
+ **/
+EggSequence *
+egg_sequence_new (GDestroyNotify data_destroy)
+{
+    EggSequence *seq = g_new (EggSequence, 1);
+    seq->data_destroy_notify = data_destroy;
+    
+    seq->end_node = node_new (seq);
+    
+    seq->access_prohibited = FALSE;
+    
+    return seq;
+}
+
+/**
+ * egg_sequence_free:
+ * @seq: a #EggSequence
+ * 
+ * Frees the memory allocated for @seq. If @seq has a destroy notify
+ * function associated with it, that function is called on all items in
+ * @seq.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_free (EggSequence *seq)
+{
+    g_return_if_fail (seq != NULL);
+    
+    check_seq_access (seq);
+    
+    node_free (seq->end_node, seq);
+    
+    g_free (seq);
+}
+
+/**
+ * egg_sequence_foreach_range:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * @func: a #GFunc
+ * @user_data: user data passed to @func
+ * 
+ * Calls @func for each item in the range (@begin, @end) passing
+ * @user_data to the function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_foreach_range (EggSequenceIter *begin,
+                           EggSequenceIter *end,
+                           GFunc            func,
+                           gpointer         user_data)
+{
+    EggSequence *seq;
+    EggSequenceIter *iter;
+    
+    g_return_if_fail (func != NULL);
+    g_return_if_fail (begin != NULL);
+    g_return_if_fail (end != NULL);
+    
+    seq = get_sequence (begin);
+    
+    seq->access_prohibited = TRUE;
+    
+    iter = begin;
+    while (iter != end)
+    {
+       EggSequenceIter *next = node_get_next (iter);
+       
+       func (iter->data, user_data);
+       
+       iter = next;
+    }
+    
+    seq->access_prohibited = FALSE;
+}
+
+/**
+ * egg_sequence_foreach:
+ * @seq: a #EggSequence
+ * @func: the function to call for each item in @seq
+ * @data: user data passed to @func
+ * 
+ * Calls @func for each item in the sequence passing @user_data
+ * to the function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_foreach (EggSequence *seq,
+                     GFunc        func,
+                     gpointer     data)
+{
+    EggSequenceIter *begin, *end;
+    
+    check_seq_access (seq);
+    
+    begin = egg_sequence_get_begin_iter (seq);
+    end   = egg_sequence_get_end_iter (seq);
+    
+    egg_sequence_foreach_range (begin, end, func, data);
+}
+
+/**
+ * egg_sequence_range_get_midpoint:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Finds an iterator somewhere in the range (@begin, @end). This
+ * iterator will be close to the middle of the range, but is not
+ * guaranteed to be <emphasize>exactly</emphasize> in the middle.
+ *
+ * The @begin and @end iterators must both point to the same sequence and
+ * @begin must come before or be equal to @end in the sequence.
+ * 
+ * Return value: A #EggSequenceIter which is close to the middle of
+ * the (@begin, @end) range.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_range_get_midpoint (EggSequenceIter *begin,
+                                EggSequenceIter *end)
+{
+    int begin_pos, end_pos, mid_pos;
+    
+    g_return_val_if_fail (begin != NULL, NULL);
+    g_return_val_if_fail (end != NULL, NULL);
+    g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL);
+
+    begin_pos = node_get_pos (begin);
+    end_pos = node_get_pos (end);
+
+    g_return_val_if_fail (end_pos >= begin_pos, NULL);
+    
+    mid_pos = begin_pos + (end_pos - begin_pos) / 2;
+
+    return node_get_by_pos (begin, mid_pos);
+}
+
+/**
+ * egg_sequence_iter_compare:
+ * @a: a #EggSequenceIter
+ * @b: a #EggSequenceIter
+ * 
+ * Returns a negative number if @a comes before @b, 0 if they are equal,
+ * and a positive number if @a comes after @b.
+ *
+ * The @a and @b iterators must point into the same sequence.
+ * 
+ * Return value: A negative number if @a comes before @b, 0 if they are
+ * equal, and a positive number if @a comes after @b.
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_iter_compare (EggSequenceIter *a,
+                          EggSequenceIter *b)
+{
+    gint a_pos, b_pos;
+    
+    g_return_val_if_fail (a != NULL, 0);
+    g_return_val_if_fail (b != NULL, 0);
+    g_return_val_if_fail (get_sequence (a) == get_sequence (b), 0);
+    
+    check_iter_access (a);
+    check_iter_access (b);
+    
+    a_pos = node_get_pos (a);
+    b_pos = node_get_pos (b);
+    
+    if (a_pos == b_pos)
+       return 0;
+    else if (a_pos > b_pos)
+       return 1;
+    else
+       return -1;
+}
+
+/**
+ * egg_sequence_append:
+ * @seq: a #EggSequencePointer
+ * @data: the data for the new item
+ * 
+ * Adds a new item to the end of @seq.
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_append (EggSequence *seq,
+                    gpointer     data)
+{
+    EggSequenceNode *node;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    node = node_new (data);
+    node_insert_before (seq->end_node, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_prepend:
+ * @seq: a #EggSequence
+ * @data: the data for the new item
+ * 
+ * Adds a new item to the front of @seq
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_prepend (EggSequence *seq,
+                     gpointer     data)
+{
+    EggSequenceNode *node, *first;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    node = node_new (data);
+    first = node_get_first (seq->end_node);
+    
+    node_insert_before (first, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_insert_before:
+ * @iter: a #EggSequenceIter
+ * @data: the data for the new item
+ * 
+ * Inserts a new item just before the item pointed to by @iter.
+ * 
+ * Return value: An iterator pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_before (EggSequenceIter *iter,
+                           gpointer         data)
+{
+    EggSequenceNode *node;
+    
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    check_iter_access (iter);
+    
+    node = node_new (data);
+    
+    node_insert_before (iter, node);
+    
+    return node;
+}
+
+/**
+ * egg_sequence_remove:
+ * @iter: a #EggSequenceIter
+ * 
+ * Removes the item pointed to by @iter. It is an error to pass the
+ * end iterator to this function.
+ *
+ * If the sequnce has a data destroy function associated with it, this
+ * function is called on the data for the removed item.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_remove (EggSequenceIter *iter)
+{
+    EggSequence *seq;
+    
+    g_return_if_fail (iter != NULL);
+    g_return_if_fail (!is_end (iter));
+    
+    check_iter_access (iter);
+    
+    seq = get_sequence (iter); 
+    
+    node_unlink (iter);
+    node_free (iter, seq);
+}
+
+/**
+ * egg_sequence_remove_range:
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Removes all items in the (@begin, @end) range.
+ *
+ * If the sequence has a data destroy function associated with it, this
+ * function is called on the data for the removed items.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_remove_range (EggSequenceIter *begin,
+                          EggSequenceIter *end)
+{
+    g_return_if_fail (get_sequence (begin) == get_sequence (end));
+
+    check_iter_access (begin);
+    check_iter_access (end);
+    
+    egg_sequence_move_range (NULL, begin, end);
+}
+
+/**
+ * egg_sequence_move_range:
+ * @dest: a #EggSequenceIter
+ * @begin: a #EggSequenceIter
+ * @end: a #EggSequenceIter
+ * 
+ * Inserts the (@begin, @end) range at the destination pointed to by ptr.
+ * The @begin and @end iters must point into the same sequence. It is
+ * allowed for @dest to point to a different sequence than the one pointed
+ * into by @begin and @end.
+ * 
+ * If @dest is NULL, the range indicated by @begin and @end is
+ * removed from the sequence. If @dest iter points to a place within
+ * the (@begin, @end) range, the range does not move.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_move_range (EggSequenceIter *dest,
+                        EggSequenceIter *begin,
+                        EggSequenceIter *end)
+{
+    EggSequence *src_seq;
+    EggSequenceNode *first;
+    
+    g_return_if_fail (begin != NULL);
+    g_return_if_fail (end != NULL);
+    
+    check_iter_access (begin);
+    check_iter_access (end);
+    if (dest)
+       check_iter_access (dest);
+    
+    src_seq = get_sequence (begin);
+    
+    g_return_if_fail (src_seq == get_sequence (end));
+
+    /* Dest points to begin or end? */
+    if (dest == begin || dest == end)
+       return;
+
+    /* begin comes after end? */
+    if (egg_sequence_iter_compare (begin, end) >= 0)
+       return;
+
+    /* dest points somewhere in the (begin, end) range? */
+    if (dest && get_sequence (dest) == src_seq &&
+       egg_sequence_iter_compare (dest, begin) > 0 &&
+       egg_sequence_iter_compare (dest, end) < 0)
+    {
+       return;
+    }
+    
+    src_seq = get_sequence (begin);
+
+    first = node_get_first (begin);
+
+    node_cut (begin);
+
+    node_cut (end);
+
+    if (first != begin)
+       node_insert_after (node_get_last (first), end);
+
+    if (dest)
+       node_insert_before (dest, begin);
+    else
+       node_free (begin, src_seq);
+}
+
+typedef struct
+{
+    GCompareDataFunc    cmp_func;
+    gpointer           cmp_data;
+    EggSequenceNode    *end_node;
+} SortInfo;
+
+/* This function compares two iters using a normal compare
+ * function and user_data passed in in a SortInfo struct
+ */
+static gint
+iter_compare (EggSequenceIter *node1,
+             EggSequenceIter *node2,
+             gpointer data)
+{
+    const SortInfo *info = data;
+    gint retval;
+    
+    if (node1 == info->end_node)
+       return 1;
+    
+    if (node2 == info->end_node)
+       return -1;
+    
+    retval = info->cmp_func (node1->data, node2->data, info->cmp_data);
+    
+    return retval;
+}
+
+/**
+ * egg_sequence_sort:
+ * @seq: a #EggSequence
+ * @cmp_func: the #GCompareDataFunc used to sort @seq. This function is
+ *       passed two items of @seq and should return 0 if they are equal,
+ *       a negative value fi the first comes before the second, and a
+ *       positive value if the second comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ * 
+ * Sorts @seq using @cmp_func.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort (EggSequence      *seq,
+                  GCompareDataFunc  cmp_func,
+                  gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, seq->end_node };
+    
+    check_seq_access (seq);
+    
+    egg_sequence_sort_iter (seq, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_insert_sorted:
+ * @seq: a #EggSequence
+ * @data: the data to insert
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ *
+ * Inserts @data into @queue using @func to determine the new position.
+ * @seq must already be sorted according to @cmp_func; otherwise the
+ * new position of is undefined.
+ *
+ * Return value: A #EggSequenceIter pointing to the new item.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_sorted (EggSequence       *seq,
+                           gpointer           data,
+                           GCompareDataFunc   cmp_func,
+                           gpointer           cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    g_return_val_if_fail (cmp_func != NULL, NULL);
+    
+    info.end_node = seq->end_node;
+    check_seq_access (seq);
+    
+    return egg_sequence_insert_sorted_iter (seq, data, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_sort_changed:
+ * @iter: A #EggSequenceIter
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ *
+ * Moves the data pointed to a new position as indicated by @cmp_func. This
+ * function should be called for items in a sequence already sorted according
+ * to @cmp_func whenever some aspect of an item changes so that @cmp_func
+ * may return different values for that item.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_changed (EggSequenceIter  *iter,
+                          GCompareDataFunc  cmp_func,
+                          gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_if_fail (!is_end (iter));
+    
+    info.end_node = get_sequence (iter)->end_node;
+    check_iter_access (iter);
+    
+    egg_sequence_sort_changed_iter (iter, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_search:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #GCompareDataFunc used to compare items in the queue. It
+ *     is called with two items of the @seq and @user_data. It should
+ *     return 0 if the items are equal, a negative value if the first
+ *     item comes before the second, and a positive value if the second
+ *     item comes before the first.
+ * @cmp_data: user data passed to @cmp_func.
+ * 
+ * Returns an iterator pointing to the position where @data would
+ * be inserted according to @cmp_func and @cmp_data.
+ * 
+ * Return value: An #EggSequenceIter pointing to the position where @data
+ * would have been inserted according to @cmp_func and @cmp_data.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_search (EggSequence      *seq,
+                    gpointer          data,
+                    GCompareDataFunc  cmp_func,
+                    gpointer          cmp_data)
+{
+    SortInfo info = { cmp_func, cmp_data, NULL };
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    info.end_node = seq->end_node;
+    check_seq_access (seq);
+    
+    return egg_sequence_search_iter (seq, data, iter_compare, &info);
+}
+
+/**
+ * egg_sequence_sort_iter:
+ * @seq: a #EggSequence
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_sort(), but uses a #EggSequenceIterCompareFunc instead
+ * of a GCompareDataFunc as the compare function
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_iter (EggSequence                *seq,
+                       EggSequenceIterCompareFunc  cmp_func,
+                       gpointer                    cmp_data)
+{
+    EggSequence *tmp;
+    EggSequenceNode *begin, *end;
+    
+    g_return_if_fail (seq != NULL);
+    g_return_if_fail (cmp_func != NULL);
+    
+    check_seq_access (seq);
+    
+    begin = egg_sequence_get_begin_iter (seq);
+    end   = egg_sequence_get_end_iter (seq);
+    
+    tmp = egg_sequence_new (NULL);
+    
+    egg_sequence_move_range (egg_sequence_get_begin_iter (tmp), begin, end);
+    
+    tmp->access_prohibited = TRUE;
+    seq->access_prohibited = TRUE;
+    
+    while (egg_sequence_get_length (tmp) > 0)
+    {
+       EggSequenceNode *node = egg_sequence_get_begin_iter (tmp);
+       
+       node_unlink (node);
+       
+       node_insert_sorted (seq->end_node, node, seq->end_node, cmp_func, cmp_data);
+    }
+    
+    tmp->access_prohibited = FALSE;
+    seq->access_prohibited = FALSE;
+    
+    egg_sequence_free (tmp);
+}
+
+/**
+ * egg_sequence_sort_changed_iter:
+ * @iter: a #EggSequenceIter
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_sort_changed(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_sort_changed_iter (EggSequenceIter            *iter,
+                               EggSequenceIterCompareFunc  iter_cmp,
+                               gpointer                    cmp_data)
+{
+    EggSequence *seq;
+    EggSequenceIter *next, *prev;
+    
+    g_return_if_fail (!is_end (iter));
+    
+    check_iter_access (iter);
+
+    /* If one of the neighbours is equal to iter, then
+     * don't move it. This ensures that sort_changed() is
+     * a stable operation.
+     */
+
+    next = node_get_next (iter);
+    prev = node_get_prev (iter);
+
+    if (prev != iter && iter_cmp (prev, iter, cmp_data) == 0)
+       return;
+
+    if (!is_end (next) && iter_cmp (next, iter, cmp_data) == 0)
+       return;
+    
+    seq = get_sequence (iter);
+    
+    seq->access_prohibited = TRUE;
+    
+    node_unlink (iter);
+    node_insert_sorted (seq->end_node, iter, seq->end_node, iter_cmp, cmp_data);
+    
+    seq->access_prohibited = FALSE;
+}
+
+/**
+ * egg_sequence_insert_sorted_iter:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ * 
+ * Like egg_sequence_insert_sorted(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Return value: A #EggSequenceIter pointing to the new item
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_insert_sorted_iter   (EggSequence                *seq,
+                                  gpointer                    data,
+                                  EggSequenceIterCompareFunc  iter_cmp,
+                                  gpointer                    cmp_data)
+{
+    EggSequenceNode *new_node;
+    EggSequence *tmp_seq;
+    
+    check_seq_access (seq);
+
+    /* Create a new temporary sequence and put the new node into
+     * that. The reason for this is that the user compare function
+     * will be called with the new node, and if it dereferences, 
+     * "is_end" will be called on it. But that will crash if the
+     * node is not actually in a sequence.
+     *
+     * node_insert_sorted() makes sure the node is unlinked before
+     * is is inserted.
+     *
+     * The reason we need the "iter" versions at all is that that
+     * is the only kind of compare functions GtkTreeView can use.
+     */
+    tmp_seq = egg_sequence_new (NULL);
+    new_node = egg_sequence_append (tmp_seq, data);
+
+    node_insert_sorted (seq->end_node, new_node,
+                       seq->end_node, iter_cmp, cmp_data);
+
+    egg_sequence_free (tmp_seq);
+    
+    return new_node;
+}
+
+/**
+ * egg_sequence_search_iter:
+ * @seq: a #EggSequence
+ * @data: data for the new item
+ * @cmp_func: the #EggSequenceItercompare used to compare iterators in the
+ *     sequence. It is called with two iterators pointing into @seq. It should
+ *     return 0 if the iterators are equal, a negative value if the first
+ *     iterator comes before the second, and a positive value if the second
+ *     iterator comes before the first.
+ * @cmp_data: user data passed to @cmp_func
+ *
+ * Like egg_sequence_search(), but uses
+ * a #EggSequenceIterCompareFunc instead of a #GCompareDataFunc as
+ * the compare function.
+ * 
+ * Return value: A #EggSequenceIter pointing to the position in @seq
+ * where @data would have been inserted according to @cmp_func and @cmp_data.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_search_iter (EggSequence                *seq,
+                         gpointer                    data,
+                         EggSequenceIterCompareFunc  cmp_func,
+                         gpointer                    cmp_data)
+{
+    EggSequenceNode *node;
+    EggSequenceNode *dummy;
+    
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    check_seq_access (seq);
+    
+    seq->access_prohibited = TRUE;
+
+    dummy = node_new (data);
+    
+    node = node_find_closest (seq->end_node, dummy,
+                             seq->end_node, cmp_func, cmp_data);
+
+    node_free (dummy, NULL);
+    
+    seq->access_prohibited = FALSE;
+    
+    return node;
+}
+
+/**
+ * egg_sequence_iter_get_sequence:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the #EggSequence that @iter points into.
+ * 
+ * Return value: The #EggSequence that @iter points into.
+ * 
+ * Since: 2.14
+ **/
+EggSequence *
+egg_sequence_iter_get_sequence (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return get_sequence (iter);
+}
+
+/**
+ * egg_sequence_get:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the data that @iter points to.
+ * 
+ * Return value: The data that @iter points to
+ * 
+ * Since: 2.14
+ **/
+gpointer
+egg_sequence_get (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    g_return_val_if_fail (!is_end (iter), NULL);
+    
+    return iter->data;
+}
+
+/**
+ * egg_sequence_set:
+ * @iter: a #EggSequenceIter
+ * @data: new data for the item
+ * 
+ * Changes the data for the item pointed to by @iter to be @data. If
+ * the sequence has a data destroy function associated with it, that
+ * function is called on the existing data that @iter pointed to.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_set (EggSequenceIter *iter,
+                 gpointer         data)
+{
+    EggSequence *seq;
+    
+    g_return_if_fail (iter != NULL);
+    g_return_if_fail (!is_end (iter));
+    
+    seq = get_sequence (iter);
+
+    /* If @data is identical to iter->data, it is destroyed
+     * here. This will work right in case of ref-counted objects. Also
+     * it is similar to what ghashtables do.
+     *
+     * For non-refcounted data it's a little less convenient, but
+     * code relying on self-setting not destroying would be
+     * pretty dubious anyway ...
+     */
+    
+    if (seq->data_destroy_notify)
+       seq->data_destroy_notify (iter->data);
+    
+    iter->data = data;
+}
+
+/**
+ * egg_sequence_get_length:
+ * @seq: a #EggSequence
+ * 
+ * Returns the length of @seq
+ * 
+ * Return value: The length of @seq
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_get_length (EggSequence *seq)
+{
+    return node_get_length (seq->end_node) - 1;
+}
+
+/**
+ * egg_sequence_get_end_iter:
+ * @seq: a #EggSequence 
+ * 
+ * Returns the end iterator for @seg
+ * 
+ * Return value: The end iterator for @seq
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_end_iter (EggSequence *seq)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    g_assert (is_end (seq->end_node));
+    
+    return seq->end_node;
+}
+
+/**
+ * egg_sequence_get_begin_iter:
+ * @seq: a #EggSequence
+ * 
+ * Returns the begin iterator for @seq.
+ * 
+ * Return value: The begin iterator for @seq.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_begin_iter (EggSequence *seq)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    return node_get_first (seq->end_node);
+}
+
+static int
+clamp_position (EggSequence *seq,
+               int          pos)
+{
+    gint len = egg_sequence_get_length (seq);
+    
+    if (pos > len || pos < 0)
+       pos = len;
+    
+    return pos;
+}
+
+/*
+ * if pos > number of items or -1, will return end pointer
+ */
+/**
+ * egg_sequence_get_iter_at_pos:
+ * @seq: a #EggSequence
+ * @pos: a position in @seq, or -1 for the end.
+ * 
+ * Returns the iterator as position @pos. If @pos is negative or larger
+ * than the number of items in @seq, the end iterator is returned.
+ * 
+ * Return value: The #EggSequenceIter at position @pos
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_get_iter_at_pos (EggSequence *seq,
+                             gint         pos)
+{
+    g_return_val_if_fail (seq != NULL, NULL);
+    
+    pos = clamp_position (seq, pos);
+    
+    return node_get_by_pos (seq->end_node, pos);
+}
+
+/**
+ * egg_sequence_move:
+ * @src: a #EggSequenceIter pointing to the item to move
+ * @dest: a #EggSequenceIter pointing to the position to which
+ *        the item is moved.
+ *
+ * Move the item pointed to by @src to the position indicated by @dest.
+ * After calling this function @dest will point to the position immediately
+ * after @src.
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_move (EggSequenceIter *src,
+                  EggSequenceIter *dest)
+{
+    g_return_if_fail (src != NULL);
+    g_return_if_fail (dest != NULL);
+    g_return_if_fail (!is_end (src));
+    
+    if (src == dest)
+       return;
+    
+    node_unlink (src);
+    node_insert_before (dest, src);
+}
+
+/* EggSequenceIter */
+
+/**
+ * egg_sequence_iter_is_end:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns whether @iter is the end iterator
+ * 
+ * Return value: Whether @iter is the end iterator.
+ * 
+ * Since: 2.14
+ **/
+gboolean
+egg_sequence_iter_is_end (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, FALSE);
+    
+    return is_end (iter);
+}
+
+/**
+ * egg_sequence_iter_is_begin:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns whether @iter is the begin iterator
+ * 
+ * Return value: Whether @iter is the begin iterator
+ * 
+ * Since: 2.14
+ **/
+gboolean
+egg_sequence_iter_is_begin (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, FALSE);
+    
+    return (node_get_prev (iter) == iter);
+}
+
+/**
+ * egg_sequence_iter_get_position:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns the position of @iter
+ * 
+ * Return value: The position of @iter
+ * 
+ * Since: 2.14
+ **/
+gint
+egg_sequence_iter_get_position (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, -1);
+    
+    return node_get_pos (iter);
+}
+
+/**
+ * egg_sequence_iter_next:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns an iterator pointing to the next position after @iter. If
+ * @iter is the end iterator, the end iterator is returned.
+ * 
+ * Return value: A #EggSequenceIter pointing to the next position after @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_next (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return node_get_next (iter);
+}
+
+/**
+ * egg_sequence_iter_prev:
+ * @iter: a #EggSequenceIter
+ * 
+ * Returns an iterator pointing to the previous position before @iter. If
+ * @iter is the begin iterator, the begin iterator is returned.
+ * 
+ * Return value: A #EggSequenceIter pointing to the previous position before
+ * @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_prev (EggSequenceIter *iter)
+{
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    return node_get_prev (iter);
+}
+
+/**
+ * egg_sequence_iter_move:
+ * @iter: a #EggSequenceIter
+ * @delta: A positive or negative number indicating how many positions away
+ *    from @iter the returned #EggSequenceIter will be.
+ *
+ * Returns the #EggSequenceIter which is @delta positions away from @iter.
+ * If @iter is closer than -@delta positions to the beginning of the sequence,
+ * the begin iterator is returned. If @iter is closer than @delta positions
+ * to the end of the queue, the end iterator is returned.
+ *
+ * Return value: a #EggSequenceIter which is @delta positions away from @iter.
+ * 
+ * Since: 2.14
+ **/
+EggSequenceIter *
+egg_sequence_iter_move (EggSequenceIter *iter,
+                       gint             delta)
+{
+    gint new_pos;
+    
+    g_return_val_if_fail (iter != NULL, NULL);
+    
+    new_pos = node_get_pos (iter) + delta;
+    
+    new_pos = clamp_position (get_sequence (iter), new_pos);
+    
+    return node_get_by_pos (iter, new_pos);
+}
+
+/**
+ * egg_sequence_swap:
+ * @a: a #EggSequenceIter
+ * @b: a #EggSequenceIter
+ * 
+ * Swaps the items pointed to by @a and @b
+ * 
+ * Since: 2.14
+ **/
+void
+egg_sequence_swap (EggSequenceIter *a,
+                  EggSequenceIter *b)
+{
+    EggSequenceNode *leftmost, *rightmost, *rightmost_next;
+    int a_pos, b_pos;
+    
+    g_return_if_fail (!egg_sequence_iter_is_end (a));
+    g_return_if_fail (!egg_sequence_iter_is_end (b));
+    
+    if (a == b)
+       return;
+    
+    a_pos = egg_sequence_iter_get_position (a);
+    b_pos = egg_sequence_iter_get_position (b);
+    
+    if (a_pos > b_pos)
+    {
+       leftmost = b;
+       rightmost = a;
+    }
+    else
+    {
+       leftmost = a;
+       rightmost = b;
+    }
+    
+    rightmost_next = node_get_next (rightmost);
+    
+    /* Situation is now like this:
+     *
+     *     ..., leftmost, ......., rightmost, rightmost_next, ...
+     *
+     */
+    egg_sequence_move (rightmost, leftmost);
+    egg_sequence_move (leftmost, rightmost_next);
+}
+
+/*
+ * Implementation of the node_* methods
+ */
+static void
+node_update_fields (EggSequenceNode *node)
+{
+    g_assert (node != NULL);
+    
+    node->n_nodes = 1;
+    
+    if (node->left)
+       node->n_nodes += node->left->n_nodes;
+    
+    if (node->right)
+       node->n_nodes += node->right->n_nodes;
+}
+
+#define NODE_LEFT_CHILD(n)  (((n)->parent) && ((n)->parent->left) == (n))
+#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
+
+static void
+node_rotate (EggSequenceNode *node)
+{
+    EggSequenceNode *tmp, *old;
+    
+    g_assert (node->parent);
+    g_assert (node->parent != node);
+    
+    if (NODE_LEFT_CHILD (node))
+    {
+       /* rotate right */
+       tmp = node->right;
+       
+       node->right = node->parent;
+       node->parent = node->parent->parent;
+       if (node->parent)
+       {
+           if (node->parent->left == node->right)
+               node->parent->left = node;
+           else
+               node->parent->right = node;
+       }
+       
+       g_assert (node->right);
+       
+       node->right->parent = node;
+       node->right->left = tmp;
+       
+       if (node->right->left)
+           node->right->left->parent = node->right;
+       
+       old = node->right;
+    }
+    else
+    {
+       /* rotate left */
+       tmp = node->left;
+       
+       node->left = node->parent;
+       node->parent = node->parent->parent;
+       if (node->parent)
+       {
+           if (node->parent->right == node->left)
+               node->parent->right = node;
+           else
+               node->parent->left = node;
+       }
+       
+       g_assert (node->left);
+       
+       node->left->parent = node;
+       node->left->right = tmp;
+       
+       if (node->left->right)
+           node->left->right->parent = node->left;
+       
+       old = node->left;
+    }
+    
+    node_update_fields (old);
+    node_update_fields (node);
+}
+
+static EggSequenceNode *
+splay (EggSequenceNode *node)
+{
+    while (node->parent)
+    {
+       if (!node->parent->parent)
+       {
+           /* zig */
+           node_rotate (node);
+       }
+       else if ((NODE_LEFT_CHILD (node) && NODE_LEFT_CHILD (node->parent)) ||
+                (NODE_RIGHT_CHILD (node) && NODE_RIGHT_CHILD (node->parent)))
+       {
+           /* zig-zig */
+           node_rotate (node->parent);
+           node_rotate (node);
+       }
+       else
+       {
+           /* zig-zag */
+           node_rotate (node);
+           node_rotate (node);
+       }
+    }
+    
+    return node;
+}
+
+static EggSequenceNode *
+node_new (gpointer data)
+{
+    EggSequenceNode *node = g_slice_new0 (EggSequenceNode);
+
+    node->parent = NULL;
+    node->parent = NULL;
+    node->left = NULL;
+    node->right = NULL;
+    
+    node->data = data;
+    node->n_nodes = 1;
+    
+    return node;
+}
+
+static EggSequenceNode *
+find_min (EggSequenceNode *node)
+{
+    splay (node);
+    
+    while (node->left)
+       node = node->left;
+    
+    return node;
+}
+
+static EggSequenceNode *
+find_max (EggSequenceNode *node)
+{
+    splay (node);
+    
+    while (node->right)
+       node = node->right;
+    
+    return node;
+}
+
+static EggSequenceNode *
+node_get_first   (EggSequenceNode    *node)
+{
+    return splay (find_min (node));
+}
+
+static EggSequenceNode *
+node_get_last    (EggSequenceNode    *node)
+{
+    return splay (find_max (node));
+}
+
+static gint
+get_n_nodes (EggSequenceNode *node)
+{
+    if (node)
+       return node->n_nodes;
+    else
+       return 0;
+}
+
+static EggSequenceNode *
+node_get_by_pos  (EggSequenceNode *node,
+                 gint             pos)
+{
+    gint i;
+    
+    g_assert (node != NULL);
+    
+    splay (node);
+    
+    while ((i = get_n_nodes (node->left)) != pos)
+    {
+       if (i < pos)
+       {
+           node = node->right;
+           pos -= (i + 1);
+       }
+       else
+       {
+           node = node->left;
+           g_assert (node->parent != NULL);
+       }
+    }
+    
+    return splay (node);
+}
+
+static EggSequenceNode *
+node_get_prev  (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    if (node->left)
+    {
+       node = node->left;
+       while (node->right)
+           node = node->right;
+    }
+    
+    return splay (node);
+}
+
+static EggSequenceNode *
+node_get_next         (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    if (node->right)
+    {
+       node = node->right;
+       while (node->left)
+           node = node->left;
+    }
+    
+    return splay (node);
+}
+
+static gint
+node_get_pos (EggSequenceNode    *node)
+{
+    splay (node);
+    
+    return get_n_nodes (node->left);
+}
+
+/* Return closest node _strictly_ bigger than @needle (does always exist because
+ * there is an end_node)
+ */
+static EggSequenceNode *
+node_find_closest (EggSequenceNode           *haystack,
+                  EggSequenceNode            *needle,
+                  EggSequenceNode            *end,
+                  EggSequenceIterCompareFunc  cmp_func,
+                  gpointer                    cmp_data)
+{
+    EggSequenceNode *best;
+    gint c;
+    
+    g_assert (haystack);
+    
+    haystack = splay (haystack);
+    
+    do
+    {
+       best = haystack;
+
+       /* cmp_func can't be called with the end node (it may be user-supplied) */
+       if (haystack == end)
+           c = 1;
+       else
+           c = cmp_func (haystack, needle, cmp_data);
+
+       /* In the following we don't break even if c == 0. Instaed we go on searching
+        * along the 'bigger' nodes, so that we find the last one that is equal
+        * to the needle.
+        */
+       if (c > 0)
+           haystack = haystack->left;
+       else
+           haystack = haystack->right;
+    }
+    while (haystack != NULL);
+    
+     /* If the best node is smaller or equal to the data, then move one step
+     * to the right to make sure the best one is strictly bigger than the data
+     */
+    if (best != end && c <= 0)
+       best = node_get_next (best);
+    
+    return best;
+}
+
+static void
+node_free (EggSequenceNode *node,
+          EggSequence     *seq)
+{
+    GQueue *stack = g_queue_new ();
+
+    splay (node);
+    
+    g_queue_push_head (stack, node);
+    
+    while (!g_queue_is_empty (stack))
+    {
+       node = g_queue_pop_head (stack);
+       
+       if (node)
+       {
+           g_queue_push_head (stack, node->right);
+           g_queue_push_head (stack, node->left);
+           
+           if (seq && seq->data_destroy_notify && node != seq->end_node)
+               seq->data_destroy_notify (node->data);
+           
+           g_slice_free (EggSequenceNode, node);
+       }
+    }
+    
+    g_queue_free (stack);
+}
+
+/* Splits into two trees, left and right. 
+ * @node will be part of the right tree
+ */
+
+static void
+node_cut (EggSequenceNode *node)
+{
+    splay (node);
+
+    g_assert (node->parent == NULL);
+    
+    if (node->left)
+       node->left->parent = NULL;
+    
+    node->left = NULL;
+    node_update_fields (node);
+}
+
+static void
+node_insert_before (EggSequenceNode *node,
+                   EggSequenceNode *new)
+{
+    g_assert (node != NULL);
+    g_assert (new != NULL);
+    
+    splay (node);
+    
+    new = splay (find_min (new));
+    g_assert (new->left == NULL);
+    
+    if (node->left)
+       node->left->parent = new;
+    
+    new->left = node->left;
+    new->parent = node;
+    
+    node->left = new;
+    
+    node_update_fields (new);
+    node_update_fields (node);
+}
+
+static void
+node_insert_after (EggSequenceNode *node,
+                  EggSequenceNode *new)
+{
+    g_assert (node != NULL);
+    g_assert (new != NULL);
+    
+    splay (node);
+    
+    new = splay (find_max (new));
+    g_assert (new->right == NULL);
+    g_assert (node->parent == NULL);
+    
+    if (node->right)
+       node->right->parent = new;
+    
+    new->right = node->right;
+    new->parent = node;
+    
+    node->right = new;
+    
+    node_update_fields (new);
+    node_update_fields (node);
+}
+
+static gint
+node_get_length (EggSequenceNode    *node)
+{
+    g_assert (node != NULL);
+    
+    splay (node);
+    return node->n_nodes;
+}
+
+static void
+node_unlink (EggSequenceNode *node)
+{
+    EggSequenceNode *right, *left;
+    
+    splay (node);
+    
+    left = node->left;
+    right = node->right;
+    
+    node->parent = node->left = node->right = NULL;
+    node_update_fields (node);
+    
+    if (right)
+    {
+       right->parent = NULL;
+       
+       right = node_get_first (right);
+       g_assert (right->left == NULL);
+       
+       right->left = left;
+       if (left)
+       {
+           left->parent = right;
+           node_update_fields (right);
+       }
+    }
+    else if (left)
+    {
+       left->parent = NULL;
+    }
+}
+
+static void
+node_insert_sorted (EggSequenceNode *node,
+                   EggSequenceNode *new,
+                   EggSequenceNode *end,
+                   EggSequenceIterCompareFunc cmp_func,
+                   gpointer cmp_data)
+{
+    EggSequenceNode *closest;
+    
+    closest = node_find_closest (node, new, end, cmp_func, cmp_data);
+
+    node_unlink (new);
+    
+    node_insert_before (closest, new);
+}
+
+static gint
+node_calc_height (EggSequenceNode *node)
+{
+    gint left_height;
+    gint right_height;
+    
+    if (node)
+    {
+       left_height = 0;
+       right_height = 0;
+       
+       if (node->left)
+           left_height = node_calc_height (node->left);
+       
+       if (node->right)
+           right_height = node_calc_height (node->right);
+       
+       return MAX (left_height, right_height) + 1;
+    }
+    
+    return 0;
+}
+
+/* Self test functions */
+
+static void
+check_node (EggSequenceNode *node)
+{
+    if (node)
+    {
+       g_assert (node->parent != node);
+       g_assert (node->n_nodes ==
+                 1 + get_n_nodes (node->left) + get_n_nodes (node->right));
+       check_node (node->left);
+       check_node (node->right);
+    }
+}
+
+void
+egg_sequence_self_test (EggSequence *seq)
+{
+    EggSequenceNode *node = splay (seq->end_node);
+    
+    check_node (node);
+}
diff --git a/attic/woohaa/eggsequence.h b/attic/woohaa/eggsequence.h
new file mode 100644 (file)
index 0000000..107db47
--- /dev/null
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Soeren Sandmann (sandmann@daimi.au.dk)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __GSEQUENCE_H__
+#define __GSEQUENCE_H__
+
+typedef struct _EggSequence      EggSequence;
+typedef struct _EggSequenceNode  EggSequenceIter;
+
+
+
+typedef gint (* EggSequenceIterCompareFunc) (EggSequenceIter *a,
+                                            EggSequenceIter *b,
+                                            gpointer         data);
+
+/* EggSequence */
+EggSequence *   egg_sequence_new                  (GDestroyNotify          data_destroy);
+void            egg_sequence_free                 (EggSequence            *seq);
+gint            egg_sequence_get_length           (EggSequence            *seq);
+void           egg_sequence_foreach              (EggSequence            *seq,
+                                                  GFunc                   func,
+                                                  gpointer                data);
+void           egg_sequence_foreach_range        (EggSequenceIter        *begin,
+                                                  EggSequenceIter        *end,
+                                                  GFunc                   func,
+                                                  gpointer                data);
+void            egg_sequence_sort                 (EggSequence            *seq,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_iter            (EggSequence            *seq,
+                                                  EggSequenceIterCompareFunc      cmp_func,
+                                                  gpointer                cmp_data);
+
+/* Getting iters */
+EggSequenceIter *egg_sequence_get_begin_iter       (EggSequence            *seq);
+EggSequenceIter *egg_sequence_get_end_iter         (EggSequence            *seq);
+EggSequenceIter *egg_sequence_get_iter_at_pos      (EggSequence            *seq,
+                                                   gint                    pos);
+EggSequenceIter *egg_sequence_append               (EggSequence            *seq,
+                                                  gpointer                data);
+EggSequenceIter *egg_sequence_prepend              (EggSequence            *seq,
+                                                  gpointer                data);
+EggSequenceIter *egg_sequence_insert_before        (EggSequenceIter *        iter,
+                                                  gpointer                data);
+void            egg_sequence_move                (EggSequenceIter *       src,
+                                                  EggSequenceIter *       dest);
+void            egg_sequence_swap                (EggSequenceIter *       a,
+                                                  EggSequenceIter *       b);
+EggSequenceIter *egg_sequence_insert_sorted        (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+EggSequenceIter *egg_sequence_insert_sorted_iter   (EggSequence                  *seq,
+                                                  gpointer                data,
+                                                  EggSequenceIterCompareFunc      iter_cmp,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_changed         (EggSequenceIter *       iter,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+void           egg_sequence_sort_changed_iter    (EggSequenceIter *       iter,
+                                                  EggSequenceIterCompareFunc      iter_cmp,
+                                                  gpointer                cmp_data);
+
+void            egg_sequence_remove               (EggSequenceIter *        iter);
+void            egg_sequence_remove_range         (EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+void            egg_sequence_move_range           (EggSequenceIter *        iter,
+                                                  EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+EggSequenceIter *egg_sequence_search               (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  GCompareDataFunc        cmp_func,
+                                                  gpointer                cmp_data);
+EggSequenceIter *egg_sequence_search_iter         (EggSequence            *seq,
+                                                  gpointer                data,
+                                                  EggSequenceIterCompareFunc     cmp_func,
+                                                  gpointer                cmp_data);
+
+/* dereferencing */
+gpointer        egg_sequence_get                  (EggSequenceIter *        iter);
+void           egg_sequence_set                  (EggSequenceIter *       iter,
+                                                  gpointer                data);
+
+
+/* operations on EggSequenceIter * */
+gboolean        egg_sequence_iter_is_begin        (EggSequenceIter *        iter);
+gboolean        egg_sequence_iter_is_end          (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_next            (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_prev            (EggSequenceIter *        iter);
+gint            egg_sequence_iter_get_position    (EggSequenceIter *        iter);
+EggSequenceIter *egg_sequence_iter_move            (EggSequenceIter *        iter,
+                                                  gint                    leap);
+EggSequence *   egg_sequence_iter_get_sequence    (EggSequenceIter *        iter);
+
+
+/* search */
+gint            egg_sequence_iter_compare         (EggSequenceIter *a,
+                                                  EggSequenceIter *        b);
+EggSequenceIter *egg_sequence_range_get_midpoint   (EggSequenceIter *        begin,
+                                                  EggSequenceIter *        end);
+
+#endif /* __GSEQUENCE_H__ */
diff --git a/attic/woohaa/totem-resources.c b/attic/woohaa/totem-resources.c
new file mode 100644 (file)
index 0000000..4758fa6
--- /dev/null
@@ -0,0 +1,121 @@
+/* 
+ * Copyright (C) 2007 Bastien Nocera <hadess@hadess.net>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gthread.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+
+#include "totem-resources.h"
+
+#define MAX_HELPER_MEMORY (256 * 1024 * 1024)  /* 256 MB */
+#define MAX_HELPER_SECONDS (15)                        /* 15 seconds */
+#define DEFAULT_SLEEP_TIME (30 * G_USEC_PER_SEC) /* 30 seconds */
+
+static guint sleep_time = DEFAULT_SLEEP_TIME;
+static gboolean finished = TRUE;
+
+static void
+set_resource_limits (const char *input)
+{
+       struct rlimit limit;
+       struct stat buf;
+       rlim_t max;
+
+       g_return_if_fail (input != NULL);
+
+       max = MAX_HELPER_MEMORY;
+
+       /* Set the maximum virtual size depending on the size
+        * of the file to process, as we wouldn't be able to
+        * mmap it otherwise */
+       if (g_stat (input, &buf) == 0) {
+               max = MAX_HELPER_MEMORY + buf.st_size;
+       } else if (g_str_has_prefix (input, "file://") != FALSE) {
+               char *file;
+               file = g_filename_from_uri (input, NULL, NULL);
+               if (file != NULL && g_stat (file, &buf) == 0)
+                       max = MAX_HELPER_MEMORY + buf.st_size;
+               g_free (file);
+       }
+
+       limit.rlim_cur = max;
+       limit.rlim_max = max;
+
+       setrlimit (RLIMIT_DATA, &limit);
+
+       limit.rlim_cur = MAX_HELPER_SECONDS;
+       limit.rlim_max = MAX_HELPER_SECONDS;
+       setrlimit (RLIMIT_CPU, &limit);
+}
+
+static gpointer
+time_monitor (gpointer data)
+{
+       const char *app_name;
+
+       g_usleep (sleep_time);
+
+       if (finished != FALSE)
+               g_thread_exit (NULL);
+
+       app_name = g_get_application_name ();
+       if (app_name == NULL)
+               app_name = g_get_prgname ();
+       g_print ("%s couln't process file: '%s'\n"
+                "Reason: Took too much time to process.\n",
+                app_name,
+                (const char *) data);
+
+       exit (0);
+}
+
+void
+totem_resources_monitor_start (const char *input, guint wall_clock_time)
+{
+       set_resource_limits (input);
+
+       if (wall_clock_time != 0)
+               sleep_time = wall_clock_time;
+
+       finished = FALSE;
+       g_thread_create (time_monitor, (gpointer) input, FALSE, NULL);
+}
+
+void
+totem_resources_monitor_stop (void)
+{
+       finished = TRUE;
+}
+
diff --git a/attic/woohaa/totem-resources.h b/attic/woohaa/totem-resources.h
new file mode 100644 (file)
index 0000000..d1c0848
--- /dev/null
@@ -0,0 +1,33 @@
+/* 
+ * Copyright (C) 2007 Bastien Nocera <hadess@hadess.net>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ *
+ */
+
+#include <glib.h>
+
+void totem_resources_monitor_start     (const char *input,
+                                        guint wall_clock_time);
+void totem_resources_monitor_stop      (void);
+
diff --git a/attic/woohaa/util.c b/attic/woohaa/util.c
new file mode 100644 (file)
index 0000000..dd7d098
--- /dev/null
@@ -0,0 +1,76 @@
+#include "util.h"
+#include "math.h"
+
+#include <gdk/gdk.h>
+
+ClutterActor*
+util_actor_from_file (const gchar *path, int width, int height)
+{
+  ClutterActor  *actor;
+
+  actor = clutter_texture_new_from_file (path, NULL);
+  if (actor)
+    clutter_actor_set_size (actor, width, height);
+
+  return actor;
+}
+
+ClutterActor*
+util_texture_from_root_window (void)
+{
+  ClutterActor *texture = NULL;
+  GdkWindow    *root;
+  GdkPixbuf    *pixbuf;
+
+  gdk_init(NULL, NULL);
+
+  root = gdk_get_default_root_window ();
+  
+  pixbuf = gdk_pixbuf_get_from_drawable (NULL, 
+                                        root, 
+                                        NULL,
+                                        0, 
+                                        0, 
+                                        0, 
+                                        0, 
+                                        gdk_screen_width(), 
+                                        gdk_screen_height());
+
+  if (pixbuf)
+    {
+
+      texture = clutter_texture_new ();
+      clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture),
+                                        gdk_pixbuf_get_pixels (pixbuf),
+                                        gdk_pixbuf_get_has_alpha (pixbuf),
+                                        gdk_pixbuf_get_width (pixbuf),
+                                        gdk_pixbuf_get_height (pixbuf),
+                                        gdk_pixbuf_get_rowstride (pixbuf),
+                                        gdk_pixbuf_get_n_channels (pixbuf), 
+                                        0,
+                                        NULL);
+    }
+
+  return texture;
+}
+
+guint32 
+alpha_sine_inc_func (ClutterAlpha *alpha,
+                    gpointer      dummy)
+{
+  ClutterTimeline *timeline;
+  gint current_frame_num, n_frames;
+  gdouble x, sine;
+  
+  timeline = clutter_alpha_get_timeline (alpha);
+
+  current_frame_num = clutter_timeline_get_current_frame (timeline);
+  n_frames = clutter_timeline_get_n_frames (timeline);
+
+  x = (gdouble) (current_frame_num * 0.5f * M_PI) / n_frames ;
+  /* sine = (sin (x - (M_PI / 0.5f)) + 1.0f) * 0.5f; */
+  sine = (sin (x - (M_PI / 0.5f))) ;
+
+  return (guint32) (sine * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);
+}
+
diff --git a/attic/woohaa/util.h b/attic/woohaa/util.h
new file mode 100644 (file)
index 0000000..a363d55
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _FOO_FOO_UTIL
+#define _FOO_FOO_UTIL
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CSW() CLUTTER_STAGE_WIDTH()
+#define CSH() CLUTTER_STAGE_HEIGHT()
+
+typedef void (*UtilAnimCompleteFunc) (ClutterActor *actor,
+                                     gpointer       user_data);
+
+guint32 
+alpha_sine_inc_func (ClutterAlpha *alpha,
+                    gpointer      dummy);
+
+ClutterActor*
+util_actor_from_file (const gchar *path, int width, int height);
+
+ClutterTimeline*
+util_actor_fade_in (ClutterActor        *actor,
+                   UtilAnimCompleteFunc func, 
+                   gpointer             data);
+
+ClutterTimeline*
+util_actor_fade_out (ClutterActor        *actor,
+                    UtilAnimCompleteFunc func, 
+                    gpointer             data);
+
+ClutterTimeline*
+util_actor_fade (ClutterActor        *actor, 
+                UtilAnimCompleteFunc func,
+                guint8               start_opacity,
+                guint8               end_opacity,
+                gpointer             data);
+
+
+ClutterTimeline*
+util_actor_zoom (ClutterActor        *actor, 
+                UtilAnimCompleteFunc func,
+                gdouble              start_scale,
+                gdouble              end_scale,
+                gpointer             data);
+
+ClutterActor*
+util_texture_from_root_window (void);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-busy.c b/attic/woohaa/wh-busy.c
new file mode 100644 (file)
index 0000000..6a0df15
--- /dev/null
@@ -0,0 +1,443 @@
+#include <glib.h>
+#include "wh-busy.h"
+
+#define CSW() CLUTTER_STAGE_WIDTH()
+#define CSH() CLUTTER_STAGE_HEIGHT()
+
+#define WOOHAA_TYPE_BEHAVIOUR_BUSY (clutter_behaviour_busy_get_type ())
+
+#define WOOHAA_BEHAVIOUR_BUSY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WOOHAA_TYPE_BEHAVIOUR_BUSY, WoohaaBehaviourBusy))
+
+#define WOOHAA_BEHAVIOUR_BUSY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WOOHAA_TYPE_BEHAVIOUR_BUSY, WoohaaBehaviourBusyClass))
+
+#define CLUTTER_IS_BEHAVIOUR_BUSY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WOOHAA_TYPE_BEHAVIOUR_BUSY))
+
+#define CLUTTER_IS_BEHAVIOUR_BUSY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WOOHAA_TYPE_BEHAVIOUR_BUSY))
+
+#define WOOHAA_BEHAVIOUR_BUSY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WOOHAA_TYPE_BEHAVIOUR_BUSY, WoohaaBehaviourBusyClass))
+
+typedef struct _WoohaaBehaviourBusy        WoohaaBehaviourBusy;
+typedef struct _WoohaaBehaviourBusyClass   WoohaaBehaviourBusyClass;
+struct _WoohaaBehaviourBusy
+{
+  ClutterBehaviour parent;
+  WoohaaBusy      *busy;
+};
+
+struct _WoohaaBehaviourBusyClass
+{
+  ClutterBehaviourClass   parent_class;
+};
+
+GType clutter_behaviour_busy_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (WoohaaBehaviourBusy, clutter_behaviour_busy, CLUTTER_TYPE_BEHAVIOUR);
+
+static ClutterBehaviour*
+clutter_behaviour_busy_new (WoohaaBusy *menu, ClutterAlpha *alpha);
+
+static void
+clutter_behaviour_alpha_notify (ClutterBehaviour *behave,
+                                guint32           alpha_value);
+
+enum
+{
+  PROP_0,
+  PROP_LABEL
+};
+
+struct _WoohaaBusyPrivate
+{
+  ClutterActor     *spinner;
+  ClutterActor     *label;
+  gchar            *label_text;
+  ClutterTimeline  *timeline;
+  guint             spinner_alpha;
+};
+
+G_DEFINE_TYPE (WoohaaBusy, woohaa_busy, CLUTTER_TYPE_ACTOR);
+
+static void
+woohaa_busy_dispose (GObject *object)
+{
+  WoohaaBusy        *self;
+  WoohaaBusyPrivate *priv; 
+
+  self = WOOHAA_BUSY(object); 
+  priv = self->priv;
+
+  G_OBJECT_CLASS (woohaa_busy_parent_class)->dispose (object);
+}
+
+static void
+woohaa_busy_finalize (GObject *object)
+{
+  WoohaaBusy        *self;
+  WoohaaBusyPrivate *priv; 
+
+  self = WOOHAA_BUSY(object); 
+  priv = self->priv;
+
+  G_OBJECT_CLASS (woohaa_busy_parent_class)->finalize (object);
+}
+
+static void
+woohaa_busy_show_cb (ClutterActor *actor, ClutterTimeline *timeline)
+{
+  clutter_timeline_start (timeline);
+}
+
+static void
+woohaa_busy_hide_cb (ClutterActor *actor, ClutterTimeline *timeline)
+{
+  clutter_timeline_stop (timeline);
+  clutter_actor_set_opacity (CLUTTER_ACTOR (actor), 0xFF);
+}
+
+static void
+newframe_cb (ClutterTimeline *timeline, 
+            gint             frame_num, 
+            ClutterActor    *spinner)
+{
+  gint x, y;
+
+  clutter_actor_get_position (spinner, &x, &y);
+  clutter_actor_set_position (spinner, x + 10 , y + 10);
+
+  clutter_actor_set_rotation (spinner, 
+                             CLUTTER_Z_AXIS,
+                              (float)frame_num * 4.0,
+                              clutter_actor_get_width (spinner) / 2,
+                              clutter_actor_get_height (spinner) / 2,
+                              0);
+}
+
+static void
+woohaa_busy_paint (ClutterActor *actor)
+{
+  WoohaaBusyPrivate *priv = (WOOHAA_BUSY (actor))->priv;
+
+  clutter_actor_paint (priv->spinner);
+  clutter_actor_paint (priv->label);
+}
+
+static void
+woohaa_busy_get_preferred_width  (ClutterActor          *actor,
+                                 ClutterUnit            for_height,
+                                 ClutterUnit           *min_width_p,
+                                 ClutterUnit           *natural_width_p)
+{
+  *min_width_p = CLUTTER_UNITS_FROM_INT (100);
+  *natural_width_p = CLUTTER_UNITS_FROM_INT (500);
+}
+
+static void
+woohaa_busy_get_preferred_height (ClutterActor          *actor,
+                                 ClutterUnit            for_width,
+                                 ClutterUnit           *min_height_p,
+                                 ClutterUnit           *natural_height_p)
+{
+  *min_height_p = CLUTTER_UNITS_FROM_INT (100);
+  *natural_height_p = CLUTTER_UNITS_FROM_INT (500);
+}
+
+static void
+woohaa_busy_allocate (ClutterActor *actor, 
+                     const ClutterActorBox *box,
+                     gboolean absolute_origin_changed)
+{
+  WoohaaBusyPrivate *priv = (WOOHAA_BUSY (actor))->priv;
+  ClutterUnit min_width, spinner_natural_width, label_natural_width;
+  ClutterUnit min_height, spinner_natural_height, label_natural_height;
+  ClutterActorBox spinner_box, label_box;
+  
+  /* query spinner width and height */
+  clutter_actor_get_preferred_width (priv->spinner, 
+                                    box->y2 - box->y1,
+                                    &min_width,
+                                    &spinner_natural_width);
+  clutter_actor_get_preferred_height (priv->spinner, 
+                                     box->x2 - box->x1,
+                                     &min_height,
+                                     &spinner_natural_height);
+
+  /* query label width and height */
+  clutter_actor_get_preferred_width (priv->label, 
+                                    box->y2 - box->y1,
+                                    &min_width,
+                                    &label_natural_width);
+  clutter_actor_get_preferred_height (priv->label, 
+                                     box->x2 - box->x1,
+                                     &min_height,
+                                     &label_natural_height);
+
+  spinner_box.x1 = CLUTTER_UNITS_FROM_INT (CSW()/2) - spinner_natural_width/2;
+  spinner_box.y1 = CLUTTER_UNITS_FROM_INT (CSH()/2) 
+    - spinner_natural_height/2 
+    - label_natural_height/2  
+    + (priv->spinner_alpha * 100);
+  spinner_box.x2 = spinner_box.x1 + spinner_natural_width;
+  spinner_box.y2 = spinner_box.y1 + spinner_natural_height;
+
+  label_box.x1 = CLUTTER_UNITS_FROM_INT (CSW()/2) - label_natural_width/2;
+  label_box.y1 = CLUTTER_UNITS_FROM_INT (CSH()/2) 
+    - spinner_natural_height/2 
+    - label_natural_height/2  
+    + spinner_natural_height;
+  label_box.x2 = label_box.x1 + label_natural_width;
+  label_box.y2 = label_box.y1 + label_natural_height;
+
+  clutter_actor_allocate (priv->spinner, 
+                         &spinner_box, 
+                         absolute_origin_changed);
+
+  clutter_actor_allocate (priv->label, 
+                         &label_box, 
+                         absolute_origin_changed);
+
+  CLUTTER_ACTOR_CLASS (woohaa_busy_parent_class)->
+         allocate (actor, box, absolute_origin_changed);
+}
+
+static void
+woohaa_busy_set_property (GObject      *object, 
+                         guint         prop_id,
+                         const GValue *value, 
+                         GParamSpec   *pspec)
+{
+  WoohaaBusy        *busy;
+  WoohaaBusyPrivate *priv;
+
+  busy = WOOHAA_BUSY(object);
+  priv = busy->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_LABEL:
+      if (priv->label_text)
+       g_free (priv->label_text);
+      priv->label_text = g_strdup(g_value_get_string (value));
+      clutter_label_set_text (CLUTTER_LABEL (priv->label), priv->label_text);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+woohaa_busy_get_property (GObject    *object, 
+                         guint       prop_id,
+                         GValue     *value, 
+                         GParamSpec *pspec)
+{
+  WoohaaBusy        *busy;
+  WoohaaBusyPrivate *priv;
+
+  busy = WOOHAA_BUSY(object);
+  priv = busy->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_LABEL:
+      g_value_set_string (value, priv->label_text);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    } 
+}
+
+static void
+woohaa_busy_class_init (WoohaaBusyClass *klass)
+{
+  GObjectClass *object_class     = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  
+  g_type_class_add_private (klass, sizeof (WoohaaBusyPrivate));
+
+  object_class->dispose      = woohaa_busy_dispose;
+  object_class->finalize     = woohaa_busy_finalize;
+  object_class->set_property = woohaa_busy_set_property;
+  object_class->get_property = woohaa_busy_get_property;
+
+  actor_class->get_preferred_width = woohaa_busy_get_preferred_width;
+  actor_class->get_preferred_height = woohaa_busy_get_preferred_height;
+  actor_class->allocate = woohaa_busy_allocate;
+  actor_class->paint    = woohaa_busy_paint;
+
+  g_object_class_install_property 
+    (object_class, PROP_LABEL,
+     g_param_spec_string ("label",
+                         "Label Text",
+                         "Label Text",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+}
+
+static void
+woohaa_busy_init (WoohaaBusy *woohaa_busy)
+{
+  WoohaaBusyPrivate   *priv;
+  gchar               *font;
+  ClutterColor grey = { 0x72, 0x9f, 0xcf, 0xff};
+
+  woohaa_busy->priv = priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (woohaa_busy,
+                                 WOOHAA_TYPE_BUSY,
+                                 WoohaaBusyPrivate);
+
+  priv->timeline = clutter_timeline_new (90, 20);
+  clutter_timeline_set_loop (priv->timeline, TRUE);
+
+  priv->spinner = clutter_texture_new_from_file (PKGDATADIR "/spinner.svg", 
+                                                NULL);
+  clutter_actor_set_position 
+    (priv->spinner, 
+     (CSW() - clutter_actor_get_width (priv->spinner))/2,
+     (CSH() - clutter_actor_get_height (priv->spinner))/2);
+  clutter_actor_show (priv->spinner);
+
+  priv->label_text = g_strdup("One moment please...");
+  font = g_strdup_printf("Sans %ipx", (CSH()/6)/2);
+  priv->label = clutter_label_new_full (font, priv->label_text,  &grey);
+  clutter_actor_set_position (priv->label,
+                             (CSW() - clutter_actor_get_width (priv->label))/2,
+                             CSH() - (3*clutter_actor_get_height (priv->label)));  
+  clutter_actor_show (priv->label);
+
+  clutter_actor_set_parent (priv->spinner, CLUTTER_ACTOR (woohaa_busy));
+  clutter_actor_set_parent (priv->label, CLUTTER_ACTOR (woohaa_busy));
+
+  g_signal_connect (priv->timeline, 
+                   "new-frame", 
+                   G_CALLBACK (newframe_cb), 
+                   priv->spinner);
+
+  g_signal_connect (woohaa_busy,
+                   "show",
+                   G_CALLBACK (woohaa_busy_show_cb),
+                   priv->timeline);
+  g_signal_connect (woohaa_busy,
+                   "hide",
+                   G_CALLBACK (woohaa_busy_hide_cb),
+                   priv->timeline);
+}
+
+void 
+fade_complete_cb (ClutterActor *actor, gpointer data)
+{
+  clutter_actor_hide(actor);
+}
+
+void
+woohaa_busy_fade_out (WoohaaBusy *busy, gint timeout)
+{
+  ClutterEffectTemplate *template;
+  ClutterTimeline *timeline;
+
+  timeline = clutter_timeline_new_for_duration (timeout);
+  template = clutter_effect_template_new (timeline, CLUTTER_ALPHA_SINE_INC);
+
+  clutter_effect_fade (template,
+                      CLUTTER_ACTOR (busy),
+                      0,
+                      fade_complete_cb,
+                      NULL);
+}
+
+void
+woohaa_busy_fade_in (WoohaaBusy *busy, gint timeout)
+{
+  ClutterEffectTemplate *template;
+  ClutterTimeline *timeline;
+
+  timeline = clutter_timeline_new_for_duration (timeout);
+  template = clutter_effect_template_new (timeline, CLUTTER_ALPHA_SINE_INC);
+
+  clutter_actor_set_opacity (CLUTTER_ACTOR (busy), 0);
+  clutter_actor_show (CLUTTER_ACTOR (busy));
+
+  clutter_effect_fade (template,
+                      CLUTTER_ACTOR (busy),
+                      0xFF,
+                      NULL,
+                      NULL);
+}
+
+void
+woohaa_busy_bounce (WoohaaBusy *busy)
+{
+  WoohaaBusyPrivate *priv;
+  ClutterTimeline *timeline;
+  ClutterAlpha *alpha;
+  ClutterGeometry geo;
+  ClutterBehaviour *behave;
+  priv = busy->priv;
+
+  timeline = clutter_timeline_new_for_duration (500);
+  alpha = clutter_alpha_new_full (timeline, CLUTTER_ALPHA_SINE, NULL, NULL);
+
+  behave = clutter_behaviour_busy_new (busy, alpha);
+
+  clutter_timeline_start (timeline);
+
+  clutter_actor_get_geometry (CLUTTER_ACTOR (busy), &geo);
+}
+
+ClutterActor*
+woohaa_busy_new (void)
+{
+  return g_object_new (WOOHAA_TYPE_BUSY, NULL);
+}
+
+/* Custom Behavior */
+
+static void
+clutter_behaviour_alpha_notify (ClutterBehaviour *behave,
+                                guint32           alpha_value)
+{
+  WoohaaBusy *busy;
+
+  busy = (WOOHAA_BEHAVIOUR_BUSY (behave))->busy;
+  
+  busy->priv->spinner_alpha = alpha_value;
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (busy));
+}
+
+static void
+clutter_behaviour_busy_class_init (WoohaaBehaviourBusyClass *klass)
+{
+  ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
+
+  behave_class->alpha_notify = clutter_behaviour_alpha_notify;
+}
+
+static void
+clutter_behaviour_busy_init (WoohaaBehaviourBusy *self)
+{
+}
+
+static ClutterBehaviour*
+clutter_behaviour_busy_new (WoohaaBusy *busy, ClutterAlpha *alpha)
+{
+  WoohaaBehaviourBusy *busy_behave;
+
+  busy_behave = g_object_new (WOOHAA_TYPE_BEHAVIOUR_BUSY, 
+                             "alpha", alpha, NULL);
+  busy_behave->busy  = busy;
+
+  return CLUTTER_BEHAVIOUR(busy_behave);
+}
diff --git a/attic/woohaa/wh-busy.h b/attic/woohaa/wh-busy.h
new file mode 100644 (file)
index 0000000..d4ccabe
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef _HAVE_WOOHAA_BUSY_H
+#define _HAVE_WOOHAA_BUSY_H
+
+#include <clutter/clutter.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+#define WOOHAA_TYPE_BUSY woohaa_busy_get_type()
+
+#define WOOHAA_BUSY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WOOHAA_TYPE_BUSY, WoohaaBusy))
+
+#define WOOHAA_BUSY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WOOHAA_TYPE_BUSY, WoohaaBusyClass))
+
+#define WOOHAA_IS_BUSY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WOOHAA_TYPE_BUSY))
+
+#define WOOHAA_IS_BUSY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WOOHAA_TYPE_BUSY))
+
+#define WOOHAA_BUSY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WOOHAA_TYPE_BUSY, WoohaaBusyClass))
+
+typedef struct _WoohaaBusy        WoohaaBusy;
+typedef struct _WoohaaBusyClass   WoohaaBusyClass;
+typedef struct _WoohaaBusyPrivate WoohaaBusyPrivate;
+
+struct _WoohaaBusy
+{
+  /*< private >*/
+  ClutterActor       parent;
+  WoohaaBusyPrivate *priv;
+}; 
+
+struct _WoohaaBusyClass 
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /* Future padding */
+  void (* __reserved1) (void);
+  void (* __reserved2) (void);
+  void (* __reserved3) (void);
+  void (* __reserved4) (void);
+  void (* __reserved5) (void);
+  void (* __reserved6) (void);
+}; 
+
+GType         woohaa_busy_get_type  (void) G_GNUC_CONST;
+ClutterActor *woohaa_busy_new       (void);
+void          woohaa_busy_fade_out (WoohaaBusy *busy, gint timeout);
+void          woohaa_busy_fade_in  (WoohaaBusy *busy, gint timeout);
+void          woohaa_busy_bounce   (WoohaaBusy *busy);
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-db.c b/attic/woohaa/wh-db.c
new file mode 100644 (file)
index 0000000..945c12c
--- /dev/null
@@ -0,0 +1,648 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <glib.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
+
+#include "wh-db.h"
+#include "wh-video-model.h"
+#include "wh-video-model-row.h"
+
+ #include "wh-video-model.h"
+#include <string.h>
+
+G_DEFINE_TYPE (WHDB, wh_db, G_TYPE_OBJECT);
+
+#define DB_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), WH_TYPE_DB, WHDBPrivate))
+
+typedef struct _WHDBPrivate WHDBPrivate;
+
+struct _WHDBPrivate
+{
+  sqlite3 *db;
+  
+  GThreadPool *thread_pool;
+};
+
+typedef struct
+{
+  WHDB *db;
+  gchar *uri;
+  GnomeVFSFileInfo *vfs_info;
+} WHDBThreadData;
+
+enum
+{
+  ROW_CREATED,
+  ROW_DELETED,
+  LAST_SIGNAL
+};
+
+static guint _db_signals[LAST_SIGNAL] = { 0 };
+
+#define SQL_CREATE_TABLES \
+ "CREATE TABLE IF NOT EXISTS meta(path text, n_views int, active int, " \
+ "                  vtime integer, mtime integer, thumbnail blob, "      \
+ "                  primary key (path), unique(path));" 
+
+enum 
+  {
+    SQL_GET_ROW_VIA_PATH = 0,
+    SQL_SET_ACTIVE_VIA_PATH,
+    SQL_ADD_NEW_ROW,
+    SQL_GET_ACTIVE_ROWS,
+    SQL_UPDATE_ROW,
+    N_SQL_STATEMENTS
+  };
+
+static gchar *SQLStatementText[] = 
+  {
+    "select n_views, vtime, mtime, thumbnail from meta where path=:path;",
+    "update meta set active=1, mtime=:mtime where path=:path;",
+    "insert into meta(path, n_views, active, vtime, mtime, thumbnail)"
+    "           values(:path, 0, 1, 0, :mtime, 0);",
+    "select path, n_views, vtime, mtime, thumbnail from meta where active=1;",
+    "update meta set thumbnail=:thumbnail, n_views=:n_views, vtime=:vtime "
+    "            where path=:path;"
+  };
+
+static sqlite3_stmt *SQLStatements[N_SQL_STATEMENTS];
+
+static gboolean
+wh_db_walk_directory (WHDB *db, const gchar *uri);
+
+static void
+wh_db_media_file_found (WHDB                    *db, 
+                       const char              *uri,
+                       GnomeVFSFileInfo        *vfs_info);
+
+static void 
+on_vfs_monitor_event (GnomeVFSMonitorHandle   *handle,
+                     const gchar             *monitor_uri,
+                     const gchar             *info_uri,
+                     GnomeVFSMonitorEventType event_type,
+                     gpointer                 user_data);
+
+static void
+wh_db_import_uri_func (gchar                  *uri,
+                       WHDB                   *db);
+
+static void
+wh_db_get_property (GObject *object, guint property_id,
+                            GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+wh_db_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+wh_db_dispose (GObject *object)
+{
+  WHDBPrivate *priv = DB_PRIVATE (object);
+  
+  if (priv->thread_pool)
+    {
+      g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
+      priv->thread_pool = NULL;
+    }
+
+  if (G_OBJECT_CLASS (wh_db_parent_class)->dispose)
+    G_OBJECT_CLASS (wh_db_parent_class)->dispose (object);
+}
+
+static void
+wh_db_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (wh_db_parent_class)->finalize (object);
+}
+
+static void
+wh_db_class_init (WHDBClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (WHDBPrivate));
+
+  object_class->get_property = wh_db_get_property;
+  object_class->set_property = wh_db_set_property;
+  object_class->dispose = wh_db_dispose;
+  object_class->finalize = wh_db_finalize;
+
+  _db_signals[ROW_CREATED] =
+    g_signal_new ("row-created",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHDBClass, row_created),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, WH_TYPE_VIDEO_MODEL_ROW);
+}
+
+static void
+wh_db_init (WHDB *self)
+{
+  int           res, i;
+  const gchar  *data_dir;
+  gchar        *db_filename, *path;
+  WHDBPrivate  *priv = DB_PRIVATE(self);
+
+  gnome_vfs_init ();
+
+  data_dir = g_get_user_data_dir ();
+
+  db_filename = g_build_filename (data_dir, "woohaa", "db", NULL);
+  path = g_path_get_dirname (db_filename);
+  g_mkdir_with_parents (path, 0755);
+  
+  res = sqlite3_open(db_filename, &priv->db);
+
+  g_free(path); 
+  g_free(db_filename);
+
+  if (res)
+    {
+      g_error("Can't open database: %s\n", sqlite3_errmsg(priv->db));
+      sqlite3_close(priv->db);
+      return;
+    }
+
+  /* Create DB if not already existing - preexisting will silently fail */
+  if (sqlite3_exec(priv->db, SQL_CREATE_TABLES, NULL, NULL, NULL))
+    g_warning("Can't create table: %s\n", sqlite3_errmsg(priv->db));
+  
+  /* Next mark fields inactive */
+  if (sqlite3_exec(priv->db, "update meta set active=0;", NULL, NULL, NULL))
+    g_warning("Can't mark table inactive: %s\n", sqlite3_errmsg(priv->db));
+  
+  /* precompile statements */
+  for (i=0; i<N_SQL_STATEMENTS; i++)
+    if (sqlite3_prepare(priv->db, SQLStatementText[i], -1, 
+                       &SQLStatements[i], NULL) != SQLITE_OK)
+      g_warning("Failed to prepare '%s' : %s", 
+               SQLStatementText[i], sqlite3_errmsg(priv->db));
+  
+  /* Create thread pool for indexing */
+  priv->thread_pool = g_thread_pool_new ((GFunc)wh_db_import_uri_func,
+                                         self,
+                                         -1,
+                                         FALSE,
+                                         NULL);
+}
+
+WHDB*
+wh_db_new ()
+{
+  return g_object_new (WH_TYPE_DB, NULL);
+}
+
+gboolean
+uri_is_media (const gchar *uri)
+{
+  /* Suck */
+  /* FIXME: use gstreamer tag foo |gvfs mime type to identify */
+  return (g_str_has_suffix(uri, ".avi")
+         || g_str_has_suffix(uri, ".mpeg")
+         || g_str_has_suffix(uri, ".wmv")
+#ifdef USE_HELIX
+         || g_str_has_suffix(uri, ".rmvb")
+#endif
+         || g_str_has_suffix(uri, ".ogg")
+         || g_str_has_suffix(uri, ".mp4")
+         || g_str_has_suffix(uri, ".mpg"));
+}
+
+static gboolean
+wh_db_monitor_add_idle (WHDBThreadData *data)
+{
+  GnomeVFSMonitorHandle   *monitor_handle;
+
+  gnome_vfs_monitor_add (&monitor_handle,
+                         data->uri,
+                         GNOME_VFS_MONITOR_DIRECTORY,
+                         on_vfs_monitor_event,
+                         data->db);
+  
+  g_free (data->uri);
+  g_slice_free (WHDBThreadData, data);
+  
+  return FALSE;
+}
+
+static gboolean
+wh_db_media_file_found_idle (WHDBThreadData *data)
+{
+  wh_db_media_file_found (data->db, data->uri, data->vfs_info); 
+
+ if (data->vfs_info)
+    gnome_vfs_file_info_unref (data->vfs_info);
+  g_free (data->uri);
+  g_slice_free (WHDBThreadData, data);
+  
+  return FALSE;
+}
+
+gboolean
+wh_db_import_uri_private (WHDB *db, const gchar *uri)
+{
+  GnomeVFSResult          vfs_result;
+  GnomeVFSFileInfo       *vfs_info = NULL;
+  GnomeVFSFileInfoOptions vfs_options;
+  gboolean                ret = FALSE;
+
+  vfs_options = 
+    GNOME_VFS_FILE_INFO_DEFAULT
+    |GNOME_VFS_FILE_INFO_FOLLOW_LINKS
+    |GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS;
+
+  vfs_info   = gnome_vfs_file_info_new ();
+  vfs_result = gnome_vfs_get_file_info (uri, vfs_info, vfs_options);
+
+  if (vfs_result != GNOME_VFS_OK)
+    goto cleanup;
+
+  if (! (vfs_info->valid_fields & (GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS
+                                  |GNOME_VFS_FILE_INFO_FIELDS_TYPE)))
+    goto cleanup;
+
+  /* GNOME_VFS_PERM_ACCESS_READABLE would be better, but only the
+   * file method implements it */
+  if (! (vfs_info->permissions & GNOME_VFS_PERM_USER_READ))
+    goto cleanup;
+
+  if (vfs_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
+    {
+      WHDBThreadData *data;
+      
+      data = g_slice_new0 (WHDBThreadData);
+      data->uri = g_strdup (uri);
+      data->db = db;
+      
+      g_idle_add ((GSourceFunc)wh_db_monitor_add_idle, data);
+
+      ret = wh_db_walk_directory (db, uri);
+    }
+  else if (vfs_info->type == GNOME_VFS_FILE_TYPE_REGULAR)
+    {
+      if (uri_is_media(uri))
+        {
+          WHDBThreadData *data;
+          
+          data = g_slice_new0 (WHDBThreadData);
+          data->uri = g_strdup (uri);
+          data->db = db;
+          data->vfs_info = vfs_info;
+          
+          g_idle_add ((GSourceFunc)wh_db_media_file_found_idle, data);
+          
+          goto skip_cleanup;
+        }
+
+      ret = TRUE;
+    }
+
+  cleanup:
+
+  if (vfs_info)
+    gnome_vfs_file_info_unref (vfs_info);
+  
+  skip_cleanup:
+  
+  return ret;
+}
+
+static gboolean
+wh_db_walk_directory (WHDB *db, const gchar *uri)
+{
+  GnomeVFSResult           vfs_result;
+  GnomeVFSDirectoryHandle *vfs_handle = NULL;
+  GnomeVFSFileInfoOptions  vfs_options;
+  GnomeVFSFileInfo        *vfs_info = NULL;
+  gboolean                 ret = TRUE;
+
+  vfs_options = 
+    GNOME_VFS_FILE_INFO_DEFAULT
+    |GNOME_VFS_FILE_INFO_FOLLOW_LINKS
+    |GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS;
+
+  vfs_result = gnome_vfs_directory_open (&vfs_handle, uri, vfs_options);
+
+  if (vfs_result != GNOME_VFS_OK)      
+    goto cleanup;
+
+  vfs_info = gnome_vfs_file_info_new ();
+
+  while (gnome_vfs_directory_read_next(vfs_handle, vfs_info) == GNOME_VFS_OK)
+    {
+      if (vfs_info->name
+         && strcmp(vfs_info->name, ".")
+         && strcmp(vfs_info->name, ".."))
+       {
+         gchar *entry_uri = NULL;
+
+         entry_uri = g_strconcat(uri, "/", vfs_info->name, NULL);
+
+         if (entry_uri)
+           {
+             ret |= wh_db_import_uri_private (db, entry_uri); 
+             g_free(entry_uri);
+           }
+       }
+    }
+
+ cleanup:
+  if (vfs_info)
+    gnome_vfs_file_info_unref (vfs_info);
+  
+  if (vfs_handle)
+    gnome_vfs_directory_close (vfs_handle);
+
+ return ret;
+}
+
+static void
+wh_db_import_uri_func (gchar *uri, WHDB *db)
+{
+  wh_db_import_uri_private (db, uri);
+  g_free (uri);
+}
+
+static gboolean 
+wh_db_get_uri (const gchar *uri, 
+              gint        *n_views, 
+              gint        *vtime, 
+              gint        *mtime,
+              GdkPixbuf  **thumb)
+{
+  gboolean      res = FALSE;
+  sqlite3_stmt *stmt = SQLStatements[SQL_GET_ROW_VIA_PATH];
+  
+  sqlite3_bind_text (stmt, 1, uri, -1, SQLITE_STATIC);
+
+  if (sqlite3_step(stmt) == SQLITE_ROW)
+    {
+      if (n_views)
+       *n_views = sqlite3_column_int(stmt, 0);
+      if (vtime)
+       *vtime = sqlite3_column_int(stmt, 1);
+      if (mtime)
+       *mtime = sqlite3_column_int(stmt, 2);
+
+      if (thumb)
+       {
+         int         len;
+         GdkPixdata *pixdata;
+         guint8 *blob = NULL;
+
+         blob = (guint8 *)sqlite3_column_blob (stmt, 3);
+         len  = sqlite3_column_bytes (stmt, 3);
+
+         if (sqlite3_column_type (stmt,3) == SQLITE_BLOB)
+           {
+             pixdata = g_new0 (GdkPixdata, 1);
+
+             if (gdk_pixdata_deserialize (pixdata, len, (const guint8*)blob, 
+                                          NULL))
+               *thumb = gdk_pixbuf_from_pixdata (pixdata, TRUE, NULL);
+
+             g_free (pixdata);
+           }
+       }
+      res = TRUE;
+    }
+
+  sqlite3_reset(stmt);
+
+  return res;
+}
+
+static gchar*
+wh_db_parse_video_uri_info (const char *uri,
+                           gchar     **series,
+                           gchar     **episode)
+{
+  gchar     *base, *res;
+  regex_t   *regex;
+  size_t     nmatch = 4;
+  regmatch_t pmatch[4];
+
+  /* HAXOR Regexp to extract 'meta data' from common TV show naming  */
+#define TV_REGEXP "(.*)\\.?[Ss]+([0-9]+)[._ ]*[Ee]+[Pp]*([0-9]+)"
+
+  base = g_path_get_basename (uri);
+
+  regex = g_malloc0(sizeof(regex_t));
+
+  if (regcomp(regex, TV_REGEXP, REG_EXTENDED) != 0)
+    {
+      printf("regexp creation failed\n");
+    }
+
+  if (regexec(regex, base, nmatch, pmatch, 0) == 0)
+    {
+      char *name;
+
+      name = g_strndup (base + pmatch[1].rm_so, 
+                       pmatch[1].rm_eo - pmatch[1].rm_so);
+
+      name = g_strdelimit (name, "._", ' ');
+
+      *series =  g_strndup (base + pmatch[2].rm_so, 
+                           pmatch[2].rm_eo - pmatch[2].rm_so);
+
+      *episode = g_strndup (base + pmatch[3].rm_so, 
+                           pmatch[3].rm_eo - pmatch[3].rm_so);
+
+      res = name;
+
+      if (res == NULL || *res == 0)
+       {
+         char *dirname;
+
+         /* Assume we have series & episode but no name so grab
+          * name from parent direcory - handles show-name/s01e01.avi
+           * style naiming.
+           */  
+         dirname = g_path_get_dirname (uri);
+         name = g_path_get_basename (dirname);
+         g_free (dirname);
+         
+         name = g_strdelimit (name, "._", ' ');
+      
+         res = name;
+       }
+
+      g_free (base);
+    }
+  else
+    {
+      gchar *p;
+
+      p = g_strrstr (base, "."); *p = '\0';
+      base = g_strdelimit (base, "._", ' ');
+
+      res = base;
+    }
+
+  g_free (regex);
+
+  return res;
+}
+
+static void
+wh_db_media_file_found (WHDB                    *db, 
+                       const char              *uri,
+                       GnomeVFSFileInfo        *vfs_info)
+{
+  WHVideoModelRow *row;
+  gchar           *title, *episode = NULL, *series = NULL;
+  gint             n_views = 0, mtime = 0, vtime = 0;  
+  GdkPixbuf       *thumb = NULL;
+
+  /* See if we already have file in db.
+   *  YES - mark active.
+   *  NO  - add it set vtime, n_views to 0 etc
+  */
+  if (wh_db_get_uri (uri, &n_views, &vtime, &mtime, &thumb))
+    {
+      /* Update  */
+      if (vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MTIME)
+       mtime = vfs_info->mtime;
+
+      sqlite3_stmt *stmt = SQLStatements[SQL_SET_ACTIVE_VIA_PATH];
+
+      sqlite3_bind_int (stmt, 1, mtime);
+      sqlite3_bind_text (stmt, 2, uri, -1, SQLITE_STATIC);
+
+      sqlite3_step(stmt);
+      sqlite3_reset(stmt);
+    }
+  else
+    {
+      /* New - create row entry*/
+      if (vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MTIME)
+       mtime = vfs_info->mtime;
+
+      sqlite3_stmt *stmt = SQLStatements[SQL_ADD_NEW_ROW];
+  
+      sqlite3_bind_text (stmt, 1, uri, -1, SQLITE_STATIC);
+      sqlite3_bind_int (stmt, 2, mtime); /* mtime */
+
+      sqlite3_step(stmt);
+      sqlite3_reset(stmt);
+    }
+
+  row = wh_video_model_row_new ();
+  wh_video_model_row_set_path (row, uri);
+
+  title = wh_db_parse_video_uri_info ((const char *)uri,
+                                     &series,
+                                     &episode);
+
+  wh_video_model_row_set_title (row, title);
+  wh_video_model_row_set_extended_info (row, series, episode);
+
+  g_free(title);
+
+  if (thumb)
+    {
+      wh_video_model_row_set_thumbnail (row, thumb);
+      g_object_unref (thumb);
+    }
+
+  wh_video_model_row_set_n_views (row, n_views);
+  wh_video_model_row_set_age (row, mtime);
+  wh_video_model_row_set_vtime (row, vtime);
+
+  g_signal_emit (db, _db_signals[ROW_CREATED], 0, row);
+
+  g_object_unref (row);
+}
+
+void
+wh_db_sync_row (WHVideoModelRow *row)
+{
+  GdkPixdata   *pixdata = NULL;
+  GdkPixbuf    *pixbuf = NULL;
+  guint8       *data = NULL;
+  sqlite3_stmt *stmt = SQLStatements[SQL_UPDATE_ROW];
+
+  sqlite3_bind_int (stmt, 2, wh_video_model_row_get_n_views (row));
+  sqlite3_bind_int (stmt, 3, wh_video_model_row_get_vtime (row));
+
+  pixbuf = wh_video_model_row_get_thumbnail (row);
+
+  if (pixbuf)
+    {
+      guint       len = 0;
+
+      pixdata = g_new0 (GdkPixdata, 1);
+      gdk_pixdata_from_pixbuf (pixdata, pixbuf, FALSE);
+
+      data = gdk_pixdata_serialize (pixdata, &len);
+
+      sqlite3_bind_blob(stmt, 1, (void*)data, len, SQLITE_STATIC);
+    }
+  else
+    {
+      sqlite3_bind_null(stmt, 1);
+    }
+
+  sqlite3_bind_text (stmt, 4, wh_video_model_row_get_path (row), 
+                    -1, SQLITE_STATIC);
+
+  sqlite3_step(stmt);
+  sqlite3_reset(stmt);
+
+  g_free (pixdata);
+  g_free (data);
+}
+
+static void 
+on_vfs_monitor_event (GnomeVFSMonitorHandle   *handle,
+                     const gchar             *monitor_uri,
+                     const gchar             *info_uri,
+                     GnomeVFSMonitorEventType event_type,
+                     gpointer                 user_data)
+{
+  WHDB *db = (WHDB*)user_data;
+
+  if (event_type == GNOME_VFS_MONITOR_EVENT_CREATED)
+    {
+      wh_db_import_uri_private (db, info_uri);
+      return;
+    }
+
+  if (event_type == GNOME_VFS_MONITOR_EVENT_DELETED)
+    printf("file '%s' deleted\n", info_uri);
+
+  if (event_type == GNOME_VFS_MONITOR_EVENT_CHANGED)
+    printf("file '%s' changed\n", info_uri);
+}
+
+gboolean
+wh_db_import_uri (WHDB *db, const gchar *uri)
+{
+  WHDBPrivate *priv = DB_PRIVATE (db);
+  
+  if (priv->thread_pool)
+    g_thread_pool_push (priv->thread_pool, g_strdup (uri), NULL);
+  
+  return TRUE;
+}
diff --git a/attic/woohaa/wh-db.h b/attic/woohaa/wh-db.h
new file mode 100644 (file)
index 0000000..248ef4f
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _WH_DB
+#define _WH_DB
+
+#include <glib-object.h>
+#include "wh-video-model-row.h"
+
+G_BEGIN_DECLS
+
+#define WH_TYPE_DB wh_db_get_type()
+
+#define WH_DB(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WH_TYPE_VIDEO_MODEL, WHVideoModel))
+
+#define WH_DB_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WH_TYPE_DB, WHDBClass))
+
+#define WH_IS_DB(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WH_TYPE_DB))
+
+#define WH_IS_DB_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WH_TYPE_DB))
+
+#define WH_DB_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WH_TYPE_DB, WHDBClass))
+
+typedef struct {
+  GObject                   parent;
+} WHDB;
+
+typedef struct {
+  GObjectClass parent_class;
+
+  void (*row_created) (WHDB *db, WHVideoModelRow *row);
+} WHDBClass;
+
+GType wh_db_get_type (void);
+
+WHDB*
+wh_db_new ();
+
+gboolean
+wh_db_import_uri (WHDB *db, const gchar *path);
+
+void
+wh_db_sync_row (WHVideoModelRow *row);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-screen-video.c b/attic/woohaa/wh-screen-video.c
new file mode 100644 (file)
index 0000000..ef3de66
--- /dev/null
@@ -0,0 +1,706 @@
+#include <clutter/clutter.h>
+
+#ifdef USE_HELIX
+#include <clutter-helix/clutter-helix.h>
+#else
+#include <clutter-gst/clutter-gst.h>
+#include <gst/gst.h>
+#endif
+
+#include "wh-screen-video.h"
+#include "util.h"
+
+G_DEFINE_TYPE (WHScreenVideo, wh_screen_video, CLUTTER_TYPE_ACTOR);
+
+#define SCREEN_VIDEO_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                WH_TYPE_SCREEN_VIDEO, WHScreenVideoPrivate))
+
+typedef struct _WHScreenVideoPrivate WHScreenVideoPrivate;
+
+struct _WHScreenVideoPrivate
+{
+  ClutterActor      *video;
+  ClutterActor      *bg;
+  ClutterActor      *video_controls;
+  ClutterActor      *video_seekbar;
+  ClutterActor      *video_seekbar_bg;
+  ClutterActor      *duration, *title, *position, *vol_label;
+  gboolean           video_playing;
+  gboolean           video_controls_visible;
+  
+  guint              controls_timeout;
+  WHVideoModelRow   *video_row;
+
+  /* Effects */
+  ClutterEffectTemplate *controls_effect_tmpl, *fadein_effect_tmpl;
+};
+
+enum
+{
+  PLAYBACK_STARTED,
+  PLAYBACK_FINISHED,
+  LAST_SIGNAL
+};
+
+static guint _screen_signals[LAST_SIGNAL] = { 0 };
+
+static void
+video_size_change (ClutterTexture *texture, 
+                  gint            width,
+                  gint            height,
+                  gpointer        user_data)
+{
+  gint           new_x, new_y, new_width, new_height;
+  
+  new_height = ( height * CLUTTER_STAGE_WIDTH() ) / width;
+
+  if (new_height <= CLUTTER_STAGE_HEIGHT())
+    {
+      new_width = CLUTTER_STAGE_WIDTH();
+      new_x = 0;
+      new_y = (CLUTTER_STAGE_HEIGHT() - new_height) / 2;
+    }
+  else
+    {
+      new_width  = ( width * CLUTTER_STAGE_HEIGHT() ) / height;
+      new_height = CLUTTER_STAGE_HEIGHT();
+      
+      new_x = (CLUTTER_STAGE_WIDTH() - new_width) / 2;
+      new_y = 0;
+    }
+  
+  clutter_actor_set_position (CLUTTER_ACTOR (texture), new_x, new_y);
+  clutter_actor_set_size (CLUTTER_ACTOR (texture), new_width, new_height);
+}
+
+void
+video_pixbuf_change (ClutterTexture *texture, WHScreenVideo  *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  g_signal_emit (screen, _screen_signals[PLAYBACK_STARTED], 0);
+
+  clutter_effect_fade (priv->fadein_effect_tmpl,
+                      CLUTTER_ACTOR(screen),
+                      0xff,
+                      NULL,
+                      NULL);
+
+  clutter_actor_show (CLUTTER_ACTOR(screen));
+  clutter_actor_set_opacity (CLUTTER_ACTOR(screen), 0);
+
+  g_signal_handlers_disconnect_by_func (priv->video, 
+                                       G_CALLBACK (video_pixbuf_change),
+                                       screen);
+} 
+
+static gchar*
+nice_time (int time)
+{
+  int    hours, minutes, seconds;
+
+  hours = time / 3600;
+  seconds = time % 3600;
+  minutes = seconds / 60;
+  seconds = seconds % 60;
+
+  if (hours > 0) 
+    return g_strdup_printf("%d:%.2d:%.2d", hours, minutes, seconds);
+  else
+    return g_strdup_printf("%.2d:%.2d", minutes, seconds);
+}
+
+
+static void 
+video_tick (GObject        *object,
+           GParamSpec     *pspec,
+           WHScreenVideo  *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+  ClutterMedia *vtex;
+  gint                    position, duration, seek_width;
+
+  vtex = CLUTTER_MEDIA(object);
+
+  position = clutter_media_get_position (CLUTTER_MEDIA(vtex));
+  duration = clutter_media_get_duration (CLUTTER_MEDIA(vtex));
+
+  if (duration == 0 || position == 0)
+    return;
+
+  if (!priv->video_playing && position > 0)
+    {
+      char *duration_txt;
+      duration_txt = nice_time (duration);
+      clutter_label_set_text (CLUTTER_LABEL(priv->duration), duration_txt);
+      g_free(duration_txt);
+
+      priv->video_playing = TRUE;
+    }
+
+  seek_width = clutter_actor_get_width(priv->video_seekbar_bg);
+
+  clutter_actor_set_size (priv->video_seekbar, 
+                         (position * seek_width) / duration, 
+                         20);  
+
+  if (priv->video_controls_visible)
+    {
+      char *position_txt;      
+
+      position_txt = nice_time (position);
+      clutter_label_set_text (CLUTTER_LABEL(priv->position), position_txt);
+      g_object_set (priv->position, "x",
+                   ((position * seek_width) / duration) + 10,
+                   NULL);
+      g_free(position_txt);
+    }
+}
+
+static void
+video_hide_controls (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  if (priv->video_controls_visible)
+    {
+      clutter_effect_fade (priv->controls_effect_tmpl,
+                          priv->video_controls,
+                          0,
+                          (ClutterEffectCompleteFunc)clutter_actor_hide,
+                          NULL);
+
+      priv->video_controls_visible = FALSE;
+    }
+}
+
+static gboolean
+video_controls_timeout_cb (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+  priv->controls_timeout = 0; 
+  video_hide_controls (screen);
+  return FALSE;
+}
+
+static void
+video_show_controls (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  if (!priv->video_controls_visible)
+    {
+      clutter_actor_show_all (CLUTTER_ACTOR(priv->video_controls));
+      clutter_actor_set_opacity (CLUTTER_ACTOR(priv->video_controls), 0);
+
+      clutter_effect_fade (priv->controls_effect_tmpl,
+                          priv->video_controls,
+                          0xff,
+                          NULL,
+                          NULL);
+      priv->video_controls_visible = TRUE;
+
+      priv->controls_timeout  
+       = g_timeout_add (5 * 1000,  
+                        (GSourceFunc)video_controls_timeout_cb,
+                        screen);
+    }
+  else if (priv->controls_timeout)
+    {
+      g_source_remove (priv->controls_timeout);
+      priv->controls_timeout  
+       = g_timeout_add (5 * 1000,  
+                        (GSourceFunc)video_controls_timeout_cb,
+                        screen);
+    }
+    
+}
+
+static gboolean
+video_input_cb (ClutterStage *stage,
+               ClutterEvent *event,
+               gpointer      user_data)
+{
+  WHScreenVideo        *screen = (WHScreenVideo*)user_data;
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+  gchar buf[16];
+  ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+  static ClutterTimeline *timeline = NULL;
+
+  switch (clutter_key_event_symbol (kev))
+    {
+    case CLUTTER_Return:
+    case CLUTTER_p:
+      if (clutter_media_get_playing (CLUTTER_MEDIA(priv->video)))
+       video_show_controls (screen);       
+      clutter_media_set_playing 
+       (CLUTTER_MEDIA(priv->video),
+        !clutter_media_get_playing (CLUTTER_MEDIA(priv->video)));
+      break;
+    case CLUTTER_Left:
+      video_show_controls (screen);
+      clutter_media_set_position 
+       (CLUTTER_MEDIA(priv->video),
+        clutter_media_get_position (CLUTTER_MEDIA(priv->video)) - 25);
+      break;
+    case CLUTTER_Right:
+      video_show_controls (screen);
+      clutter_media_set_position 
+       (CLUTTER_MEDIA(priv->video),
+        clutter_media_get_position (CLUTTER_MEDIA(priv->video)) + 25);
+      break;
+    case CLUTTER_Up:
+      clutter_media_set_volume 
+       (CLUTTER_MEDIA(priv->video),
+        clutter_media_get_volume (CLUTTER_MEDIA(priv->video)) + 0.02);
+      g_snprintf (buf, sizeof(buf), "Vol:%.2i", 
+                 (gint)(clutter_media_get_volume (CLUTTER_MEDIA(priv->video))/0.01));
+      clutter_label_set_text (CLUTTER_LABEL(priv->vol_label), buf);
+      video_show_controls (screen);
+      break;
+    case CLUTTER_Down:
+      clutter_media_set_volume 
+       (CLUTTER_MEDIA(priv->video),
+        clutter_media_get_volume (CLUTTER_MEDIA(priv->video)) - 0.02);
+      g_snprintf (buf, sizeof(buf), "Vol:%.2i", 
+                 (gint)(clutter_media_get_volume (CLUTTER_MEDIA(priv->video))/0.01));
+      clutter_label_set_text (CLUTTER_LABEL(priv->vol_label), buf);
+      video_show_controls (screen);
+      break;
+    case CLUTTER_r:
+      if (!timeline || !clutter_timeline_is_playing (timeline))
+        {
+         ClutterEffectTemplate *template;
+         static gint rotation;
+
+         if (clutter_actor_is_rotated (CLUTTER_ACTOR (priv->video)))
+           rotation = 0;
+         else
+           rotation = 180;
+         
+         template = clutter_effect_template_new_for_duration 
+           (1000, CLUTTER_ALPHA_SINE_INC);
+         timeline = clutter_effect_rotate (template,
+                                           CLUTTER_ACTOR (priv->video),
+                                           CLUTTER_Y_AXIS,
+                                           rotation,
+                                           CSW()/2, CSH()/2, 0,
+                                           rotation ? CLUTTER_ROTATE_CW : CLUTTER_ROTATE_CCW,
+                                           NULL,
+                                           NULL);
+       }
+      break;
+    case CLUTTER_Escape:
+    case CLUTTER_q:
+      wh_screen_video_deactivate (screen);
+      break;
+    default:
+      break;
+    }
+
+  return FALSE;
+}
+
+static void
+wh_screen_video_paint (ClutterActor *actor)
+{
+  WHScreenVideo *screen = WH_SCREEN_VIDEO(actor);
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  clutter_actor_paint (priv->bg); 
+  clutter_actor_paint (priv->video); 
+
+  clutter_actor_paint (priv->video_controls); 
+}
+
+static void
+wh_screen_video_get_preferred_width (ClutterActor *self,
+                                    ClutterUnit   for_height,
+                                    ClutterUnit  *min_width_p,
+                                    ClutterUnit  *natural_width_p)
+{
+  *min_width_p = CLUTTER_UNITS_FROM_INT (1); 
+  *natural_width_p = CLUTTER_UNITS_FROM_INT (CSW ());
+}
+
+static void
+wh_screen_video_get_preferred_height (ClutterActor *self,
+                                     ClutterUnit   for_width,
+                                     ClutterUnit  *min_height_p,
+                                     ClutterUnit  *natural_height_p)
+{
+  *min_height_p = CLUTTER_UNITS_FROM_INT (1); 
+  *natural_height_p = CLUTTER_UNITS_FROM_INT (CSH ());
+}
+
+static void
+wh_screen_video_allocate (ClutterActor *actor, 
+                         const ClutterActorBox *box,
+                         gboolean absolute_origin_changed)
+{
+  WHScreenVideo        *screen = WH_SCREEN_VIDEO (actor);
+  WHScreenVideoPrivate *priv   = SCREEN_VIDEO_PRIVATE (screen);
+  ClutterActorBox child_box;
+  ClutterUnit controls_x, controls_y;
+
+  child_box.x1 = 0;
+  child_box.y1 = 0;
+  child_box.x2 = CLUTTER_UNITS_FROM_INT (CSW ());
+  child_box.y2 = CLUTTER_UNITS_FROM_INT (CSH ());
+  clutter_actor_allocate (priv->bg, &child_box, absolute_origin_changed);
+  clutter_actor_allocate (priv->video, &child_box, absolute_origin_changed);
+
+  controls_x = CLUTTER_UNITS_FROM_INT (CSW()/8);
+  controls_y = CLUTTER_UNITS_FROM_INT ((CSH()/4)/3);
+
+  clutter_actor_get_preferred_size (priv->video_controls,
+                                   NULL,
+                                   NULL,
+                                   &child_box.x2,
+                                   &child_box.y2);
+  child_box.x1 = controls_x;
+  child_box.y1 = controls_y;
+  child_box.x2 += controls_x;
+  child_box.y2 += controls_y;
+  clutter_actor_allocate (priv->video_controls, 
+                         &child_box, 
+                         absolute_origin_changed);
+
+  CLUTTER_ACTOR_CLASS (wh_screen_video_parent_class)->
+         allocate (actor, box, absolute_origin_changed);
+}
+
+static void
+wh_screen_video_get_property (GObject *object, guint property_id,
+                              GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+wh_screen_video_set_property (GObject *object, guint property_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+wh_screen_video_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (wh_screen_video_parent_class)->dispose)
+    G_OBJECT_CLASS (wh_screen_video_parent_class)->dispose (object);
+}
+
+static void
+wh_screen_video_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (wh_screen_video_parent_class)->finalize (object);
+}
+
+
+
+static void
+wh_screen_video_class_init (WHScreenVideoClass *klass)
+{
+  GObjectClass      *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class  = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (WHScreenVideoPrivate));
+
+  object_class->get_property = wh_screen_video_get_property;
+  object_class->set_property = wh_screen_video_set_property;
+  object_class->dispose = wh_screen_video_dispose;
+  object_class->finalize = wh_screen_video_finalize;
+
+  actor_class->paint                = wh_screen_video_paint;
+  actor_class->get_preferred_width  = wh_screen_video_get_preferred_width;
+  actor_class->get_preferred_height = wh_screen_video_get_preferred_height;
+  actor_class->allocate             = wh_screen_video_allocate;
+
+  _screen_signals[PLAYBACK_STARTED] =
+    g_signal_new ("playback-started",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHScreenVideoClass, started),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+  _screen_signals[PLAYBACK_FINISHED] =
+    g_signal_new ("playback-finished",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHScreenVideoClass, finished),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+}
+
+static void
+video_make_controls (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+  gchar                 font_desc[32];
+  gint                  h, w, so;
+  ClutterActor         *actor;
+  ClutterColor          seekcol = { 0xbb, 0xbb, 0xbb, 0xff },
+                        txtcol = { 0x72, 0x9f, 0xcf, 0xff },
+                        fgcol = { 0x72, 0x9f, 0xcf, 0xff };
+
+  priv->video_controls = clutter_group_new();
+
+  /* And this code here is why some kind of optional simple layout engine 
+   * would be a good idea in cluter...
+  */
+  h = CSH()/6;
+  w = CSW() - CSW()/4;
+
+  actor = util_actor_from_file (PKGDATADIR "/header.svg", w, h);
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), actor);
+
+  g_snprintf(font_desc, 32, "Sans Bold %ipx", h/8); 
+  priv->duration = clutter_label_new_full (font_desc, "00:00", &fgcol);
+  priv->position = clutter_label_new_full (font_desc, "00:00", &fgcol);
+
+  so = clutter_actor_get_width (priv->position)/2 + 10;
+
+  g_snprintf(font_desc, 32, "Sans Bold %ipx", h/6); 
+
+  priv->title = clutter_label_new_with_text (font_desc, " ");
+  clutter_label_set_color (CLUTTER_LABEL(priv->title), &txtcol);
+  clutter_label_set_line_wrap (CLUTTER_LABEL(priv->title), FALSE);
+  clutter_label_set_ellipsize  (CLUTTER_LABEL(priv->title), 
+                               PANGO_ELLIPSIZE_MIDDLE);
+  clutter_actor_set_width (priv->title, w/2);
+  clutter_actor_set_position (priv->title, so, 10);
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), priv->title);
+
+  priv->vol_label = clutter_label_new_with_text (font_desc, "");
+  clutter_label_set_color (CLUTTER_LABEL(priv->vol_label), &seekcol);
+  clutter_label_set_line_wrap (CLUTTER_LABEL(priv->vol_label), FALSE);
+  clutter_actor_set_width (priv->vol_label, w/8);
+  clutter_actor_set_position (priv->vol_label, w-(w/8)-10, 10);
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), priv->vol_label);
+
+  /* Seek bar */
+  priv->video_seekbar_bg = clutter_rectangle_new_with_color (&seekcol);
+  clutter_actor_set_size (priv->video_seekbar_bg, w - (2*so), 20);
+  clutter_actor_set_position (priv->video_seekbar_bg, so, 
+                             15 + clutter_actor_get_height (priv->title));
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), 
+                    priv->video_seekbar_bg);
+
+  priv->video_seekbar = clutter_rectangle_new_with_color (&fgcol);
+  clutter_actor_set_size (priv->video_seekbar, 0, 20);
+  clutter_actor_set_position (priv->video_seekbar, so, 
+                             15 + clutter_actor_get_height (priv->title));
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), priv->video_seekbar);
+
+
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), priv->duration);
+  clutter_actor_set_position (priv->duration, 
+                             w - clutter_actor_get_width (priv->duration)-10, 
+                             15 + clutter_actor_get_height (priv->title) + 20);  
+
+  clutter_group_add (CLUTTER_GROUP(priv->video_controls), priv->position);
+  clutter_actor_set_position (priv->position, so, 15 + clutter_actor_get_height (priv->title) + 20);  
+
+  clutter_actor_set_position (priv->video_controls, 
+                             CSW()/8, h/3);
+
+  clutter_actor_set_parent (CLUTTER_ACTOR(priv->video_controls), 
+                           CLUTTER_ACTOR(screen)); 
+
+  clutter_actor_set_opacity (CLUTTER_ACTOR(priv->video_controls), 0);
+
+  priv->controls_effect_tmpl 
+    = clutter_effect_template_new (clutter_timeline_new (30, 60),
+                                  CLUTTER_ALPHA_SINE_INC);
+
+  priv->fadein_effect_tmpl 
+    = clutter_effect_template_new (clutter_timeline_new (30, 60),
+                                  CLUTTER_ALPHA_SINE_INC);
+}
+
+static void
+wh_screen_video_init (WHScreenVideo *self)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(self);
+  ClutterColor          black = { 0,0,0,255 };
+
+  /* Create child video texture */
+#ifdef USE_HELIX
+  priv->video = clutter_helix_video_texture_new ();
+#else
+  priv->video = clutter_gst_video_texture_new ();
+#endif
+
+  /* Dont let the underlying pixbuf dictate size */
+  g_object_set (G_OBJECT(priv->video), "sync-size", FALSE, NULL);
+
+  /* Handle it ourselves so can scale up for fullscreen better */
+  g_signal_connect (CLUTTER_TEXTURE(priv->video), 
+                   "size-change",
+                   G_CALLBACK (video_size_change), NULL);
+
+  priv->bg = clutter_rectangle_new_with_color (&black);
+  clutter_actor_set_size (priv->bg, 
+                         CLUTTER_STAGE_WIDTH(), CLUTTER_STAGE_HEIGHT());
+  clutter_actor_set_opacity (priv->bg, 0);
+
+  clutter_actor_set_parent (priv->bg, CLUTTER_ACTOR(self)); 
+  clutter_actor_set_parent (priv->video, CLUTTER_ACTOR(self)); 
+
+  clutter_actor_show (priv->video);
+
+  /* Make  */
+  video_make_controls (self);
+}
+
+ClutterActor*
+wh_screen_video_new (void)
+{
+  return CLUTTER_ACTOR(g_object_new (WH_TYPE_SCREEN_VIDEO, NULL));
+}
+
+static void
+on_wh_screen_video_error (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  /* Hack to stop looping on an unplayable file. 
+   * FIXME: Need much better error handling..
+  */
+
+  g_signal_emit (screen, _screen_signals[PLAYBACK_STARTED], 0);
+
+  g_signal_handlers_disconnect_by_func (priv->video, 
+                                       G_CALLBACK (video_tick),
+                                       screen);
+
+  g_signal_handlers_disconnect_by_func(clutter_stage_get_default(),
+                                      video_input_cb,
+                                      screen);
+
+  g_signal_emit (screen, _screen_signals[PLAYBACK_FINISHED], 0);
+}
+
+
+void
+wh_screen_video_deactivate (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  if (clutter_actor_is_rotated (priv->video))
+    {
+      ClutterEffectTemplate *template;
+         
+      template = clutter_effect_template_new_for_duration 
+       (1000, CLUTTER_ALPHA_SINE_INC);
+      clutter_effect_rotate (template,
+                            CLUTTER_ACTOR (priv->video),
+                            CLUTTER_Y_AXIS,
+                            0,
+                            CSW()/2, CSH()/2, 0,
+                            CLUTTER_ROTATE_CCW,
+                            NULL,
+                            NULL);
+    }
+
+  g_signal_handlers_disconnect_by_func (priv->video, 
+                                       G_CALLBACK (video_tick),
+                                       screen);
+
+  clutter_media_set_playing (CLUTTER_MEDIA(priv->video), FALSE);
+
+  priv->video_playing = FALSE;
+
+  video_hide_controls (screen);
+
+  g_signal_handlers_disconnect_by_func(clutter_stage_get_default(),
+                                      video_input_cb,
+                                      screen);
+
+  g_signal_emit (screen, _screen_signals[PLAYBACK_FINISHED], 0);
+}
+
+gboolean
+wh_screen_video_get_playing (WHScreenVideo *screen)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+
+  return priv->video_playing;
+}
+
+gboolean
+wh_screen_video_activate (WHScreenVideo *screen, WHVideoView *view)
+{
+  WHScreenVideoPrivate *priv  = SCREEN_VIDEO_PRIVATE(screen);
+  gchar *episode = NULL, *series = NULL, *title = NULL, buf[16];
+
+  priv->video_row = wh_video_view_get_selected (WH_VIDEO_VIEW(view));
+
+  if (priv->video_row == NULL 
+      || wh_video_model_row_get_path(priv->video_row) == NULL)
+    return FALSE;
+
+  g_signal_connect (clutter_stage_get_default(), 
+                   "key-release-event",
+                   G_CALLBACK (video_input_cb),
+                   screen);
+
+  g_signal_connect (priv->video,
+                   "notify::position",
+                   G_CALLBACK (video_tick),
+                   screen);
+
+  g_signal_connect_swapped (priv->video,
+                   "eos",
+                   G_CALLBACK (wh_screen_video_deactivate),
+                   screen);
+
+  g_signal_connect_swapped (priv->video,
+                   "error",
+                   G_CALLBACK (on_wh_screen_video_error),
+                   screen);
+
+  g_signal_connect (priv->video,
+                   "pixbuf-change",
+                   G_CALLBACK(video_pixbuf_change),
+                   screen);
+
+  priv->video_controls_visible = FALSE;
+
+  g_snprintf (buf, sizeof(buf), "Vol:%.2i", 
+             (gint)(clutter_media_get_volume (CLUTTER_MEDIA(priv->video))/0.1));
+  clutter_label_set_text (CLUTTER_LABEL(priv->vol_label), buf);
+
+  wh_video_model_row_get_extended_info (priv->video_row, &series, &episode);
+  
+  title = g_strdup_printf("%s%s%s%s%s%s",
+                         wh_video_model_row_get_title (priv->video_row),
+                         (series != NULL || episode != NULL) ? " (" : "", 
+                         series != NULL  ?  series : "",
+                         (series != NULL && episode != NULL) ? "/" : "", 
+                         episode != NULL ?  episode : "",
+                         (series != NULL || episode != NULL) ? ")" : "");
+      
+  clutter_label_set_text (CLUTTER_LABEL(priv->title), title);
+  clutter_actor_set_width (priv->title, CSW()/2);
+
+  g_free (title);
+
+  clutter_media_set_uri(CLUTTER_MEDIA(priv->video), 
+                       wh_video_model_row_get_path(priv->video_row));
+  clutter_media_set_playing (CLUTTER_MEDIA(priv->video), TRUE);
+
+  return TRUE;
+}
diff --git a/attic/woohaa/wh-screen-video.h b/attic/woohaa/wh-screen-video.h
new file mode 100644 (file)
index 0000000..84f3738
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _HAVE_WH_SCREEN_VIDEO_H
+#define _HAVE_WH_SCREEN_VIDEO_H
+
+#include <clutter/clutter.h>
+#include "wh-video-view.h"
+
+G_BEGIN_DECLS
+
+#define WH_TYPE_SCREEN_VIDEO wh_screen_video_get_type()
+
+#define WH_SCREEN_VIDEO(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WH_TYPE_SCREEN_VIDEO, WHScreenVideo))
+
+#define WH_SCREEN_VIDEO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WH_TYPE_SCREEN_VIDEO, WHScreenVideoClass))
+
+#define WH_IS_SCREEN_VIDEO(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WH_TYPE_SCREEN_VIDEO))
+
+#define WH_IS_SCREEN_VIDEO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WH_TYPE_SCREEN_VIDEO))
+
+#define WH_SCREEN_VIDEO_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WH_TYPE_SCREEN_VIDEO, WHScreenVideoClass))
+
+typedef struct {
+  ClutterActor parent;
+} WHScreenVideo;
+
+typedef struct {
+  ClutterActorClass parent_class;
+
+  void (*started) (WHScreenVideo *screen);
+  void (*finished) (WHScreenVideo *screen);
+
+} WHScreenVideoClass;
+
+GType wh_screen_video_get_type (void);
+
+ClutterActor* wh_screen_video_new (void);
+
+gboolean
+wh_screen_video_activate (WHScreenVideo *screen, WHVideoView *view);
+
+void
+wh_screen_video_deactivate (WHScreenVideo *screen);
+
+gboolean
+wh_screen_video_get_playing (WHScreenVideo *screen);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-slider-menu.c b/attic/woohaa/wh-slider-menu.c
new file mode 100644 (file)
index 0000000..8195405
--- /dev/null
@@ -0,0 +1,518 @@
+#include <glib.h>
+#include "wh-slider-menu.h"
+
+#define CSW() CLUTTER_STAGE_WIDTH()
+#define CSH() CLUTTER_STAGE_HEIGHT()
+
+#define SELECTED_OFFSET (CLUTTER_STAGE_WIDTH()/5)
+
+typedef struct WoohaaSliderMenuEntry
+{
+  ClutterActor                   *actor;
+  WoohaaSliderMenuSelectedFunc    selected_func;
+  gpointer                        userdata;
+  gint                            offset;
+}
+WoohaaSliderMenuEntry;
+
+#define WOOHAA_TYPE_BEHAVIOUR_SLIDER (clutter_behaviour_slider_get_type ())
+
+#define WOOHAA_BEHAVIOUR_SLIDER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WOOHAA_TYPE_BEHAVIOUR_SLIDER, WoohaaBehaviourSlider))
+
+#define WOOHAA_BEHAVIOUR_SLIDER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WOOHAA_TYPE_BEHAVIOUR_SLIDER, WoohaaBehaviourSliderClass))
+
+#define CLUTTER_IS_BEHAVIOUR_SLIDER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WOOHAA_TYPE_BEHAVIOUR_SLIDER))
+
+#define CLUTTER_IS_BEHAVIOUR_SLIDER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WOOHAA_TYPE_BEHAVIOUR_SLIDER))
+
+#define WOOHAA_BEHAVIOUR_SLIDER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WOOHAA_TYPE_BEHAVIOUR_SLIDER, WoohaaBehaviourSliderClass))
+
+typedef struct _WoohaaBehaviourSlider        WoohaaBehaviourSlider;
+typedef struct _WoohaaBehaviourSliderClass   WoohaaBehaviourSliderClass;
+struct _WoohaaBehaviourSlider
+{
+  ClutterBehaviour        parent;
+  WoohaaSliderMenuEntry  *old;
+  WoohaaSliderMenuEntry  *new;
+  WoohaaSliderMenu       *menu;
+};
+
+struct _WoohaaBehaviourSliderClass
+{
+  ClutterBehaviourClass   parent_class;
+};
+
+GType clutter_behaviour_slider_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (WoohaaBehaviourSlider, clutter_behaviour_slider, CLUTTER_TYPE_BEHAVIOUR);
+
+static ClutterBehaviour*
+clutter_behaviour_slider_new (WoohaaSliderMenu *menu,
+                             WoohaaSliderMenuEntry *start,
+                             WoohaaSliderMenuEntry *end);
+
+struct _WoohaaSliderMenuPrivate
+{
+  GList           *entrys;
+  gint             entry_height;
+  gint             menu_width;
+  gint             n_entrys;
+  gint             active_entry_num;
+  gint             offset;         /* current offset */
+  gint             unclipped_width;
+  ClutterActor    *bg;
+  ClutterActor    *entry_group;
+
+  guint            alpha_value;
+
+  ClutterTimeline        *timeline;
+  ClutterAlpha           *alpha;
+  ClutterBehaviour       *behave;
+  ClutterEffectTemplate  *effect_template;
+
+  gchar            *font;
+  ClutterColor     *font_color;
+  ClutterActor     *next, *prev;
+};
+
+G_DEFINE_TYPE (WoohaaSliderMenu, woohaa_slider_menu, CLUTTER_TYPE_ACTOR);
+
+#define WOOHAA_SLIDER_MENU_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), WOOHAA_TYPE_SLIDER_MENU, WoohaaSliderMenuPrivate))
+
+static void
+woohaa_slider_menu_dispose (GObject *object)
+{
+  WoohaaSliderMenu        *self;
+  WoohaaSliderMenuPrivate *priv; 
+
+  self = WOOHAA_SLIDER_MENU(object); 
+  priv = self->priv;
+
+  G_OBJECT_CLASS (woohaa_slider_menu_parent_class)->dispose (object);
+}
+
+static void
+woohaa_slider_menu_finalize (GObject *object)
+{
+  WoohaaSliderMenu        *self;
+  WoohaaSliderMenuPrivate *priv; 
+
+  self = WOOHAA_SLIDER_MENU(object); 
+  priv = self->priv;
+
+  G_OBJECT_CLASS (woohaa_slider_menu_parent_class)->finalize (object);
+}
+
+static void
+woohaa_slider_menu_paint (ClutterActor *actor)
+{
+  WoohaaSliderMenuPrivate *priv = (WOOHAA_SLIDER_MENU (actor))->priv;
+  
+  clutter_actor_paint (priv->bg);
+  clutter_actor_paint (priv->next);
+  clutter_actor_paint (priv->prev);
+  clutter_actor_paint (priv->entry_group);
+}
+
+static void
+woohaa_slider_menu_get_preferred_width  (ClutterActor *actor,
+                                        ClutterUnit   for_height,
+                                        ClutterUnit  *min_width_p,
+                                        ClutterUnit  *natural_width_p)
+{
+  *min_width_p = CLUTTER_UNITS_FROM_INT (100);
+  *natural_width_p = CLUTTER_UNITS_FROM_INT (CSW());
+}
+
+static void
+woohaa_slider_menu_get_preferred_height (ClutterActor *actor,
+                                        ClutterUnit   for_width,
+                                        ClutterUnit  *min_height_p,
+                                        ClutterUnit  *natural_height_p)
+{
+  WoohaaSliderMenuPrivate *priv = (WOOHAA_SLIDER_MENU (actor))->priv;
+
+  *min_height_p = CLUTTER_UNITS_FROM_INT (1);
+  if (priv->entry_height)
+         *natural_height_p = CLUTTER_UNITS_FROM_INT (priv->entry_height * 2);
+  else
+         *natural_height_p = CLUTTER_UNITS_FROM_INT (200);
+}
+
+static void
+woohaa_slider_menu_allocate (ClutterActor *actor, 
+                            const ClutterActorBox *box,
+                            gboolean absolute_origin_changed)
+{
+  WoohaaSliderMenuPrivate *priv = (WOOHAA_SLIDER_MENU (actor))->priv;
+  ClutterUnit natural_width, natural_height;
+  ClutterActorBox child_box;
+  ClutterUnit focal_x, focal_y;
+  ClutterUnit entry_offset = 0, entry_width = 0;
+  WoohaaSliderMenuEntry *current, *old;
+  
+  clutter_actor_get_preferred_size (priv->bg, NULL, NULL, 
+                                   &natural_width, &natural_height);
+  child_box.x1 = 0;
+  child_box.y1 = 0;
+  child_box.x2 = natural_width;
+  child_box.y2 = natural_height;
+  clutter_actor_allocate (priv->bg, &child_box, absolute_origin_changed);
+
+  focal_x = CLUTTER_UNITS_FROM_INT(CSW()/4);
+  focal_y = 0;
+
+  if (priv->entrys)
+  {
+    current = (WOOHAA_BEHAVIOUR_SLIDER (priv->behave))->new;
+    old = (WOOHAA_BEHAVIOUR_SLIDER (priv->behave))->old;
+    
+    if (current && old)
+      {
+       entry_offset = (clutter_actor_get_xu (current->actor) - clutter_actor_get_xu (old->actor)) * 
+         ((gdouble)(priv->alpha_value) / (gdouble)CLUTTER_ALPHA_MAX_ALPHA) +
+         clutter_actor_get_xu (old->actor);
+
+       entry_width = (clutter_actor_get_widthu (current->actor) - clutter_actor_get_widthu (old->actor)) * 
+         ((gdouble)(priv->alpha_value) / (gdouble)CLUTTER_ALPHA_MAX_ALPHA) +
+         clutter_actor_get_widthu (old->actor);
+      }
+
+  }
+
+  child_box.x1 = focal_x - entry_offset;
+  child_box.y1 = focal_y;
+  child_box.x2 = natural_height/2 + child_box.x1 - entry_offset;
+  child_box.y2 = natural_height/2 + child_box.y1;
+  clutter_actor_allocate (priv->entry_group, 
+                         &child_box, 
+                         absolute_origin_changed);
+
+  if (priv->active_entry_num > 0)
+    {
+      clutter_actor_set_opacity (priv->prev, 0xAA);
+
+      child_box.x1 = focal_x - natural_height/2;
+      child_box.y1 = focal_y + natural_height/10;
+      child_box.x2 = natural_height/2 + child_box.x1;
+      child_box.y2 = natural_height/2 + child_box.y1;
+      clutter_actor_allocate (priv->prev, &child_box, absolute_origin_changed);
+    }
+  else
+    {
+      clutter_actor_set_opacity (priv->prev, 
+                                0xff + (priv->alpha_value * (-0xff)
+                                        / CLUTTER_ALPHA_MAX_ALPHA));
+    }
+
+  if (priv->active_entry_num < priv->n_entrys - 1)
+    {
+      clutter_actor_set_opacity (priv->next, 0xAA);
+
+      child_box.x1 = focal_x + entry_width;
+      child_box.y1 = focal_y + natural_height/10;
+      child_box.x2 = natural_height/2 + child_box.x1;
+      child_box.y2 = natural_height/2 + child_box.y1;
+      clutter_actor_allocate (priv->next, &child_box, absolute_origin_changed);
+    }
+  else
+    {
+      clutter_actor_set_opacity (priv->next, 
+                                0xff + (priv->alpha_value * (-0xff)
+                                        / CLUTTER_ALPHA_MAX_ALPHA));
+    }
+
+  CLUTTER_ACTOR_CLASS (woohaa_slider_menu_parent_class)->
+         allocate (actor, box, absolute_origin_changed);
+}
+
+static void
+woohaa_slider_menu_class_init (WoohaaSliderMenuClass *klass)
+{
+  GObjectClass *object_class     = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (WoohaaSliderMenuPrivate));
+
+  object_class->dispose      = woohaa_slider_menu_dispose;
+  object_class->finalize     = woohaa_slider_menu_finalize;
+
+  actor_class->get_preferred_width  = woohaa_slider_menu_get_preferred_width;
+  actor_class->get_preferred_height = woohaa_slider_menu_get_preferred_height;
+  actor_class->allocate             = woohaa_slider_menu_allocate;
+  actor_class->paint                = woohaa_slider_menu_paint;
+}
+
+static void
+woohaa_slider_menu_init (WoohaaSliderMenu *woohaa_slider_menu)
+{
+  WoohaaSliderMenuPrivate   *priv;
+
+  woohaa_slider_menu->priv = priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (woohaa_slider_menu,
+                                 WOOHAA_TYPE_SLIDER_MENU,
+                                 WoohaaSliderMenuPrivate);
+
+  priv->menu_width = CSW();
+
+  priv->timeline = clutter_timeline_new (30, 60);
+
+  priv->alpha = clutter_alpha_new_full (priv->timeline,
+                                       CLUTTER_ALPHA_SINE_INC,
+                                       NULL, NULL);
+
+  priv->behave = clutter_behaviour_slider_new (woohaa_slider_menu, 0, 0);
+
+  priv->effect_template 
+    = clutter_effect_template_new (clutter_timeline_new (20, 60),
+                                  CLUTTER_ALPHA_SINE_INC);
+
+  priv->font_color = g_new0(ClutterColor, 1);
+  clutter_color_parse ("#ccccccff", priv->font_color);
+
+  priv->bg = clutter_texture_new_from_file (PKGDATADIR "/header.svg", NULL);
+  if (!priv->bg) g_warning ("Unable to load heaer.svg");
+
+  clutter_actor_set_parent (priv->bg, CLUTTER_ACTOR (woohaa_slider_menu));
+
+  clutter_actor_set_width (priv->bg, CSW());
+  
+  clutter_actor_show (priv->bg);
+
+  priv->next = clutter_texture_new_from_file (PKGDATADIR "/arrow-next.svg", 
+                                             NULL);
+  if (!priv->next) g_warning ("Unable to load arror-next.svg");
+
+  clutter_actor_hide (priv->next);
+  clutter_actor_set_parent (priv->next, CLUTTER_ACTOR (woohaa_slider_menu));
+
+  priv->prev = clutter_texture_new_from_file (PKGDATADIR "/arrow-prev.svg", 
+                                             NULL);
+  if (!priv->prev) g_warning ("Unable to load arror-prev.svg");
+
+  clutter_actor_hide (priv->prev);
+  clutter_actor_set_parent (priv->prev, CLUTTER_ACTOR (woohaa_slider_menu));
+
+  priv->entry_group = clutter_group_new ();
+  clutter_actor_set_parent (priv->entry_group, 
+                           CLUTTER_ACTOR (woohaa_slider_menu));
+  clutter_actor_show (priv->entry_group);
+}
+
+ClutterActor*
+woohaa_slider_menu_new (const gchar *font)
+{
+  ClutterActor         *menu;
+  WoohaaSliderMenuPrivate  *priv;
+
+  menu = g_object_new (WOOHAA_TYPE_SLIDER_MENU, NULL);
+  priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
+  priv->font = g_strdup(font);
+
+  return menu;
+}
+
+void
+woohaa_slider_menu_add_option (WoohaaSliderMenu            *menu, 
+                              const gchar                 *text,
+                              WoohaaSliderMenuSelectedFunc selected,
+                              gpointer                     userdata)
+{
+  WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
+  WoohaaSliderMenuEntry    *entry;
+  ClutterActor             *actor;
+  gint                      pad = 0;
+
+  actor = clutter_label_new_with_text (priv->font, text);
+  clutter_label_set_color (CLUTTER_LABEL(actor), priv->font_color);
+  clutter_label_set_line_wrap (CLUTTER_LABEL(actor), FALSE);
+
+  entry = g_new0(WoohaaSliderMenuEntry, 1);
+  entry->actor = actor;
+  entry->selected_func = selected;
+  entry->userdata = userdata;
+
+  if (clutter_actor_get_height(actor) > priv->entry_height)
+    {
+      priv->entry_height = clutter_actor_get_height(actor);
+
+      clutter_actor_set_width (priv->bg, CSW());
+      clutter_actor_set_height (priv->bg, priv->entry_height
+       + (priv->entry_height/2));
+    }
+
+  if (clutter_actor_get_height(priv->next) > priv->entry_height)
+    {
+      gint w, h;
+
+      w = priv->entry_height/8;
+      h = priv->entry_height/4;
+      
+      clutter_actor_set_size (priv->next, w, h);
+      clutter_actor_set_size (priv->prev, w, h);
+    }
+
+  pad = clutter_actor_get_width (priv->next) * 2;
+
+  entry->offset = priv->unclipped_width + pad;
+
+  if (priv->entrys == NULL)
+    priv->unclipped_width += pad;
+
+  priv->unclipped_width += clutter_actor_get_width(actor) + pad;
+
+  if (priv->entrys == 0)
+    {
+      /* First Entry */
+      clutter_actor_set_opacity (actor, 0xff);
+    }
+  else
+    {
+      clutter_actor_set_opacity (actor, 0x33);
+      clutter_actor_set_scale (actor, 0.7, 0.7);
+    }
+
+  clutter_group_add (CLUTTER_GROUP (priv->entry_group), actor);
+
+  priv->entrys = g_list_append (priv->entrys, entry);
+
+  clutter_actor_set_position (actor, 
+                             entry->offset, 
+                             priv->entry_height/12);
+
+  priv->n_entrys++;
+}
+
+void
+woohaa_slider_menu_activate (WoohaaSliderMenu *menu,
+                            gint              entry_num)
+{
+  WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
+  WoohaaSliderMenuEntry *selected, *current;
+
+  if (entry_num < 0 || entry_num >= priv->n_entrys)
+      return;
+
+  if (clutter_timeline_is_playing(priv->timeline))
+    return;
+
+  current 
+    = (WoohaaSliderMenuEntry *)g_list_nth_data(priv->entrys, 
+                                              priv->active_entry_num);
+
+  selected = (WoohaaSliderMenuEntry *)g_list_nth_data(priv->entrys, 
+                                                     entry_num);
+
+  priv->active_entry_num = entry_num;
+
+  WOOHAA_BEHAVIOUR_SLIDER(priv->behave)->old = current;
+  WOOHAA_BEHAVIOUR_SLIDER(priv->behave)->new = selected;
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (menu));
+
+  /* FIXME: Should be a signal */
+  if (selected->selected_func)
+    selected->selected_func(menu, selected->actor, selected->userdata);
+
+  clutter_timeline_start (priv->timeline);    
+}
+
+void
+woohaa_slider_menu_advance (WoohaaSliderMenu *menu, gint n)
+{
+  WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
+  woohaa_slider_menu_activate (menu, priv->active_entry_num + n);
+}
+
+/* Custom behaviour */
+
+static void
+clutter_behaviour_alpha_notify (ClutterBehaviour *behave,
+                                guint32           alpha_value)
+{
+  WoohaaBehaviourSlider *slide = WOOHAA_BEHAVIOUR_SLIDER(behave);
+  WoohaaSliderMenu      *menu;
+  gdouble                scale;
+  WoohaaSliderMenuPrivate  *priv;
+
+  if (!(slide->old) || !(slide->new))
+    return;
+
+  menu = slide->menu;
+  priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
+
+  priv->offset = slide->old->offset + 
+                      (((gint)alpha_value * 
+                          (slide->new->offset - slide->old->offset))
+                              / CLUTTER_ALPHA_MAX_ALPHA);
+
+  clutter_actor_set_opacity (slide->old->actor, 
+                            0xff + (alpha_value 
+                                    * (0x66 - 0xff)
+                                    / CLUTTER_ALPHA_MAX_ALPHA));
+
+  clutter_actor_set_opacity (slide->new->actor, 
+                            0x66 + (alpha_value 
+                                    * (0xff - 0x66)
+                                    / CLUTTER_ALPHA_MAX_ALPHA));
+
+  scale = (0.3 * alpha_value) / (gdouble)CLUTTER_ALPHA_MAX_ALPHA;
+
+  clutter_actor_set_scale (slide->new->actor,
+                          0.7 + scale,
+                          0.7 + scale);
+
+  if (slide->new->actor != slide->old->actor)
+    clutter_actor_set_scale (slide->old->actor,
+                            1.0 - scale,
+                            1.0 - scale);
+
+  priv->alpha_value = alpha_value;
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(menu)))
+    clutter_actor_queue_relayout (CLUTTER_ACTOR (menu));
+}
+
+static void
+clutter_behaviour_slider_class_init (WoohaaBehaviourSliderClass *klass)
+{
+  ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
+
+  behave_class->alpha_notify = clutter_behaviour_alpha_notify;
+}
+
+static void
+clutter_behaviour_slider_init (WoohaaBehaviourSlider *self)
+{
+}
+
+static ClutterBehaviour*
+clutter_behaviour_slider_new (WoohaaSliderMenu      *menu,
+                             WoohaaSliderMenuEntry *old,
+                             WoohaaSliderMenuEntry *new)
+{
+  WoohaaSliderMenuPrivate  *priv = WOOHAA_SLIDER_MENU_GET_PRIVATE (menu);
+  WoohaaBehaviourSlider *slide_behave;
+
+  slide_behave = g_object_new (WOOHAA_TYPE_BEHAVIOUR_SLIDER, 
+                              "alpha", priv->alpha,
+                              NULL);
+
+  slide_behave->old   = old;
+  slide_behave->new   = new;
+  slide_behave->menu  = menu;
+
+  return CLUTTER_BEHAVIOUR(slide_behave);
+}
diff --git a/attic/woohaa/wh-slider-menu.h b/attic/woohaa/wh-slider-menu.h
new file mode 100644 (file)
index 0000000..eaa04e8
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef _HAVE_WOOHAA_SLIDER_MENU_H
+#define _HAVE_WOOHAA_SLIDER_MENU_H
+
+#include <clutter/clutter.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+#define WOOHAA_TYPE_SLIDER_MENU woohaa_slider_menu_get_type()
+
+#define WOOHAA_SLIDER_MENU(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WOOHAA_TYPE_SLIDER_MENU, WoohaaSliderMenu))
+
+#define WOOHAA_SLIDER_MENU_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WOOHAA_TYPE_SLIDER_MENU, WoohaaSliderMenuClass))
+
+#define WOOHAA_IS_SLIDER_MENU(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WOOHAA_TYPE_SLIDER_MENU))
+
+#define WOOHAA_IS_SLIDER_MENU_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WOOHAA_TYPE_SLIDER_MENU))
+
+#define WOOHAA_SLIDER_MENU_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WOOHAA_TYPE_SLIDER_MENU, WoohaaSliderMenuClass))
+
+typedef struct _WoohaaSliderMenu        WoohaaSliderMenu;
+typedef struct _WoohaaSliderMenuClass   WoohaaSliderMenuClass;
+typedef struct _WoohaaSliderMenuPrivate WoohaaSliderMenuPrivate;
+
+struct _WoohaaSliderMenu
+{
+  /*< private >*/
+  ClutterActor             parent;
+  WoohaaSliderMenuPrivate *priv;
+}; 
+
+struct _WoohaaSliderMenuClass 
+{
+  /*< private >*/
+  ClutterActorClass parent_class;
+
+  /* Future padding */
+  void (* __reserved1) (void);
+  void (* __reserved2) (void);
+  void (* __reserved3) (void);
+  void (* __reserved4) (void);
+  void (* __reserved5) (void);
+  void (* __reserved6) (void);
+}; 
+
+typedef void (*WoohaaSliderMenuSelectedFunc) (WoohaaSliderMenu *menu,
+                                             ClutterActor     *actor,
+                                             gpointer          userdata);
+
+GType         woohaa_slider_menu_get_type  (void) G_GNUC_CONST;
+ClutterActor *woohaa_slider_menu_new       (const gchar *font);
+
+void woohaa_slider_menu_add_option (WoohaaSliderMenu            *menu, 
+                                   const gchar                 *text,
+                                   WoohaaSliderMenuSelectedFunc selected,
+                                   gpointer                     userdata);
+void woohaa_slider_menu_activate   (WoohaaSliderMenu             *menu,
+                                   gint                         entry_num);
+void woohaa_slider_menu_advance    (WoohaaSliderMenu             *menu, 
+                                   gint                          n);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-theme.c b/attic/woohaa/wh-theme.c
new file mode 100644 (file)
index 0000000..e611580
--- /dev/null
@@ -0,0 +1,78 @@
+#include "wh-theme.h"
+
+#define FONT_DEFAULT "Sans"
+
+#define PIXBUF_BG        PKGDATADIR "/bg.png"
+#define PIXBUF_BUSY      PKGDATADIR "/busy.png"
+#define PIXBUF_THUMBNAIL PKGDATADIR "/thumbnail-default.png"
+
+#define COLOR_SLIDER
+#define COLOR_SELECTOR
+#define COLOR_TITLE_ACTIVE
+#define COLOR_TITLE_INACTIVE
+#define COLOR_DETAIS
+
+
+typedef struct WHTheme
+{
+  GHashTable *sounds, *fonts, *colors, *pixbufs;
+}
+WHTheme;
+
+static WHTheme *_theme = NULL;
+
+void
+wh_theme_init()
+{
+  GdkPixbuf    *pixbuf;
+
+  _theme = g_new(WHTheme, 1);
+
+  _theme->fonts   = g_hash_table_new (g_str_hash, g_str_equal);
+  _theme->sounds  = g_hash_table_new (NULL, NULL);
+  _theme->colors  = g_hash_table_new (NULL, NULL);
+  _theme->pixbufs = g_hash_table_new (NULL, NULL);
+
+  g_hash_table_insert (_theme->fonts, "default", FONT_DEFAULT);
+
+  pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR "/busy.png", NULL);
+  if (pixbuf == NULL)
+    g_error ("Failed to load" PKGDATADIR "/busy.png");
+  g_hash_table_insert (_theme->pixbufs, "busy", pixbuf);
+
+  pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR "/bg.png", NULL);
+  if (pixbuf == NULL)
+    g_error ("Failed to load" PKGDATADIR "/bg.png");
+  g_hash_table_insert (_theme->pixbufs, "bg", pixbuf);
+
+  pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR "/default-thumb.png", NULL);
+  if (pixbuf == NULL)
+    g_error ("Failed to load " PKGDATADIR "/default-thumb.png");
+  g_hash_table_insert (_theme->pixbufs, "default-thumbnail", pixbuf);
+}
+
+const char*
+wh_theme_get_font (const char *id)
+{
+  return (const char*)g_hash_table_lookup (_theme->fonts, id);
+}
+
+const ClutterColor*
+wh_theme_get_color(const char *id)
+{
+  /* FIXME */
+  return NULL;
+}
+
+const ClutterMedia*
+wh_theme_get_sound(const char *id)
+{
+  return NULL;
+}
+
+GdkPixbuf*
+wh_theme_get_pixbuf(const char *id)
+{
+  /* FIXME */
+    return (GdkPixbuf*)g_hash_table_lookup (_theme->pixbufs, id);
+}
diff --git a/attic/woohaa/wh-theme.h b/attic/woohaa/wh-theme.h
new file mode 100644 (file)
index 0000000..afce57e
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _WH_THEME
+#define _WH_THEME
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+void
+wh_theme_init();
+
+const char*
+wh_theme_get_font (const char *id);
+
+const ClutterColor*
+wh_theme_get_color(const char *id);
+
+const ClutterMedia*
+wh_theme_get_sound(const char *id);
+
+GdkPixbuf*
+wh_theme_get_pixbuf(const char *id);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-video-model-row.c b/attic/woohaa/wh-video-model-row.c
new file mode 100644 (file)
index 0000000..778f559
--- /dev/null
@@ -0,0 +1,468 @@
+/* wh-video-model-row.c */
+
+#include "wh-video-model-row.h"
+#include "wh-video-row-renderer.h"
+
+G_DEFINE_TYPE (WHVideoModelRow, wh_video_model_row, G_TYPE_OBJECT);
+
+#define VIDEO_MODEL_ROW_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), WH_TYPE_VIDEO_MODEL_ROW, WHVideoModelRowPrivate))
+
+typedef struct _WHVideoModelRowPrivate WHVideoModelRowPrivate;
+
+struct _WHVideoModelRowPrivate
+{
+  gchar              *path;
+  gchar              *title;
+  gchar              *series;
+  gchar              *episode;
+  gint                n_views;
+  time_t              age;
+  time_t              vtime;
+  GdkPixbuf          *thumbnail;
+  WHVideoRowRenderer *renderer; 
+};
+
+enum
+{
+  PROP_0,
+  PROP_PATH,
+  PROP_TITLE,
+  PROP_N_VIEWS,
+  PROP_AGE,
+  PROP_RENDERER,
+  PROP_VTIME,
+  PROP_SERIES,
+  PROP_EPISODE,
+  PROP_THUMBNAIL
+};
+
+static void
+wh_video_model_row_get_property (GObject *object, guint property_id,
+                                GValue *value, GParamSpec *pspec)
+{
+  WHVideoModelRow        *row = WH_VIDEO_MODEL_ROW(object);
+  WHVideoModelRowPrivate *priv;  
+  
+  priv = VIDEO_MODEL_ROW_PRIVATE(row);
+  
+  switch (property_id) 
+    {
+    case PROP_PATH:
+      g_value_set_string (value, priv->path);
+      break;
+    case PROP_TITLE:
+      g_value_set_string (value, priv->title);
+      break;
+    case PROP_SERIES:
+      g_value_set_string (value, priv->series);
+      break;
+    case PROP_EPISODE:
+      g_value_set_string (value, priv->episode);
+      break;
+    case PROP_N_VIEWS:
+      g_value_set_int (value, wh_video_model_row_get_n_views (row));
+      break;
+    case PROP_AGE:
+      g_value_set_int (value, wh_video_model_row_get_age (row));
+      break;
+    case PROP_VTIME:
+      g_value_set_int (value, wh_video_model_row_get_vtime (row));
+      break;
+    case PROP_RENDERER:
+      g_value_set_object (value, priv->renderer);
+      break;
+    case PROP_THUMBNAIL:
+      g_value_set_object (value, priv->thumbnail);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+wh_video_model_row_set_property (GObject *object, guint property_id,
+                                const GValue *value, GParamSpec *pspec)
+{
+ WHVideoModelRow *row = WH_VIDEO_MODEL_ROW(object);
+  WHVideoModelRowPrivate *priv;  
+  
+  priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  switch (property_id) 
+    {
+    case PROP_PATH:
+      wh_video_model_row_set_path (row, g_value_get_string (value));
+      break;
+    case PROP_TITLE:
+      wh_video_model_row_set_title (row, g_value_get_string (value));
+      break;
+    case PROP_SERIES:
+      wh_video_model_row_set_extended_info (row, 
+                                           g_value_get_string (value),
+                                           priv->episode);
+      break;
+    case PROP_EPISODE:
+      wh_video_model_row_set_extended_info (row,
+                                           priv->series,
+                                           g_value_get_string (value));
+      break;
+    case PROP_N_VIEWS:
+      wh_video_model_row_set_n_views (row, g_value_get_int (value));
+      break;
+    case PROP_AGE:
+      wh_video_model_row_set_age (row, g_value_get_int (value));
+      break;
+    case PROP_VTIME:
+      wh_video_model_row_set_vtime (row, g_value_get_int (value));
+      break;
+    case PROP_RENDERER:
+      wh_video_model_row_set_renderer (row, g_value_get_object (value));
+      break;
+    case PROP_THUMBNAIL:
+      wh_video_model_row_set_thumbnail (row, 
+                                       g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+wh_video_model_row_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (wh_video_model_row_parent_class)->dispose)
+    G_OBJECT_CLASS (wh_video_model_row_parent_class)->dispose (object);
+}
+
+static void
+wh_video_model_row_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (wh_video_model_row_parent_class)->finalize (object);
+}
+
+static void
+wh_video_model_row_class_init (WHVideoModelRowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (WHVideoModelRowPrivate));
+
+  object_class->get_property = wh_video_model_row_get_property;
+  object_class->set_property = wh_video_model_row_set_property;
+  object_class->dispose = wh_video_model_row_dispose;
+  object_class->finalize = wh_video_model_row_finalize;
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_PATH,
+     g_param_spec_string ("path",
+                         "Path",
+                         "path to rows video file",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_TITLE,
+     g_param_spec_string ("title",
+                         "title",
+                         "Title of row entry",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_SERIES,
+     g_param_spec_string ("series",
+                         "series",
+                         "Series",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_EPISODE,
+     g_param_spec_string ("episode",
+                         "episide",
+                         "Episode",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_N_VIEWS,
+     g_param_spec_int ("n-views",
+                      "n-views",
+                      "Numberof times video file has been watched",
+                      0, G_MAXINT,
+                      0,
+                      G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_AGE,
+     g_param_spec_int ("age",
+                      "Age",
+                      "Age in seconds",
+                      0, G_MAXINT,
+                      0,
+                      G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_VTIME,
+     g_param_spec_int ("last-viewed-time",
+                      "Last-Viewed-Time",
+                      "When file was last viewed",
+                      0, G_MAXINT,
+                      0,
+                      G_PARAM_READWRITE));
+
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_RENDERER,
+     g_param_spec_object ("renderer",
+                         "Renderer",
+                         "Renderer Object used to paint the row",
+                         WH_TYPE_VIDEO_ROW_RENDERER,
+                         G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_THUMBNAIL,
+     g_param_spec_object ("thumbnail",
+                         "Thumbnail",
+                         "Thumbnail image of video file",
+                         GDK_TYPE_PIXBUF,
+                         G_PARAM_READWRITE));
+
+}
+
+static void
+wh_video_model_row_init (WHVideoModelRow *self)
+{
+}
+
+WHVideoModelRow*
+wh_video_model_row_new (void)
+{
+  return g_object_new (WH_TYPE_VIDEO_MODEL_ROW, NULL);
+}
+
+G_CONST_RETURN gchar*
+wh_video_model_row_get_path (WHVideoModelRow *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->path;
+}
+
+void
+wh_video_model_row_set_path (WHVideoModelRow *row, const gchar *path)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  g_free (priv->path);
+  
+  if (path && path[0] != '\0')
+    priv->path = g_strdup(path);
+
+  g_object_notify (G_OBJECT (row), "path");
+  g_object_unref (row);
+}
+
+G_CONST_RETURN gchar*
+wh_video_model_row_get_title (WHVideoModelRow *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->title;
+}
+
+void
+wh_video_model_row_set_title (WHVideoModelRow *row, const gchar *title)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  g_free (priv->title);
+  priv->title = NULL;
+
+  if (title && title[0] != '\0')
+    priv->title = g_strdup(title);
+
+  g_object_notify (G_OBJECT (row), "title");
+  g_object_unref (row);
+}
+
+void
+wh_video_model_row_set_extended_info (WHVideoModelRow *row,
+                                     const gchar     *series,
+                                     const gchar     *episode)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  g_free (priv->series);
+  priv->series = NULL;
+  
+  if (series && series[0] != '\0')
+    priv->series = g_strdup(series);
+
+  g_object_notify (G_OBJECT (row), "series");
+
+  g_free (priv->episode);
+  priv->episode = NULL;
+  
+  if (episode && episode[0] != '\0')
+    priv->episode = g_strdup(episode);
+
+  g_object_notify (G_OBJECT (row), "episode");
+
+  g_object_unref (row);
+}
+
+void
+wh_video_model_row_get_extended_info (WHVideoModelRow *row,
+                                     gchar          **series,
+                                     gchar          **episode)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  if (priv->series)
+    *series = g_strdup (priv->series);
+  else
+    *series = NULL;
+
+  if (priv->episode)
+    *episode = g_strdup (priv->episode);
+  else
+    *episode = NULL;
+}
+
+
+gint
+wh_video_model_row_get_age (WHVideoModelRow *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->age;
+}
+
+void
+wh_video_model_row_set_age (WHVideoModelRow *row, gint age)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  priv->age = age;
+
+  g_object_notify (G_OBJECT (row), "age");
+  g_object_unref (row);
+}
+
+gint
+wh_video_model_row_get_vtime (WHVideoModelRow *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->vtime;
+}
+
+void
+wh_video_model_row_set_vtime (WHVideoModelRow *row, gint vtime)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  priv->vtime = vtime;
+
+  g_object_notify (G_OBJECT (row), "last-viewed-time");
+  g_object_unref (row);
+}
+
+gint
+wh_video_model_row_get_n_views (WHVideoModelRow *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->n_views;
+}
+
+void
+wh_video_model_row_set_renderer (WHVideoModelRow    *row, 
+                                WHVideoRowRenderer *renderer)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  if (priv->renderer)
+    g_object_unref (priv->renderer);
+
+  priv->renderer = renderer;
+
+  if (priv->renderer)
+    g_object_ref (priv->renderer);
+
+  g_object_notify (G_OBJECT (row), "renderer");
+  g_object_unref (row);
+}
+
+WHVideoRowRenderer*
+wh_video_model_row_get_renderer (WHVideoModelRow    *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->renderer;
+}
+
+void
+wh_video_model_row_set_n_views (WHVideoModelRow *row, gint n_views)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  priv->n_views = n_views;
+
+  g_object_notify (G_OBJECT (row), "n-views");
+  g_object_unref (row);
+}
+
+GdkPixbuf*
+wh_video_model_row_get_thumbnail (WHVideoModelRow *row)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  return priv->thumbnail;
+}
+
+void
+wh_video_model_row_set_thumbnail (WHVideoModelRow *row,
+                                 GdkPixbuf       *pixbuf)
+{
+  WHVideoModelRowPrivate *priv = VIDEO_MODEL_ROW_PRIVATE(row);
+
+  g_object_ref (row);
+
+  if (priv->thumbnail)
+    g_object_unref (priv->thumbnail);
+
+  if (pixbuf == NULL)
+    g_warning("got a null pixbuf so I will now likely crash");
+
+  priv->thumbnail = pixbuf;
+  g_object_ref (pixbuf);
+
+  g_object_notify (G_OBJECT (row), "thumbnail");
+  g_object_unref (row);
+}
diff --git a/attic/woohaa/wh-video-model-row.h b/attic/woohaa/wh-video-model-row.h
new file mode 100644 (file)
index 0000000..fce0fdd
--- /dev/null
@@ -0,0 +1,103 @@
+/* wh-video-model-row.h */
+#ifndef _WH_VIDEO_MODEL_ROW
+#define _WH_VIDEO_MODEL_ROW
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define WH_TYPE_VIDEO_MODEL_ROW wh_video_model_row_get_type()
+
+#define WH_VIDEO_MODEL_ROW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WH_TYPE_VIDEO_MODEL_ROW, WHVideoModelRow))
+
+#define WH_VIDEO_MODEL_ROW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WH_TYPE_VIDEO_MODEL_ROW, WHVideoModelRowClass))
+
+#define WH_IS_VIDEO_MODEL_ROW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WH_TYPE_VIDEO_MODEL_ROW))
+
+#define WH_IS_VIDEO_MODEL_ROW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WH_TYPE_VIDEO_MODEL_ROW))
+
+#define WH_VIDEO_MODEL_ROW_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WH_TYPE_VIDEO_MODEL_ROW, WHVideoModelRowClass))
+
+typedef struct {
+  GObject parent;
+} WHVideoModelRow;
+
+typedef struct {
+  GObjectClass parent_class;
+} WHVideoModelRowClass;
+
+#include "wh-video-row-renderer.h"
+
+GType wh_video_model_row_get_type (void);
+
+WHVideoModelRow* wh_video_model_row_new (void);
+
+G_CONST_RETURN gchar*
+wh_video_model_row_get_path (WHVideoModelRow *row);
+
+void
+wh_video_model_row_set_path (WHVideoModelRow *row, const gchar *path);
+
+G_CONST_RETURN gchar*
+wh_video_model_row_get_title (WHVideoModelRow *row);
+
+void
+wh_video_model_row_set_title (WHVideoModelRow *row, const gchar *title);
+
+gint
+wh_video_model_row_get_age (WHVideoModelRow *row);
+
+void
+wh_video_model_row_set_age (WHVideoModelRow *row, gint age);
+
+gint
+wh_video_model_row_get_n_views (WHVideoModelRow *row);
+
+void
+wh_video_model_row_set_n_views (WHVideoModelRow *row, gint n_views);
+
+gint
+wh_video_model_row_get_vtime (WHVideoModelRow *row);
+
+void
+wh_video_model_row_set_vtime (WHVideoModelRow *row, gint vtime);
+
+void
+wh_video_model_row_set_renderer (WHVideoModelRow    *row, 
+                                WHVideoRowRenderer *renderer);
+
+WHVideoRowRenderer*
+wh_video_model_row_get_renderer (WHVideoModelRow    *row);
+
+void
+wh_video_model_row_set_extended_info (WHVideoModelRow *row,
+                                     const gchar     *series,
+                                     const gchar     *episode);
+
+void
+wh_video_model_row_get_extended_info (WHVideoModelRow *row,
+                                     gchar          **series,
+                                     gchar          **episode);
+
+GdkPixbuf*
+wh_video_model_row_get_thumbnail (WHVideoModelRow *row);
+
+void
+wh_video_model_row_set_thumbnail (WHVideoModelRow *row,
+                                 GdkPixbuf       *pixbuf);
+
+G_END_DECLS
+
+#endif /* _WH_VIDEO_MODEL_ROW */
+
diff --git a/attic/woohaa/wh-video-model.c b/attic/woohaa/wh-video-model.c
new file mode 100644 (file)
index 0000000..3d9e4f8
--- /dev/null
@@ -0,0 +1,298 @@
+#include "wh-video-model.h"
+#include <string.h>
+
+G_DEFINE_TYPE (WHVideoModel, wh_video_model, G_TYPE_OBJECT);
+
+#define VIDEO_MODEL_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), WH_TYPE_VIDEO_MODEL, WHVideoModelPrivate))
+
+typedef struct _WHVideoModelPrivate WHVideoModelPrivate;
+
+enum
+{
+  REORDERED,
+  ROW_CHANGED,
+  ROW_ADDED,
+  FILTER,
+  LAST_SIGNAL
+};
+
+static guint _model_signals[LAST_SIGNAL] = { 0 };
+
+struct _WHVideoModelPrivate
+{
+  WHFilterRowFunc  filter;
+  gpointer         filter_data;
+  WHCompareRowFunc sort;
+  gpointer         sort_data;
+  EggSequence     *rows;
+};
+
+static void
+wh_video_model_get_property (GObject *object, guint property_id,
+                            GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+wh_video_model_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+wh_video_model_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (wh_video_model_parent_class)->dispose)
+    G_OBJECT_CLASS (wh_video_model_parent_class)->dispose (object);
+}
+
+static void
+wh_video_model_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (wh_video_model_parent_class)->finalize (object);
+}
+
+static void
+wh_video_model_class_init (WHVideoModelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (WHVideoModelPrivate));
+
+  object_class->get_property = wh_video_model_get_property;
+  object_class->set_property = wh_video_model_set_property;
+  object_class->dispose = wh_video_model_dispose;
+  object_class->finalize = wh_video_model_finalize;
+
+  _model_signals[REORDERED] =
+    g_signal_new ("rows-reordered",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHVideoModelClass, reordered),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+  _model_signals[FILTER] =
+    g_signal_new ("filter-changed",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHVideoModelClass, filter_change),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+  _model_signals[ROW_CHANGED] =
+    g_signal_new ("row-changed",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHVideoModelClass, row_change),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, WH_TYPE_VIDEO_MODEL_ROW);
+
+  _model_signals[ROW_ADDED] =
+    g_signal_new ("row-added",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (WHVideoModelClass, row_added),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, WH_TYPE_VIDEO_MODEL_ROW);
+
+}
+
+static void
+wh_video_model_init (WHVideoModel *self)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(self);
+
+  priv->rows = egg_sequence_new (NULL);
+}
+
+static gboolean 
+check_filter (WHVideoModel *model, EggSequenceIter *iter)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);  
+  gboolean res;
+
+  if (priv->filter == NULL)
+    return TRUE;
+
+  res = priv->filter(model, 
+                    (WHVideoModelRow*)egg_sequence_get (iter), 
+                    priv->filter_data); 
+  return res;
+}
+
+guint
+wh_video_model_row_count (WHVideoModel *model)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);  
+  EggSequenceIter     *iter;
+  gint                 n = 0;
+
+  if (priv->filter == NULL)
+    return egg_sequence_get_length (priv->rows);    
+
+  iter = egg_sequence_get_begin_iter (priv->rows);
+
+  while (!egg_sequence_iter_is_end (iter))
+    {
+      if (check_filter (model, iter))
+       n++;
+      iter = egg_sequence_iter_next (iter);
+    }
+
+  return n;
+}
+
+WHVideoModelRow*
+wh_video_model_get_row (WHVideoModel *model, gint index)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);
+  EggSequenceIter     *iter;
+  gint                 n = 0;
+
+  if (priv->filter == NULL)
+    return (WHVideoModelRow*)egg_sequence_get 
+      (egg_sequence_get_iter_at_pos (priv->rows, index));
+
+  iter = egg_sequence_get_begin_iter (priv->rows);
+
+  while (!egg_sequence_iter_is_end (iter))
+    {
+      if (check_filter (model, iter))
+       {
+         if (n == index)
+           return (WHVideoModelRow*)egg_sequence_get (iter);
+         n++;
+       }
+      iter = egg_sequence_iter_next (iter);
+    }
+
+  return NULL;
+}
+
+static void
+on_row_changed (GObject      *obj,
+               GParamSpec   *arg1,
+               gpointer      data)
+{
+  WHVideoModel        *model = WH_VIDEO_MODEL(data);
+  WHVideoModelPrivate *priv;
+
+  priv = VIDEO_MODEL_PRIVATE(model);
+
+  /* thumbnail changing does not effect ordering */
+  if (!strcmp(g_param_spec_get_name(arg1), "thumbnail"))
+    return;
+
+  if (priv->sort)
+    {
+      egg_sequence_sort (priv->rows, 
+                        (GCompareDataFunc)priv->sort, priv->sort_data);
+      g_signal_emit (model, _model_signals[REORDERED], 0);
+    }
+
+  g_signal_emit (model, _model_signals[ROW_CHANGED], 0, 
+                WH_VIDEO_MODEL_ROW(obj));
+} 
+
+void
+wh_video_model_append_row (WHVideoModel *model, WHVideoModelRow *row)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);
+  EggSequenceIter     *iter;
+
+  g_signal_connect (row,
+                   "notify",
+                   G_CALLBACK (on_row_changed),
+                   model);
+
+  g_object_ref (row);
+
+  if (priv->sort)
+    iter = egg_sequence_insert_sorted (priv->rows,
+                                      (gpointer)row,
+                                      (GCompareDataFunc)priv->sort,
+                                      priv->sort_data);
+  else
+    iter = egg_sequence_append (priv->rows, (gpointer)row);
+
+  if (check_filter (model, iter))
+    g_signal_emit (model, _model_signals[ROW_ADDED], 0, row);
+}
+
+
+void
+wh_video_model_foreach (WHVideoModel      *model, 
+                       WHForeachRowFunc   func,
+                       gpointer           data)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);
+  EggSequenceIter     *iter;
+
+  iter = egg_sequence_get_begin_iter (priv->rows);
+
+    while (!egg_sequence_iter_is_end (iter))
+    {
+      if (check_filter (model, iter))
+       if (func (model, 
+                 (WHVideoModelRow*)egg_sequence_get (iter),
+                 data) == FALSE)
+         return;
+       
+      iter = egg_sequence_iter_next (iter);
+    }
+}
+
+void
+wh_video_model_set_sort_func (WHVideoModel     *model, 
+                             WHCompareRowFunc  func, 
+                             gpointer          userdata)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);
+
+  priv->sort      = func;
+  priv->sort_data = userdata;
+
+  if (func)
+    {
+      egg_sequence_sort (priv->rows, (GCompareDataFunc)func, userdata);
+      g_signal_emit (model, _model_signals[REORDERED], 0);
+    }
+}
+
+void
+wh_video_model_set_filter (WHVideoModel    *model,
+                          WHFilterRowFunc  filter, 
+                          gpointer         data)
+{
+  WHVideoModelPrivate *priv = VIDEO_MODEL_PRIVATE(model);
+  WHFilterRowFunc      prev_filter;
+
+  prev_filter = priv->filter;
+
+  priv->filter      = filter;
+  priv->filter_data = data;
+
+  if (prev_filter != priv->filter)
+    g_signal_emit (model, _model_signals[FILTER], 0);
+}
+
+WHVideoModel*
+wh_video_model_new ()
+{
+  return g_object_new (WH_TYPE_VIDEO_MODEL, NULL);
+}
+
diff --git a/attic/woohaa/wh-video-model.h b/attic/woohaa/wh-video-model.h
new file mode 100644 (file)
index 0000000..fd705e3
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef _WH_VIDEO_MODEL
+#define _WH_VIDEO_MODEL
+
+#include <clutter/clutter.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <glib-object.h>
+#include "wh-video-model-row.h"
+#include "eggsequence.h"
+
+G_BEGIN_DECLS
+
+#define WH_TYPE_VIDEO_MODEL wh_video_model_get_type()
+
+#define WH_VIDEO_MODEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WH_TYPE_VIDEO_MODEL, WHVideoModel))
+
+#define WH_VIDEO_MODEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WH_TYPE_VIDEO_MODEL, WHVideoModelClass))
+
+#define CLUTTER_IS_VIDEO_MODEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WH_TYPE_VIDEO_MODEL))
+
+#define CLUTTER_IS_VIDEO_MODEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WH_TYPE_VIDEO_MODEL))
+
+#define WH_VIDEO_MODEL_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WH_TYPE_VIDEO_MODEL, WHVideoModelClass))
+
+typedef struct {
+  GObject                   parent;
+} WHVideoModel;
+
+typedef struct {
+  GObjectClass parent_class;
+
+  void (*reordered) (WHVideoModel *model);
+  void (*filter_change) (WHVideoModel *model);
+  void (*row_change) (WHVideoModel *model, WHVideoModelRow *row);
+  void (*row_added) (WHVideoModel *model, WHVideoModelRow *row);
+
+} WHVideoModelClass;
+
+typedef gint (*WHCompareRowFunc) (WHVideoModelRow *a,
+                                 WHVideoModelRow *b,
+                                 gpointer        data);
+
+typedef gboolean  (*WHFilterRowFunc) (WHVideoModel    *model,
+                                     WHVideoModelRow *row,
+                                     gpointer         data);
+
+typedef gboolean (*WHForeachRowFunc) (WHVideoModel    *model,
+                                     WHVideoModelRow *row,
+                                     gpointer         data);
+
+GType wh_video_model_get_type (void);
+
+WHVideoModel*
+wh_video_model_new ();
+
+guint
+wh_video_model_row_count (WHVideoModel *model);
+
+WHVideoModelRow*
+wh_video_model_get_row (WHVideoModel *model, gint index);
+
+void
+wh_video_model_append_row (WHVideoModel *model, WHVideoModelRow *row);
+
+void
+wh_video_model_set_filter (WHVideoModel    *model,
+                          WHFilterRowFunc  filter, 
+                          gpointer         data);
+
+void
+wh_video_model_set_sort_func (WHVideoModel     *model, 
+                             WHCompareRowFunc  func, 
+                             gpointer          userdata);
+
+void
+wh_video_model_foreach (WHVideoModel      *model, 
+                       WHForeachRowFunc   func,
+                       gpointer           data);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/wh-video-row-renderer.c b/attic/woohaa/wh-video-row-renderer.c
new file mode 100644 (file)
index 0000000..3120b0b
--- /dev/null
@@ -0,0 +1,373 @@
+#include "wh-video-row-renderer.h"
+#include "wh-video-model.h"
+#include "wh-video-model-row.h"
+#include "util.h"
+
+G_DEFINE_TYPE (WHVideoRowRenderer, wh_video_row_renderer, CLUTTER_TYPE_ACTOR);
+
+#define PAD 4
+
+#define VIDEO_ROW_RENDERER_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), WH_TYPE_VIDEO_ROW_RENDERER, WHVideoRowRendererPrivate))
+
+typedef struct _WHVideoRowRendererPrivate WHVideoRowRendererPrivate;
+
+struct _WHVideoRowRendererPrivate
+{
+  WHVideoModelRow *row;
+  ClutterActor    *container;
+  ClutterActor    *thumbnail, *thumbnail_image;
+  ClutterActor    *title_label, *info_label, *date_label, *hr;
+  gint             width, height;
+  gboolean         active;
+};
+
+enum
+{
+  PROP_0,
+  PROP_ROW
+};
+
+static void
+sync_thumbnail (WHVideoRowRenderer *renderer)
+{
+  GdkPixbuf                 *pixbuf; 
+  WHVideoRowRendererPrivate *priv;  
+
+  priv = VIDEO_ROW_RENDERER_PRIVATE(renderer);
+
+  pixbuf = wh_video_model_row_get_thumbnail (priv->row);
+
+  if (pixbuf)
+    {
+      ClutterEffectTemplate *effect;
+
+      if (priv->thumbnail_image)
+       g_object_unref (priv->thumbnail_image);
+
+      
+      priv->thumbnail_image = clutter_texture_new ();
+      if (priv->thumbnail_image == NULL)
+       return;
+
+      clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (priv->thumbnail_image),
+                                        gdk_pixbuf_get_pixels (pixbuf),
+                                        gdk_pixbuf_get_has_alpha (pixbuf),
+                                        gdk_pixbuf_get_width (pixbuf),
+                                        gdk_pixbuf_get_height (pixbuf),
+                                        gdk_pixbuf_get_rowstride (pixbuf),
+                                        gdk_pixbuf_get_n_channels (pixbuf), 
+                                        0,
+                                        NULL);
+
+      clutter_actor_set_position (priv->thumbnail_image, PAD + 2, PAD + 2);
+      clutter_actor_set_size (priv->thumbnail_image, 
+                             priv->height - (PAD*2) - 4, 
+                             priv->height - (PAD*2) - 4);
+      clutter_group_add(CLUTTER_GROUP(priv->container),
+                       priv->thumbnail_image);
+
+      effect
+       = clutter_effect_template_new (clutter_timeline_new (20, 60),
+                                      CLUTTER_ALPHA_SINE_INC);
+
+      clutter_actor_set_opacity (priv->thumbnail_image, 0);
+      clutter_actor_show (priv->thumbnail_image);
+      clutter_effect_fade (effect,
+                          priv->thumbnail_image,
+                          0xff,
+                          NULL,
+                          NULL);
+      g_object_unref (effect);
+    }
+}
+
+static void 
+on_thumbnail_change (GObject        *object,
+                    GParamSpec     *pspec,
+                    WHVideoRowRenderer *renderer)
+{
+  sync_thumbnail (renderer);
+}
+
+static void
+wh_video_row_renderer_get_property (GObject *object, guint property_id,
+                                   GValue *value, GParamSpec *pspec)
+{
+  WHVideoRowRenderer        *row = WH_VIDEO_ROW_RENDERER(object);
+  WHVideoRowRendererPrivate *priv;  
+  
+  priv = VIDEO_ROW_RENDERER_PRIVATE(row);
+
+  switch (property_id) 
+    {
+    case PROP_ROW:
+      g_value_set_object (value, priv->row);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+wh_video_row_renderer_set_property (GObject *object, guint property_id,
+                                   const GValue *value, GParamSpec *pspec)
+{
+  WHVideoRowRenderer        *row = WH_VIDEO_ROW_RENDERER(object);
+  WHVideoRowRendererPrivate *priv;  
+  
+  priv = VIDEO_ROW_RENDERER_PRIVATE(row);
+
+  switch (property_id) 
+    {
+    case PROP_ROW:
+      if (priv->row)
+       g_object_unref(priv->row);
+      priv->row = g_value_get_object (value);
+      g_signal_connect (priv->row,
+                       "notify::thumbnail",
+                       G_CALLBACK (on_thumbnail_change),
+                       row);
+      g_object_ref(priv->row);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+wh_video_row_renderer_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (wh_video_row_renderer_parent_class)->dispose)
+    G_OBJECT_CLASS (wh_video_row_renderer_parent_class)->dispose (object);
+}
+
+static void
+wh_video_row_renderer_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (wh_video_row_renderer_parent_class)->finalize (object);
+}
+
+static void
+wh_video_row_renderer_allocate (ClutterActor    *self,
+                               const ClutterActorBox *box,
+                               gboolean absolute_origin_changed)
+{
+  WHVideoRowRenderer        *row = WH_VIDEO_ROW_RENDERER(self);
+  WHVideoRowRendererPrivate *priv;  
+  ClutterActorBox            child_box;
+  ClutterUnit                container_width, container_height;
+  
+  priv = VIDEO_ROW_RENDERER_PRIVATE(row);
+
+  if ( (CLUTTER_UNITS_TO_INT(box->x2 - box->x1) != priv->width) 
+       || (CLUTTER_UNITS_TO_INT(box->y2 - box->y1) != priv->height))
+    {
+      ClutterColor color      = { 0xcc, 0xcc, 0xcc, 0xff };
+      ClutterColor info_color = { 0xde, 0xde, 0xde, 0xff };
+      gint  w,h;
+      gchar font_desc[32];
+      gchar *episode = NULL, *series = NULL, *info = NULL;
+      GDate *date;      
+      gchar  date_buf[32];
+
+      /* Keep a simple cache to avoid setting fonts up too much */
+      w = priv->width  = CLUTTER_UNITS_TO_INT(box->x2 - box->x1);
+      h = priv->height = CLUTTER_UNITS_TO_INT(box->y2 - box->y1);
+
+      clutter_actor_set_position (priv->thumbnail, PAD, PAD);
+      clutter_actor_set_size (priv->thumbnail, h-(PAD*2), h-(PAD*2));
+
+      g_snprintf(font_desc, 32, "Sans %ipx", (h*4)/8); 
+
+      clutter_label_set_text (CLUTTER_LABEL(priv->title_label),
+                             wh_video_model_row_get_title (priv->row));
+      clutter_label_set_font_name (CLUTTER_LABEL(priv->title_label), 
+                                  font_desc); 
+      clutter_label_set_color (CLUTTER_LABEL(priv->title_label), &color);
+      clutter_label_set_line_wrap (CLUTTER_LABEL(priv->title_label), FALSE);
+      clutter_label_set_ellipsize  (CLUTTER_LABEL(priv->title_label), 
+                                   PANGO_ELLIPSIZE_MIDDLE);
+
+      clutter_actor_set_width (priv->title_label, w - ((2*(h+PAD))));
+      clutter_actor_set_position (priv->title_label, h + PAD, PAD); 
+
+      g_snprintf(font_desc, 32, "Sans %ipx", (h*3)/12); 
+      wh_video_model_row_get_extended_info (priv->row, &series, &episode);
+
+      date = g_date_new();
+      
+      g_date_set_time_t (date, wh_video_model_row_get_age(priv->row)); 
+      g_date_strftime (date_buf, 32, "%x", date);
+      
+      info = g_strdup_printf("%s%s%s%s%s%s"
+                            "Added: %s",
+                            series != NULL  ? "Series: " : "",
+                            series != NULL  ?  series : "",
+                            series != NULL  ?  " " : "",
+                            episode != NULL ? "Episode: " : "",
+                            episode != NULL ?  episode : "",
+                            episode != NULL ?  " " : "",
+                            date_buf);
+      
+      clutter_label_set_text (CLUTTER_LABEL(priv->info_label), info);
+      clutter_label_set_font_name (CLUTTER_LABEL(priv->info_label), 
+                                  font_desc); 
+      clutter_label_set_color (CLUTTER_LABEL(priv->info_label), 
+                              &info_color);
+      clutter_label_set_line_wrap (CLUTTER_LABEL(priv->info_label), FALSE);
+      clutter_label_set_use_markup (CLUTTER_LABEL(priv->info_label), TRUE);
+      
+      clutter_actor_set_position (priv->info_label, 
+                                 h + PAD, 
+                                 PAD + clutter_actor_get_height(priv->title_label)); 
+      clutter_actor_set_width (priv->title_label, w - (2*h) + (2*PAD));
+      
+      g_free (info);
+      g_free (series);
+      g_free (episode);
+      g_date_free(date);
+
+      clutter_actor_set_size (priv->hr, w, 1);
+      clutter_actor_set_position (priv->hr, 0, h-1);
+
+      sync_thumbnail (row);
+
+      /* Force Update active look */
+      priv->active = ~priv->active;
+      wh_video_row_renderer_set_active (row, ~priv->active); 
+    }
+  
+  clutter_actor_get_sizeu (priv->container, 
+                          &container_width,
+                          &container_height);
+  child_box.x1 = 0;
+  child_box.y1 = 0;
+  child_box.x2 = container_width;
+  child_box.y2 = container_height;
+  clutter_actor_allocate (priv->container, 
+                         &child_box, 
+                         absolute_origin_changed);
+
+  CLUTTER_ACTOR_CLASS (wh_video_row_renderer_parent_class)->
+    allocate (self, box, absolute_origin_changed);
+}
+
+static void
+wh_video_row_renderer_paint (ClutterActor *actor)
+{
+  WHVideoRowRenderer        *row = WH_VIDEO_ROW_RENDERER(actor);
+  WHVideoRowRendererPrivate *priv;  
+  
+  priv = VIDEO_ROW_RENDERER_PRIVATE(row);
+
+  if (priv->width == 0 || priv->height ==0)
+    return;
+
+  clutter_actor_paint (CLUTTER_ACTOR(priv->container));
+}
+
+static void
+wh_video_row_renderer_class_init (WHVideoRowRendererClass *klass)
+{
+  GObjectClass        *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (WHVideoRowRendererPrivate));
+
+  object_class->get_property = wh_video_row_renderer_get_property;
+  object_class->set_property = wh_video_row_renderer_set_property;
+  object_class->dispose      = wh_video_row_renderer_dispose;
+  object_class->finalize     = wh_video_row_renderer_finalize;
+
+  actor_class->paint          = wh_video_row_renderer_paint;
+  actor_class->allocate = wh_video_row_renderer_allocate;
+  /* 
+   *  actor_class->realize    = wh_video_row_renderer__realize;
+   *  actor_class->unrealize  = parent_class->unrealize;
+  */  
+
+  g_object_class_install_property 
+    (object_class,
+     PROP_ROW,
+     g_param_spec_object ("row",
+                         "Row",
+                         "Row to render",
+                         WH_TYPE_VIDEO_MODEL_ROW,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+}
+
+static void
+wh_video_row_renderer_init (WHVideoRowRenderer *self)
+{
+  ClutterColor color = { 0xcc, 0xcc, 0xcc, 0xff };
+  ClutterColor grey_col = { 0xde, 0xde, 0xde, 0xff };
+  WHVideoRowRendererPrivate *priv;  
+  
+  priv = VIDEO_ROW_RENDERER_PRIVATE(self);
+
+  priv->hr = clutter_rectangle_new_with_color (&grey_col);
+
+  priv->thumbnail = clutter_rectangle_new_with_color(&color);
+
+  priv->title_label = clutter_label_new();
+  priv->info_label = clutter_label_new();
+
+  priv->container = clutter_group_new();
+  clutter_actor_set_parent (priv->container, CLUTTER_ACTOR(self));
+
+  clutter_group_add_many (CLUTTER_GROUP(priv->container), 
+                         priv->hr,
+                         priv->thumbnail,
+                         priv->title_label,
+                         priv->info_label,
+                         NULL);
+
+  clutter_actor_show_all (priv->container);
+}
+
+void
+wh_video_row_renderer_set_active (WHVideoRowRenderer *renderer, 
+                                 gboolean            setting)
+{
+  /* FIXME: should be prop */
+  WHVideoRowRendererPrivate *priv = VIDEO_ROW_RENDERER_PRIVATE(renderer);
+
+  ClutterColor inactive_col = { 0xaa, 0xaa, 0xaa, 0xff };
+  ClutterColor   active_col = { 0xff, 0xff, 0xff, 0xff };
+  ClutterColor info_inactive_col = { 0xbb, 0xbb, 0xbb, 0xff };
+  ClutterColor info_active_col   = { 0xf3, 0xf3, 0xf3, 0xff };
+
+  if (priv->active == setting)
+    return;
+
+  priv->active = setting;
+
+  if (setting)
+    {
+      clutter_label_set_color (CLUTTER_LABEL(priv->title_label), 
+                              &active_col);
+      clutter_label_set_color (CLUTTER_LABEL(priv->info_label), 
+                              &info_active_col);
+      clutter_actor_set_opacity (CLUTTER_ACTOR(renderer), 0xff);
+
+    }
+  else
+    {
+      clutter_label_set_color (CLUTTER_LABEL(priv->title_label), 
+                              &inactive_col);
+      clutter_label_set_color (CLUTTER_LABEL(priv->info_label), 
+                              &info_inactive_col);
+      clutter_actor_set_opacity (CLUTTER_ACTOR(renderer), 0xff);
+    }
+
+
+
+}
+
+WHVideoRowRenderer*
+wh_video_row_renderer_new (WHVideoModelRow *row)
+{
+  return g_object_new (WH_TYPE_VIDEO_ROW_RENDERER, "row", row, NULL);
+}
+
diff --git a/attic/woohaa/wh-video-row-renderer.h b/attic/woohaa/wh-video-row-renderer.h
new file mode 100644 (file)
index 0000000..15e8591
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _WH_VIDEO_ROW_RENDERER
+#define _WH_VIDEO_ROW_RENDERER
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define WH_TYPE_VIDEO_ROW_RENDERER wh_video_row_renderer_get_type()
+
+#define WH_VIDEO_ROW_RENDERER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WH_TYPE_VIDEO_ROW_RENDERER, WHVideoRowRenderer))
+
+#define WH_VIDEO_ROW_RENDERER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WH_TYPE_VIDEO_ROW_RENDERER, WHVideoRowRendererClass))
+
+#define WH_IS_VIDEO_ROW_RENDERER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WH_TYPE_VIDEO_ROW_RENDERER))
+
+#define WH_IS_VIDEO_ROW_RENDERER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WH_TYPE_VIDEO_ROW_RENDERER))
+
+#define WH_VIDEO_ROW_RENDERER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WH_TYPE_VIDEO_ROW_RENDERER, WHVideoRowRendererClass))
+
+typedef struct {
+  ClutterActor         parent;
+} WHVideoRowRenderer;
+
+typedef struct {
+  ClutterActorClass parent_class;
+} WHVideoRowRendererClass;
+
+#include "wh-video-model-row.h"
+
+GType wh_video_row_renderer_get_type (void);
+
+WHVideoRowRenderer*
+wh_video_row_renderer_new (WHVideoModelRow *row);
+
+void
+wh_video_row_renderer_set_active (WHVideoRowRenderer *renderer, 
+                                 gboolean            setting);
+
+G_END_DECLS
+
+#endif /* _WH_VIDEO_ROW_RENDERER */
diff --git a/attic/woohaa/wh-video-thumbnailer.c b/attic/woohaa/wh-video-thumbnailer.c
new file mode 100644 (file)
index 0000000..3441358
--- /dev/null
@@ -0,0 +1,157 @@
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifdef USE_HELIX
+#include <clutter-helix/clutter-helix.h>
+#else
+#include <clutter-gst/clutter-gst.h>
+#include <gst/gst.h>
+#endif
+
+
+#include "totem-resources.h"
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor   *video;
+  GdkPixbuf      *shot = NULL;
+  gint            duration;
+  CoglHandle      tex_id;
+  CoglPixelFormat format;
+  gint            size;
+  gint            width;
+  gint            height; 
+  gint            rowstride;
+  guchar         *data = NULL;
+
+#ifdef USE_HELIX
+  clutter_helix_init (&argc, &argv);
+#else
+  gst_init (&argc, &argv);
+#endif
+  clutter_init (&argc, &argv);
+
+  if (argc < 3)
+    {
+      g_print ("Usage: %s <path to movie file> <output png>\n", argv[0]);
+      exit(-1);
+    }
+
+  totem_resources_monitor_start (argv[1], 60 * G_USEC_PER_SEC);
+
+#ifdef USE_HELIX
+  video = clutter_helix_video_texture_new ();
+#else
+  video = clutter_gst_video_texture_new ();
+#endif
+
+  if (argv[1][0] == '/')
+    clutter_media_set_filename(CLUTTER_MEDIA(video), argv[1]);
+  else
+    clutter_media_set_uri(CLUTTER_MEDIA(video), argv[1]);
+  clutter_media_set_volume (CLUTTER_MEDIA(video), 0);
+  clutter_media_set_playing (CLUTTER_MEDIA(video), TRUE);
+
+  do {
+
+    while (g_main_context_pending (NULL))
+      g_main_context_iteration (NULL, FALSE);
+
+    duration = clutter_media_get_duration (CLUTTER_MEDIA(video));
+
+  } while (duration == 0);
+
+  clutter_actor_realize (video);
+
+  clutter_media_set_position (CLUTTER_MEDIA(video), duration/3);
+
+  do {
+
+    while (g_main_context_pending (NULL))
+      g_main_context_iteration (NULL, FALSE);
+
+  } while (clutter_media_get_position (CLUTTER_MEDIA(video)) <= duration/3);
+
+  tex_id = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (video));
+  if (tex_id)
+    {
+      format = cogl_texture_get_format (tex_id);
+      size = cogl_texture_get_data (tex_id, format, 0, NULL);
+      width = cogl_texture_get_width (tex_id);
+      height = cogl_texture_get_height (tex_id);
+      rowstride = cogl_texture_get_rowstride (tex_id);
+      
+      data = (guchar*) g_malloc (sizeof(guchar) * size);
+      if (!data)
+       g_error ("malloc");;
+
+      cogl_texture_get_data (tex_id, format, rowstride, data);
+
+
+      shot = gdk_pixbuf_new_from_data (data, 
+                                      GDK_COLORSPACE_RGB, 
+                                      FALSE, 
+                                      8,
+                                      width, 
+                                      height, 
+                                      rowstride, 
+                                      NULL, 
+                                      NULL);
+      
+    }
+
+  totem_resources_monitor_stop ();
+
+  if (shot)
+    {
+      GdkPixbuf *thumb, *pic;
+      gint       x, y, nw, nh, w, h, size;
+      
+      size = 128;
+
+      /* FIXME swap RGB pixels */
+
+      w = clutter_actor_get_width (video);
+      h = clutter_actor_get_height (video);
+      
+      nh = ( h * size) / w;
+
+      if (nh <= size)
+       {
+         nw = size;
+         x = 0;
+         y = (size - nh) / 2;
+       }
+      else
+       {
+         nw  = ( w * size ) / h;
+         nh = size;
+         x = (size - nw) / 2;
+         y = 0;
+       }
+
+      thumb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
+      gdk_pixbuf_fill (thumb, 0x000000FF);
+
+      pic = gdk_pixbuf_scale_simple (shot, nw, nh, GDK_INTERP_BILINEAR);
+      gdk_pixbuf_copy_area  (pic, 0, 0, nw, nh, thumb, x, y);
+      
+      if (!gdk_pixbuf_save (thumb, argv[2], "png", NULL, NULL))
+       {
+         g_error ("%s: Pixbuf save failed\n", argv[0]);
+         exit(-1);
+       }
+
+      g_object_unref (shot);
+      g_object_unref (thumb);
+      g_object_unref (pic);
+
+      exit(0);
+    }
+
+  exit (-1);
+}
diff --git a/attic/woohaa/wh-video-view.c b/attic/woohaa/wh-video-view.c
new file mode 100644 (file)
index 0000000..b99675e
--- /dev/null
@@ -0,0 +1,543 @@
+#include "wh-video-view.h"
+#include "wh-video-model.h"
+#include "util.h"
+
+#include <cogl/cogl.h>
+
+G_DEFINE_TYPE (WHVideoView, wh_video_view, CLUTTER_TYPE_ACTOR);
+
+#define WH_VIDEO_VIEW_GET_PRIVATE(obj)                \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj),              \
+                                  WH_TYPE_VIDEO_VIEW, \
+                                  WHVideoViewPrivate))
+
+struct _WHVideoViewPrivate
+{
+  WHVideoModel      *model;
+  gint               n_rows_visible;
+  gint               active_item_num;
+  gint               n_rows;
+
+  ClutterActor      *rows;
+
+  ClutterActor      *selection_indicator;
+  ClutterActor      *selection;
+  ClutterActor      *up_arrow; 
+  ClutterActor      *down_arrow;
+
+  gboolean           animation_running;
+};
+
+enum
+{
+  PROP_0,
+  PROP_MODEL,
+  PROP_N_ROWS
+};
+
+void wh_video_view_activate (WHVideoView *view, gint entry_num);
+
+static gboolean 
+populate_rows (WHVideoModel    *model,
+              WHVideoModelRow *row,
+              gpointer         data)
+{
+  WHVideoView          *view;
+  WHVideoViewPrivate    *priv;
+  WHVideoRowRenderer    *renderer;
+  gint                   r_width, r_height, position;
+  ClutterEffectTemplate *template;
+
+  view = WH_VIDEO_VIEW (data);
+  priv = WH_VIDEO_VIEW_GET_PRIVATE (view);
+
+  template = clutter_effect_template_new_for_duration (500, 
+                                                      CLUTTER_ALPHA_SINE_INC);
+
+  r_height = clutter_actor_get_height (CLUTTER_ACTOR (view)) /
+    priv->n_rows_visible;
+  r_width = clutter_actor_get_width (CLUTTER_ACTOR (view));
+
+  if (priv->n_rows == 0)
+    {
+      ClutterUnit width, height;
+      double scale;
+
+      /* 
+       * Scale the up and down indication arrows 
+       */
+      clutter_actor_get_preferred_size (priv->up_arrow,
+                                       NULL,
+                                       NULL,
+                                       &width,
+                                       &height);       
+      scale = (double)CLUTTER_UNITS_FROM_INT (r_height/4) / (double) height;
+      height = CLUTTER_UNITS_FROM_INT (r_height/4);
+      width = width * scale;
+      clutter_actor_set_sizeu (priv->up_arrow, width, height);
+      clutter_actor_set_sizeu (priv->down_arrow, width, height);
+
+      clutter_actor_set_size (priv->selection, r_width, r_height);
+
+      width = CLUTTER_UNITS_FROM_INT (r_width - r_width/100) - width;
+      clutter_actor_set_positionu (priv->up_arrow, width, 
+                                  CLUTTER_UNITS_FROM_INT (r_height/10));
+
+      height = CLUTTER_UNITS_FROM_INT (r_height - r_height/10) - height;
+      clutter_actor_set_positionu (priv->down_arrow, width, height);
+
+      clutter_actor_set_opacity (priv->selection_indicator, 0);
+    }
+
+  position = priv->n_rows++ + priv->active_item_num;
+
+  renderer = wh_video_model_row_get_renderer (row);
+
+  clutter_actor_set_size (CLUTTER_ACTOR (renderer), 
+                         clutter_actor_get_width (CLUTTER_ACTOR (view)), 
+                         r_height);
+  clutter_actor_show (CLUTTER_ACTOR (renderer));
+
+  clutter_effect_move (template,
+                      CLUTTER_ACTOR (renderer), 
+                      0, 
+                      position * r_height,
+                      NULL,
+                      NULL);
+
+  clutter_effect_fade (template,
+                      CLUTTER_ACTOR (renderer),
+                      position >= priv->n_rows_visible ? 0x00 : 0xff,
+                      NULL,
+                      NULL);
+
+  if (priv->n_rows == 1)
+    wh_video_row_renderer_set_active (renderer, TRUE);
+  else
+    wh_video_row_renderer_set_active (renderer, FALSE);
+
+  clutter_group_add (priv->rows, CLUTTER_ACTOR (renderer));
+
+  return TRUE;
+}
+
+static void
+on_model_rows_change (WHVideoModel *model, gpointer *userdata)
+{
+  WHVideoView        *view;
+  WHVideoViewPrivate *priv;
+
+  view = WH_VIDEO_VIEW(userdata);
+  priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+
+  clutter_actor_set_opacity (priv->selection_indicator, 0);
+  clutter_group_remove_all (CLUTTER_GROUP (priv->rows));
+  priv->n_rows = 0;
+  priv->active_item_num = 0;
+
+  wh_video_model_foreach (model, 
+                         populate_rows,
+                         view);
+
+  wh_video_view_activate(view, 0);
+}
+
+static void
+wh_video_view_set_property (GObject      *object, 
+                           guint         prop_id,
+                           const GValue *value, 
+                           GParamSpec   *pspec)
+{
+  WHVideoView        *view;
+  WHVideoViewPrivate *priv;
+
+  view = WH_VIDEO_VIEW(object);
+  priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+
+  switch (prop_id) 
+    {
+    case PROP_MODEL:
+      if (priv->model)
+        {
+         clutter_group_remove_all (CLUTTER_GROUP (priv->rows));
+         g_object_unref (priv->model);
+       }
+      priv->model = g_value_get_object (value);
+
+      wh_video_model_foreach (priv->model, 
+                             populate_rows,
+                             priv->rows);
+
+      g_signal_connect(priv->model, 
+                      "rows-reordered",
+                      G_CALLBACK(on_model_rows_change), 
+                      object);
+      break;
+    case PROP_N_ROWS:
+      priv->n_rows_visible = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+wh_video_view_get_property (GObject    *object, 
+                           guint       prop_id,
+                           GValue     *value, 
+                           GParamSpec *pspec)
+{
+  WHVideoView        *view;
+  WHVideoViewPrivate *priv;
+
+  view = WH_VIDEO_VIEW(object);
+  priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+
+  switch (prop_id) 
+    {
+    case PROP_MODEL:
+      g_value_set_object (value, priv->model);
+      break;
+    case PROP_N_ROWS:
+      g_value_set_int (value, priv->n_rows_visible);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    } 
+}
+
+static void
+wh_video_view_get_preferred_width  (ClutterActor          *actor,
+                                   ClutterUnit            for_height,
+                                   ClutterUnit           *min_width_p,
+                                   ClutterUnit           *natural_width_p)
+{
+  WHVideoView         *self = WH_VIDEO_VIEW(actor);
+  WHVideoViewPrivate  *priv;
+  
+  priv = self->priv;
+  
+  clutter_actor_get_preferred_height (priv->rows, 
+                                     for_height,
+                                     min_width_p,
+                                     natural_width_p);
+}
+
+static void
+wh_video_view_get_preferred_height (ClutterActor          *actor,
+                                   ClutterUnit            for_width,
+                                   ClutterUnit           *min_height_p,
+                                   ClutterUnit           *natural_height_p)
+{
+  WHVideoView         *self = WH_VIDEO_VIEW(actor);
+  WHVideoViewPrivate  *priv;  
+  
+  priv = self->priv;
+
+  clutter_actor_get_preferred_height (priv->rows, 
+                                     for_width,
+                                     min_height_p,
+                                     natural_height_p);
+}
+
+static void
+wh_video_view_allocate (ClutterActor    *actor,
+                       const ClutterActorBox *box,
+                       gboolean absolute_origin_changed)
+{
+  WHVideoView         *self = WH_VIDEO_VIEW(actor);
+  WHVideoViewPrivate  *priv;  
+  ClutterActorBox      child_box;
+  ClutterUnit          width, height;
+
+  priv = self->priv;
+
+  CLUTTER_ACTOR_CLASS (wh_video_view_parent_class)->
+         allocate (actor, box, absolute_origin_changed);
+
+  clutter_actor_get_preferred_size (priv->rows,
+                                   NULL,
+                                   NULL,
+                                   &width,
+                                   &height);
+  
+  child_box.x1 = 0;
+  child_box.y1 = 0;
+  child_box.x2 = box->x1 + width;
+  child_box.y2 = box->y1 + height;
+  clutter_actor_allocate (priv->rows, 
+                         &child_box,
+                         absolute_origin_changed);
+
+  clutter_actor_get_preferred_size (priv->selection_indicator,
+                                   NULL,
+                                   NULL,
+                                   &width,
+                                   &height);
+  
+  child_box.x1 = 0;
+  child_box.y1 = 0;
+  child_box.x2 = box->x1 + width;
+  child_box.y2 = box->y1 + height;
+  clutter_actor_allocate (priv->selection_indicator, 
+                         &child_box,
+                         absolute_origin_changed);
+}
+
+static void
+wh_video_view_paint (ClutterActor *actor)
+{
+  WHVideoView         *self = WH_VIDEO_VIEW(actor);
+  WHVideoViewPrivate  *priv = self->priv;  
+
+  priv = self->priv;
+
+  clutter_actor_paint (priv->selection_indicator);
+  clutter_actor_paint (priv->rows);
+}
+
+static void 
+wh_video_view_dispose (GObject *object)
+{
+  WHVideoView         *self = WH_VIDEO_VIEW(object);
+  WHVideoViewPrivate  *priv;
+
+  priv = self->priv;
+  
+  G_OBJECT_CLASS (wh_video_view_parent_class)->dispose (object);
+}
+
+static void 
+wh_video_view_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (wh_video_view_parent_class)->finalize (object);
+}
+
+static void
+wh_video_view_class_init (WHVideoViewClass *klass)
+{
+  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass   *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  ClutterActorClass   *parent_class; 
+
+  parent_class = CLUTTER_ACTOR_CLASS (wh_video_view_parent_class);
+
+  actor_class->paint           = wh_video_view_paint;
+  actor_class->allocate        = wh_video_view_allocate;
+  actor_class->get_preferred_width  = wh_video_view_get_preferred_width;
+  actor_class->get_preferred_height = wh_video_view_get_preferred_height;
+
+  gobject_class->finalize     = wh_video_view_finalize;
+  gobject_class->dispose      = wh_video_view_dispose;
+  gobject_class->set_property = wh_video_view_set_property;
+  gobject_class->get_property = wh_video_view_get_property;
+
+  g_type_class_add_private (gobject_class, sizeof (WHVideoViewPrivate));
+
+  g_object_class_install_property 
+    (gobject_class,
+     PROP_MODEL,
+     g_param_spec_object ("model",
+                         "Model",
+                         "Underlying video model",
+                         WH_TYPE_VIDEO_MODEL,
+                         G_PARAM_CONSTRUCT|G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+    (gobject_class,
+     PROP_N_ROWS,
+     g_param_spec_int ("n-rows-visible",
+                      "n-rows-visible",
+                      "Number of row to display",
+                      0, G_MAXINT,
+                      0,
+                      G_PARAM_READWRITE));
+}
+
+static void
+row_move_complete (ClutterActor *actor, gpointer data)
+{
+  WHVideoView        *view = WH_VIDEO_VIEW (data);   
+  WHVideoViewPrivate *priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+
+  priv->animation_running = FALSE;
+}
+
+void
+wh_video_view_activate (WHVideoView  *view,
+                       gint          entry_num)
+{
+  WHVideoViewPrivate    *priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+  ClutterActor          *child;
+  gint                   i, r_height, position;
+  ClutterEffectTemplate *template;
+  guint8                 opacity;
+
+  priv->animation_running = TRUE;
+
+  r_height = clutter_actor_get_height (CLUTTER_ACTOR (view)) /
+    priv->n_rows_visible;
+
+  template = clutter_effect_template_new_for_duration (250, 
+                                                      CLUTTER_ALPHA_SINE_INC);
+
+  for ( i = 0; i < priv->n_rows + 1; i++ )
+    {
+      child = clutter_group_get_nth_child (CLUTTER_GROUP (priv->rows), i);
+      if (!child)
+       return;
+
+      position = i - priv->active_item_num;
+
+      if (position < -1 || position >= priv->n_rows_visible)
+       opacity = 0;
+      else
+       opacity = 0xff;
+       
+      clutter_effect_move (template,
+                          child, 
+                          0, 
+                          position * r_height,
+                          row_move_complete,
+                          view);
+      clutter_effect_fade (template,
+                          child,
+                          opacity,
+                          NULL,
+                          NULL);
+
+      if (priv->active_item_num == i)
+        {
+         wh_video_row_renderer_set_active (WH_VIDEO_ROW_RENDERER (child), 
+                                           TRUE);
+
+         if (i > 0)
+           {
+             if (clutter_actor_get_opacity (priv->up_arrow) != 0xff)
+               clutter_effect_fade (template, 
+                                    priv->up_arrow, 
+                                    0xff, 
+                                    NULL, 
+                                    NULL);
+           }
+         else if (clutter_actor_get_opacity (priv->up_arrow) != 0)
+           clutter_effect_fade (template, priv->up_arrow, 0, NULL, NULL);
+
+         if (i < priv->n_rows - 1)
+           {
+             if (clutter_actor_get_opacity (priv->down_arrow) != 0xff)
+               clutter_effect_fade (template, 
+                                    priv->down_arrow, 
+                                    0xff, 
+                                    NULL, 
+                                    NULL);
+           }
+         else if (clutter_actor_get_opacity (priv->down_arrow) != 0)
+           clutter_effect_fade (template, priv->down_arrow, 0, NULL, NULL);
+
+         clutter_actor_set_opacity (priv->selection_indicator, 0xff);
+       }
+      else
+       wh_video_row_renderer_set_active (WH_VIDEO_ROW_RENDERER (child), 
+                                         FALSE);
+    }
+}
+
+void
+wh_video_view_advance (WHVideoView *view, gint n)
+{
+  WHVideoViewPrivate *priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+  gint new_index;
+
+  if (priv->animation_running)
+    return;
+
+  new_index = priv->active_item_num + n;
+  
+  if (new_index > priv->n_rows - 1)
+    new_index = priv->n_rows - 1;
+  else if (new_index < 0)
+    new_index = 0;
+
+  if (new_index == priv->active_item_num)
+    return;
+
+  priv->active_item_num = new_index;
+
+  wh_video_view_activate (view, priv->active_item_num);
+}
+
+WHVideoModelRow*
+wh_video_view_get_selected (WHVideoView *view)
+{
+  WHVideoViewPrivate *priv = WH_VIDEO_VIEW_GET_PRIVATE(view);
+
+  return wh_video_model_get_row (priv->model, priv->active_item_num);
+}
+
+void
+wh_video_view_enable_animation (WHVideoView *view, gboolean active)
+{
+}
+
+static void
+wh_video_view_init (WHVideoView *self)
+{
+  WHVideoViewPrivate *priv;
+
+  self->priv = priv = WH_VIDEO_VIEW_GET_PRIVATE (self);
+
+  priv->rows = clutter_group_new ();
+
+  priv->selection_indicator = clutter_group_new ();
+  clutter_actor_set_opacity (priv->selection_indicator, 0);
+  clutter_actor_set_parent (priv->rows, CLUTTER_ACTOR (self));
+
+  /* Load the position backgroud image */
+  priv->selection = clutter_texture_new_from_file (PKGDATADIR "/selected.svg",
+                                                  NULL);
+  if (!priv->selection)
+    g_warning ("Unable to load %s\n",  PKGDATADIR "/selected.svg");
+
+  clutter_actor_show (priv->selection);
+  clutter_group_add (CLUTTER_GROUP (priv->selection_indicator), 
+                    priv->selection);
+
+  /* Load the up arrow image */
+  priv->up_arrow = clutter_texture_new_from_file (PKGDATADIR "/arrow-up.svg",
+                                                 NULL);
+  if (!priv->up_arrow)
+    g_warning ("Unable to load %s\n",  PKGDATADIR "/arrow-up.svg");
+
+  clutter_actor_show (priv->up_arrow);
+  clutter_group_add (CLUTTER_GROUP (priv->selection_indicator), 
+                    priv->up_arrow);
+  
+  /* Load the down arrow image */
+  priv->down_arrow = clutter_texture_new_from_file (PKGDATADIR "/arrow-down.svg",
+                                                   NULL);
+  if (!priv->down_arrow)
+    g_warning ("Unable to load %s\n",  PKGDATADIR "/arrow-down.svg");
+
+  clutter_actor_show (priv->down_arrow);
+  clutter_group_add (CLUTTER_GROUP (priv->selection_indicator), 
+                    priv->down_arrow);
+
+}
+
+ClutterActor*
+wh_video_view_new (WHVideoModel      *model, 
+                  gint               n_rows_visible)
+{
+  ClutterActor         *view;
+
+  view = g_object_new (WH_TYPE_VIDEO_VIEW, 
+                      "n-rows-visible", n_rows_visible,
+                      "model", model,
+                      NULL);
+
+  return view;
+}
+
diff --git a/attic/woohaa/wh-video-view.h b/attic/woohaa/wh-video-view.h
new file mode 100644 (file)
index 0000000..6a99ae5
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *
+ * Authored By XXXXX
+ *
+ * Copyright (C) 2006 XXXXXX
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_WH_VIDEO_VIEW_H
+#define _HAVE_WH_VIDEO_VIEW_H
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+#include "wh-video-model.h"
+#include "wh-video-model-row.h"
+
+G_BEGIN_DECLS
+
+#define WH_TYPE_VIDEO_VIEW wh_video_view_get_type()
+
+#define WH_VIDEO_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  WH_TYPE_VIDEO_VIEW, WHVideoView))
+
+#define WH_VIDEO_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  WH_TYPE_VIDEO_VIEW, WHVideoViewClass))
+
+#define WH_IS_VIDEO_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  WH_TYPE_VIDEO_VIEW))
+
+#define WH_IS_VIDEO_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  WH_TYPE_VIDEO_VIEW))
+
+#define WH_VIDEO_VIEW_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  WH_TYPE_VIDEO_VIEW, WHVideoViewClass))
+
+typedef struct _WHVideoView WHVideoView;
+typedef struct _WHVideoViewClass WHVideoViewClass;
+typedef struct _WHVideoViewPrivate WHVideoViewPrivate;
+
+struct _WHVideoView
+{
+  ClutterActor         parent;
+  /*< private >*/
+  WHVideoViewPrivate   *priv;
+};
+
+struct _WHVideoViewClass 
+{
+  /*< private >*/
+  ClutterActorClass parent_class;
+
+  void (*_wh_video_view_1) (void);
+  void (*_wh_video_view_2) (void);
+  void (*_wh_video_view_3) (void);
+  void (*_wh_video_view_4) (void);
+}; 
+
+GType wh_video_view_get_type (void) G_GNUC_CONST;
+
+ClutterActor*
+wh_video_view_new (WHVideoModel      *model, 
+                  gint               n_items_visible);
+void
+wh_video_view_advance (WHVideoView *view, gint n);
+
+void
+wh_video_view_enable_animation (WHVideoView *view, gboolean active);
+
+WHVideoModelRow*
+wh_video_view_get_selected (WHVideoView *view);
+
+G_END_DECLS
+
+#endif
diff --git a/attic/woohaa/woohaa.c b/attic/woohaa/woohaa.c
new file mode 100644 (file)
index 0000000..df463b2
--- /dev/null
@@ -0,0 +1,782 @@
+#include <clutter/clutter.h>
+#include <clutter-gst/clutter-gst.h>
+#include <gconf/gconf-client.h>
+#include <gst/gst.h>
+#include <sqlite3.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <glib/gstdio.h>
+
+#ifdef USE_HELIX
+#include <clutter-helix/clutter-helix.h>
+#endif
+
+#include "wh-slider-menu.h"
+#include "wh-video-model.h"
+#include "wh-video-model-row.h"
+#include "wh-video-view.h"
+#include "wh-db.h"
+#include "wh-screen-video.h"
+#include "wh-busy.h"
+#include "wh-theme.h"
+#include "util.h"
+
+#define FONT "VistaSansBook 75px"
+#define WOOHAA_GCONF_PREFIX   "/apps/woohaa"
+
+typedef struct WooHaa
+{
+  ClutterActor      *screen_browse, *screen_video;
+  WHVideoModel      *model;
+  ClutterActor      *view;
+  ClutterActor      *menu;
+  ClutterActor      *busy;
+  WHDB              *db;
+
+  ClutterEffectTemplate *video_effect_tmpl;
+
+  /* For thumbnailer */
+  gint             tn_pending_child_pid;
+  WHVideoModelRow *tn_pending_row;
+  gint             tn_trys;
+}
+WooHaa;
+
+gboolean
+browse_input_cb (ClutterStage *stage,
+                ClutterEvent *event,
+                gpointer      user_data);
+
+void 
+video_input_cb (ClutterStage *stage,
+               ClutterEvent *event,
+               gpointer      user_data);
+
+static void
+thumbnail_find_empty (WooHaa *wh);
+
+static gboolean
+check_thumbnailer_child(gpointer data)
+{
+  WooHaa    *wh = (WooHaa *)data;
+  GdkPixbuf *pixbuf;
+  gint       status;
+
+  if (wh->tn_pending_child_pid == 0 || wh->tn_pending_row == NULL)
+    return FALSE;
+
+  if (waitpid (wh->tn_pending_child_pid, 
+              &status, 
+              WNOHANG) != wh->tn_pending_child_pid)
+    {
+      /* Try again soon */
+      wh->tn_trys++;
+
+      if (wh->tn_trys > 5)
+       {
+         g_warning("timed out making thumbnail");
+         /* Insert a blank pixbuf */
+         wh_video_model_row_set_thumbnail 
+           (wh->tn_pending_row, wh_theme_get_pixbuf("default-thumbnail"));
+         kill (wh->tn_pending_child_pid, SIGKILL);
+         waitpid (wh->tn_pending_child_pid, &status, 0);
+         goto cleanup;
+       }
+      return TRUE;
+    }
+
+  pixbuf = gdk_pixbuf_new_from_file ("/tmp/wh-thumb.png", NULL);
+
+  if (pixbuf == NULL)
+    {
+      /* Insert a blank pixbuf */
+      wh_video_model_row_set_thumbnail 
+       (wh->tn_pending_row, wh_theme_get_pixbuf("default-thumbnail"));
+      g_warning("failed to load pixbuf from thumbnailed");
+      goto cleanup;
+    }
+
+  wh_video_model_row_set_thumbnail (wh->tn_pending_row, pixbuf);
+  g_object_unref (pixbuf);
+
+  wh_db_sync_row (wh->tn_pending_row);
+
+ cleanup:
+  g_object_unref(wh->tn_pending_row);
+  wh->tn_pending_child_pid = 0;
+  wh->tn_pending_row = NULL;
+  wh->tn_trys = 0;
+  g_remove ("/tmp/wh-thumb.png");
+
+  thumbnail_find_empty (wh);
+
+  /* All done */
+  return FALSE;
+}
+
+gboolean
+thumbnail_create (WooHaa *wh, WHVideoModelRow *row)
+{
+  gboolean result;
+  gchar  **argv;
+
+  if (wh->tn_pending_child_pid > 0 || wh->tn_pending_row != NULL)
+    return TRUE;
+
+  argv = g_new(gchar *, 4);
+  argv[0] = g_strdup("wh-video-thumbnailer");
+  argv[1] = g_strdup(wh_video_model_row_get_path(row));
+  argv[2] = g_strdup("/tmp/wh-thumb.png");
+  argv[3] = NULL;
+
+  result = g_spawn_async (NULL,
+                         argv,
+                         NULL,
+                         G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
+                         NULL,
+                         NULL,
+                         &wh->tn_pending_child_pid,
+                         NULL);
+  g_strfreev(argv);
+
+  if (result == FALSE)
+    {
+      g_warning("failed to spawn wh-video-thumbnailer");
+
+      wh_video_model_row_set_thumbnail 
+       (row, wh_theme_get_pixbuf("default-thumbnail"));
+
+      wh->tn_pending_row       = NULL;
+      wh->tn_pending_child_pid = 0;
+
+      return FALSE;
+    }
+
+  wh->tn_pending_row = row;
+  g_object_ref(row);
+  g_timeout_add (2500, check_thumbnailer_child, wh);
+
+  return TRUE;
+}
+
+static gboolean
+thumbnail_find_empty_foreach (WHVideoModel    *model,
+                             WHVideoModelRow *row,
+                             gpointer         data)
+{
+  if (wh_video_model_row_get_thumbnail (row) == NULL)
+    {
+      if (thumbnail_create ((WooHaa *)data, row))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+thumbnail_find_empty (WooHaa *wh)
+{
+  if (!wh_screen_video_get_playing(WH_SCREEN_VIDEO(wh->screen_video))
+      && wh->tn_pending_child_pid == 0)
+    wh_video_model_foreach (wh->model, 
+                           thumbnail_find_empty_foreach, 
+                           (gpointer)wh); 
+}
+
+void
+playback_finish_complete (ClutterActor *actor, WooHaa *wh)
+{
+  wh_video_view_enable_animation (WH_VIDEO_VIEW(wh->view), TRUE);
+  thumbnail_find_empty(wh);
+}
+
+void
+on_video_playback_start (WHScreenVideo *video,
+                        WooHaa      *wh)
+{
+  clutter_actor_raise_top (wh->screen_video);
+
+  clutter_actor_set_scale (wh->screen_browse, 0.7, 0.7);
+  clutter_effect_scale (wh->video_effect_tmpl,
+                       wh->screen_browse,
+                       0.0,
+                       0.0,
+                       NULL,
+                       NULL);
+
+  clutter_effect_fade (wh->video_effect_tmpl,
+                      wh->screen_browse,
+                      0,
+                      NULL,
+                      NULL);
+
+  wh_video_view_enable_animation (WH_VIDEO_VIEW(wh->view), FALSE);
+
+  /* Stop the busy 'cursor' */
+  woohaa_busy_fade_out (WOOHAA_BUSY (wh->busy), 500);
+}
+
+void
+on_video_playback_finish (WHScreenVideo *video,
+                         WooHaa        *wh)
+{
+  WHVideoModelRow *row;
+
+  g_signal_connect (clutter_stage_get_default(),
+                   "key-release-event",
+                   G_CALLBACK (browse_input_cb),
+                   wh);
+
+  /* update db */
+  row = wh_video_view_get_selected (WH_VIDEO_VIEW(wh->view));
+  wh_video_model_row_set_n_views (row, 
+                                 wh_video_model_row_get_n_views(row)+1);
+  wh_video_model_row_set_vtime (row, time(NULL));
+  wh_db_sync_row (row);
+
+  clutter_actor_show (wh->screen_browse);
+
+  clutter_effect_fade (wh->video_effect_tmpl,
+                      wh->screen_browse,
+                      0xff,
+                      NULL,
+                      NULL);
+
+  clutter_effect_scale (wh->video_effect_tmpl,
+                       wh->screen_browse,
+                       1.0,
+                       1.0,
+                       NULL,
+                       NULL);
+
+  clutter_effect_fade (wh->video_effect_tmpl,
+                      wh->screen_video,
+                      0,
+                      (ClutterEffectCompleteFunc)playback_finish_complete,
+                      wh);
+}
+
+gboolean
+browse_input_cb (ClutterStage *stage,
+                ClutterEvent *event,
+                gpointer      user_data)
+{
+  WooHaa *wh = (WooHaa*)user_data;
+
+  if (event->type == CLUTTER_KEY_RELEASE)
+    {
+      ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+
+      switch (clutter_key_event_symbol (kev))
+       {
+       case CLUTTER_Left:
+         woohaa_slider_menu_advance (WOOHAA_SLIDER_MENU(wh->menu), -1);
+         thumbnail_find_empty (wh);
+         break;
+       case CLUTTER_Right:
+         woohaa_slider_menu_advance (WOOHAA_SLIDER_MENU(wh->menu), 1);
+         thumbnail_find_empty (wh);
+         break;
+       case CLUTTER_Up:
+         wh_video_view_advance (WH_VIDEO_VIEW(wh->view), -1);
+         break;
+       case CLUTTER_Down:
+         wh_video_view_advance (WH_VIDEO_VIEW(wh->view), 1);
+         break;
+       case CLUTTER_Return:
+         if (!wh_screen_video_activate (WH_SCREEN_VIDEO(wh->screen_video), 
+                                        WH_VIDEO_VIEW(wh->view)))
+                 break;
+
+         g_signal_handlers_disconnect_by_func(clutter_stage_get_default(),
+                                              browse_input_cb,
+                                              wh);
+
+         clutter_effect_scale (wh->video_effect_tmpl,
+                               wh->screen_browse,
+                               0.0,
+                               0.0,
+                               NULL,
+                               NULL);
+
+         woohaa_busy_fade_in (WOOHAA_BUSY (wh->busy), 500);
+         break;
+       case CLUTTER_Escape:
+       case CLUTTER_q:
+         clutter_main_quit();
+         break;
+       default:
+         break;
+       }
+    }
+
+  return TRUE;
+}
+
+static gint
+model_sort_mtime (WHVideoModelRow *rowa, WHVideoModelRow *rowb, gpointer data)
+{
+  time_t a, b;
+
+  a = wh_video_model_row_get_age(rowa);
+  b = wh_video_model_row_get_age(rowb);
+
+  if (a > b) return -1;
+  else if (a < b) return 1;
+  else  return 0;
+}
+
+static gboolean  
+model_recently_added_filter (WHVideoModel    *model,
+                            WHVideoModelRow *row,
+                            gpointer         data)
+{
+  return TRUE;
+}
+
+static void
+view_recently_added_selected (WoohaaSliderMenu *menu,
+                             ClutterActor      *actor,
+                             gpointer           userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_recently_added_filter, wh);
+  wh_video_model_set_sort_func (wh->model, model_sort_mtime, NULL);
+}
+
+static gint
+model_sort_alpha (WHVideoModelRow *rowa, WHVideoModelRow *rowb, gpointer data)
+{
+  return strcmp (wh_video_model_row_get_title(rowa),
+                wh_video_model_row_get_title(rowb));
+}
+
+#define FILTER_AF 0
+#define FILTER_GL 1
+#define FILTER_MR 2
+#define FILTER_SZ 3
+
+static gboolean  
+model_alpha_filter (WHVideoModel    *model,
+                   WHVideoModelRow *row,
+                   gpointer         data)
+{
+  gint type = GPOINTER_TO_INT(data);
+  gchar lo, hi;
+  const gchar *title;
+
+  title = wh_video_model_row_get_title(row);
+
+  switch (type)
+    {
+    case FILTER_AF:
+      lo = 'a'; hi = 'f';
+      /* Also numerical titles */
+      if (g_ascii_tolower(title[0]) >= '0' && g_ascii_tolower(title[0]) <= '9')
+       return TRUE;
+      break;
+    case FILTER_GL:
+      lo = 'g'; hi = 'l';
+      break;
+    case FILTER_MR:
+      lo = 'm'; hi = 'r';
+      break;
+    case FILTER_SZ:
+      lo = 's'; hi = 'z';
+      break;
+    default:
+      lo = 's'; hi = 'z';
+      break;
+    }
+
+  /* FIXME UTF8 */
+  if (g_ascii_tolower(title[0]) >= lo && g_ascii_tolower(title[0]) <= hi)
+    return TRUE;
+
+  return FALSE;
+}
+
+static void
+view_af_selected (WoohaaSliderMenu *menu,
+                 ClutterActor      *actor,
+                 gpointer           userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+  
+  wh_video_model_set_filter (wh->model, model_alpha_filter, 
+                            GINT_TO_POINTER(FILTER_AF));
+  wh_video_model_set_sort_func (wh->model, model_sort_alpha, NULL);
+}
+
+static void
+view_gl_selected (WoohaaSliderMenu *menu,
+                 ClutterActor      *actor,
+                 gpointer           userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_alpha_filter, 
+                            GINT_TO_POINTER(FILTER_GL));
+  wh_video_model_set_sort_func (wh->model, model_sort_alpha, NULL);
+}
+
+static void
+view_mr_selected (WoohaaSliderMenu *menu,
+                 ClutterActor      *actor,
+                 gpointer           userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_alpha_filter, 
+                            GINT_TO_POINTER(FILTER_MR));
+  wh_video_model_set_sort_func (wh->model, model_sort_alpha, NULL);
+}
+
+static void
+view_sz_selected (WoohaaSliderMenu *menu,
+                 ClutterActor      *actor,
+                 gpointer           userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_alpha_filter, 
+                            GINT_TO_POINTER(FILTER_SZ));
+  wh_video_model_set_sort_func (wh->model, model_sort_alpha, NULL);
+}
+
+static gint
+model_sort_vtime (WHVideoModelRow *rowa, WHVideoModelRow *rowb, gpointer data)
+{
+  time_t a, b;
+
+  a = wh_video_model_row_get_vtime(rowa);
+  b = wh_video_model_row_get_vtime(rowb);
+
+  if (a > b) return -1;
+  else if (a < b) return 1;
+  else  return 0;
+}
+
+static gboolean  
+model_recently_viewed_filter (WHVideoModel    *model,
+                             WHVideoModelRow *row,
+                             gpointer         data)
+{
+  if (wh_video_model_row_get_n_views(row) == 0) 
+    return FALSE;
+
+  return TRUE;
+}
+
+void
+view_recently_viewed_selected (WoohaaSliderMenu  *menu,
+                              ClutterActor  *actor,
+                              gpointer       userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_recently_viewed_filter, wh);
+  wh_video_model_set_sort_func (wh->model, model_sort_vtime, NULL);
+}
+
+static gboolean  
+model_not_viewed_filter (WHVideoModel    *model,
+                        WHVideoModelRow *row,
+                        gpointer         data)
+{
+  if (wh_video_model_row_get_n_views(row) > 0) 
+    return FALSE;
+
+  return TRUE;
+}
+
+void
+view_not_viewed_selected (WoohaaSliderMenu *menu,
+                         ClutterActor      *actor,
+                         gpointer           userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_not_viewed_filter, wh);
+  wh_video_model_set_sort_func (wh->model, model_sort_mtime, NULL);
+}
+
+static gint
+model_sort_popular (WHVideoModelRow *rowa, 
+                   WHVideoModelRow *rowb, 
+                   gpointer         data)
+{
+  gint a, b;
+
+  a = wh_video_model_row_get_n_views(rowa);
+  b = wh_video_model_row_get_n_views(rowb);
+
+  if (a > b) return -1;
+  else if (a < b) return 1;
+  else  return 0;
+}
+
+
+void
+view_popular_selected (WoohaaSliderMenu *menu,
+                      ClutterActor *actor,
+                      gpointer      userdata)
+{
+  WooHaa *wh = (WooHaa*)userdata;
+
+  wh_video_model_set_filter (wh->model, model_recently_viewed_filter, wh);
+  wh_video_model_set_sort_func (wh->model, model_sort_popular, NULL);
+}
+
+void
+on_db_row_created (WHDB *db, WHVideoModelRow *row, gpointer data)
+{
+  WooHaa *wh = (WooHaa *)data;
+
+  wh_video_model_row_set_renderer (row, wh_video_row_renderer_new (row)); 
+  wh_video_model_append_row (wh->model, row);
+}
+
+static void 
+on_desktop_fade_complete (ClutterActor *actor, gpointer user_data)
+{
+
+  WooHaa *wh = (WooHaa *) user_data;
+  WoohaaSliderMenu *menu = WOOHAA_SLIDER_MENU (wh->menu);
+
+  /* Sort the model to correspond to insitial menu option */
+  view_not_viewed_selected (menu, NULL, (gpointer)wh);
+}
+
+int
+main (int argc, char *argv[])
+{
+  WooHaa        *wh;
+  ClutterActor  *stage, *bg, *desktop;
+  GConfClient   *client;
+  GSList         *gconf_paths, *path;
+  gchar         *font_str;
+  gint           menu_h, browse_h;
+  GError        *error = NULL;
+  ClutterEffectTemplate *effect_template;
+  ClutterColor   stage_color = { 0xff, 0xff, 0xf7, 0xff };
+
+  gnome_vfs_init ();
+#ifdef USE_HELIX
+  clutter_helix_init (&argc, &argv);
+#else
+  gst_init (&argc, &argv);
+#endif
+  clutter_init (&argc, &argv);
+
+  client = gconf_client_get_default ();
+  gconf_paths = gconf_client_get_list (client,
+                                      WOOHAA_GCONF_PREFIX "/paths",
+                                      GCONF_VALUE_STRING,
+                                      &error);
+  g_object_unref (client);
+
+  if (gconf_paths == NULL)
+    {
+      g_printf("\n ***************************************************************************\n");
+      g_printf("  To run woohaa you must set the GConf key; \n");
+      g_printf("    '" WOOHAA_GCONF_PREFIX "/paths' \n");
+      g_printf("  to a list of paths containing movie files.\n\n");
+      g_printf("  To set the key, run;\n\n");
+      g_printf("    gconftool-2 -s -t list --list-type=string " WOOHAA_GCONF_PREFIX "/paths \'[/path1,smb://10.1.1.1/path2]\'\n");
+      g_printf("\n ***************************************************************************\n\n");
+
+      exit(-1);
+    }
+
+  wh_theme_init();
+
+  wh = g_new0(WooHaa, 1);
+
+  wh->model = wh_video_model_new ();
+  wh->db    = wh_db_new ();
+
+  effect_template
+    = clutter_effect_template_new (clutter_timeline_new_for_duration (1000),
+                                  CLUTTER_ALPHA_SINE_INC);
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_set_size (stage, 800, 600); 
+  g_object_set (stage, "fullscreen", TRUE, "cursor-visible", FALSE, NULL);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+  bg = util_actor_from_file (PKGDATADIR"/bg.png", CSW(), CSH());
+
+  clutter_group_add (CLUTTER_GROUP(stage), bg);
+  clutter_actor_show (bg);
+
+  clutter_actor_show (stage);
+
+  /* General setup */
+
+  wh->screen_browse = clutter_group_new();
+  clutter_actor_set_size (wh->screen_browse, CSW(), CSH());
+
+  menu_h     = CSH()/6;
+  browse_h   = CSH() - 2 * menu_h;
+  font_str   = g_strdup_printf("Sans %ipx", menu_h/2);
+  
+  wh->menu = woohaa_slider_menu_new (font_str);
+  clutter_actor_set_size (wh->menu, CSW(), menu_h);
+  clutter_actor_set_position (wh->menu, 0, menu_h/10);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "Not Viewed",
+                                view_not_viewed_selected, 
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "Recently Added",
+                                view_recently_added_selected, 
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "A-F",
+                                view_af_selected,
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "G-L",
+                                view_gl_selected,
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "M-R",
+                                view_mr_selected,
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "S-Z",
+                                view_sz_selected,
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "Popular",
+                                view_popular_selected,
+                                wh);
+
+  woohaa_slider_menu_add_option (WOOHAA_SLIDER_MENU (wh->menu), 
+                                "Recently Viewed",
+                                view_recently_viewed_selected, 
+                                wh);
+
+  woohaa_slider_menu_advance (WOOHAA_SLIDER_MENU (wh->menu), 0);
+
+  clutter_group_add (CLUTTER_GROUP(wh->screen_browse), wh->menu);
+
+  /* Video screen */
+
+
+  wh->screen_video = wh_screen_video_new ();
+
+  g_signal_connect(wh->screen_video, 
+                  "playback-started",
+                  G_CALLBACK(on_video_playback_start), 
+                  wh);
+
+  g_signal_connect(wh->screen_video, 
+                  "playback-finished",
+                  G_CALLBACK(on_video_playback_finish), 
+                  wh);
+
+  clutter_group_add (CLUTTER_GROUP(stage), wh->screen_video);
+
+  /* Startup screen */
+
+  desktop = util_texture_from_root_window ();
+  clutter_group_add (CLUTTER_GROUP(stage), desktop);
+  clutter_actor_show (desktop);
+
+  wh->busy = woohaa_busy_new();
+  clutter_group_add (CLUTTER_GROUP(stage), wh->busy);
+  clutter_actor_hide (wh->busy);
+  
+  wh->video_effect_tmpl
+    = clutter_effect_template_new (clutter_timeline_new_for_duration (500),
+                                  CLUTTER_ALPHA_SINE_INC);
+
+  clutter_actor_set_scale (wh->busy, 0.2, 0.2);
+  clutter_effect_scale (effect_template,
+                       wh->busy,
+                       1.0,
+                       1.0,
+                       NULL,
+                       NULL);
+
+  clutter_effect_fade (effect_template,
+                      desktop,
+                      0,
+                      on_desktop_fade_complete,
+                      wh);
+  clutter_effect_scale (effect_template,
+                       desktop,
+                       0.1,
+                       0.1,
+                       NULL,
+                       NULL);
+
+  /* show stage for desktop zoom  */
+  clutter_actor_show (stage);
+
+  /* below actually spins main loop (for busy icon)  */
+
+  g_signal_connect (wh->db, 
+                   "row-created", 
+                   G_CALLBACK (on_db_row_created), 
+                   wh);
+
+  for (path = gconf_paths; path != NULL; path = path->next)
+    {
+      char *uri = NULL;
+      if (strstr (path->data, "://") == NULL)
+        uri = g_filename_to_uri (path->data, NULL, NULL);
+      wh_db_import_uri (wh->db, uri ? uri : path->data);
+      g_free (uri);
+      g_free (path->data);
+    }
+  g_slist_free (gconf_paths);
+
+  /* view widget */
+
+  /* FIXME: Should be able to do this before importing 
+   * and get a smoother transition, but something appears wrong
+   * with add signal.      
+  */
+  wh->view = wh_video_view_new (wh->model, 5);
+  /* menu_h is CSH()/12 */
+  clutter_actor_set_size (wh->view, CSW() - menu_h, browse_h);
+  clutter_actor_set_position (wh->view, 
+                             (CSW() - clutter_actor_get_width(wh->view)) / 2, 
+                             menu_h + (menu_h/2) + (menu_h/6));
+
+  clutter_group_add (CLUTTER_GROUP(wh->screen_browse), wh->view);
+
+  clutter_group_add (CLUTTER_GROUP (stage), wh->screen_browse);
+
+  /* Zoom to browse screen */
+
+  clutter_actor_raise_top (wh->busy);
+
+  clutter_actor_show_all (wh->screen_browse);
+
+  g_signal_connect (stage, 
+                   "key-release-event",
+                   G_CALLBACK (browse_input_cb),
+                   wh);
+
+  g_remove ("/tmp/wh-thumb.png");
+  thumbnail_find_empty(wh);
+
+  clutter_main();
+
+  g_remove ("/tmp/wh-thumb.png");
+
+  return 0;
+}
diff --git a/attic/youhaa/AUTHORS b/attic/youhaa/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/youhaa/ChangeLog b/attic/youhaa/ChangeLog
new file mode 100644 (file)
index 0000000..5cc17b1
--- /dev/null
@@ -0,0 +1,106 @@
+2008-05-03  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c (yh_youtube_curl_close), (yh_youtube_query),
+       (yh_youtube_header_cb):
+       Stop freeing cURL's internal URL - what the hell was I doing this
+       for?! Fixes crash on ia64 (why this didn't crash on ia32, no idea)
+
+2008-05-02  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c: (yh_youtube_pause):
+       * src/yh-youtube.h:
+       Add a function to pause/resume transfers
+
+2008-05-02  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c: (yh_youtube_curl_close),
+       (yh_youtube_get_http_link_cb), (yh_youtube_get_http_link):
+       Reuse the same handle when handling redirects
+
+2008-05-01  Chris Lord  <chris@openedhand.com>
+
+       Add support for related-videos query (tested, works)
+
+       * src/yh-main.c (model_cb), (animate_search), (button_pressed_cb),
+       (related_cb):
+       Hook onto YHYoutubeBrowser's 'related' signal
+
+       * src/yh-youtube-browser.c (yh_youtube_browser_request_coords),
+       (yh_youtube_browser_class_init), (related_pressed_cb),
+       (yh_youtube_browser_init):
+       Add a new button underneath the video preview image to search for
+       related videos, emit a signal, 'related', when its clicked
+
+       * src/yh-youtube-browser.h:
+       Add 'related' signal
+
+       * src/yh-youtube.c (yh_youtube_create_model),
+       (yh_youtube_curl_close), (yh_youtube_query_manual):
+       * src/yh-youtube.h:
+       Add related videos link to the model, add a new function to query an
+       abitrary link (assumed to be a well-formed youtube json query link)
+
+2008-04-28  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c: (yh_youtube_header_cb):
+       Don't use Google cache for videos
+
+2008-04-28  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c: (yh_youtube_header_cb):
+       Again, fix video URL mangling
+
+2008-04-25  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c (yh_youtube_curl_close), (yh_youtube_header_cb):
+       Remove accidentally committed debugging statements - Also, tested flv
+       downloading with recently added videos, seems to work correctly
+
+2008-04-24  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c (yh_youtube_curl_close), (yh_youtube_header_cb):
+       Actually fix flv downloading - This may not work on recent videos,
+       needs testing
+
+2008-04-24  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c (yh_youtube_header_cb):
+       Update mangling URL for YouTube flv download
+
+2008-04-03  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c (yh_youtube_curl_close):
+       Remove curl_easy_cleanup (fixes glibc corruption warning), I suppose 
+       this is unnecessary
+
+2008-03-25  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube.c: (yh_youtube_create_model):
+       Fix ratings
+
+2008-02-22  Chris Lord  <chris@openedhand.com>
+
+       * src/yh-youtube-browser.c: (free_thumbs),
+       (yh_youtube_browser_dispose):
+       Disconnect signals from the Youtube object on dispose, also free
+       effects template and unparent internal group - the first of these
+       fixes crashes when doing a second successful query, the others stop
+       leaking memory
+
+2008-02-22  Chris Lord  <chris@openedhand.com>
+
+       * Makefile.am:
+       * autogen.sh:
+       * configure.ac:
+       * data/Makefile.am:
+       * data/go-next.svg:
+       * data/go-previous.svg:
+       * libcurl.m4:
+       * src/Makefile.am:
+       * src/glibcurl.[ch]:
+       * src/yh-main.c:
+       * src/yh-theme.[ch]:
+       * src/yh-youtube-browser.[ch]:
+       * src/yh-youtube.[ch]:
+       Initial check-in of YouTube browser/player app
+
diff --git a/attic/youhaa/Makefile.am b/attic/youhaa/Makefile.am
new file mode 100644 (file)
index 0000000..ef2a989
--- /dev/null
@@ -0,0 +1,7 @@
+SUBDIRS=data src
+
+MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub configure depcomp install-sh ltmain.sh Makefile.in missing
+
+snapshot:
+       $(MAKE) dist distdir=$(PACKAGE)-snap`date +"%Y%m%d"`
+
diff --git a/attic/youhaa/NEWS b/attic/youhaa/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/youhaa/README b/attic/youhaa/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/attic/youhaa/autogen.sh b/attic/youhaa/autogen.sh
new file mode 100755 (executable)
index 0000000..b1376df
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/attic/youhaa/configure.ac b/attic/youhaa/configure.ac
new file mode 100644 (file)
index 0000000..053cd3f
--- /dev/null
@@ -0,0 +1,36 @@
+AC_PREREQ(2.53)
+AC_INIT(youhaa, 0.0, [])
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/yh-main.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+
+m4_include(libcurl.m4)
+
+PKG_CHECK_MODULES(DEPS, clutter-0.6 clutter-gst-0.6 json-glib-1.0)
+
+LIBCURL_CHECK_CONFIG([yes], [7.14.0],
+       [DEPS_CFLAGS="$DEPS_CFLAGS $LIBCURL_CPPFLAGS"
+       DEPS_LIBS="$DEPS_LIBS $LIBCURL"
+       ],
+       AC_MSG_ERROR([libcurl >= 7.14.0 not found]))
+
+AC_SUBST(DEPS_CFLAGS)
+AC_SUBST(DEPS_LIBS)
+
+if test "x$GCC" = "xyes"; then
+        GCC_FLAGS="-g -Wall"
+fi
+
+AC_SUBST(GCC_FLAGS)
+
+AC_OUTPUT([
+Makefile
+data/Makefile
+src/Makefile
+])
+
diff --git a/attic/youhaa/data/Makefile.am b/attic/youhaa/data/Makefile.am
new file mode 100644 (file)
index 0000000..9976a4f
--- /dev/null
@@ -0,0 +1,6 @@
+
+resdir = $(datadir)/youhaa
+res_DATA = go-previous.svg go-next.svg
+
+EXTRA_DIST = $(res_DATA)
+
diff --git a/attic/youhaa/data/go-next.svg b/attic/youhaa/data/go-next.svg
new file mode 100644 (file)
index 0000000..989bff5
--- /dev/null
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   sodipodi:docname="go-next.svg"
+   sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/actions"
+   inkscape:version="0.43+devel"
+   sodipodi:version="0.32"
+   id="svg11300"
+   height="48"
+   width="48"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-ydpi="90.000000"
+   version="1.0"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs3">
+    <linearGradient
+       id="linearGradient2591">
+      <stop
+         style="stop-color:#73d216"
+         offset="0"
+         id="stop2593" />
+      <stop
+         style="stop-color:#4e9a06"
+         offset="1.0000000"
+         id="stop2595" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8662"
+       inkscape:collect="always">
+      <stop
+         id="stop8664"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop8666"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8650"
+       inkscape:collect="always">
+      <stop
+         id="stop8652"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop8654"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.046729,-3.749427e-16,2.853404e-16,1.557610,-19.51799,3.452086)"
+       r="17.171415"
+       fy="2.8969381"
+       fx="19.701141"
+       cy="2.8969381"
+       cx="19.701141"
+       id="radialGradient8656"
+       xlink:href="#linearGradient8650"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.536723,2.511012e-15,16.87306)"
+       r="15.644737"
+       fy="36.421127"
+       fx="24.837126"
+       cy="36.421127"
+       cx="24.837126"
+       id="radialGradient8668"
+       xlink:href="#linearGradient8662"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2591"
+       id="radialGradient2597"
+       cx="22.291636"
+       cy="32.797512"
+       fx="22.291636"
+       fy="32.797512"
+       r="16.9562"
+       gradientTransform="matrix(0.843022,1.871885e-16,-2.265228e-16,1.020168,4.499298,1.381992)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="25"
+     inkscape:window-x="0"
+     inkscape:window-height="885"
+     inkscape:window-width="1280"
+     inkscape:showpageshadow="false"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:cy="27.398876"
+     inkscape:cx="34.827552"
+     inkscape:zoom="11.313708"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.25490196"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     fill="#4e9a06"
+     stroke="#4e9a06" />
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+        <dc:title>Go Next</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>go</rdf:li>
+            <rdf:li>next</rdf:li>
+            <rdf:li>right</rdf:li>
+            <rdf:li>arrow</rdf:li>
+            <rdf:li>pointer</rdf:li>
+            <rdf:li>&gt;</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Attribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1"
+     id="layer1">
+    <path
+       transform="matrix(1.271186,0.000000,0.000000,1.271186,-8.119376,-15.10179)"
+       d="M 40.481863 36.421127 A 15.644737 8.3968935 0 1 1  9.1923885,36.421127 A 15.644737 8.3968935 0 1 1  40.481863 36.421127 z"
+       sodipodi:ry="8.3968935"
+       sodipodi:rx="15.644737"
+       sodipodi:cy="36.421127"
+       sodipodi:cx="24.837126"
+       id="path8660"
+       style="opacity:0.29946522;color:#000000;fill:url(#radialGradient8668);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:nodetypes="cccccccc"
+       id="path8643"
+       d="M 8.5541875,15.517348 L 8.5541875,32.511768 L 21.538,32.511768 L 21.538,41.056806 L 41.497835,24.150365 L 21.41919,7.1251168 L 21.41919,15.522652 L 8.5541875,15.517348 z "
+       style="opacity:1;color:#000000;fill:url(#radialGradient2597);fill-opacity:1;fill-rule:evenodd;stroke:#3a7304;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       sodipodi:nodetypes="cccccc"
+       id="path8645"
+       d="M 21.962385,8.2485033 L 21.962385,16.054978 L 9.1452151,16.054978 L 9.1452151,25.095691 C 26.895215,27.095691 25.778752,17.640403 40.528752,24.140403 L 21.962385,8.2485033 z "
+       style="opacity:0.5080214;color:#000000;fill:url(#radialGradient8656);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       style="opacity:0.48128339;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 9.537702,16.561892 L 9.537702,31.546332 L 22.523069,31.546332 L 22.523069,38.941498 L 40.001083,24.145807 L 22.507108,9.3654066 L 22.507108,16.566789 L 9.537702,16.561892 z "
+       id="path8658"
+       sodipodi:nodetypes="cccccccc" />
+  </g>
+</svg>
diff --git a/attic/youhaa/data/go-previous.svg b/attic/youhaa/data/go-previous.svg
new file mode 100644 (file)
index 0000000..f1eb977
--- /dev/null
@@ -0,0 +1,852 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   sodipodi:docname="go-previous.svg"
+   sodipodi:docbase="/home/andreas/projekt/tango/scalable"
+   inkscape:version="0.42+0.43pre2"
+   sodipodi:version="0.32"
+   id="svg11300"
+   height="48px"
+   width="48px"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-ydpi="90.000000">
+  <defs
+     id="defs3">
+    <linearGradient
+       id="linearGradient2591">
+      <stop
+         style="stop-color:#73d216"
+         offset="0"
+         id="stop2593" />
+      <stop
+         style="stop-color:#4e9a06"
+         offset="1.0000000"
+         id="stop2595" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient10314">
+      <stop
+         style="stop-color:#7ea5d6;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop10316" />
+      <stop
+         style="stop-color:#467ec5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop10318" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8938">
+      <stop
+         id="stop8940"
+         offset="0.0000000"
+         style="stop-color:#fdc674;stop-opacity:1.0000000;" />
+      <stop
+         id="stop8942"
+         offset="1.0000000"
+         style="stop-color:#d88103;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8662"
+       inkscape:collect="always">
+      <stop
+         id="stop8664"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop8666"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8650"
+       inkscape:collect="always">
+      <stop
+         id="stop8652"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop8654"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7636"
+       inkscape:collect="always">
+      <stop
+         id="stop7638"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop7640"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7614">
+      <stop
+         id="stop7616"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.21590909"
+         id="stop7649" />
+      <stop
+         style="stop-color:#838383;stop-opacity:1.0000000;"
+         offset="0.50000000"
+         id="stop7632" />
+      <stop
+         id="stop7618"
+         offset="1"
+         style="stop-color:#838383;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7608">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop7610" />
+      <stop
+         id="stop7622"
+         offset="0.46022728"
+         style="stop-color:#e3e3e3;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#dadada;stop-opacity:0.67058824;"
+         offset="0.61970556"
+         id="stop7624" />
+      <stop
+         style="stop-color:#d1d1d1;stop-opacity:0.34285715;"
+         offset="1.0000000"
+         id="stop7612" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7602">
+      <stop
+         id="stop7604"
+         offset="0.0000000"
+         style="stop-color:#f6f6f6;stop-opacity:1.0000000;" />
+      <stop
+         id="stop7606"
+         offset="1.0000000"
+         style="stop-color:#e0e0e0;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7586">
+      <stop
+         id="stop7588"
+         offset="0.0000000"
+         style="stop-color:#525252;stop-opacity:1.0000000;" />
+      <stop
+         id="stop7590"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient12836">
+      <stop
+         style="stop-color:#515152;stop-opacity:1;"
+         offset="0"
+         id="stop12838" />
+      <stop
+         style="stop-color:#515152;stop-opacity:0;"
+         offset="1"
+         id="stop12840" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient12828">
+      <stop
+         style="stop-color:#cccccd;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop12830" />
+      <stop
+         id="stop12862"
+         offset="0.0000000"
+         style="stop-color:#adadae;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#8f8f90;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop12832" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient12810">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop12812" />
+      <stop
+         style="stop-color:#e5e5e5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop12814" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11625">
+      <stop
+         style="stop-color:#fce94f;stop-opacity:1;"
+         offset="0"
+         id="stop11627" />
+      <stop
+         style="stop-color:#fce94f;stop-opacity:0;"
+         offset="1"
+         id="stop11629" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11615">
+      <stop
+         style="stop-color:#636363;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop11617" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11619" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11602">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop11604" />
+      <stop
+         style="stop-color:#c5c5c5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11606" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11594">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop11596" />
+      <stop
+         style="stop-color:#d1d1d1;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11598" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11520">
+      <stop
+         style="stop-color:#fbfbfb;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop11522" />
+      <stop
+         style="stop-color:#dcdcdc;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11524" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11508">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop11510" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop11512" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11494">
+      <stop
+         style="stop-color:#ef2929;stop-opacity:1;"
+         offset="0"
+         id="stop11496" />
+      <stop
+         style="stop-color:#ef2929;stop-opacity:0;"
+         offset="1"
+         id="stop11498" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11415">
+      <stop
+         style="stop-color:#204a87;stop-opacity:0.0000000;"
+         offset="0.0000000"
+         id="stop11417" />
+      <stop
+         id="stop11423"
+         offset="0.50000000"
+         style="stop-color:#204a87;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#204a87;stop-opacity:0;"
+         offset="1"
+         id="stop11419" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11399">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop11401" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop11403" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11415"
+       id="linearGradient11425"
+       gradientUnits="userSpaceOnUse"
+       x1="15.828360"
+       y1="3.7744560"
+       x2="43.615788"
+       y2="34.462429"
+       gradientTransform="translate(-60.28571,-0.285714)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11415"
+       id="linearGradient11427"
+       gradientUnits="userSpaceOnUse"
+       x1="9.6957054"
+       y1="9.3458843"
+       x2="35.679932"
+       y2="39.033859"
+       gradientTransform="translate(-60.57143,0.000000)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11415"
+       id="linearGradient11439"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-60.85714,0.428571)"
+       x1="13.267134"
+       y1="19.774456"
+       x2="26.758644"
+       y2="33.462429" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11399"
+       id="radialGradient11441"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.487395,0.000000,20.06483)"
+       cx="12.071428"
+       cy="39.142857"
+       fx="12.071428"
+       fy="39.142857"
+       r="8.5000000" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11494"
+       id="radialGradient11500"
+       cx="27.577173"
+       cy="15.048258"
+       fx="27.577173"
+       fy="15.048258"
+       r="3.8335034"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11494"
+       id="radialGradient11504"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)"
+       cx="27.577173"
+       cy="16.049133"
+       fx="27.577173"
+       fy="16.049133"
+       r="3.8335034" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11508"
+       id="radialGradient11514"
+       cx="30.203562"
+       cy="44.565483"
+       fx="30.203562"
+       fy="44.565483"
+       r="6.5659914"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,2.166583e-14,29.48178)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11520"
+       id="radialGradient11526"
+       cx="24.445690"
+       cy="35.878170"
+       fx="24.445690"
+       fy="35.878170"
+       r="20.530962"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.995058,-1.535926e-32,0.000000,1.855412,24.94925,-30.20430)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11508"
+       id="radialGradient11532"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,-5.348412e-14,29.48178)"
+       cx="30.203562"
+       cy="44.565483"
+       fx="30.203562"
+       fy="44.565483"
+       r="6.5659914" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11594"
+       id="linearGradient11600"
+       x1="20.092352"
+       y1="8.9471626"
+       x2="31.799011"
+       y2="38.947163"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.045319,0.000000,0.000000,0.957884,48.16627,1.415543)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11520"
+       id="linearGradient11608"
+       x1="24.445671"
+       y1="0.49847093"
+       x2="24.445671"
+       y2="39.447163"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.984324,0.000000,0.000000,0.957884,49.65734,1.415543)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11615"
+       id="radialGradient11621"
+       cx="25.000000"
+       cy="27.749998"
+       fx="25.000000"
+       fy="27.749998"
+       r="4.7500000"
+       gradientTransform="matrix(3.570338,3.171097e-15,-4.005596e-15,4.509900,-64.25843,-94.25499)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11631"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11635"
+       gradientUnits="userSpaceOnUse"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000"
+       gradientTransform="translate(2.000000,0.000000)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11639"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11643"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(6.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11647"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(8.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11655"
+       gradientUnits="userSpaceOnUse"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11657"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11659"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11661"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(6.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12816"
+       x1="65.623963"
+       y1="21.459777"
+       x2="87.528968"
+       y2="21.459777"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12818"
+       gradientUnits="userSpaceOnUse"
+       x1="84.998962"
+       y1="25.209778"
+       x2="62.591469"
+       y2="12.022278" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12828"
+       id="radialGradient12834"
+       cx="88.593018"
+       cy="33.398670"
+       fx="88.593018"
+       fy="33.398670"
+       r="7.0056136"
+       gradientTransform="matrix(0.969219,0.227988,-0.194668,0.827570,9.443870,-15.99848)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12836"
+       id="linearGradient12842"
+       x1="88.750000"
+       y1="31.656250"
+       x2="92.062500"
+       y2="36.656250"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12878"
+       gradientUnits="userSpaceOnUse"
+       x1="65.623963"
+       y1="21.459777"
+       x2="87.528968"
+       y2="21.459777" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12836"
+       id="linearGradient12880"
+       gradientUnits="userSpaceOnUse"
+       x1="88.750000"
+       y1="31.656250"
+       x2="92.062500"
+       y2="36.656250" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12828"
+       id="radialGradient12882"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.969219,0.227988,-0.194668,0.827570,9.443870,-15.99848)"
+       cx="88.593018"
+       cy="33.398670"
+       fx="88.593018"
+       fy="33.398670"
+       r="7.0056136" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12884"
+       gradientUnits="userSpaceOnUse"
+       x1="84.998962"
+       y1="25.209778"
+       x2="62.591469"
+       y2="12.022278" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11615"
+       id="radialGradient12894"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.570338,3.171097e-15,-4.005596e-15,4.509900,-64.25843,-94.25499)"
+       cx="25.000000"
+       cy="27.749998"
+       fx="25.000000"
+       fy="27.749998"
+       r="4.7500000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12896"
+       gradientUnits="userSpaceOnUse"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000"
+       gradientTransform="translate(7.267442e-2,-0.181686)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12898"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12900"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12902"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(6.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12911"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(7.267442e-2,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12913"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12915"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       y2="21.067410"
+       x2="24.445690"
+       y1="33.447811"
+       x1="31.597168"
+       gradientTransform="matrix(0.476329,0.000000,0.000000,0.627721,62.07560,9.156933)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7584"
+       xlink:href="#linearGradient11594"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.407878,2.776254e-16,-5.900875e-16,1.861050,14.96976,-20.55775)"
+       r="6.0270013"
+       fy="29.099535"
+       fx="24.399090"
+       cy="29.099535"
+       cx="24.399090"
+       id="radialGradient7592"
+       xlink:href="#linearGradient7586"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="11.042997"
+       x2="22.585604"
+       y1="34.149513"
+       x1="22.585604"
+       gradientTransform="matrix(1.059222,0.000000,0.000000,0.808101,48.08657,4.001391)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7596"
+       xlink:href="#linearGradient7608"
+       inkscape:collect="always" />
+    <linearGradient
+       gradientTransform="translate(49.32070,0.000000)"
+       gradientUnits="userSpaceOnUse"
+       y2="38.454056"
+       x2="28.284273"
+       y1="28.554562"
+       x1="25.279068"
+       id="linearGradient7642"
+       xlink:href="#linearGradient7636"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.777122,-8.126449e-2,6.891211e-2,2.223012,4.035118,-33.24798)"
+       r="4.4774761"
+       fy="29.609560"
+       fx="24.483574"
+       cy="29.609560"
+       cx="24.483574"
+       id="radialGradient7647"
+       xlink:href="#linearGradient7614"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-2.046729,-3.749427e-16,-2.853404e-16,1.557610,67.59375,3.275309)"
+       r="17.171415"
+       fy="5.7859797"
+       fx="25.075571"
+       cy="5.7859797"
+       cx="25.075571"
+       id="radialGradient8656"
+       xlink:href="#linearGradient8650"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.536723,6.772795e-15,16.87306)"
+       r="15.644737"
+       fy="36.421127"
+       fx="24.837126"
+       cy="36.421127"
+       cx="24.837126"
+       id="radialGradient8668"
+       xlink:href="#linearGradient8662"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2591"
+       id="radialGradient2597"
+       cx="22.291636"
+       cy="32.797512"
+       fx="22.291636"
+       fy="32.797512"
+       r="16.956199"
+       gradientTransform="matrix(-0.843022,1.871885e-16,2.265228e-16,1.020168,43.57646,1.205215)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="25"
+     inkscape:window-x="0"
+     inkscape:window-height="885"
+     inkscape:window-width="1280"
+     inkscape:showpageshadow="false"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:cy="25.461494"
+     inkscape:cx="25.558072"
+     inkscape:zoom="16"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.25490196"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     fill="#4e9a06"
+     stroke="#4e9a06" />
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+        <dc:title>Go Previous</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>go</rdf:li>
+            <rdf:li>previous</rdf:li>
+            <rdf:li>left</rdf:li>
+            <rdf:li>arrow</rdf:li>
+            <rdf:li>pointer</rdf:li>
+            <rdf:li>&lt;</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Attribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1"
+     id="layer1">
+    <path
+       transform="matrix(-1.271186,0.000000,0.000000,1.271186,56.19514,-15.27857)"
+       d="M 40.481863 36.421127 A 15.644737 8.3968935 0 1 1  9.1923885,36.421127 A 15.644737 8.3968935 0 1 1  40.481863 36.421127 z"
+       sodipodi:ry="8.3968935"
+       sodipodi:rx="15.644737"
+       sodipodi:cy="36.421127"
+       sodipodi:cx="24.837126"
+       id="path8660"
+       style="opacity:0.29946521;color:#000000;fill:url(#radialGradient8668);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:nodetypes="cccccccc"
+       id="path8643"
+       d="M 39.490316,15.496821 L 39.490316,32.491241 L 26.537753,32.491241 L 26.537753,40.973779 L 6.577917,23.973588 L 26.531563,6.7295901 L 26.531563,15.502125 L 39.490316,15.496821 z "
+       style="opacity:1.0000000;color:#000000;fill:url(#radialGradient2597);fill-opacity:1.0000000;fill-rule:evenodd;stroke:#3a7304;stroke-width:1.0000004;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       sodipodi:nodetypes="cccccc"
+       id="path8645"
+       d="M 25.988368,7.9779766 L 25.988368,16.034451 L 38.930538,16.034451 L 38.930538,24.918914 C 22.180538,18.668914 22.797001,30.213626 7.547,23.963626 L 25.988368,7.9779766 z "
+       style="opacity:0.50802141;color:#000000;fill:url(#radialGradient8656);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible" />
+    <path
+       style="opacity:0.48128340;color:#000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000004;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
+       d="M 38.475551,16.541365 L 38.475551,31.463305 L 25.490184,31.463305 L 25.490184,38.764721 L 8.168419,23.96903 L 25.506145,9.0636299 L 25.506145,16.546262 L 38.475551,16.541365 z "
+       id="path8658"
+       sodipodi:nodetypes="cccccccc" />
+  </g>
+</svg>
diff --git a/attic/youhaa/libcurl.m4 b/attic/youhaa/libcurl.m4
new file mode 100644 (file)
index 0000000..798427c
--- /dev/null
@@ -0,0 +1,236 @@
+# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
+#                       [ACTION-IF-YES], [ACTION-IF-NO])
+# ----------------------------------------------------------
+#      David Shaw <dshaw@jabberwocky.com>   Jan-17-2006
+#
+# Checks for libcurl.  DEFAULT-ACTION is the string yes or no to
+# specify whether to default to --with-libcurl or --without-libcurl.
+# If not supplied, DEFAULT-ACTION is yes.  MINIMUM-VERSION is the
+# minimum version of libcurl to accept.  Pass the version as a regular
+# version number like 7.10.1. If not supplied, any version is
+# accepted.  ACTION-IF-YES is a list of shell commands to run if
+# libcurl was successfully found and passed the various tests.
+# ACTION-IF-NO is a list of shell commands that are run otherwise.
+# Note that using --without-libcurl does run ACTION-IF-NO.
+#
+# This macro #defines HAVE_LIBCURL if a working libcurl setup is
+# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
+# values.  Other useful defines are LIBCURL_FEATURE_xxx where xxx are
+# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
+# where yyy are the various protocols supported by libcurl.  Both xxx
+# and yyy are capitalized.  See the list of AH_TEMPLATEs at the top of
+# the macro for the complete list of possible defines.  Shell
+# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
+# defined to 'yes' for those features and protocols that were found.
+# Note that xxx and yyy keep the same capitalization as in the
+# curl-config list (e.g. it's "HTTP" and not "http").
+#
+# Users may override the detected values by doing something like:
+# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
+#
+# For the sake of sanity, this macro assumes that any libcurl that is
+# found is after version 7.7.2, the first version that included the
+# curl-config script.  Note that it is very important for people
+# packaging binary versions of libcurl to include this script!
+# Without curl-config, we can only guess what protocols are available,
+# or use curl_version_info to figure it out at runtime.
+
+AC_DEFUN([LIBCURL_CHECK_CONFIG],
+[
+  AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
+  AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
+  AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
+  AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
+  AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
+  AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
+  AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
+  AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
+
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+
+  AC_ARG_WITH(libcurl,
+     AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
+     [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
+
+  if test "$_libcurl_with" != "no" ; then
+
+     AC_PROG_AWK
+
+     _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
+
+     _libcurl_try_link=yes
+
+     if test -d "$_libcurl_with" ; then
+        LIBCURL_CPPFLAGS="-I$withval/include"
+        _libcurl_ldflags="-L$withval/lib"
+        AC_PATH_PROG([_libcurl_config],["$withval/bin/curl-config"])
+     else
+       AC_PATH_PROG([_libcurl_config],[curl-config])
+     fi
+
+     if test x$_libcurl_config != "x" ; then
+        AC_CACHE_CHECK([for the version of libcurl],
+          [libcurl_cv_lib_curl_version],
+           [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+       _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+       _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+        if test $_libcurl_wanted -gt 0 ; then
+          AC_CACHE_CHECK([for libcurl >= version $2],
+             [libcurl_cv_lib_version_ok],
+              [
+             if test $_libcurl_version -ge $_libcurl_wanted ; then
+                libcurl_cv_lib_version_ok=yes
+             else
+                libcurl_cv_lib_version_ok=no
+             fi
+              ])
+        fi
+
+       if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+           if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+              LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+           fi
+           if test x"$LIBCURL" = "x" ; then
+              LIBCURL=`$_libcurl_config --libs`
+
+              # This is so silly, but Apple actually has a bug in their
+             # curl-config script.  Fixed in Tiger, but there are still
+             # lots of Panther installs around.
+              case "${host}" in
+                 powerpc-apple-darwin7*)
+                    LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+                 ;;
+              esac
+           fi
+
+          # All curl-config scripts support --feature
+          _libcurl_features=`$_libcurl_config --feature`
+
+           # Is it modern enough to have --protocols? (7.12.4)
+          if test $_libcurl_version -ge 461828 ; then
+              _libcurl_protocols=`$_libcurl_config --protocols`
+           fi
+       else
+           _libcurl_try_link=no
+       fi
+
+       unset _libcurl_wanted
+     fi
+
+     if test $_libcurl_try_link = yes ; then
+
+        # we didn't find curl-config, so let's see if the user-supplied
+        # link line (or failing that, "-lcurl") is enough.
+        LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+
+        AC_CACHE_CHECK([whether libcurl is usable],
+           [libcurl_cv_lib_curl_usable],
+           [
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBCURL $LIBS"
+
+           AC_LINK_IFELSE(AC_LANG_PROGRAM([#include <curl/curl.h>],[
+/* Try and use a few common options to force a failure if we are
+   missing symbols or can't link. */
+int x;
+curl_easy_setopt(NULL,CURLOPT_URL,NULL);
+x=CURL_ERROR_SIZE;
+x=CURLOPT_WRITEFUNCTION;
+x=CURLOPT_FILE;
+x=CURLOPT_ERRORBUFFER;
+x=CURLOPT_STDERR;
+x=CURLOPT_VERBOSE;
+]),libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+           ])
+
+        if test $libcurl_cv_lib_curl_usable = yes ; then
+
+          # Does curl_free() exist in this version of libcurl?
+          # If not, fake it with free()
+
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBS $LIBCURL"
+
+           AC_CHECK_FUNC(curl_free,,
+             AC_DEFINE(curl_free,free,
+               [Define curl_free() as free() if our version of curl lacks curl_free.]))
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+
+           AC_DEFINE(HAVE_LIBCURL,1,
+             [Define to 1 if you have a functional curl library.])
+           AC_SUBST(LIBCURL_CPPFLAGS)
+           AC_SUBST(LIBCURL)
+
+           for _libcurl_feature in $_libcurl_features ; do
+             AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+             eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+           done
+
+          if test "x$_libcurl_protocols" = "x" ; then
+
+             # We don't have --protocols, so just assume that all
+             # protocols are available
+             _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT"
+
+             if test x$libcurl_feature_SSL = xyes ; then
+                _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+                # FTPS wasn't standards-compliant until version
+                # 7.11.0
+                if test $_libcurl_version -ge 461568; then
+                   _libcurl_protocols="$_libcurl_protocols FTPS"
+                fi
+             fi
+          fi
+
+          for _libcurl_protocol in $_libcurl_protocols ; do
+             AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+             eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+           done
+        fi
+     fi
+
+     unset _libcurl_try_link
+     unset _libcurl_version_parse
+     unset _libcurl_config
+     unset _libcurl_feature
+     unset _libcurl_features
+     unset _libcurl_protocol
+     unset _libcurl_protocols
+     unset _libcurl_version
+     unset _libcurl_ldflags
+  fi
+
+  if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
+     # This is the IF-NO path
+     ifelse([$4],,:,[$4])
+  else
+     # This is the IF-YES path
+     ifelse([$3],,:,[$3])
+  fi
+
+  unset _libcurl_with
+])dnl
diff --git a/attic/youhaa/src/Makefile.am b/attic/youhaa/src/Makefile.am
new file mode 100644 (file)
index 0000000..4b2a969
--- /dev/null
@@ -0,0 +1,20 @@
+bin_PROGRAMS=youhaa
+
+PKGDATADIR = $(datadir)/youhaa
+
+AM_CFLAGS = $(DEPS_CFLAGS) $(GCC_FLAGS) -D_GNU_SOURCE -DPKGDATADIR=\"$(PKGDATADIR)\"
+
+youhaa_LDADD  = $(DEPS_LIBS)
+youhaa_SOURCES = \
+               yh-main.c               \
+               yh-theme.c              \
+               yh-theme.h              \
+               yh-youtube-browser.c    \
+               yh-youtube-browser.h    \
+               yh-youtube.c            \
+               yh-youtube.h            \
+               glibcurl.c              \
+               glibcurl.h              \
+               pause_png.h             \
+               play_png.h
+
diff --git a/attic/youhaa/src/glibcurl.c b/attic/youhaa/src/glibcurl.c
new file mode 100644 (file)
index 0000000..8299d30
--- /dev/null
@@ -0,0 +1,546 @@
+/* $Id: glibcurl.c,v 1.14 2004/12/05 16:15:12 atterer Exp $ -*- C -*-
+  __   _
+  |_) /|  Copyright (C) 2004  |  richard@
+  | \/¯|  Richard Atterer     |  atterer.net
+  ¯ '` ¯
+  All rights reserved.
+
+  Permission to use, copy, modify, and distribute this software for any
+  purpose with or without fee is hereby granted, provided that the above
+  copyright notice and this permission notice appear in all copies.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+  USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+  Except as contained in this notice, the name of a copyright holder shall
+  not be used in advertising or otherwise to promote the sale, use or other
+  dealings in this Software without prior written authorization of the
+  copyright holder.
+
+*/
+
+#include <glib.h>
+#include <glibcurl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+/* #define D(_args) fprintf _args; */
+#define D(_args)
+
+/* #if 1 */
+#ifdef G_OS_WIN32
+/*______________________________________________________________________*/
+
+/* Timeout for the fds passed to glib's poll() call, in millisecs.
+   curl_multi_fdset(3) says we should call curl_multi_perform() at regular
+   intervals. */
+#define GLIBCURL_TIMEOUT 500
+
+/* A structure which "derives" (in glib speak) from GSource */
+typedef struct CurlGSource_ {
+  GSource source; /* First: The type we're deriving from */
+
+  CURLM* multiHandle;
+  GThread* selectThread;
+  GCond* cond; /* To signal selectThread => main thread: call perform() */
+  GMutex* mutex; /* Not held by selectThread whenever it is waiting */
+
+  gboolean callPerform; /* TRUE => Call curl_multi_perform() Real Soon */
+  gint gtkBlockAndWait;
+  gboolean selectRunning; /* FALSE => selectThread terminates */
+
+  /* For data returned by curl_multi_fdset */
+  fd_set fdRead;
+  fd_set fdWrite;
+  fd_set fdExc;
+  int fdMax;
+
+} CurlGSource;
+
+/* Global state: Our CurlGSource object */
+static CurlGSource* curlSrc = 0;
+
+/* The "methods" of CurlGSource */
+static gboolean prepare(GSource* source, gint* timeout);
+static gboolean check(GSource* source);
+static gboolean dispatch(GSource* source, GSourceFunc callback,
+                         gpointer user_data);
+static void finalize(GSource* source);
+
+static GSourceFuncs curlFuncs = {
+  &prepare, &check, &dispatch, &finalize, 0, 0
+};
+/*______________________________________________________________________*/
+
+void glibcurl_init() {
+  /* Create source object for curl file descriptors, and hook it into the
+     default main context. */
+  GSource* src = g_source_new(&curlFuncs, sizeof(CurlGSource));
+  curlSrc = (CurlGSource*)src;
+  g_source_attach(&curlSrc->source, NULL);
+
+  if (!g_thread_supported()) g_thread_init(NULL);
+
+  /* Init rest of our data */
+  curlSrc->callPerform = 0;
+  curlSrc->selectThread = 0;
+  curlSrc->cond = g_cond_new();
+  curlSrc->mutex = g_mutex_new();
+  curlSrc->gtkBlockAndWait = 0;
+
+  /* Init libcurl */
+  curl_global_init(CURL_GLOBAL_ALL);
+  curlSrc->multiHandle = curl_multi_init();
+}
+/*______________________________________________________________________*/
+
+void glibcurl_cleanup() {
+  D((stderr, "glibcurl_cleanup\n"));
+  /* You must call curl_multi_remove_handle() and curl_easy_cleanup() for all
+     requests before calling this. */
+/*   assert(curlSrc->callPerform == 0); */
+
+  /* All easy handles must be finished */
+
+  /* Lock before accessing selectRunning/selectThread */
+  g_mutex_lock(curlSrc->mutex);
+  curlSrc->selectRunning = FALSE;
+  while (curlSrc->selectThread != NULL) {
+    g_mutex_unlock(curlSrc->mutex);
+    g_thread_yield();
+    g_cond_signal(curlSrc->cond); /* Make the select thread shut down */
+    g_thread_yield();
+    g_mutex_lock(curlSrc->mutex); /* Wait until it has shut down */
+  }
+  g_mutex_unlock(curlSrc->mutex);
+
+  assert(curlSrc->selectThread == NULL);
+
+  g_cond_free(curlSrc->cond);
+  g_mutex_free(curlSrc->mutex);
+
+  curl_multi_cleanup(curlSrc->multiHandle);
+  curlSrc->multiHandle = 0;
+  curl_global_cleanup();
+
+  g_source_unref(&curlSrc->source);
+  curlSrc = 0;
+}
+/*______________________________________________________________________*/
+
+CURLM* glibcurl_handle() {
+  return curlSrc->multiHandle;
+}
+/*______________________________________________________________________*/
+
+CURLMcode glibcurl_add(CURL *easy_handle) {
+  assert(curlSrc != 0);
+  assert(curlSrc->multiHandle != 0);
+  glibcurl_start();
+  return curl_multi_add_handle(curlSrc->multiHandle, easy_handle);
+}
+/*______________________________________________________________________*/
+
+CURLMcode glibcurl_remove(CURL *easy_handle) {
+  D((stderr, "glibcurl_remove %p\n", easy_handle));
+  assert(curlSrc != 0);
+  assert(curlSrc->multiHandle != 0);
+  return curl_multi_remove_handle(curlSrc->multiHandle, easy_handle);
+}
+/*______________________________________________________________________*/
+
+/* Call this whenever you have added a request using
+   curl_multi_add_handle(). */
+void glibcurl_start() {
+  D((stderr, "glibcurl_start\n"));
+  curlSrc->callPerform = TRUE;
+}
+/*______________________________________________________________________*/
+
+void glibcurl_set_callback(GlibcurlCallback function, void* data) {
+  g_source_set_callback(&curlSrc->source, (GSourceFunc)function, data,
+                        NULL);
+}
+/*______________________________________________________________________*/
+
+static gpointer selectThread(gpointer data) {
+  int fdCount;
+  struct timeval timeout;
+  assert(data == 0); /* Just to get rid of unused param warning */
+
+  D((stderr, "selectThread\n"));
+  g_mutex_lock(curlSrc->mutex);
+  D((stderr, "selectThread: got lock\n"));
+
+  curlSrc->selectRunning = TRUE;
+  while (curlSrc->selectRunning) {
+
+    FD_ZERO(&curlSrc->fdRead);
+    FD_ZERO(&curlSrc->fdWrite);
+    FD_ZERO(&curlSrc->fdExc);
+    curlSrc->fdMax = -1;
+    /* What fds does libcurl want us to poll? */
+    curl_multi_fdset(curlSrc->multiHandle, &curlSrc->fdRead,
+                     &curlSrc->fdWrite, &curlSrc->fdExc, &curlSrc->fdMax);
+    timeout.tv_sec = GLIBCURL_TIMEOUT / 1000;
+    timeout.tv_usec = (GLIBCURL_TIMEOUT % 1000) * 1000;
+    fdCount = select(curlSrc->fdMax + 1, &curlSrc->fdRead, &curlSrc->fdWrite,
+                     &curlSrc->fdExc, &timeout);
+    D((stderr, "selectThread: select() fdCount=%d\n", fdCount));
+
+    g_atomic_int_inc(&curlSrc->gtkBlockAndWait); /* "GTK thread, block!" */
+    D((stderr, "selectThread: waking up GTK thread %d\n",
+       curlSrc->gtkBlockAndWait));
+    /* GTK thread will almost immediately block in prepare() */
+    g_main_context_wakeup(NULL);
+
+    /* Now unblock GTK thread, continue after it signals us */
+    D((stderr, "selectThread: pre-wait\n"));
+    g_cond_wait(curlSrc->cond, curlSrc->mutex);
+    D((stderr, "selectThread: post-wait\n"));
+
+  }
+
+  curlSrc->selectThread = NULL;
+  D((stderr, "selectThread: exit\n"));
+  g_mutex_unlock(curlSrc->mutex);
+  return NULL;
+}
+/*______________________________________________________________________*/
+
+/* Returning FALSE may cause the main loop to block indefinitely, but that is
+   not a problem, we use g_main_context_wakeup to wake it up */
+/* Returns TRUE iff it holds the mutex lock */
+gboolean prepare(GSource* source, gint* timeout) {
+  assert(source == &curlSrc->source);
+  D((stderr, "prepare: callPerform=%d, thread=%p\n",
+     curlSrc->callPerform, curlSrc->selectThread));
+
+  *timeout = -1;
+
+  if (g_atomic_int_dec_and_test(&curlSrc->gtkBlockAndWait)) {
+    /* The select thread wants us to block */
+    D((stderr, "prepare: trying lock\n"));
+    g_mutex_lock(curlSrc->mutex);
+    D((stderr, "prepare: got lock\n"));
+    return TRUE;
+  } else {
+    g_atomic_int_inc(&curlSrc->gtkBlockAndWait);
+  }
+
+  /* Usual behaviour: Nothing happened, so don't dispatch. */
+  if (!curlSrc->callPerform) return FALSE;
+
+  /* Always dispatch if callPerform, i.e. 1st download just starting. */
+  D((stderr, "prepare: trying lock 2\n"));
+  /* Problem: We can block up to GLIBCURL_TIMEOUT msecs here, until the
+     select() call returns. However, under Win32 this does not appear to be a
+     problem (don't know why) - it _does_ tend to block the GTK thread under
+     Linux. */
+  g_mutex_lock(curlSrc->mutex);
+  D((stderr, "prepare: got lock 2\n"));
+  curlSrc->callPerform = FALSE;
+  if (curlSrc->selectThread == NULL) {
+    D((stderr, "prepare: starting select thread\n"));
+    /* Note that the thread will stop soon because we hold mutex */
+    curlSrc->selectThread = g_thread_create(&selectThread, 0, FALSE, NULL);
+    assert(curlSrc->selectThread != NULL);
+  }
+  return TRUE;
+}
+/*______________________________________________________________________*/
+
+/* Called after all the file descriptors are polled by glib. */
+gboolean check(GSource* source) {
+  assert(source == &curlSrc->source);
+  return FALSE;
+}
+/*______________________________________________________________________*/
+
+gboolean dispatch(GSource* source, GSourceFunc callback,
+                  gpointer user_data) {
+  CURLMcode x;
+  int multiCount;
+
+  assert(source == &curlSrc->source);
+  do {
+    x = curl_multi_perform(curlSrc->multiHandle, &multiCount);
+    D((stderr, "dispatched: code=%d, reqs=%d\n", x, multiCount));
+  } while (x == CURLM_CALL_MULTI_PERFORM);
+
+  if (multiCount == 0)
+    curlSrc->selectRunning = FALSE;
+
+  if (callback != 0) (*callback)(user_data);
+
+  /* Let selectThread call select() again */
+  g_cond_signal(curlSrc->cond);
+  g_mutex_unlock(curlSrc->mutex);
+
+  return TRUE; /* "Do not destroy me" */
+}
+/*______________________________________________________________________*/
+
+void finalize(GSource* source) {
+  assert(source == &curlSrc->source);
+}
+/*======================================================================*/
+
+#else /* !G_OS_WIN32 */
+
+/* Number of highest allowed fd */
+#define GLIBCURL_FDMAX 127
+
+/* Timeout for the fds passed to glib's poll() call, in millisecs.
+   curl_multi_fdset(3) says we should call curl_multi_perform() at regular
+   intervals. */
+#define GLIBCURL_TIMEOUT 1000
+
+/* GIOCondition event masks */
+#define GLIBCURL_READ  (G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP)
+#define GLIBCURL_WRITE (G_IO_OUT | G_IO_ERR | G_IO_HUP)
+#define GLIBCURL_EXC   (G_IO_ERR | G_IO_HUP)
+
+/** A structure which "derives" (in glib speak) from GSource */
+typedef struct CurlGSource_ {
+  GSource source; /* First: The type we're deriving from */
+
+  CURLM* multiHandle;
+
+  /* Previously seen FDs, for comparing with libcurl's current fd_sets */
+  GPollFD lastPollFd[GLIBCURL_FDMAX + 1];
+  int lastPollFdMax; /* Index of highest non-empty entry in lastPollFd */
+
+  int callPerform; /* Non-zero => curl_multi_perform() gets called */
+
+  /* For data returned by curl_multi_fdset */
+  fd_set fdRead;
+  fd_set fdWrite;
+  fd_set fdExc;
+  int fdMax;
+
+} CurlGSource;
+
+/* Global state: Our CurlGSource object */
+static CurlGSource* curlSrc = 0;
+
+/* The "methods" of CurlGSource */
+static gboolean prepare(GSource* source, gint* timeout);
+static gboolean check(GSource* source);
+static gboolean dispatch(GSource* source, GSourceFunc callback,
+                         gpointer user_data);
+static void finalize(GSource* source);
+
+static GSourceFuncs curlFuncs = {
+  &prepare, &check, &dispatch, &finalize, 0, 0
+};
+/*______________________________________________________________________*/
+
+void glibcurl_init() {
+  int fd;
+  /* Create source object for curl file descriptors, and hook it into the
+     default main context. */
+  curlSrc = (CurlGSource*)g_source_new(&curlFuncs, sizeof(CurlGSource));
+  g_source_attach(&curlSrc->source, NULL);
+
+  /* Init rest of our data */
+  memset(&curlSrc->lastPollFd, 0, sizeof(curlSrc->lastPollFd));
+  for (fd = 1; fd <= GLIBCURL_FDMAX; ++fd)
+    curlSrc->lastPollFd[fd].fd = fd;
+  curlSrc->lastPollFdMax = 0;
+  curlSrc->callPerform = 0;
+
+  /* Init libcurl */
+  curl_global_init(CURL_GLOBAL_ALL);
+  curlSrc->multiHandle = curl_multi_init();
+
+  D((stderr, "events: R=%x W=%x X=%x\n", GLIBCURL_READ, GLIBCURL_WRITE,
+     GLIBCURL_EXC));
+}
+/*______________________________________________________________________*/
+
+CURLM* glibcurl_handle() {
+  return curlSrc->multiHandle;
+}
+/*______________________________________________________________________*/
+
+CURLMcode glibcurl_add(CURL *easy_handle) {
+  assert(curlSrc->multiHandle != 0);
+  curlSrc->callPerform = -1;
+  return curl_multi_add_handle(curlSrc->multiHandle, easy_handle);
+}
+/*______________________________________________________________________*/
+
+CURLMcode glibcurl_remove(CURL *easy_handle) {
+  assert(curlSrc != 0);
+  assert(curlSrc->multiHandle != 0);
+  return curl_multi_remove_handle(curlSrc->multiHandle, easy_handle);
+}
+/*______________________________________________________________________*/
+
+/* Call this whenever you have added a request using curl_multi_add_handle().
+   This is necessary to start new requests. It does so by triggering a call
+   to curl_multi_perform() even in the case where no open fds cause that
+   function to be called anyway. */
+void glibcurl_start() {
+  curlSrc->callPerform = -1;
+}
+/*______________________________________________________________________*/
+
+void glibcurl_set_callback(GlibcurlCallback function, void* data) {
+  g_source_set_callback(&curlSrc->source, (GSourceFunc)function, data,
+                        NULL);
+}
+/*______________________________________________________________________*/
+
+void glibcurl_cleanup() {
+  /* You must call curl_multi_remove_handle() and curl_easy_cleanup() for all
+     requests before calling this. */
+/*   assert(curlSrc->callPerform == 0); */
+
+  curl_multi_cleanup(curlSrc->multiHandle);
+  curlSrc->multiHandle = 0;
+  curl_global_cleanup();
+
+/*   g_source_destroy(&curlSrc->source); */
+  g_source_unref(&curlSrc->source);
+  curlSrc = 0;
+}
+/*______________________________________________________________________*/
+
+static void registerUnregisterFds() {
+  int fd, fdMax;
+
+  FD_ZERO(&curlSrc->fdRead);
+  FD_ZERO(&curlSrc->fdWrite);
+  FD_ZERO(&curlSrc->fdExc);
+  curlSrc->fdMax = -1;
+  /* What fds does libcurl want us to poll? */
+  curl_multi_fdset(curlSrc->multiHandle, &curlSrc->fdRead,
+                   &curlSrc->fdWrite, &curlSrc->fdExc, &curlSrc->fdMax);
+  /*fprintf(stderr, "registerUnregisterFds: fdMax=%d\n", curlSrc->fdMax);*/
+  assert(curlSrc->fdMax >= -1 && curlSrc->fdMax <= GLIBCURL_FDMAX);
+
+  fdMax = curlSrc->fdMax;
+  if (fdMax < curlSrc->lastPollFdMax) fdMax = curlSrc->lastPollFdMax;
+
+  /* Has the list of required events for any of the fds changed? */
+  for (fd = 0; fd <= fdMax; ++fd) {
+    gushort events = 0;
+    if (FD_ISSET(fd, &curlSrc->fdRead))  events |= GLIBCURL_READ;
+    if (FD_ISSET(fd, &curlSrc->fdWrite)) events |= GLIBCURL_WRITE;
+    if (FD_ISSET(fd, &curlSrc->fdExc))   events |= GLIBCURL_EXC;
+
+    /* List of events unchanged => no (de)registering */
+    if (events == curlSrc->lastPollFd[fd].events) continue;
+
+    D((stderr, "registerUnregisterFds: fd %d: old events %x, "
+       "new events %x\n", fd, curlSrc->lastPollFd[fd].events, events));
+
+    /* fd is already a lastPollFd, but event type has changed => do nothing.
+       Due to the implementation of g_main_context_query(), the new event
+       flags will be picked up automatically. */
+    if (events != 0 && curlSrc->lastPollFd[fd].events != 0) {
+      curlSrc->lastPollFd[fd].events = events;
+      continue;
+    }
+    curlSrc->lastPollFd[fd].events = events;
+
+    /* Otherwise, (de)register as appropriate */
+    if (events == 0) {
+      g_source_remove_poll(&curlSrc->source, &curlSrc->lastPollFd[fd]);
+      curlSrc->lastPollFd[fd].revents = 0;
+      D((stderr, "unregister fd %d\n", fd));
+    } else {
+      g_source_add_poll(&curlSrc->source, &curlSrc->lastPollFd[fd]);
+      D((stderr, "register fd %d\n", fd));
+    }
+  }
+
+  curlSrc->lastPollFdMax = curlSrc->fdMax;
+}
+
+/* Called before all the file descriptors are polled by the glib main loop.
+   We must have a look at all fds that libcurl wants polled. If any of them
+   are new/no longer needed, we have to (de)register them with glib. */
+gboolean prepare(GSource* source, gint* timeout) {
+  D((stderr, "prepare\n"));
+  assert(source == &curlSrc->source);
+
+  if (curlSrc->multiHandle == 0) return FALSE;
+
+  registerUnregisterFds();
+
+  *timeout = GLIBCURL_TIMEOUT;
+/*   return FALSE; */
+  return curlSrc->callPerform == -1 ? TRUE : FALSE;
+}
+/*______________________________________________________________________*/
+
+/* Called after all the file descriptors are polled by glib.
+   g_main_context_check() has copied back the revents fields (set by glib's
+   poll() call) to our GPollFD objects. How inefficient all that copying
+   is... let's add some more and copy the results of these revents into
+   libcurl's fd_sets! */
+gboolean check(GSource* source) {
+  int fd, somethingHappened = 0;
+
+  if (curlSrc->multiHandle == 0) return FALSE;
+
+  assert(source == &curlSrc->source);
+  FD_ZERO(&curlSrc->fdRead);
+  FD_ZERO(&curlSrc->fdWrite);
+  FD_ZERO(&curlSrc->fdExc);
+  for (fd = 0; fd <= curlSrc->fdMax; ++fd) {
+    gushort revents = curlSrc->lastPollFd[fd].revents;
+    if (revents == 0) continue;
+    somethingHappened = 1;
+/*     D((stderr, "[fd%d] ", fd)); */
+    if (revents & (G_IO_IN | G_IO_PRI))
+      FD_SET((unsigned)fd, &curlSrc->fdRead);
+    if (revents & G_IO_OUT)
+      FD_SET((unsigned)fd, &curlSrc->fdWrite);
+    if (revents & (G_IO_ERR | G_IO_HUP))
+      FD_SET((unsigned)fd, &curlSrc->fdExc);
+  }
+/*   D((stderr, "check: fdMax %d\n", curlSrc->fdMax)); */
+
+/*   return TRUE; */
+/*   return FALSE; */
+  return curlSrc->callPerform == -1 || somethingHappened != 0 ? TRUE : FALSE;
+}
+/*______________________________________________________________________*/
+
+gboolean dispatch(GSource* source, GSourceFunc callback,
+                  gpointer user_data) {
+  CURLMcode x;
+
+  assert(source == &curlSrc->source);
+  assert(curlSrc->multiHandle != 0);
+  do {
+    x = curl_multi_perform(curlSrc->multiHandle, &curlSrc->callPerform);
+/*     D((stderr, "dispatched %d\n", x)); */
+  } while (x == CURLM_CALL_MULTI_PERFORM);
+
+  /* If no more calls to curl_multi_perform(), unregister left-over fds */
+  if (curlSrc->callPerform == 0) registerUnregisterFds();
+
+  if (callback != 0) (*callback)(user_data);
+
+  return TRUE; /* "Do not destroy me" */
+}
+/*______________________________________________________________________*/
+
+void finalize(GSource* source) {
+  assert(source == &curlSrc->source);
+  registerUnregisterFds();
+}
+
+#endif
diff --git a/attic/youhaa/src/glibcurl.h b/attic/youhaa/src/glibcurl.h
new file mode 100644 (file)
index 0000000..fa167e3
--- /dev/null
@@ -0,0 +1,80 @@
+/* $Id: glibcurl.h,v 1.7 2004/12/04 13:58:29 atterer Exp $ -*- C -*-
+  __   _
+  |_) /|  Copyright (C) 2004  |  richard@
+  | \/¯|  Richard Atterer     |  atterer.net
+  ¯ '` ¯
+  All rights reserved.
+
+  Permission to use, copy, modify, and distribute this software for any
+  purpose with or without fee is hereby granted, provided that the above
+  copyright notice and this permission notice appear in all copies.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+  USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+  Except as contained in this notice, the name of a copyright holder shall
+  not be used in advertising or otherwise to promote the sale, use or other
+  dealings in this Software without prior written authorization of the
+  copyright holder.
+
+*/
+
+/** @file
+    Use the libcurl multi interface from GTK+/glib programs without having to
+    resort to multithreading */
+
+#ifndef GLIBCURL_H
+#define GLIBCURL_H
+
+#include <curl/curl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Initialize libcurl. Call this once at the beginning of your program. This
+    function makes calls to curl_global_init() and curl_multi_init() */
+void glibcurl_init();
+
+/** Return global multi handle */
+CURLM* glibcurl_handle();
+
+/** Convenience function, just executes
+    curl_multi_add_handle(glibcurl_handle(), easy_handle); glibcurl_start()*/
+CURLMcode glibcurl_add(CURL* easy_handle);
+
+/** Convenience function, just executes
+    curl_multi_remove_handle(glibcurl_handle(), easy_handle) */
+CURLMcode glibcurl_remove(CURL* easy_handle);
+
+/** Call this whenever you have added a request using
+    curl_multi_add_handle(). This is necessary to start new requests. It does
+    so by triggering a call to curl_multi_perform() even in the case where no
+    open fds cause that function to be called anyway. The call happens
+    "later", i.e. during the next iteration of the glib main loop.
+    glibcurl_start() only sets a flag to make it happen. */
+void glibcurl_start();
+
+/** Callback function for glibcurl_set_callback */
+typedef void (*GlibcurlCallback)(void*);
+/** Set function to call after each invocation of curl_multi_perform(). Pass
+    function==0 to unregister a previously set callback. The callback
+    function will be called with the supplied data pointer as its first
+    argument. */
+void glibcurl_set_callback(GlibcurlCallback function, void* data);
+
+/** You must call glibcurl_remove() and curl_easy_cleanup() for all requests
+    before calling this. This function makes calls to curl_multi_cleanup()
+    and curl_global_cleanup(). */
+void glibcurl_cleanup();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/attic/youhaa/src/yh-main.c b/attic/youhaa/src/yh-main.c
new file mode 100644 (file)
index 0000000..1be0fba
--- /dev/null
@@ -0,0 +1,377 @@
+
+#include <string.h>
+#include <clutter/clutter.h>
+#include <clutter-gst/clutter-gst.h>
+
+#include "yh-theme.h"
+#include "yh-youtube.h"
+#include "yh-youtube-browser.h"
+
+typedef struct {
+  ClutterActor *entry;
+  ClutterActor *button;
+  ClutterActor *throbber;
+  ClutterActor *logo;
+
+  ClutterActor *results;
+  
+  ClutterTimeline *throbber_timeline;
+  ClutterTimeline *transition;
+  
+  ClutterEffectTemplate *template;
+  
+  gboolean query_changed;
+  YHYoutube *youtube;
+} YouhaaData;
+
+static void related_cb (YHYoutubeBrowser *browser, ClutterModelIter *iter,
+                        YouhaaData *data);
+
+static void
+button_in_complete (ClutterActor *actor, YouhaaData *data)
+{
+  data->transition = NULL;
+}
+
+static void
+throbber_out_complete (ClutterActor *actor, YouhaaData *data)
+{
+  clutter_actor_hide (data->throbber);
+  clutter_actor_show (data->button);
+
+  clutter_timeline_stop (data->throbber_timeline);
+
+  data->transition = clutter_effect_rotate (data->template,
+                         data->button,
+                         CLUTTER_Y_AXIS,
+                         0,
+                         clutter_actor_get_width (data->button)/2,
+                         0,
+                         0,
+                         CLUTTER_ROTATE_CCW,
+                         (ClutterEffectCompleteFunc)button_in_complete,
+                         data);
+}
+
+static void
+destroy_out_complete (ClutterActor *actor, YouhaaData *data)
+{
+  clutter_actor_destroy (actor);
+}
+
+static void
+model_cb (YHYoutube *youtube, ClutterModel *model, YouhaaData *data)
+{
+  if (data->results)
+    {
+      /* Fade out old view */
+      clutter_effect_fade (data->template,
+                           data->results,
+                           0x00,
+                           (ClutterEffectCompleteFunc)destroy_out_complete,
+                           data);
+      data->results = NULL;
+    }
+  
+  /* Animate out throbber */
+  if (data->transition)
+    clutter_timeline_stop (data->transition);
+  data->transition = clutter_effect_rotate (data->template,
+                         data->throbber,
+                         CLUTTER_Y_AXIS,
+                         90,
+                         0,
+                         0,
+                         0,
+                         CLUTTER_ROTATE_CW,
+                         (ClutterEffectCompleteFunc)throbber_out_complete,
+                         data);
+  
+  if (model)
+    {
+      /* Create and fade in new view */
+      ClutterActor *view;
+      
+      view = yh_youtube_browser_new (model, data->youtube);
+      data->results = clutter_group_new ();
+      clutter_actor_show (data->results);
+      clutter_actor_show (view);
+      clutter_container_add_actor (CLUTTER_CONTAINER (data->results), view);
+      clutter_container_add_actor (
+        CLUTTER_CONTAINER (clutter_stage_get_default ()),
+        data->results);
+      
+      clutter_actor_set_position (data->results, BORDER, BORDER);
+      clutter_actor_set_size (view,
+                              CLUTTER_STAGE_WIDTH() - (BORDER*2),
+                              clutter_actor_get_y (data->button) - (BORDER*2));
+      
+      clutter_actor_set_opacity (data->results, 0x00);
+      clutter_effect_fade (data->template,
+                           data->results,
+                           0xFF,
+                           NULL,
+                           NULL);
+      
+      /* Connected to related-videos button click */
+      g_signal_connect (view, "related",
+                        G_CALLBACK (related_cb), data);
+    }
+  else
+    {
+      /* TODO: Fade in 'No results' indicator */
+      g_debug ("0 results");
+    }
+}
+
+static void
+throbber_in_complete (ClutterActor *actor, YouhaaData *data)
+{
+  data->transition = NULL;
+}
+
+static void
+button_out_complete (ClutterActor *actor, YouhaaData *data)
+{
+  clutter_actor_hide (data->button);
+  clutter_actor_show (data->throbber);
+
+  clutter_timeline_start (data->throbber_timeline);
+
+  data->transition = clutter_effect_rotate (data->template,
+                         data->throbber,
+                         CLUTTER_Y_AXIS,
+                         0,
+                         0,
+                         0,
+                         0,
+                         CLUTTER_ROTATE_CCW,
+                         (ClutterEffectCompleteFunc)throbber_in_complete,
+                         data);
+}
+
+static void
+animate_search (YouhaaData *data)
+{
+  static gboolean first_time = TRUE;
+  
+  if (first_time)
+    {
+      /* Fade out and destroy logo */
+      clutter_effect_fade (data->template,
+                           data->logo,
+                           0x00,
+                           (ClutterEffectCompleteFunc)destroy_out_complete,
+                           data);
+      first_time = FALSE;
+    }
+  
+  /* Animate the throbber in */
+  if (data->transition)
+    clutter_timeline_stop (data->transition);
+  data->transition = clutter_effect_rotate (data->template,
+                         data->button,
+                         CLUTTER_Y_AXIS,
+                         90,
+                         clutter_actor_get_width (data->button)/2,
+                         0,
+                         0,
+                         CLUTTER_ROTATE_CW,
+                         (ClutterEffectCompleteFunc)button_out_complete,
+                         data);
+}
+
+static gboolean
+button_pressed_cb (ClutterActor *button, ClutterEvent *event, YouhaaData *data)
+{
+  if (data->query_changed)
+    {
+      yh_youtube_query (data->youtube,
+                        clutter_entry_get_text (CLUTTER_ENTRY (data->entry)));
+      animate_search (data);
+    }
+  
+  return TRUE;
+}
+
+static void
+related_cb (YHYoutubeBrowser *browser, ClutterModelIter *iter, YouhaaData *data)
+{
+  gchar *url;
+  
+  clutter_model_iter_get (iter, YH_YOUTUBE_COL_RELATED, &url, -1);
+  if (url)
+    {
+      yh_youtube_query_manual (data->youtube, url);
+      g_free (url);
+      animate_search (data);
+    }
+}
+
+static gboolean
+stage_key_press_event_cb (ClutterActor *actor,
+                          ClutterKeyEvent *event,
+                          YouhaaData *data)
+{
+  data->query_changed = TRUE;
+  clutter_entry_handle_key_event (CLUTTER_ENTRY (data->entry), event);
+
+  return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+  YouhaaData data;
+  ClutterAlpha *alpha;
+  ClutterBehaviour *behaviour;
+  ClutterActor *stage, *button, *box, *label, *box2, *label2;
+  
+  clutter_init (&argc, &argv);
+  clutter_gst_init (&argc, &argv);
+  
+  /* Setup stage */
+  stage = clutter_stage_get_default ();
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  clutter_actor_set_size (stage, 800, 600);
+  
+  /* Initialise data */
+  data.query_changed = FALSE;
+  data.results = NULL;
+  data.transition = NULL;
+  data.youtube = yh_youtube_get_default ();
+  g_signal_connect (data.youtube,
+                    "model",
+                    G_CALLBACK (model_cb),
+                    &data);
+  data.template = clutter_effect_template_new (
+                    clutter_timeline_new_for_duration (250),
+                    CLUTTER_ALPHA_RAMP_INC);
+  
+  /* Create actors */
+  
+  /* Logo */
+  data.logo = clutter_group_new ();
+  box = clutter_rectangle_new_with_color (&white);
+  label = clutter_label_new_full ("Sans 48", "You", &black);
+  box2 = clutter_rectangle_new_with_color (&red);
+  label2 = clutter_label_new_full ("Sans 48", "Tube", &white);
+  clutter_container_add (CLUTTER_CONTAINER (data.logo),
+                         box, label, box2, label2, NULL);
+  clutter_actor_set_size (box,
+                          clutter_actor_get_width (label2) + BORDER,
+                          clutter_actor_get_height (label2) + BORDER/2);
+  clutter_actor_set_size (box2,
+                          clutter_actor_get_width (box),
+                          clutter_actor_get_height (box));
+  clutter_actor_set_y (box2, clutter_actor_get_height (box));
+  clutter_actor_set_anchor_point_from_gravity (label, CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_anchor_point_from_gravity (label2, CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (label,
+                              clutter_actor_get_width (box)/2,
+                              clutter_actor_get_height (box)/2);
+  clutter_actor_set_position (label2,
+                              clutter_actor_get_width (box)/2,
+                              (clutter_actor_get_height (box)*3)/2);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), data.logo);
+  
+  /* Search box + button */
+  box = clutter_rectangle_new_with_color (&entry_color);
+  clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (box), FRAME);
+  clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (box), &frame_color);
+  
+  data.entry = clutter_entry_new_full (font, "", &text_color);
+  
+  data.button = clutter_group_new ();
+  
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage),
+                               box);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage),
+                               data.entry);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), data.button);
+  
+  clutter_actor_set_height (box,
+                            clutter_actor_get_height (data.entry) + (BORDER/2));
+  clutter_actor_set_width (box, CLUTTER_STAGE_WIDTH() - (BORDER*2) -
+                           clutter_actor_get_height (box));
+  clutter_actor_set_position (box, BORDER, CLUTTER_STAGE_HEIGHT() - BORDER -
+                              clutter_actor_get_height (box));
+  
+  clutter_actor_set_width (data.entry,
+                           clutter_actor_get_width (box) - (BORDER/2));
+  clutter_actor_set_position (data.entry, 30, CLUTTER_STAGE_HEIGHT () -
+                              clutter_actor_get_height (data.entry) -
+                              BORDER + FRAME);
+  
+  button = clutter_rectangle_new_with_color (&bg_color);
+  clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (button), FRAME);
+  clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (button), &frame_color);
+  label = clutter_label_new_full (font, "Go!", &entry_color);
+  clutter_actor_set_size (button, clutter_actor_get_height (box),
+                          clutter_actor_get_height (box));
+  clutter_container_add (CLUTTER_CONTAINER (data.button), button, label, NULL);
+  clutter_actor_set_anchor_point_from_gravity (label, CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (label,
+                              clutter_actor_get_width (button)/2,
+                              clutter_actor_get_height (button)/2);
+  
+  clutter_actor_set_position (data.button, CLUTTER_STAGE_WIDTH() - BORDER -
+                              clutter_actor_get_width (data.button),
+                              CLUTTER_STAGE_HEIGHT() - BORDER -
+                              clutter_actor_get_height (data.button));
+  
+  /* Set position of logo */
+  clutter_actor_set_anchor_point_from_gravity (data.logo,
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (data.logo,
+                              CLUTTER_STAGE_WIDTH () / 2,
+                              clutter_actor_get_y (data.button) / 2);
+  
+  /* Throbber */
+  data.throbber = clutter_label_new_full ("Sans 22", "+", &frame_color);
+  clutter_actor_set_position (data.throbber,
+                              clutter_actor_get_x (data.button) +
+                              (clutter_actor_get_width (data.button) -
+                               clutter_actor_get_width (data.throbber))/2,
+                              clutter_actor_get_y (data.button) +
+                              (clutter_actor_get_height (data.button) -
+                               clutter_actor_get_height (data.throbber))/2);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), data.throbber);
+  clutter_actor_move_anchor_point_from_gravity (data.throbber,
+                                                CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_rotation (data.throbber,
+                              CLUTTER_Y_AXIS,
+                              90,
+                              0,
+                              0,
+                              0);
+
+  data.throbber_timeline = clutter_timeline_new_for_duration (500);
+  alpha = clutter_alpha_new_full (data.throbber_timeline,
+                                  CLUTTER_ALPHA_RAMP_INC, NULL, NULL);
+  behaviour = clutter_behaviour_rotate_new (alpha,
+                                            CLUTTER_Z_AXIS,
+                                            CLUTTER_ROTATE_CW,
+                                            0,
+                                            360);
+  clutter_timeline_set_loop (data.throbber_timeline, TRUE);
+  clutter_behaviour_apply (behaviour, data.throbber);
+
+  clutter_actor_show_all (stage);
+  clutter_actor_show_all (data.button);
+  clutter_actor_show_all (data.logo);
+  clutter_actor_hide (data.throbber);
+  
+  clutter_actor_set_reactive (data.button, TRUE);
+  g_signal_connect (data.button, "button-press-event",
+                    G_CALLBACK (button_pressed_cb), &data);
+  
+  /* Hook up key events on stage to entry */
+  g_signal_connect (stage, "key-press-event",
+                    G_CALLBACK (stage_key_press_event_cb), &data);
+  
+  clutter_main ();
+  
+  return 0;
+}
+
diff --git a/attic/youhaa/src/yh-theme.c b/attic/youhaa/src/yh-theme.c
new file mode 100644 (file)
index 0000000..83ad9dc
--- /dev/null
@@ -0,0 +1,14 @@
+
+#include "yh-theme.h"
+
+const ClutterColor stage_color = { 0x10, 0x10, 0x10, 0xff };
+const ClutterColor frame_color = { 0xc0, 0xc0, 0xc0, 0xff };
+const ClutterColor bg_color = { 0x80, 0x80, 0x80, 0xff };
+const ClutterColor entry_color = { 0xff, 0xff, 0xff, 0xff };
+const ClutterColor text_color = { 0x00, 0x00, 0x00, 0xff };
+const ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
+const ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
+const ClutterColor red = { 0xff, 0x00, 0x00, 0xff };
+const gchar *font = "Sans 22";
+const gchar *small_font = "Sans 16";
+
diff --git a/attic/youhaa/src/yh-theme.h b/attic/youhaa/src/yh-theme.h
new file mode 100644 (file)
index 0000000..fdd904b
--- /dev/null
@@ -0,0 +1,24 @@
+
+#ifndef _YH_THEME_H
+#define _YH_THEME_H
+
+#include <clutter/clutter-color.h>
+
+#define BORDER  24
+#define UBORDER CLUTTER_UNITS_FROM_INT(BORDER)
+#define FRAME   6
+#define UFRAME  CLUTTER_UNITS_FROM_INT(FRAME)
+
+extern const ClutterColor stage_color;
+extern const ClutterColor frame_color;
+extern const ClutterColor bg_color;
+extern const ClutterColor entry_color;
+extern const ClutterColor text_color;
+extern const ClutterColor black;
+extern const ClutterColor white;
+extern const ClutterColor red;
+extern const gchar *font;
+extern const gchar *small_font;
+
+#endif
+
diff --git a/attic/youhaa/src/yh-youtube-browser.c b/attic/youhaa/src/yh-youtube-browser.c
new file mode 100644 (file)
index 0000000..5d4bc57
--- /dev/null
@@ -0,0 +1,828 @@
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "yh-youtube-browser.h"
+#include "yh-youtube.h"
+#include "yh-theme.h"
+
+#include <clutter/clutter.h>
+#include <clutter-gst/clutter-gst.h>
+#include <string.h>
+
+enum
+{
+  PROP_0,
+  
+  PROP_MODEL,
+  PROP_YOUTUBE,
+};
+
+struct _YHYoutubeBrowserPrivate {
+  ClutterModel     *model;
+  YHYoutube        *youtube;
+  ClutterModelIter *iter;
+  
+  ClutterActor     *group;
+  
+  ClutterActor     *frame;
+  ClutterActor     *related;
+  ClutterActor     *related_label;
+  ClutterActor     *prev;
+  ClutterActor     *next;
+  ClutterActor     *thumb;
+  ClutterActor     *title;
+  ClutterActor     *author;
+  ClutterActor     *rating;
+  ClutterActor     *description;
+  
+  GList            *thumb_handles;
+  GList            *thumbs;
+  GList            *current_thumb;
+  ClutterTimeline  *timeline_in;
+  ClutterTimeline  *timeline_out;
+  guint             fade_timeout;
+  ClutterEffectTemplate *template;
+  gboolean          loading;
+};
+
+G_DEFINE_TYPE (YHYoutubeBrowser, yh_youtube_browser, CLUTTER_TYPE_ACTOR)
+
+#define YOUTUBE_BROWSER_PRIVATE(obj) \
+        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+        YH_TYPE_YOUTUBE_BROWSER, \
+        YHYoutubeBrowserPrivate))
+
+enum
+{
+  RELATED,
+
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static void
+video_out_complete_cb (ClutterActor *actor, YHYoutubeBrowser *browser)
+{
+  clutter_actor_destroy (actor);
+}
+
+static gboolean
+true_function ()
+{
+  return TRUE;
+}
+
+static gboolean
+video_bg_button_press_cb (ClutterActor       *actor,
+                          ClutterButtonEvent *event,
+                          YHYoutubeBrowser   *browser)
+{
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+
+  clutter_effect_fade (priv->template,
+                       actor,
+                       0x00,
+                       (ClutterEffectCompleteFunc)video_out_complete_cb,
+                       browser);
+  
+  /* Disconnect handler and just block events until we're faded out */
+  g_signal_handlers_disconnect_by_func (actor,
+                                        video_bg_button_press_cb,
+                                        browser);
+  g_signal_connect (actor, "button-press-event",
+                    G_CALLBACK (true_function), NULL);
+  
+  return TRUE;
+}
+
+static void
+video_in_complete_cb (ClutterActor *actor, YHYoutubeBrowser *browser)
+{
+  g_signal_handlers_disconnect_by_func (actor,
+                                        true_function,
+                                        browser);
+  g_signal_connect (actor, "button-press-event",
+                    G_CALLBACK (video_bg_button_press_cb), browser);
+}
+
+static void
+video_error_cb (ClutterMedia *media, GError *error)
+{
+  g_warning ("Error from video: %s", error->message);
+}
+
+static void
+video_buffer_notify_cb (ClutterMedia *media,
+                        GParamSpec *pspec,
+                        YHYoutubeBrowser *browser)
+{
+  if ((clutter_media_get_buffer_percent (media) == 100) &&
+      (!clutter_media_get_playing (media)))
+    clutter_media_set_playing (media, TRUE);
+}
+
+static void
+link_cb (YHYoutube *youtube, const gchar *url, YHYoutubeBrowser *browser)
+{
+  ClutterUnit width, height;
+  ClutterActor *group, *rect, *player, *player_bg;
+  
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+
+  priv->loading = FALSE;
+  
+  clutter_actor_get_sizeu (priv->frame, &width, &height);
+  
+  group = clutter_group_new ();
+  
+  rect = clutter_rectangle_new_with_color (&stage_color);
+  clutter_actor_set_opacity (rect, 128);
+  clutter_actor_set_size (rect, CLUTTER_STAGE_WIDTH(), CLUTTER_STAGE_HEIGHT());
+  
+  player_bg = clutter_rectangle_new_with_color (&frame_color);
+  clutter_actor_set_sizeu (player_bg,
+                           (width*4)/5 + UFRAME,
+                           (height*4)/5 + UFRAME);
+  
+  player = clutter_gst_video_texture_new ();
+  g_signal_connect (player, "error", G_CALLBACK (video_error_cb), browser);
+  g_signal_connect (player, "notify::buffer-percent",
+                    G_CALLBACK (video_buffer_notify_cb), browser);
+
+  g_object_set (G_OBJECT (player),
+                "sync-size", FALSE,
+                "uri", url,
+                "playing", FALSE,
+                NULL);
+  
+  clutter_actor_set_sizeu (player,
+                           (width*4)/5,
+                           (height*4)/5);
+  
+  clutter_container_add (CLUTTER_CONTAINER (group),
+                         rect, player_bg, player, NULL);
+  clutter_actor_show_all (group);
+  
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->group), group);
+  clutter_actor_set_position (group, 0, 0);
+  
+  clutter_actor_set_anchor_point_from_gravity (player,
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_anchor_point_from_gravity (player_bg,
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_positionu (player, width/2, height/2);
+  clutter_actor_set_positionu (player_bg, width/2, height/2);
+  
+  clutter_actor_set_opacity (group, 0x00);
+  clutter_effect_fade (priv->template,
+                       group,
+                       0xFF,
+                       (ClutterEffectCompleteFunc)video_in_complete_cb,
+                       browser);
+  clutter_actor_set_reactive (group, TRUE);
+  g_signal_connect (group, "button-press-event",
+                    G_CALLBACK (true_function), browser);
+}
+
+static gboolean
+thumb_button_press_cb (ClutterActor       *actor,
+                       ClutterButtonEvent *event,
+                       YHYoutubeBrowser   *browser)
+{
+  gchar **uris;
+  
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+
+  if (priv->loading)
+    return TRUE;
+
+  clutter_model_iter_get (priv->iter, YH_YOUTUBE_COL_URIS, &uris, -1);
+  
+  if (!uris)
+    return TRUE;
+  
+  if (!uris[0])
+    {
+      g_strfreev (uris);
+      return TRUE;
+    }
+
+  /* We assume the http link comes first
+   * (which it does, but should probably check)
+   */
+  yh_youtube_get_http_link (priv->youtube, uris[0]);
+  
+  g_strfreev (uris);
+  priv->loading = TRUE;
+  
+  return TRUE;
+}
+
+static void
+in_complete_cb (ClutterActor *actor, YHYoutubeBrowser *browser)
+{
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+  
+  priv->timeline_in = NULL;
+}
+
+static void
+out_complete_cb (ClutterActor *actor, YHYoutubeBrowser *browser)
+{
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+  
+  priv->timeline_out = NULL;
+}
+
+static gboolean
+crossfade_timeout (YHYoutubeBrowser *browser)
+{
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+  
+  if (!priv->current_thumb)
+    return FALSE;
+  
+  if (priv->current_thumb->next ||
+      (priv->current_thumb != priv->thumbs))
+    {
+      ClutterActor *in, *out;
+      
+      out = CLUTTER_ACTOR (priv->current_thumb->data);
+      
+      priv->current_thumb = priv->current_thumb->next ?
+        priv->current_thumb->next : priv->thumbs;
+      
+      in = CLUTTER_ACTOR (priv->current_thumb->data);
+      
+      /* Cross-fade effect */
+      priv->timeline_out = clutter_effect_fade (priv->template,
+                                                out,
+                                                0x00,
+                                                (ClutterEffectCompleteFunc)
+                                                 out_complete_cb,
+                                                browser);
+      priv->timeline_in = clutter_effect_fade (priv->template,
+                                               in,
+                                               0xFF,
+                                               (ClutterEffectCompleteFunc)
+                                                in_complete_cb,
+                                               browser);
+    }
+  
+  return TRUE;
+}
+
+static void
+complete_cb (YHYoutube *youtube, void *handle, YHYoutubeBrowser *browser)
+{
+  GList *l;
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+  
+  if ((l = g_list_find (priv->thumb_handles, handle)))
+    priv->thumb_handles = g_list_delete_link (priv->thumb_handles, l);
+}
+
+static void
+thumbnail_cb (YHYoutube *youtube, GdkPixbuf *pixbuf, YHYoutubeBrowser *browser)
+{
+  ClutterActor *thumb;
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+  
+  if (!pixbuf)
+    return;
+  
+  thumb = clutter_texture_new_from_pixbuf (pixbuf);
+  if (!thumb)
+    return;
+  
+  priv->thumbs = g_list_append (priv->thumbs, thumb);
+  
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->group), thumb);
+  clutter_actor_set_positionu (thumb,
+                               clutter_actor_get_xu (priv->prev),
+                               UBORDER/2);
+  clutter_actor_set_sizeu (thumb,
+                           clutter_actor_get_widthu (priv->frame)/2 -
+                           (UBORDER*3)/2,
+                           (clutter_actor_get_heightu (priv->frame)*3)/4 -
+                           UBORDER);
+  clutter_actor_show (thumb);
+  clutter_actor_set_opacity (thumb, 0x00);
+  
+  clutter_actor_set_reactive (thumb, TRUE);
+  g_signal_connect (thumb, "button-press-event",
+                    G_CALLBACK (thumb_button_press_cb), browser);
+
+  if (!priv->current_thumb)
+    {
+      /* Fade in */
+      priv->current_thumb = priv->thumbs;
+      priv->timeline_in = clutter_effect_fade (priv->template,
+                                               thumb,
+                                               0xFF,
+                                               (ClutterEffectCompleteFunc)
+                                                in_complete_cb,
+                                               browser);
+      priv->fade_timeout = g_timeout_add_seconds (5,
+                                                  (GSourceFunc)crossfade_timeout,
+                                                  browser);
+    }
+}
+
+static void
+free_thumbs (YHYoutubeBrowser *self)
+{
+  YHYoutubeBrowserPrivate *priv = self->priv;
+  
+  if (priv->fade_timeout)
+    {
+      g_source_remove (priv->fade_timeout);
+      priv->fade_timeout = 0;
+    }
+  
+  if (priv->timeline_in)
+    {
+      clutter_timeline_pause (priv->timeline_in);
+      g_object_unref (priv->timeline_in);
+      priv->timeline_in = NULL;
+    }
+
+  if (priv->timeline_out)
+    {
+      clutter_timeline_pause (priv->timeline_out);
+      g_object_unref (priv->timeline_out);
+      priv->timeline_out = NULL;
+    }
+  
+  while (priv->thumb_handles)
+    {
+      yh_youtube_cancel (priv->youtube, priv->thumb_handles->data);
+      priv->thumb_handles = g_list_delete_link (priv->thumb_handles,
+                                                priv->thumb_handles);
+    }
+
+  while (priv->thumbs)
+    {
+      clutter_actor_destroy (CLUTTER_ACTOR (priv->thumbs->data));
+      priv->thumbs = g_list_delete_link (priv->thumbs, priv->thumbs);
+    }
+  
+  priv->current_thumb = NULL;
+}
+
+static void
+fill_details (YHYoutubeBrowser *self)
+{
+  gchar *title, *author, *description, **thumbs;
+  ClutterModelIter *next_iter;
+  gdouble rating;
+  guint row;
+  
+  YHYoutubeBrowserPrivate *priv = self->priv;
+  
+  free_thumbs (self);
+  if (!priv->iter)
+    return;
+  
+  clutter_model_iter_get (priv->iter,
+                          YH_YOUTUBE_COL_TITLE, &title,
+                          YH_YOUTUBE_COL_AUTHOR, &author,
+                          YH_YOUTUBE_COL_DESCRIPTION, &description,
+                          YH_YOUTUBE_COL_RATING, &rating,
+                          YH_YOUTUBE_COL_THUMBS, &thumbs,
+                          -1);
+  
+  clutter_label_set_text (CLUTTER_LABEL (priv->title), title);
+  clutter_label_set_text (CLUTTER_LABEL (priv->author), author);
+  clutter_label_set_text (CLUTTER_LABEL (priv->description), description);
+  
+  switch ((gint)(rating + 0.5))
+    {
+    case 1 :
+      clutter_label_set_text (CLUTTER_LABEL (priv->rating), "★••••");
+      break;
+    case 2 :
+      clutter_label_set_text (CLUTTER_LABEL (priv->rating), "★★•••");
+      break;
+    case 3 :
+      clutter_label_set_text (CLUTTER_LABEL (priv->rating), "★★★••");
+      break;
+    case 4 :
+      clutter_label_set_text (CLUTTER_LABEL (priv->rating), "★★★★•");
+      break;
+    case 5 :
+      clutter_label_set_text (CLUTTER_LABEL (priv->rating), "★★★★★");
+      break;
+    default :
+      clutter_label_set_text (CLUTTER_LABEL (priv->rating), "No rating");
+    }
+  
+  if (clutter_model_iter_is_first (priv->iter))
+    {
+      clutter_actor_set_opacity (priv->prev, 128);
+      clutter_actor_set_reactive (priv->prev, FALSE);
+    }
+  else
+    {
+      clutter_actor_set_opacity (priv->prev, 255);
+      clutter_actor_set_reactive (priv->prev, TRUE);
+    }
+
+  row = clutter_model_iter_get_row (priv->iter);
+  next_iter = clutter_model_get_iter_at_row (priv->model, row + 1);
+  if (!next_iter)
+    {
+      clutter_actor_set_opacity (priv->next, 128);
+      clutter_actor_set_reactive (priv->next, FALSE);
+    }
+  else
+    {
+      clutter_actor_set_opacity (priv->next, 255);
+      clutter_actor_set_reactive (priv->next, TRUE);
+      g_object_unref (next_iter);
+    }
+  
+  if (thumbs)
+    {
+      gint i;
+      for (i = 0; thumbs[i]; i++)
+        {
+          priv->thumb_handles = g_list_append (priv->thumb_handles,
+                                        yh_youtube_get_thumb (priv->youtube,
+                                                              thumbs[i]));
+        }
+      g_strfreev (thumbs);
+    }
+}
+
+static void
+yh_youtube_browser_get_property (GObject *object, guint property_id,
+                                 GValue *value, GParamSpec *pspec)
+{
+  YHYoutubeBrowser *self = YH_YOUTUBE_BROWSER (object);
+  
+  switch (property_id)
+    {
+    case PROP_MODEL :
+      g_value_set_object (value, self->priv->model);
+      break;
+    
+    case PROP_YOUTUBE :
+      g_value_set_object (value, self->priv->youtube);
+      break;
+    
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+yh_youtube_browser_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+  YHYoutubeBrowser *self = YH_YOUTUBE_BROWSER (object);
+  
+  switch (property_id)
+    {
+    case PROP_MODEL :
+      self->priv->model = CLUTTER_MODEL (g_value_dup_object (value));
+      self->priv->iter = clutter_model_get_first_iter (self->priv->model);
+      if (self->priv->youtube)
+        fill_details (self);
+      break;
+    
+    case PROP_YOUTUBE :
+      self->priv->youtube = YH_YOUTUBE (g_value_dup_object (value));
+      g_signal_connect (self->priv->youtube, "complete",
+                        G_CALLBACK (complete_cb), self);
+      g_signal_connect (self->priv->youtube, "thumbnail",
+                        G_CALLBACK (thumbnail_cb), self);
+      g_signal_connect (self->priv->youtube, "link",
+                        G_CALLBACK (link_cb), self);
+      if (self->priv->model)
+        fill_details (self);
+      break;
+    
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+yh_youtube_browser_dispose (GObject *object)
+{
+  YHYoutubeBrowser *browser = YH_YOUTUBE_BROWSER (object);
+  YHYoutubeBrowserPrivate *priv = browser->priv;
+  
+  free_thumbs (browser);
+  
+  if (priv->iter)
+    {
+      g_object_unref (priv->iter);
+      priv->iter = NULL;
+    }
+  
+  if (priv->model)
+    {
+      g_object_unref (priv->model);
+      priv->model = NULL;
+    }
+  
+  if (priv->template)
+    {
+      g_object_unref (priv->template);
+      priv->template = NULL;
+    }
+  
+  if (priv->group)
+    {
+      clutter_actor_unparent (priv->group);
+      priv->group = NULL;
+    }
+  
+  if (priv->youtube)
+    {
+      g_signal_handlers_disconnect_by_func (priv->youtube,
+                                            complete_cb,
+                                            browser);
+      g_signal_handlers_disconnect_by_func (priv->youtube,
+                                            thumbnail_cb,
+                                            browser);
+      g_signal_handlers_disconnect_by_func (priv->youtube,
+                                            link_cb,
+                                            browser);
+      g_object_unref (priv->youtube);
+      priv->youtube = NULL;
+    }
+  
+  if (G_OBJECT_CLASS (yh_youtube_browser_parent_class)->dispose)
+    G_OBJECT_CLASS (yh_youtube_browser_parent_class)->dispose (object);
+}
+
+static void
+yh_youtube_browser_paint (ClutterActor *actor)
+{
+  YHYoutubeBrowserPrivate *priv = YH_YOUTUBE_BROWSER (actor)->priv;
+  
+  clutter_actor_paint (priv->group);
+}
+
+static void
+yh_youtube_browser_pick (ClutterActor *actor, const ClutterColor *color)
+{
+  yh_youtube_browser_paint (actor);
+}
+
+static void
+yh_youtube_browser_request_coords (ClutterActor *actor, ClutterActorBox *box)
+{
+  ClutterUnit width, height;
+  
+  YHYoutubeBrowserPrivate *priv = YH_YOUTUBE_BROWSER (actor)->priv;
+  
+  width = box->x2 - box->x1;
+  height = box->y2 - box->y1;
+  
+  clutter_actor_set_sizeu (priv->frame, width, height);
+  
+  clutter_actor_set_widthu (priv->title, width/2 - (UBORDER*3)/2);
+  clutter_actor_set_widthu (priv->author, width/2 - (UBORDER*3)/2);
+  clutter_actor_set_widthu (priv->rating, width/2 - (UBORDER*3)/2);
+  clutter_actor_set_widthu (priv->description,
+                           width/2 - (UBORDER*3)/2);
+  clutter_actor_set_clipu (priv->description, 0, 0,
+                           clutter_actor_get_widthu (priv->description),
+                           height - clutter_actor_get_yu (priv->description) -
+                           UBORDER/2);
+  
+  clutter_actor_set_positionu (priv->related,
+                               width/2 + UBORDER/2,
+                               (height*3)/4 - UBORDER/2);
+  clutter_actor_set_sizeu (priv->related, width/2 - (UBORDER*3)/2,
+                           height/10);
+  clutter_actor_set_anchor_point_from_gravity (priv->related_label,
+                                               CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_positionu (priv->related_label,
+                               clutter_actor_get_xu (priv->related) +
+                               clutter_actor_get_widthu (priv->related)/2,
+                               clutter_actor_get_yu (priv->related) +
+                               clutter_actor_get_heightu (priv->related)/2);
+  
+  clutter_actor_set_positionu (priv->prev,
+                               width/2 + UBORDER/2,
+                               (height*3)/4 +
+                               clutter_actor_get_heightu (priv->related));
+  clutter_actor_set_sizeu (priv->prev, width/4 - UBORDER, height/4 - UBORDER/2 -
+                           clutter_actor_get_heightu (priv->related));
+
+  clutter_actor_set_positionu (priv->next,
+                       clutter_actor_get_xu (priv->prev) +
+                       clutter_actor_get_widthu (priv->prev) + UBORDER/2,
+                       (height*3)/4 +
+                       clutter_actor_get_heightu (priv->related));
+  clutter_actor_set_sizeu (priv->next, width/4 - UBORDER, height/4 - UBORDER/2 -
+                           clutter_actor_get_heightu (priv->related));
+
+  CLUTTER_ACTOR_CLASS (yh_youtube_browser_parent_class)->
+    request_coords (actor, box);
+}
+
+static void
+yh_youtube_browser_class_init (YHYoutubeBrowserClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (YHYoutubeBrowserPrivate));
+
+  object_class->get_property = yh_youtube_browser_get_property;
+  object_class->set_property = yh_youtube_browser_set_property;
+  object_class->dispose = yh_youtube_browser_dispose;
+  
+  actor_class->paint = yh_youtube_browser_paint;
+  actor_class->pick = yh_youtube_browser_pick;
+  actor_class->request_coords = yh_youtube_browser_request_coords;
+
+  g_object_class_install_property (object_class,
+                                   PROP_MODEL,
+                                   g_param_spec_object ("model",
+                                                        "Model",
+                                                        "ClutterModel",
+                                                        CLUTTER_TYPE_MODEL,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_YOUTUBE,
+                                   g_param_spec_object ("youtube",
+                                                        "YHYoutube",
+                                                        "Youtube data provider",
+                                                        YH_TYPE_YOUTUBE,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+
+  signals[RELATED] =
+    g_signal_new ("related",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (YHYoutubeBrowserClass, related),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, CLUTTER_TYPE_MODEL_ITER);
+}
+
+static gboolean
+prev_pressed_cb (ClutterActor     *actor,
+                 ClutterEvent     *event,
+                 YHYoutubeBrowser *self)
+{
+  self->priv->iter = clutter_model_iter_prev (self->priv->iter);
+  fill_details (self);
+  return TRUE;
+}
+
+static gboolean
+next_pressed_cb (ClutterActor     *actor,
+                 ClutterEvent     *event,
+                 YHYoutubeBrowser *self)
+{
+  self->priv->iter = clutter_model_iter_next (self->priv->iter);
+  fill_details (self);
+  return TRUE;
+}
+
+static gboolean
+related_pressed_cb (ClutterActor     *actor,
+                    ClutterEvent     *event,
+                    YHYoutubeBrowser *self)
+{
+  g_signal_emit (self, signals[RELATED], 0, self->priv->iter);
+  return TRUE;
+}
+
+static void
+yh_youtube_browser_init (YHYoutubeBrowser *self)
+{
+  GdkPixbuf *pixbuf;
+  
+  GError *error = NULL;
+  YHYoutubeBrowserPrivate *priv = self->priv = YOUTUBE_BROWSER_PRIVATE (self);
+  
+  priv->group = clutter_group_new ();
+  clutter_actor_set_parent (priv->group, CLUTTER_ACTOR (self));
+  
+  /* Frame */
+  priv->frame = clutter_rectangle_new_with_color (&entry_color);
+  clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (priv->frame), 6);
+  clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (priv->frame),
+                                      &frame_color);
+  
+  /* Related videos button */
+  priv->related = clutter_rectangle_new_with_color (&bg_color);
+  clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (priv->related), FRAME);
+  clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (priv->related),
+                                      &frame_color);
+  priv->related_label = clutter_label_new_full (font, "Related videos",
+                                                &entry_color);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->related), TRUE);
+  g_signal_connect (priv->related, "button-press-event",
+                    G_CALLBACK (related_pressed_cb), self);
+  
+  /* Previous arrow */
+  pixbuf = gdk_pixbuf_new_from_file_at_size (PKGDATADIR "/go-previous.svg",
+                                             CLUTTER_STAGE_WIDTH () / 5,
+                                             CLUTTER_STAGE_HEIGHT () / 4,
+                                             &error);
+  if (!pixbuf)
+    {
+      g_warning ("Error loading pixbuf: %s", error->message);
+      g_error_free (error);
+      error = NULL;
+    }
+  
+  priv->prev = clutter_texture_new_from_pixbuf (pixbuf);
+  g_signal_connect (priv->prev, "button-press-event",
+                    G_CALLBACK (prev_pressed_cb), self);
+  
+  /* Next arrow */
+  pixbuf = gdk_pixbuf_new_from_file_at_size (PKGDATADIR "/go-next.svg",
+                                             CLUTTER_STAGE_WIDTH () / 5,
+                                             CLUTTER_STAGE_HEIGHT () / 4,
+                                             &error);
+  if (!pixbuf)
+    {
+      g_warning ("Error loading pixbuf: %s", error->message);
+      g_error_free (error);
+    }
+  
+  priv->next = clutter_texture_new_from_pixbuf (pixbuf);
+  g_signal_connect (priv->next, "button-press-event",
+                    G_CALLBACK (next_pressed_cb), self);
+  
+  /* Title */
+  priv->title = clutter_label_new_full (font, "", &text_color);
+  clutter_label_set_ellipsize (CLUTTER_LABEL (priv->title),
+                               PANGO_ELLIPSIZE_END);
+  
+  /* Author */
+  priv->author = clutter_label_new_full (small_font, "", &text_color);
+  clutter_label_set_ellipsize (CLUTTER_LABEL (priv->author),
+                               PANGO_ELLIPSIZE_END);
+
+  /* Rating */
+  priv->rating = clutter_label_new_full (small_font, "", &text_color);
+  clutter_label_set_ellipsize (CLUTTER_LABEL (priv->rating),
+                               PANGO_ELLIPSIZE_END);
+
+  /* Description */
+  priv->description = clutter_label_new_full (small_font, "", &text_color);
+  clutter_label_set_line_wrap (CLUTTER_LABEL (priv->description), TRUE);
+  
+  /* Add widgets to group, they'll be sized (mostly) by request-coords */
+  clutter_container_add (CLUTTER_CONTAINER (priv->group),
+                         priv->frame,
+                         priv->related,
+                         priv->related_label,
+                         priv->prev,
+                         priv->next,
+                         priv->title,
+                         priv->author,
+                         priv->rating,
+                         priv->description,
+                         NULL);
+  clutter_actor_set_position (priv->title, BORDER, BORDER/2);
+  clutter_actor_set_position (priv->author,
+                              BORDER,
+                              clutter_actor_get_y (priv->title) +
+                              clutter_actor_get_height (priv->title) +
+                              BORDER/2);
+  clutter_actor_set_position (priv->rating,
+                              BORDER,
+                              clutter_actor_get_y (priv->author) +
+                              clutter_actor_get_height (priv->author) +
+                              BORDER/2);
+  clutter_actor_set_position (priv->description,
+                              BORDER,
+                              clutter_actor_get_y (priv->rating) +
+                              clutter_actor_get_height (priv->rating) +
+                              BORDER/2);
+  
+  clutter_actor_show_all (priv->group);
+  
+  /* Create template for cycling preview image cross-fades */
+  priv->template = clutter_effect_template_new (
+                   clutter_timeline_new_for_duration (750),
+                   CLUTTER_ALPHA_RAMP_INC);
+}
+
+ClutterActor *
+yh_youtube_browser_new (ClutterModel *model, YHYoutube *youtube)
+{
+  return CLUTTER_ACTOR (g_object_new (YH_TYPE_YOUTUBE_BROWSER,
+                                      "model", model,
+                                      "youtube", youtube, NULL));
+}
+
diff --git a/attic/youhaa/src/yh-youtube-browser.h b/attic/youhaa/src/yh-youtube-browser.h
new file mode 100644 (file)
index 0000000..87b88a3
--- /dev/null
@@ -0,0 +1,58 @@
+
+#ifndef _YH_YOUTUBE_BROWSER_H
+#define _YH_YOUTUBE_BROWSER_H
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+#include "yh-youtube.h"
+
+G_BEGIN_DECLS
+
+#define YH_TYPE_YOUTUBE_BROWSER yh_youtube_browser_get_type()
+
+#define YH_YOUTUBE_BROWSER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  YH_TYPE_YOUTUBE_BROWSER, YHYoutubeBrowser))
+
+#define YH_YOUTUBE_BROWSER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  YH_TYPE_YOUTUBE_BROWSER, YHYoutubeBrowserClass))
+
+#define YH_IS_YOUTUBE_BROWSER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  YH_TYPE_YOUTUBE_BROWSER))
+
+#define YH_IS_YOUTUBE_BROWSER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  YH_TYPE_YOUTUBE_BROWSER))
+
+#define YH_YOUTUBE_BROWSER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  YH_TYPE_YOUTUBE_BROWSER, YHYoutubeBrowserClass))
+
+typedef struct _YHYoutubeBrowser         YHYoutubeBrowser;
+typedef struct _YHYoutubeBrowserClass    YHYoutubeBrowserClass;
+typedef struct _YHYoutubeBrowserPrivate  YHYoutubeBrowserPrivate;
+
+struct _YHYoutubeBrowser {
+  ClutterActor             parent;
+  
+  YHYoutubeBrowserPrivate *priv;
+};
+
+struct _YHYoutubeBrowserClass {
+  ClutterActorClass parent_class;
+
+  /* Signals */
+  void (* related)  (YHYoutubeBrowser *browser, ClutterModelIter *iter);
+};
+
+GType yh_youtube_browser_get_type (void);
+
+ClutterActor *
+yh_youtube_browser_new (ClutterModel *model, YHYoutube *youtube);
+
+G_END_DECLS
+
+#endif /* _YH_YOUTUBE_BROWSER_H */
+
diff --git a/attic/youhaa/src/yh-youtube.c b/attic/youhaa/src/yh-youtube.c
new file mode 100644 (file)
index 0000000..d68d870
--- /dev/null
@@ -0,0 +1,826 @@
+
+#include "yh-youtube.h"
+
+#include <regex.h>
+#include <stdlib.h>
+#include <string.h>
+#include <clutter/clutter.h>
+#include "glibcurl.h"
+
+typedef enum {
+  TYPE_QUERY,
+  TYPE_THUMB,
+  TYPE_LINK,
+} YHYoutubeRequestType;
+
+typedef struct {
+  gchar *url;
+  gchar *data;
+  gint size;
+  YHYoutubeRequestType type;
+} YHYoutubeRequest;
+
+enum
+{
+  COMPLETE,
+  MODEL,
+  THUMBNAIL,
+  LINK,
+
+  LAST_SIGNAL
+};
+
+#define YOUTUBE_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), YH_TYPE_YOUTUBE, YHYoutubePrivate))
+
+struct _YHYoutubePrivate {
+  JsonParser *parser;
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (YHYoutube, yh_youtube, G_TYPE_OBJECT)
+
+static void yh_youtube_curl_close (void *userp);
+static void yh_youtube_get_http_link_cb (YHYoutubeRequest *request,
+                                         CURL *handle);
+
+static void
+yh_youtube_get_property (GObject *object, guint property_id,
+                         GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+yh_youtube_set_property (GObject *object, guint property_id,
+                         const GValue *value, GParamSpec *pspec)
+{
+  switch (property_id) {
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+yh_youtube_dispose (GObject *object)
+{
+  YHYoutubePrivate *priv = YOUTUBE_PRIVATE (object);
+  
+  if (priv->parser)
+    {
+      g_object_unref (priv->parser);
+      priv->parser = NULL;
+    }
+  
+  if (G_OBJECT_CLASS (yh_youtube_parent_class)->dispose)
+    G_OBJECT_CLASS (yh_youtube_parent_class)->dispose (object);
+}
+
+static void
+yh_youtube_finalize (GObject *object)
+
+{
+  G_OBJECT_CLASS (yh_youtube_parent_class)->finalize (object);
+}
+
+static void
+yh_youtube_class_init (YHYoutubeClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (YHYoutubePrivate));
+
+  object_class->get_property = yh_youtube_get_property;
+  object_class->set_property = yh_youtube_set_property;
+  object_class->dispose = yh_youtube_dispose;
+  object_class->finalize = yh_youtube_finalize;
+
+  signals[COMPLETE] =
+    g_signal_new ("complete",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (YHYoutubeClass, complete),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+  signals[MODEL] =
+    g_signal_new ("model",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (YHYoutubeClass, model),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+  signals[THUMBNAIL] =
+    g_signal_new ("thumbnail",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (YHYoutubeClass, thumbnail),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+  signals[LINK] =
+    g_signal_new ("link",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (YHYoutubeClass, link),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+static void
+yh_youtube_init (YHYoutube *self)
+{
+  static gboolean first_call = TRUE;
+  
+  YHYoutubePrivate *priv = self->priv = YOUTUBE_PRIVATE (self);
+  
+  if (first_call)
+    {
+           glibcurl_init ();
+           glibcurl_set_callback (yh_youtube_curl_close, self);
+           
+           first_call = FALSE;
+    }
+  else
+    {
+      g_warning ("This class is a singleton, it can only be created once");
+      return;
+    }
+  
+  priv->parser = json_parser_new ();
+           
+}
+
+static ClutterModel *
+yh_youtube_create_model (YHYoutube *youtube)
+{
+  gint i;
+  JsonNode *node;
+  JsonArray *array;
+  JsonObject *object;
+  ClutterModel *model;
+  
+  if (!(node = json_parser_get_root (youtube->priv->parser)))
+    {
+      g_warning ("Error retrieving root node");
+      return NULL;
+    }
+  
+  if (!(object = json_node_get_object (node)))
+    {
+      g_warning ("Error retrieving object from root node");
+      return NULL;
+    }
+  
+  if (!(node = json_object_get_member (object, "feed")))
+    {
+      g_warning ("Error retrieving 'feed' member");
+      return NULL;
+    }
+  
+  if (!(object = json_node_get_object (node)))
+    {
+      g_warning ("Error retreiving 'feed' as an object");
+      return NULL;
+    }
+  
+  if (!(node = json_object_get_member (object, "entry")))
+    {
+      /* No error message, no entry means zero results */
+      return NULL;
+    }
+  
+  if (!(array = json_node_get_array (node)))
+    {
+      g_warning ("Error retrieving 'entry' as an array");
+      return NULL;
+    }
+
+  model = clutter_list_model_new (YH_YOUTUBE_COL_LAST,
+                                  G_TYPE_STRING, "Title",
+                                  G_TYPE_STRING, "Author",
+                                  G_TYPE_STRING, "Description",
+                                  G_TYPE_DOUBLE, "Rating",
+                                  G_TYPE_STRV, "Thumbnails",
+                                  G_TYPE_STRV, "MIME types",
+                                  G_TYPE_STRV, "URIs",
+                                  G_TYPE_STRING, "Related videos");
+  
+  for (i = 0; i < json_array_get_length (array); i++)
+    {
+      ClutterModelIter *iter;
+      JsonNode *prop_node;
+      JsonArray *prop_array;
+      JsonObject *prop_object;
+      
+      if (!(node = json_array_get_element (array, i)))
+        continue;
+      
+      if (!(object = json_node_get_object (node)))
+        continue;
+
+      clutter_model_insert (model, -1,
+                            YH_YOUTUBE_COL_TITLE, NULL,
+                            YH_YOUTUBE_COL_AUTHOR, NULL,
+                            YH_YOUTUBE_COL_DESCRIPTION, NULL,
+                            YH_YOUTUBE_COL_RATING, 0.0,
+                            YH_YOUTUBE_COL_THUMBS, NULL,
+                            YH_YOUTUBE_COL_MIMES, NULL,
+                            YH_YOUTUBE_COL_URIS, NULL,
+                            YH_YOUTUBE_COL_RELATED, NULL,
+                            -1);
+      iter = clutter_model_get_last_iter (model);
+      
+      /* The 'JSON' that GData returns is really horrible :( */
+      
+      /* Title */
+      if ((prop_node = json_object_get_member (object, "title")))
+        if ((prop_object = json_node_get_object (prop_node)))
+          if ((prop_node = json_object_get_member (prop_object, "$t")))
+            clutter_model_iter_set (iter,
+                                    YH_YOUTUBE_COL_TITLE,
+                                    json_node_get_string (prop_node),
+                                    -1);
+      
+      /* Author */
+      if ((prop_node = json_object_get_member (object, "author")))
+        if ((prop_array = json_node_get_array (prop_node)))
+          if ((prop_node = json_array_get_element (prop_array, 0)))
+            if ((prop_object = json_node_get_object (prop_node)))
+              if ((prop_node = json_object_get_member (prop_object, "name")))
+                if ((prop_object = json_node_get_object (prop_node)))
+                  if ((prop_node = json_object_get_member (prop_object, "$t")))
+                    clutter_model_iter_set (iter,
+                                            YH_YOUTUBE_COL_AUTHOR,
+                                            json_node_get_string (prop_node),
+                                            -1);
+      
+      /* Description */
+      if ((prop_node = json_object_get_member (object, "content")))
+        if ((prop_object = json_node_get_object (prop_node)))
+          if ((prop_node = json_object_get_member (prop_object, "$t")))
+            clutter_model_iter_set (iter,
+                                    YH_YOUTUBE_COL_DESCRIPTION,
+                                    json_node_get_string (prop_node),
+                                    -1);
+      
+      /* Rating */
+      if ((prop_node = json_object_get_member (object, "gd$rating")))
+        if ((prop_object = json_node_get_object (prop_node)))
+          if ((prop_node = json_object_get_member (prop_object, "average")))
+            {
+              /* FIXME: This is probably insecure? */
+              gdouble rating = atof (json_node_get_string (prop_node));
+              clutter_model_iter_set (iter,
+                                      YH_YOUTUBE_COL_RATING,
+                                      rating, -1);
+            }
+      
+      /* Related content URL */
+      if ((prop_node = json_object_get_member (object, "link")))
+        if ((prop_array = json_node_get_array (prop_node)))
+        {
+          JsonObject *link_object;
+          JsonNode *link_node;
+          gint j;
+          
+          for (j = 0; j < json_array_get_length (prop_array); j++)
+            {
+              const gchar *rel, *url;
+              gchar *jurl;
+              
+              if (!(prop_node = json_array_get_element (prop_array, j)))
+                continue;
+              
+              if (!(link_object = json_node_get_object (prop_node)))
+                continue;
+              
+              if (!(link_node = json_object_get_member (link_object, "rel")))
+                continue;
+              
+              if (!(rel = json_node_get_string (link_node)))
+                continue;
+              
+              if (strcmp (rel,
+                          "http://gdata.youtube.com/schemas/2007#video.related")
+                          != 0)
+                continue;
+
+              if (!(link_node = json_object_get_member (link_object, "href")))
+                continue;
+              
+              if (!(url = json_node_get_string (link_node)))
+                continue;
+              
+              /* Note: should probably check that the URL doesn't already have 
+               * some parameters, and if it does, use "&alt=json" instead,
+               * but we know that it doesn't (for now).
+               */
+              jurl = g_strconcat (url, "?alt=json", NULL);
+              clutter_model_iter_set (iter, YH_YOUTUBE_COL_RELATED, jurl, -1);
+              g_free (jurl);
+              
+              break;
+            }
+        }
+      
+      if ((prop_node = json_object_get_member (object, "media$group")))
+        if ((prop_object = json_node_get_object (prop_node)))
+          {
+            JsonObject *media_object;
+            JsonNode *media_node;
+            gint j;
+            
+            /* Formats/URIs */
+            if ((prop_node = json_object_get_member (prop_object,
+                                                     "media$content")))
+              if ((prop_array = json_node_get_array (prop_node)))
+                {
+                  GList *uris = NULL;
+                  GList *formats = NULL;
+                  
+                  for (j = 0; j < json_array_get_length (prop_array); j++)
+                    {
+                      const gchar *format, *uri;
+                      
+                      if (!(prop_node = json_array_get_element (prop_array, j)))
+                        continue;
+                      
+                      if (!(media_object = json_node_get_object (prop_node)))
+                        continue;
+                      
+                      if (!(media_node = json_object_get_member (media_object,
+                                                                 "type")))
+                        continue;
+                      
+                      if (!(format = json_node_get_string (media_node)))
+                        continue;
+                      
+                      if (!(media_node = json_object_get_member (media_object,
+                                                                "url")))
+                        continue;
+                      
+                      if (!(uri = json_node_get_string (media_node)))
+                        continue;
+                      
+                      uris = g_list_append (uris, (gpointer)uri);
+                      formats = g_list_append (formats, (gpointer)format);
+                    }
+                  
+                  if (uris)
+                    {
+                      GList *l;
+                      gchar **string_list;
+                      
+                      string_list = g_new0 (gchar *, g_list_length (uris) + 1);
+                      
+                      /* Set URI list */
+                      for (j = 0, l = uris; l; l = l->next, j++)
+                        {
+                          string_list[j] = (gchar *)l->data;
+                        }
+                      clutter_model_iter_set (iter,
+                                              YH_YOUTUBE_COL_URIS,
+                                              string_list,
+                                              -1);
+
+                      /* Set format (MIME type) list */
+                      for (j = 0, l = formats; l; l = l->next, j++)
+                        {
+                          string_list[j] = (gchar *)l->data;
+                        }
+                      clutter_model_iter_set (iter,
+                                              YH_YOUTUBE_COL_MIMES,
+                                              string_list,
+                                              -1);
+                      
+                      g_free (string_list);
+                      g_list_free (uris);
+                      g_list_free (formats);
+                    }
+                }
+
+            /* Thumbnails */
+            if ((prop_node = json_object_get_member (prop_object,
+                                                     "media$thumbnail")))
+              if ((prop_array = json_node_get_array (prop_node)))
+                {
+                  GList *urls = NULL;
+                  
+                  for (j = 0; j < json_array_get_length (prop_array); j++)
+                    {
+                      const gchar *url;
+                      
+                      if (!(prop_node = json_array_get_element (prop_array, j)))
+                        continue;
+                      
+                      if (!(media_object = json_node_get_object (prop_node)))
+                        continue;
+                      
+                      if (!(media_node = json_object_get_member (media_object,
+                                                                 "url")))
+                        continue;
+                      
+                      if (!(url = json_node_get_string (media_node)))
+                        continue;
+                      
+                      urls = g_list_append (urls, (gpointer)url);
+                    }
+                  
+                  if (urls)
+                    {
+                      GList *l;
+                      gchar **string_list;
+                      
+                      string_list = g_new0 (gchar *, g_list_length (urls) + 1);
+                      
+                      /* Set URL list */
+                      for (j = 0, l = urls; l; l = l->next, j++)
+                        {
+                          string_list[j] = (gchar *)l->data;
+                        }
+                      clutter_model_iter_set (iter,
+                                              YH_YOUTUBE_COL_THUMBS,
+                                              string_list,
+                                              -1);
+                      
+                      g_free (string_list);
+                      g_list_free (urls);
+                    }
+                }
+          }
+      
+      g_object_unref (iter);
+    }
+  
+  return model;
+}
+
+static void
+yh_youtube_curl_close (void *userp)
+{
+  CURLMsg *msg;
+  int in_queue;
+  CURL *handle;
+  YHYoutubeRequest *request;
+
+  YHYoutube *youtube = YH_YOUTUBE (userp);
+  YHYoutubePrivate *priv = youtube->priv;
+  
+  while ((msg = curl_multi_info_read (glibcurl_handle (), &in_queue))) {
+    gboolean remove_handle = TRUE;
+    GError *error = NULL;
+    
+    if (msg->msg != CURLMSG_DONE)
+      continue;
+    
+    handle = msg->easy_handle;
+    
+    if (curl_easy_getinfo (msg->easy_handle,
+                           CURLINFO_PRIVATE,
+                           &request) == CURLE_OK)
+      {
+        switch (request->type)
+          {
+          case TYPE_QUERY : {
+              ClutterModel *model = NULL;
+              
+              /* Parse the data into the model */
+              if (request->data)
+                {
+                  /*g_debug ("JSON:\n%.*s", request->size, request->data);*/
+                  if (!json_parser_load_from_data (priv->parser,
+                                                   request->data,
+                                                   request->size,
+                                                   &error))
+                    {
+                      g_warning ("Error parsing JSON: %s", error->message);
+                      g_error_free (error);
+                    }
+                  else
+                    model = yh_youtube_create_model (youtube);
+                }
+              
+              g_signal_emit (youtube, signals[MODEL], 0, model);
+              if (model)
+                g_object_unref (model);
+            }
+            break;
+          case TYPE_THUMB : {
+              GdkPixbuf *pixbuf = NULL;
+              
+              /* Create a GdkPixbuf from the data */
+              if (request->data)
+                {
+                  GdkPixbufLoader *loader;
+                  
+                  loader = gdk_pixbuf_loader_new ();
+                  if (!gdk_pixbuf_loader_write (loader,
+                                                (const guchar *)request->data,
+                                                request->size,
+                                                &error))
+                    {
+                      g_warning ("Error decoding image: %s", error->message);
+                      g_error_free (error);
+                    }
+                  else
+                    {
+                      if (!gdk_pixbuf_loader_close (loader, &error))
+                        {
+                          g_warning ("Error closing pixbuf loader: %s",
+                                     error->message);
+                          g_error_free (error);
+                        }
+                      else
+                        pixbuf = g_object_ref (
+                          gdk_pixbuf_loader_get_pixbuf (loader));
+                    }
+                    g_object_unref (loader);
+                }
+              
+              g_signal_emit (youtube, signals[THUMBNAIL], 0, pixbuf);
+              if (pixbuf)
+                g_object_unref (pixbuf);
+            }
+            break;
+          case TYPE_LINK : {
+              long error_code;
+              
+              /* If we can't get the error code for whatever reason, just 
+               * assume success.
+               */
+              if (curl_easy_getinfo (handle,
+                                     CURLINFO_RESPONSE_CODE,
+                                     &error_code) != CURLE_OK)
+                error_code = 200;
+              
+              /* Recursively solve redirects */
+              if ((error_code >= 300) && (error_code < 400))
+                {
+                  yh_youtube_get_http_link_cb (request, handle);
+                  glibcurl_remove (handle);
+                  glibcurl_add (handle);
+                  remove_handle = FALSE;
+                }
+              else
+                g_signal_emit (youtube, signals[LINK], 0, request->url);
+            }
+            break;
+          }
+        
+        if (remove_handle)
+          {
+            g_free (request->data);
+            g_free (request->url);
+            g_slice_free (YHYoutubeRequest, request);
+          }
+      }
+    else
+      g_warning ("Error retrieving user data, something has gone wrong...");
+    
+    if (remove_handle)
+      {
+        g_signal_emit (youtube, signals[COMPLETE], 0, handle);
+        glibcurl_remove (handle);
+        curl_easy_cleanup (handle);
+      }
+  }
+}
+
+static size_t
+yh_youtube_curl_read (void *buffer, size_t size, size_t nmemb, void *userp)
+{
+  YHYoutubeRequest *request = (YHYoutubeRequest *) userp;
+  gint real_size = (gint)(size * nmemb);
+  
+  if (!request->data) {
+      request->data = g_memdup (buffer, real_size);
+      request->size = real_size;
+    }
+  else
+    {
+      request->data = g_realloc (request->data, request->size + real_size);
+      g_memmove (request->data + request->size, buffer, real_size);
+      request->size += real_size;
+    }
+  
+  return (size_t)real_size;
+}
+
+YHYoutube *
+yh_youtube_get_default ()
+{
+  static YHYoutube *youtube = NULL;
+  
+  if (!youtube)
+    {
+      youtube = YH_YOUTUBE (g_object_new (YH_TYPE_YOUTUBE, NULL));
+    }
+
+  return youtube;
+}
+
+void *
+yh_youtube_query (YHYoutube *youtube, const gchar *search_string)
+{
+  CURL *handle;
+  YHYoutubeRequest *request;
+
+  /* Make request to Youtube GData url */
+  request = g_slice_new0 (YHYoutubeRequest);
+  search_string = curl_escape (search_string, 0);
+  request->type = TYPE_QUERY;
+  request->url =
+    g_strconcat ("http://gdata.youtube.com/feeds/api/videos?alt=json&vq=",
+                 search_string, NULL);
+  curl_free ((char *)search_string);
+  
+  handle = curl_easy_init ();
+  curl_easy_setopt (handle, CURLOPT_URL, request->url);
+  curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, yh_youtube_curl_read);
+  curl_easy_setopt (handle, CURLOPT_WRITEDATA, request);
+  curl_easy_setopt (handle, CURLOPT_PRIVATE, request);
+  
+  glibcurl_add (handle);
+  
+  return handle;
+}
+
+void *
+yh_youtube_query_manual (YHYoutube *youtube, const gchar *url)
+{
+  CURL *handle;
+  YHYoutubeRequest *request;
+
+  /* Make request to Youtube GData url */
+  request = g_slice_new0 (YHYoutubeRequest);
+  request->type = TYPE_QUERY;
+  request->url = g_strdup (url);
+  
+  /* Don't free url, CURL doesn't make a copy */
+  handle = curl_easy_init ();
+  curl_easy_setopt (handle, CURLOPT_URL, request->url);
+  curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, yh_youtube_curl_read);
+  curl_easy_setopt (handle, CURLOPT_WRITEDATA, request);
+  curl_easy_setopt (handle, CURLOPT_PRIVATE, request);
+  
+  glibcurl_add (handle);
+  
+  return handle;
+}
+
+void *
+yh_youtube_get_thumb (YHYoutube *youtube, const gchar *url)
+{
+  CURL *handle;
+  YHYoutubeRequest *request;
+
+  /* Download image */
+  request = g_slice_new0 (YHYoutubeRequest);
+  request->type = TYPE_THUMB;
+  request->url = g_strdup (url);
+  
+  handle = curl_easy_init ();
+  curl_easy_setopt (handle, CURLOPT_URL, request->url);
+  curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, yh_youtube_curl_read);
+  curl_easy_setopt (handle, CURLOPT_WRITEDATA, request);
+  curl_easy_setopt (handle, CURLOPT_PRIVATE, request);
+  
+  glibcurl_add (handle);
+  
+  return handle;
+}
+
+void
+yh_youtube_cancel (YHYoutube *youtube, void *handle)
+{
+  YHYoutubeRequest *request;
+  
+  CURL *curl_handle = (CURL *)handle;
+  
+  if (curl_easy_getinfo (curl_handle,
+                         CURLINFO_PRIVATE,
+                         &request) == CURLE_OK)
+    {
+      g_free (request->data);
+      g_free (request->url);
+      g_slice_free (YHYoutubeRequest, request);
+    }
+  
+  glibcurl_remove(curl_handle);
+  curl_easy_cleanup (curl_handle);
+}
+
+static size_t
+yh_youtube_header_cb (void *buffer, size_t size, size_t nmemb, void *userp)
+{
+  YHYoutubeRequest *request = (YHYoutubeRequest *)userp;
+  gint real_size = (gint)(size *nmemb);
+  gchar *header = g_strstrip (g_strndup (buffer, real_size));
+  
+#define YOUTUBE_REGEX "video_id=([^&]*)&.*t=([^&]*)"  
+
+  if (header && strncmp (header, "Location: ", 10) == 0)
+    {
+      const gchar *url = header + 10;
+      
+      g_free (request->url);
+      
+      /* Hacky URL mangling */
+      if (strstr (url, "/swf/l.swf?video_id="))
+        {
+          /* NOTE: This URL/method subject to change. FREQUENTLY. */
+          regex_t regex;
+          regmatch_t pmatch[3];
+          
+          if ((regcomp (&regex, YOUTUBE_REGEX, REG_EXTENDED) == 0) &&
+              (regexec (&regex, url, 3, pmatch, 0) == 0))
+            {
+              gchar *video, *t;
+              video = g_strndup (url + pmatch[1].rm_so,
+                                 pmatch[1].rm_eo - pmatch[1].rm_so);
+              t = g_strndup (url + pmatch[2].rm_so,
+                             pmatch[2].rm_eo - pmatch[2].rm_so);
+              request->url =
+                g_strdup_printf (
+                  "http://www.youtube.com/get_video?video_id=%s&"
+                  "t=%s", video, t);
+            }
+          else
+            request->url = NULL;
+        }
+      else if (url[0] == '/')
+        {
+          request->url = g_strconcat ("http://www.youtube.com", url, NULL);
+        }
+      else
+        {
+          request->url = g_strdup (url);
+        }
+      
+      /* Set the size to -1 (cancels transfer) -
+       * this is the header we were looking for
+       */
+      real_size = -1;
+    }
+  g_free (header);
+
+  return real_size;
+}
+
+static size_t
+yh_youtube_minus_one ()
+{
+  return -1;
+}
+
+static void
+yh_youtube_get_http_link_cb (YHYoutubeRequest *request, CURL *handle)
+{
+  curl_easy_setopt (handle, CURLOPT_URL, request->url);
+  curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, yh_youtube_minus_one);
+  curl_easy_setopt (handle, CURLOPT_WRITEDATA, request);
+  curl_easy_setopt (handle, CURLOPT_PRIVATE, request);
+  curl_easy_setopt (handle, CURLOPT_HEADERFUNCTION, yh_youtube_header_cb);
+  curl_easy_setopt (handle, CURLOPT_HEADERDATA, request);
+}
+
+/* This is a nasty function required because YouTube uses HTTP 303's
+ * to 'redirect' :( (but even then, the location needs mangling)
+ */
+void *
+yh_youtube_get_http_link  (YHYoutube *youtube, const gchar *url)
+{
+  CURL *handle;
+  YHYoutubeRequest *request;
+  
+  /* Download image */
+  request = g_slice_new0 (YHYoutubeRequest);
+  request->type = TYPE_LINK;
+  request->url = g_strdup (url);
+  
+  handle = curl_easy_init ();
+  yh_youtube_get_http_link_cb (request, handle);
+  
+  glibcurl_add (handle);
+  
+  return handle;
+}
+
+void
+yh_youtube_pause (YHYoutube *youtube, void *handle, gboolean resume)
+{
+  if (resume)
+    glibcurl_add ((CURL *)handle);
+  else
+    glibcurl_remove ((CURL *)handle);
+}
diff --git a/attic/youhaa/src/yh-youtube.h b/attic/youhaa/src/yh-youtube.h
new file mode 100644 (file)
index 0000000..2d55c98
--- /dev/null
@@ -0,0 +1,81 @@
+
+#ifndef _YH_YOUTUBE_H
+#define _YH_YOUTUBE_H
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define YH_TYPE_YOUTUBE yh_youtube_get_type()
+
+#define YH_YOUTUBE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  YH_TYPE_YOUTUBE, YHYoutube))
+
+#define YH_YOUTUBE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  YH_TYPE_YOUTUBE, YHYoutubeClass))
+
+#define YH_IS_YOUTUBE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  YH_TYPE_YOUTUBE))
+
+#define YH_IS_YOUTUBE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  YH_TYPE_YOUTUBE))
+
+#define YH_YOUTUBE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  YH_TYPE_YOUTUBE, YHYoutubeClass))
+
+enum {
+  YH_YOUTUBE_COL_TITLE,
+  YH_YOUTUBE_COL_AUTHOR,
+  YH_YOUTUBE_COL_DESCRIPTION,
+  YH_YOUTUBE_COL_RATING,
+  YH_YOUTUBE_COL_THUMBS,
+  YH_YOUTUBE_COL_MIMES,
+  YH_YOUTUBE_COL_URIS,
+  YH_YOUTUBE_COL_RELATED,
+  
+  YH_YOUTUBE_COL_LAST
+};
+
+typedef struct _YHYoutube         YHYoutube;
+typedef struct _YHYoutubeClass    YHYoutubeClass;
+typedef struct _YHYoutubePrivate  YHYoutubePrivate;
+
+struct _YHYoutube {
+  GObject           parent;
+  
+  YHYoutubePrivate *priv;
+};
+
+struct _YHYoutubeClass {
+  GObjectClass parent_class;
+  
+  /* Signals */
+  void (* complete)  (YHYoutube *youtube, void *handle);
+  void (* model)     (YHYoutube *youtube, ClutterModel *model);
+  void (* thumbnail) (YHYoutube *youtube, GdkPixbuf *pixbuf);
+  void (* link)      (YHYoutube *youtube, const gchar *url);
+};
+
+GType yh_youtube_get_type (void);
+
+YHYoutube *
+yh_youtube_get_default ();
+
+void *yh_youtube_query         (YHYoutube *youtube, const gchar *search_string);
+void *yh_youtube_query_manual  (YHYoutube *youtube, const gchar *url);
+void *yh_youtube_get_thumb     (YHYoutube *youtube, const gchar *url);
+void  yh_youtube_cancel        (YHYoutube *youtube, void        *handle);
+void *yh_youtube_get_http_link (YHYoutube *youtube, const gchar *url);
+void  yh_youtube_pause         (YHYoutube *youtube, void        *handle,
+                                gboolean   resume);
+
+G_END_DECLS
+
+#endif /* _YH_YOUTUBE_H */
+
diff --git a/circles/Makefile b/circles/Makefile
new file mode 100644 (file)
index 0000000..a63d0f3
--- /dev/null
@@ -0,0 +1,13 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: circles
+
+circles: circles.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ circles.o -lm $(LIBS)
+
+clean:
+       rm -fr *.o circles
diff --git a/circles/circles.c b/circles/circles.c
new file mode 100644 (file)
index 0000000..eecd572
--- /dev/null
@@ -0,0 +1,109 @@
+#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
+#include <clutter/clutter.h>
+#include <math.h>
+
+#define N_CIRCLES 3     /* number of circles */
+#define CIRCLE_W 128    /* width */
+#define CIRCLE_G 32     /* gap */
+#define CIRCLE_S 3      /* segments */
+#define SCREEN_W 640
+#define SCREEN_H 480
+
+#ifndef CLUTTER_ANGLE_FROM_RAD
+#define CLUTTER_ANGLE_FROM_RAD(x) ((x) * 180.0 / G_PI)
+#endif
+
+static void
+circle_paint_cb (ClutterActor *actor)
+{
+  const CoglColor fill_color = { 0xff, 0xff, 0xff, 0x80 };
+  gint i;
+  gdouble angle;
+  guint radius = clutter_actor_get_width (actor) / 2;
+
+  cogl_set_source_color (&fill_color);
+
+  angle = *((gdouble *)g_object_get_data (G_OBJECT (actor), "angle"));
+  for (i = 0; i < CIRCLE_S; i++, angle += (2.0 * G_PI) / (gdouble) CIRCLE_S)
+    {
+      gdouble angle2 = angle + ((2.0 * G_PI) / (gdouble)CIRCLE_S) / 2.0;
+      cogl_path_move_to (((radius - CIRCLE_W) * cos (angle)) + radius,
+                         ((radius - CIRCLE_W) * sin (angle)) + radius);
+      cogl_path_arc (radius, radius, radius, radius,
+                     CLUTTER_ANGLE_FROM_RAD (angle),
+                     CLUTTER_ANGLE_FROM_RAD (angle2));
+      cogl_path_line_to (((radius - CIRCLE_W) * cos (angle2)) + radius,
+                         ((radius - CIRCLE_W) * sin (angle2)) + radius);
+      cogl_path_arc (radius, radius, radius - CIRCLE_W, radius - CIRCLE_W,
+                     CLUTTER_ANGLE_FROM_RAD (angle2),
+                     CLUTTER_ANGLE_FROM_RAD (angle));
+      cogl_path_close ();
+      cogl_path_fill ();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  const ClutterColor transp = { 0x00, 0x00, 0x00, 0x00 };
+  const ClutterColor bg_color = { 0xe0, 0xf2, 0xfc, 0xff };
+  ClutterTimeline *timeline;
+  ClutterActor *stage;
+  gint i;
+
+  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+    return 1;
+
+  stage = clutter_stage_new ();
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "Circles");
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &bg_color);
+  clutter_actor_set_size (stage, SCREEN_W, SCREEN_H);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  timeline = clutter_timeline_new (5000);
+  clutter_timeline_set_loop (timeline, TRUE);
+
+  for (i = 0; i < N_CIRCLES; i++)
+    {
+      gint size;
+      gdouble *angle;
+      ClutterActor *actor;
+      ClutterAlpha *alpha;
+      ClutterBehaviour *behaviour;
+      
+      actor = clutter_rectangle_new_with_color (&transp);
+      
+      size = (i + 1) * (CIRCLE_W + CIRCLE_G) * 2;
+      clutter_actor_set_size (actor, size, size);
+      clutter_actor_set_position (actor,
+                                  SCREEN_W - size / 2.0,
+                                  SCREEN_H - size / 2.0);
+      
+      clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
+      
+      angle = g_slice_new (gdouble);
+      *angle = g_random_double_range (0.0, 90.0);
+      g_object_set_data (G_OBJECT (actor), "angle", angle);
+      g_signal_connect (actor, "paint", G_CALLBACK (circle_paint_cb), NULL);
+      
+      /* Animate */
+      alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR);
+      behaviour = clutter_behaviour_rotate_new (alpha, CLUTTER_Z_AXIS,
+                                                (i % 2) ? CLUTTER_ROTATE_CW
+                                                        : CLUTTER_ROTATE_CCW,
+                                                0.0, 0.0);
+      clutter_behaviour_rotate_set_center (CLUTTER_BEHAVIOUR_ROTATE (behaviour),
+                                           size / 2,
+                                           size / 2,
+                                           0);
+      clutter_behaviour_apply (behaviour, actor);
+    }
+  
+  clutter_actor_show_all (stage);
+  
+  clutter_timeline_start (timeline);
+  
+  clutter_main ();
+  
+  return 0;
+}
diff --git a/courasel/Makefile b/courasel/Makefile
new file mode 100644 (file)
index 0000000..233dc58
--- /dev/null
@@ -0,0 +1,14 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+CFLAGS="-lm"
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: courasel
+
+courasel: courasel.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ courasel.o $(LIBS)
+
+clean:
+       rm -fr *.o courasel
diff --git a/courasel/accessories-text-editor.png b/courasel/accessories-text-editor.png
new file mode 100644 (file)
index 0000000..02361a9
Binary files /dev/null and b/courasel/accessories-text-editor.png differ
diff --git a/courasel/applications-games.png b/courasel/applications-games.png
new file mode 100644 (file)
index 0000000..67a1a4c
Binary files /dev/null and b/courasel/applications-games.png differ
diff --git a/courasel/courasel.c b/courasel/courasel.c
new file mode 100644 (file)
index 0000000..5f66707
--- /dev/null
@@ -0,0 +1,309 @@
+#include <clutter/clutter.h>
+#include <math.h>
+
+#define CSW() CLUTTER_STAGE_WIDTH()
+#define CSH() CLUTTER_STAGE_HEIGHT()
+
+#define N_ITEMS 8
+#define STEP (360.0/N_ITEMS)
+#define CLAMP_ANG(x) (((x) > 360.0) ? ((x) - 360.0) : (x))
+
+struct { gchar *img; gchar *title; } ItemDetails[] =
+{
+  { "accessories-text-editor.png", "Text Editor" },
+  { "applications-games.png", "Game" },
+  { "dates.png", "Dates" },
+  { "im-client.png", "Chat" },
+  { "preferences-desktop-theme.png", "Preferences" },
+  { "tasks.png", "Todo List" },
+  { "utilities-terminal.png", "Terminal" },
+  { "web-browser.png", "Browser"},
+};
+
+typedef struct Item
+{
+  ClutterActor     *actor;
+  ClutterBehaviour *ellipse_behave, *opacity_behave, *scale_behave;
+}
+Item;
+
+typedef struct App
+{
+  ClutterTimeline *timeline;
+  ClutterAlpha    *alpha_sine_inc, *alpha_ramp;
+  GSList          *items;
+  Item            *active;
+  gdouble          off;
+  int              selected_index;
+  ClutterActor    *label;
+}
+App;
+
+void
+introduce_items (App *app)
+{
+  gint     i;
+  GSList  *node;
+  gdouble  ang_start, ang_end;
+
+  node = app->items;
+
+  for (i=0; i<N_ITEMS; i++)
+    {
+      Item *item = node->data;
+
+      ang_start = -90.0;
+      ang_end   = (STEP * i);
+
+      clutter_behaviour_ellipse_set_angle_start
+       (CLUTTER_BEHAVIOUR_ELLIPSE(item->ellipse_behave), ang_start);
+
+      clutter_behaviour_ellipse_set_angle_end
+       (CLUTTER_BEHAVIOUR_ELLIPSE(item->ellipse_behave), ang_end);
+
+      if (i == app->selected_index)
+       {
+         g_object_set (item->opacity_behave,
+                       "opacity-start", 0x66,
+                       "opacity-end", 0xff,
+                       NULL);
+         g_object_set (item->scale_behave,
+                       "x-scale-start", 0.6,
+                       "y-scale-start", 0.6,
+                       "x-scale-end", 1.0,
+                       "y-scale-end", 1.0,
+                       NULL);
+       }
+      node = node->next;
+    }
+
+  clutter_timeline_start (app->timeline);
+}
+
+
+void
+rotate_items (App *app, int step)
+{
+  gint     i, from_index;
+  GSList  *node;
+  gdouble  ang = 0.0, ang_start, ang_end;
+
+  from_index = app->selected_index;
+
+  app->selected_index += (-1 * step);
+  if (app->selected_index < 0) app->selected_index = 7;
+  if (app->selected_index > 7) app->selected_index = 0;
+
+  ang = app->off;
+
+  node = app->items;
+
+  for (i=0; i<N_ITEMS; i++)
+    {
+      Item *item = node->data;
+
+      ang_start = ang;
+      ang_end   = ang + (STEP * step);
+
+      clutter_behaviour_ellipse_set_direction
+       (CLUTTER_BEHAVIOUR_ELLIPSE(item->ellipse_behave),
+        step > 0 ? CLUTTER_ROTATE_CW : CLUTTER_ROTATE_CCW);
+
+      clutter_behaviour_ellipse_set_angle_start
+       (CLUTTER_BEHAVIOUR_ELLIPSE(item->ellipse_behave), ang_start);
+
+      clutter_behaviour_ellipse_set_angle_end
+       (CLUTTER_BEHAVIOUR_ELLIPSE(item->ellipse_behave), ang_end);
+
+      if (i == from_index)
+       {
+         g_object_set (item->opacity_behave,
+                       "opacity-start", 0xff,
+                       "opacity-end", 0x66,
+                       NULL);
+
+         g_object_set (item->scale_behave,
+                       "x-scale-start", 1.0,
+                       "y-scale-start", 1.0,
+                       "x-scale-end", 0.6,
+                       "y-scale-end", 0.6,
+                       NULL);
+       }
+      else if (i == app->selected_index)
+       {
+         g_object_set (item->opacity_behave,
+                       "opacity-start", 0x66,
+                       "opacity-end", 0xff,
+                       NULL);
+         g_object_set (item->scale_behave,
+                       "x-scale-start", 0.6,
+                       "y-scale-start", 0.6,
+                       "x-scale-end", 1.0,
+                       "y-scale-end", 1.0,
+                       NULL);
+       }
+      else
+       {
+         g_object_set (item->opacity_behave,
+                       "opacity-start", 0x66,
+                       "opacity-end", 0x66,
+                       NULL);
+         g_object_set (item->scale_behave,
+                       "x-scale-start", 0.6,
+                       "y-scale-start", 0.6,
+                       "x-scale-end", 0.6,
+                       "y-scale-end", 0.6,
+                       NULL);
+       }
+
+      ang += STEP;
+      node = node->next;
+    }
+
+  clutter_timeline_start (app->timeline);
+
+  app->off += (STEP * step);
+  app->off = CLAMP_ANG(app->off);
+}
+
+static gboolean
+on_input (ClutterActor *stage,
+         ClutterEvent *event,
+         gpointer      user_data)
+{
+  App *app = user_data;
+
+  if (event->type == CLUTTER_KEY_RELEASE)
+    {
+      if (clutter_timeline_is_playing(app->timeline))
+       return FALSE;
+
+      switch (clutter_event_get_key_symbol (event))
+       {
+       case CLUTTER_Left:
+         rotate_items (app, -1);
+         break;
+       case CLUTTER_Right:
+         rotate_items (app, 1);
+         break;
+       case CLUTTER_Return:
+         break;
+       case CLUTTER_q:
+         clutter_main_quit();
+         break;
+       default:
+         break;
+       }
+    }
+
+  return FALSE;
+}
+
+void
+on_timeline_new_frame (ClutterTimeline *timeline,
+                              gint             frame_msecs,
+                      App             *app)
+{
+  if (frame_msecs > clutter_timeline_get_duration (timeline)/2)
+    clutter_text_set_text (CLUTTER_TEXT(app->label),
+                           ItemDetails[app->selected_index].title);
+}
+
+/* An alpha function that goes from 0->1->0 along a sine. */
+gdouble
+label_opacity_alpha_func (ClutterAlpha *alpha,
+                          gpointer unused)
+{
+  ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
+  return sin (clutter_timeline_get_progress (timeline) * M_PI);
+}
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor    *stage;
+  ClutterColor     stage_color = { 0x34, 0x39, 0x39, 0xff };
+  ClutterColor     white = { 0x72, 0x9f, 0xcf, 0xff };
+  gint             i = 0;
+  Item            *item;
+  App             *app;
+  gdouble          ang = 0.0;
+  ClutterBehaviour *behave;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  clutter_actor_set_size (stage, 800, 600);
+
+  app = g_new0(App, 1);
+  app->off = 0.0;
+  app->timeline = clutter_timeline_new (300);
+  app->alpha_sine_inc
+    = clutter_alpha_new_full (app->timeline, CLUTTER_EASE_OUT_SINE);
+
+  app->alpha_ramp
+    = clutter_alpha_new_with_func (app->timeline, label_opacity_alpha_func,
+                                   NULL, NULL);
+
+  for (i=0; i<N_ITEMS; i++)
+    {
+      item = g_new0 (Item, 1);
+
+      item->actor = clutter_texture_new_from_file (ItemDetails[i].img, NULL);
+      if (!item->actor)
+       g_error ("Unable to load '%s'", ItemDetails[i].img);
+
+      clutter_group_add (CLUTTER_GROUP(stage), item->actor);
+
+      item->ellipse_behave
+       = clutter_behaviour_ellipse_new (app->alpha_sine_inc,
+                                        CSW()/4,   /* center x */
+                                        CSH() - (CSH()/3),   /* center y */
+                                        CSW()/2,   /* width */
+                                        CSH() - (CSH()/4),   /* height */
+                                        CLUTTER_ROTATE_CW,
+                                        ang,
+                                        ang + STEP);
+      item->opacity_behave
+       = clutter_behaviour_opacity_new (app->alpha_sine_inc, 0x66, 0x66);
+
+      item->scale_behave
+       = clutter_behaviour_scale_new (app->alpha_sine_inc,
+                                      0.6, 0.6, 0.6, 0.6);
+
+      clutter_behaviour_apply (item->ellipse_behave, item->actor);
+      clutter_behaviour_apply (item->opacity_behave, item->actor);
+      clutter_behaviour_apply (item->scale_behave, item->actor);
+
+      app->items = g_slist_append (app->items, item);
+
+      ang += STEP;
+    }
+
+  app->label = clutter_text_new_full ("Bitstream Vera Sans 60px", "", &white);
+  clutter_actor_set_position (app->label, CSW()/2 - 30, CSH()/3 - 40);
+  clutter_group_add (CLUTTER_GROUP(stage), app->label);
+
+  behave = clutter_behaviour_opacity_new (app->alpha_ramp, 0xff, 0);
+  clutter_behaviour_apply (behave, app->label);
+
+  g_signal_connect (app->timeline,
+                   "new-frame",
+                   G_CALLBACK(on_timeline_new_frame),
+                   app);
+
+  g_signal_connect (stage,
+                   "event",
+                   G_CALLBACK (on_input),
+                   app);
+
+  introduce_items (app);
+
+  clutter_actor_show_all (stage);
+
+  clutter_main();
+
+  return 0;
+}
diff --git a/courasel/dates.png b/courasel/dates.png
new file mode 100644 (file)
index 0000000..2824813
Binary files /dev/null and b/courasel/dates.png differ
diff --git a/courasel/im-client.png b/courasel/im-client.png
new file mode 100644 (file)
index 0000000..561519d
Binary files /dev/null and b/courasel/im-client.png differ
diff --git a/courasel/preferences-desktop-theme.png b/courasel/preferences-desktop-theme.png
new file mode 100644 (file)
index 0000000..8c93c14
Binary files /dev/null and b/courasel/preferences-desktop-theme.png differ
diff --git a/courasel/tasks.png b/courasel/tasks.png
new file mode 100644 (file)
index 0000000..e9ea953
Binary files /dev/null and b/courasel/tasks.png differ
diff --git a/courasel/utilities-terminal.png b/courasel/utilities-terminal.png
new file mode 100644 (file)
index 0000000..693c685
Binary files /dev/null and b/courasel/utilities-terminal.png differ
diff --git a/courasel/web-browser.png b/courasel/web-browser.png
new file mode 100644 (file)
index 0000000..1df505c
Binary files /dev/null and b/courasel/web-browser.png differ
diff --git a/foofone/Makefile b/foofone/Makefile
new file mode 100644 (file)
index 0000000..1a7d3d4
--- /dev/null
@@ -0,0 +1,14 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+CFLAGS="-lm"
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: foofone
+
+foofone: foofone.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ foofone.o $(LIBS)
+
+clean:
+       rm -fr *.o foofone
diff --git a/foofone/button.png b/foofone/button.png
new file mode 100644 (file)
index 0000000..e643c30
Binary files /dev/null and b/foofone/button.png differ
diff --git a/foofone/call-background.png b/foofone/call-background.png
new file mode 100644 (file)
index 0000000..0131d8f
Binary files /dev/null and b/foofone/call-background.png differ
diff --git a/foofone/display.png b/foofone/display.png
new file mode 100644 (file)
index 0000000..7bf4dd6
Binary files /dev/null and b/foofone/display.png differ
diff --git a/foofone/foofone.c b/foofone/foofone.c
new file mode 100644 (file)
index 0000000..f732ea6
--- /dev/null
@@ -0,0 +1,446 @@
+/* 
+ * foofone
+ *
+ * Foofone is a quick 3 hour hack to experiment with effects and create a
+ * dummy phone interface. Thats all it is.
+ *
+ * Copyright 2007 OpenedHand Ltd
+ * Authored by Matthew Allum <mallum@o-hand.com>
+ * Licensed under the GPL v2 or greater.
+ *
+ */
+
+#include <clutter/clutter.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define CSW 240
+#define CSH 320
+
+typedef struct Button
+{
+  ClutterActor     *actor;
+  gchar            *face;
+  gint              sx, sy;
+} 
+Button;
+
+typedef struct App
+{
+  Button                *buttons[12];
+  ClutterActor          *dpy, *dpy_entry;
+  gint                   dpyx, dpyy;
+  ClutterActor          *screen_dialpad, *screen_dial, *dial_label;
+  gboolean               dialing_state;
+  ClutterTimeline       *dialing_timeline;
+} 
+App;
+
+/* An alpha function that goes from 0->1->0 along a sine. */
+static gdouble
+alpha_sine_func (ClutterAlpha *alpha,
+                 gpointer unused)
+{
+  ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
+  return sin(clutter_timeline_get_progress (timeline) * M_PI);
+}
+
+gulong ALPHA_SINE;
+
+/* A boolean 'interpolator', switching from 'a' to 'b' when 'progress' = 0.5 */ 
+static gboolean
+boolean_progress (const GValue *a,
+                  const GValue *b,
+                  gdouble       progress,
+                  GValue       *retval)
+{
+  gboolean ba = g_value_get_boolean (a);
+  gboolean bb = g_value_get_boolean (b);
+  gboolean res = (progress <= 0.5) ? ba : bb;
+  g_value_set_boolean (retval, res);
+  return TRUE;
+}
+
+void
+on_call_deactivate_complete (ClutterTimeline *timeline,
+                            gpointer         user_data)
+{
+  App *app = (App*)user_data;
+  /* reset the now hidden dialing screen */
+  clutter_actor_set_rotation (app->screen_dial, CLUTTER_Y_AXIS, 0, 0, 0, 0);
+}
+
+void
+call_deactivate (App *app)
+{
+  int               i;
+  ClutterAnimation *anim;
+  ClutterAlpha     *alpha;
+
+  /* stop the flashing text */
+  clutter_timeline_stop (app->dialing_timeline);
+
+  /* clear dialpad entry ready */
+  clutter_text_set_text (CLUTTER_TEXT(app->dpy_entry), "");
+
+  /* rotate screen_dial, and hide it at mid-animation */
+  clutter_actor_set_rotation (app->screen_dial, CLUTTER_Y_AXIS, 0.0, 0.0, 0.0, 0.0);
+  anim = clutter_actor_animate (app->screen_dial, CLUTTER_LINEAR, 150,
+                                "rotation-angle-y", -180.0,
+                                "visible", FALSE,
+                                NULL);
+  alpha = clutter_animation_get_alpha (anim);
+
+  /* reset positions of dialer actors, needed back for flip */
+  for (i=0; i<12; i++)
+    {
+      clutter_actor_set_position (app->buttons[i]->actor,
+                                  app->buttons[i]->sx, app->buttons[i]->sy);
+      clutter_actor_set_opacity (app->buttons[i]->actor, 0xff);
+    }
+  clutter_actor_set_position (app->dpy, app->dpyx, app->dpyy);
+
+  /* rotate hidden screen_dialpad, and show it at mid-animation */
+  clutter_actor_set_rotation (app->screen_dialpad, CLUTTER_Y_AXIS, 180.0, 0.0, 0.0, 0.0);
+  clutter_actor_animate_with_alpha (app->screen_dialpad, alpha,
+                                    "rotation-angle-y", 0.0,
+                                    "visible", TRUE,
+                                    "signal-after::completed",
+                                      G_CALLBACK(on_call_deactivate_complete),
+                                      app,
+                                    NULL);
+
+  app->dialing_state = FALSE;
+}
+
+void
+on_call_activate_complete (ClutterActor *actor,
+                          gpointer user_data)
+{
+  ClutterAlpha     *alpha;
+  ClutterBehaviour *behave;
+  App *app = (App*)user_data;
+
+  clutter_actor_hide (app->screen_dialpad);
+
+  /* Setup the pulsing 'calling..' text if need be */
+  if (app->dialing_timeline == NULL)
+    {
+      app->dialing_timeline = clutter_timeline_new (1000);
+      clutter_timeline_set_loop (app->dialing_timeline, TRUE);
+      alpha = clutter_alpha_new_full (app->dialing_timeline, ALPHA_SINE);
+      behave = clutter_behaviour_opacity_new (alpha, 0xff, 0);
+      clutter_behaviour_apply (behave, app->dial_label);
+    }
+  clutter_timeline_start (app->dialing_timeline);
+
+  app->dialing_state = TRUE;
+}
+
+void
+call_activate (App *app)
+{
+  gint i;
+  gfloat x, y;
+  ClutterAnimation *anim;
+  ClutterAlpha     *alpha;
+
+  /* zoom in the dialing window */
+  clutter_actor_set_scale (app->screen_dial, 0.1, 0.1);
+  clutter_actor_set_opacity (app->screen_dial, 0x66);
+  clutter_actor_show_all (app->screen_dial);
+
+  anim = clutter_actor_animate (app->screen_dial, CLUTTER_EASE_OUT_SINE, 150,
+                                "opacity", 0xff,
+                                "scale-x", 1.0,
+                                "scale-y", 1.0,
+                                NULL);
+  alpha = clutter_animation_get_alpha (anim);
+
+  /* Set up effects to shoot everything offscreen, synchronized with screen_dial animation */
+  for (i=0; i<12; i++)
+    {
+      clutter_actor_set_position (app->buttons[i]->actor,
+                                  app->buttons[i]->sx,
+                                  app->buttons[i]->sy);
+
+      switch ((i+1) % 3)
+         {
+         case 0:
+            x = CSW + clutter_actor_get_width (app->buttons[i]->actor) / 2;
+           y = app->buttons[i]->sy;
+           break;
+         case 1:
+            x = -clutter_actor_get_width (app->buttons[i]->actor) / 2;
+           y = app->buttons[i]->sy;
+           break;
+         case 2:
+           x = app->buttons[i]->sx;
+           if (i < 3)
+              y = -clutter_actor_get_height (app->buttons[i]->actor) / 2;
+           else
+              y = CSH + clutter_actor_get_height (app->buttons[i]->actor) / 2;
+           break;
+         }
+
+      clutter_actor_animate_with_alpha (app->buttons[i]->actor, alpha,
+                                        "opacity", 0x00,
+                                        "x", x,
+                                        "y", y,
+                                       NULL);
+    }
+
+  clutter_actor_set_position (app->dpy, app->dpyx, app->dpyy);
+  clutter_actor_animate_with_alpha(app->dpy, alpha,
+                                   "x", (float)app->dpyx,
+                                   "y", -clutter_actor_get_height (app->dpy),
+                                   "signal-after::completed",
+                                     on_call_activate_complete,
+                                     app,
+                                   NULL);
+}
+
+void  
+on_button_effect_complete (ClutterAnimation *animation,
+                                      gpointer user_data)
+{
+  ClutterActor *actor = (ClutterActor*)user_data;
+
+  /* reset after effect */
+  clutter_actor_set_opacity (actor, 0xff);
+  clutter_actor_set_scale (actor, 1.0, 1.0);
+}
+
+void
+button_activate (App *app, Button *b)
+{
+  // Wait for the previous animation to end
+  if (clutter_actor_get_animation (b->actor))
+    return;
+
+  clutter_text_insert_text (CLUTTER_TEXT(app->dpy_entry), b->face, -1);
+
+  clutter_actor_set_opacity (b->actor, 0xff);
+  clutter_actor_set_scale (b->actor, 1.0, 1.0);
+  clutter_actor_animate (b->actor, CLUTTER_LINEAR, 50,
+                         "opacity", 0x00,
+                         "scale-x", 1.5,
+                         "scale-y", 1.5,
+                         "signal-after::completed", on_button_effect_complete, b->actor,
+                         NULL);
+}
+
+static gboolean 
+on_input (ClutterStage *stage,
+         ClutterEvent *event,
+         gpointer      user_data)
+{
+  App *app = (App*)user_data;
+
+  if (event->type == CLUTTER_BUTTON_PRESS)
+    {
+      ClutterActor *actor = clutter_event_get_source (event);
+      const gchar  *label = clutter_actor_get_name (actor);
+      int          label_val;
+
+      if (app->dialing_state == TRUE)
+           {
+             call_deactivate(app);
+             return TRUE;
+           }
+
+      /* retrieve button id (stored in the Actor's name) */
+      if ( !label )
+        return FALSE;
+      label_val = atoi(label);
+      if ( label_val < 1 || label_val > 12 )
+        return FALSE;
+      --label_val;
+
+      if (label_val == 11) /* 'dial' key */
+        call_activate (app);
+      else
+        button_activate (app, app->buttons[label_val]);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+void
+make_ui (App *app)
+{
+  gint          i, xpad, ypad, x ,y, xinit, xdpy, ydpy;
+  ClutterActor *button_texture, *a;
+  ClutterColor  text_color = { 0xff, 0xff, 0xff, 0xff },
+                rect_color = { 0, 0, 0, 0x99 },
+                black_color = { 0, 0, 0, 0xff };
+
+  button_texture =  clutter_texture_new_from_file ("button.png", NULL);
+
+  xpad = (CSW-(3*clutter_actor_get_width(button_texture)))/4;
+  x = xinit = xpad;
+  ypad = xpad/2;
+  y = (CSH - (4 * (ypad + clutter_actor_get_height(button_texture))));
+
+  /*
+   * screen_dialpad (group)
+   *  +----dpy (group)
+   *        +---- (texture:display.png)
+   *        +----dpy_entry (text)
+   *        +----buttons[0:11]->actor (group)
+   *              +---- (texture:button.png)
+   *              +---- (text)
+   */
+
+  app->screen_dialpad = clutter_group_new();
+  clutter_actor_set_size (app->screen_dialpad, CSW, CSH);
+  clutter_actor_set_anchor_point_from_gravity (app->screen_dialpad, CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (app->screen_dialpad, CSW/2, CSH/2);
+
+  app->dpy = clutter_group_new();
+
+  a = clutter_texture_new_from_file ("display.png", NULL);
+  clutter_group_add (CLUTTER_GROUP(app->dpy), a);
+  app->dpyx = xdpy = x;
+  app->dpyy = ydpy = (y - clutter_actor_get_height(app->dpy))/2;
+  clutter_actor_set_position (app->dpy, xdpy, ydpy);
+
+  clutter_group_add(CLUTTER_GROUP(app->screen_dialpad), app->dpy);
+
+  app->dpy_entry = clutter_text_new_full ("Sans Bold 32px", "", &text_color);
+  clutter_text_set_editable (CLUTTER_TEXT(app->dpy_entry), TRUE);
+  clutter_actor_set_position (app->dpy_entry, 8, 8);
+  clutter_actor_set_size (app->dpy_entry, clutter_actor_get_width (app->dpy) - 16, 32);
+  clutter_group_add (CLUTTER_GROUP(app->dpy), app->dpy_entry);
+
+  for (i=0; i<12; i++)
+    {
+      gchar       buf[8];
+      gchar       label[8];
+
+      app->buttons[i] = g_new0(Button, 1);
+      app->buttons[i]->actor = clutter_group_new ();
+      g_snprintf (label, 8, "%d", i+1);
+      clutter_actor_set_name (app->buttons[i]->actor, label);
+      clutter_actor_set_reactive (app->buttons[i]->actor, TRUE);
+      clutter_actor_set_anchor_point_from_gravity (app->buttons[i]->actor,
+                                                   CLUTTER_GRAVITY_CENTER);
+      
+      if ( i == 0 )
+        a = button_texture;
+      else
+        a = clutter_clone_new(button_texture);
+      clutter_group_add(CLUTTER_GROUP(app->buttons[i]->actor), a);
+      
+      switch (i)
+        {
+        case 9:
+          g_snprintf(buf, 8, "#");
+          break;
+        case 10:
+          g_snprintf(buf, 8, "0");
+          break;
+        case 11:
+          g_snprintf(buf, 8, "*");
+          break;
+        default:
+          g_snprintf(buf, 8, "%i", i+1);
+          break;
+        }
+
+      a = clutter_text_new_full("Sans Bold 32px", buf, &text_color);
+      clutter_actor_set_position (a, 
+        (clutter_actor_get_width (button_texture)  - clutter_actor_get_width (a))/2,
+        (clutter_actor_get_height (button_texture) - clutter_actor_get_height (a))/2);
+      clutter_group_add (CLUTTER_GROUP (app->buttons[i]->actor), a);
+
+      clutter_group_add (CLUTTER_GROUP (app->screen_dialpad), app->buttons[i]->actor);
+
+      /* need to remember positions for anim - sucky */
+      app->buttons[i]->sx = x + clutter_actor_get_width (app->buttons[i]->actor)/2;
+      app->buttons[i]->sy = y + clutter_actor_get_height (app->buttons[i]->actor)/2;
+      clutter_actor_set_position (app->buttons[i]->actor,
+                                  app->buttons[i]->sx,
+                                  app->buttons[i]->sy);
+
+      /* Really we should use a Clutter*Box here.. */
+      if (i % 3 == 2)
+        {
+          x = xinit;
+          y += (ypad + clutter_actor_get_height (button_texture));
+        }
+      else
+        x += (xpad + clutter_actor_get_width(button_texture));
+
+      app->buttons[i]->face = g_strdup (buf);
+    }
+
+    /*
+     * screen_dial
+     *  +---- (rectangle:black)
+     *  +---- (texture:call-background.png)
+     *  +---- (rectangle:semi transparent)
+     *  +----dial_label (text:"Calling...")
+     */
+
+  app->screen_dial = clutter_group_new();
+  clutter_actor_set_anchor_point_from_gravity (app->screen_dial, CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_position (app->screen_dial, CSW/2, CSH/2);
+
+  a = clutter_rectangle_new_with_color (&black_color);
+  clutter_actor_set_size (a, CSW, CSH);
+  clutter_group_add (CLUTTER_GROUP(app->screen_dial), a);
+
+  a = clutter_texture_new_from_file ("call-background.png", NULL);
+  clutter_group_add (CLUTTER_GROUP(app->screen_dial), a);
+
+  a = clutter_rectangle_new_with_color (&rect_color);
+  clutter_actor_set_size (a, CSW, CSH/6);
+  clutter_actor_set_position (a, 0, (CSH - (CSH/6))/2);
+  clutter_group_add (CLUTTER_GROUP(app->screen_dial), a);
+
+  app->dial_label = clutter_text_new_full ("Sans Bold 32px", "Calling...", &text_color);
+  clutter_actor_set_position (app->dial_label, 10, (CSH - (CSH/6))/2 + 10);
+  clutter_group_add (CLUTTER_GROUP (app->screen_dial), app->dial_label);
+}
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor    *stage;
+  ClutterColor     stage_color = { 0x0, 0x0, 0x0, 0xff };
+
+  App             *app;
+
+  clutter_init (&argc, &argv);
+
+  ALPHA_SINE = clutter_alpha_register_func (alpha_sine_func, NULL);
+  clutter_interval_register_progress_func (G_TYPE_BOOLEAN, boolean_progress);
+
+  app = g_new0(App, 1);
+
+  stage = clutter_stage_get_default ();
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  clutter_actor_set_size (stage, CSW, CSH);
+
+  make_ui (app);
+
+  clutter_group_add (CLUTTER_GROUP(stage), app->screen_dial);
+  clutter_group_add (CLUTTER_GROUP(stage), app->screen_dialpad);
+
+  clutter_actor_hide_all (app->screen_dial);
+  clutter_actor_show_all (stage);
+
+  g_signal_connect (stage, 
+                   "event",
+                   G_CALLBACK (on_input),
+                   app);
+
+  printf("\n..Press '*' to dial..\n\n");
+
+  clutter_main ();
+
+  return 0;
+}
diff --git a/gps-globe/.gitignore b/gps-globe/.gitignore
new file mode 100644 (file)
index 0000000..f73f324
--- /dev/null
@@ -0,0 +1,23 @@
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/config.h
+/config.h.in
+/config.log
+/config.status
+/configure
+/depcomp
+/install-sh
+/missing
+/stamp-h1
+/src/Makefile
+/src/Makefile.in
+/src/gps-globe
+/src/gpsg-enum-types.c
+/src/gpsg-enum-types.h
+/src/stamp-gpsg-enum-types.h
+/src/gpsg-sphere-vertex-shader.c
+
+.deps
+*.o
diff --git a/gps-globe/AUTHORS b/gps-globe/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gps-globe/COPYING b/gps-globe/COPYING
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/gps-globe/ChangeLog b/gps-globe/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gps-globe/INSTALL b/gps-globe/INSTALL
new file mode 100644 (file)
index 0000000..8b82ade
--- /dev/null
@@ -0,0 +1,291 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008 Free Software Foundation, Inc.
+
+   This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  6. Often, you can also type `make uninstall' to remove the installed
+     files again.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *Note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/gps-globe/Makefile.am b/gps-globe/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/gps-globe/NEWS b/gps-globe/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gps-globe/README b/gps-globe/README
new file mode 100644 (file)
index 0000000..a0aeabb
--- /dev/null
@@ -0,0 +1,13 @@
+GpsGlobe
+========
+
+GpsGlobe is a small program to display a GPS position on a 3D model of
+the earth.
+
+Data
+====
+
+The image data for the earth is taken from the NASA Visible Earth
+project here:
+
+http://visibleearth.nasa.gov/view_rec.php?id=2430
diff --git a/gps-globe/autogen.sh b/gps-globe/autogen.sh
new file mode 100755 (executable)
index 0000000..7784749
--- /dev/null
@@ -0,0 +1,14 @@
+#! /bin/sh
+
+PROJECT=gps-globe
+
+AUTORECONF=`which autoreconf`
+
+if test -z "$AUTORECONF"; then
+        echo "*** No autoreconf found ***"
+        exit 1
+else
+        autoreconf -v --install || exit $?
+fi
+
+./configure "$@" && echo "Now type 'make' to compile $PROJECT."
diff --git a/gps-globe/configure.ac b/gps-globe/configure.ac
new file mode 100644 (file)
index 0000000..8aff462
--- /dev/null
@@ -0,0 +1,20 @@
+AC_INIT([gps-globe], 0.1)
+
+AM_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE([1.9])
+
+AC_PROG_CC
+AC_PROG_RANLIB
+
+PKG_CHECK_MODULES(CLUTTER, [clutter-1.0])
+
+AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal])
+AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums])
+
+AC_CONFIG_FILES([
+        Makefile
+        src/Makefile
+])
+
+AC_OUTPUT
diff --git a/gps-globe/data/visible-earth.jpg b/gps-globe/data/visible-earth.jpg
new file mode 100644 (file)
index 0000000..f656b43
Binary files /dev/null and b/gps-globe/data/visible-earth.jpg differ
diff --git a/gps-globe/src/Makefile.am b/gps-globe/src/Makefile.am
new file mode 100644 (file)
index 0000000..5358c61
--- /dev/null
@@ -0,0 +1,54 @@
+bin_PROGRAMS = gps-globe
+
+INCLUDES = \
+       @CLUTTER_CFLAGS@
+
+source_h = \
+       gpsg-sphere.h
+
+gps_globe_SOURCES = \
+       gpsg-main.c \
+       gpsg-sphere.c \
+       gpsg-enum-types.c \
+       gpsg-enum-types.h \
+       gpsg-sphere-vertex-shader.c \
+       gpsg-sphere-vertex-shader.h \
+       $(source_h)
+
+.glsl.c :
+       echo $< | \
+       sed -e 's/-/_/g' -e 's/^\(.\+\)\.glsl$$/const char \1[] =/' > $@ ; \
+       sed -e 's/["\\]/\\&/g' -e 's/^/"/' -e 's/$$/\\n"/' $< >> $@ ; \
+       echo ";" >> $@
+
+gps_globe_LDADD = \
+       @CLUTTER_LIBS@
+
+ENUMFILES = gpsg-enum-types.c gpsg-enum-types.h
+STAMPFILES = stamp-gpsg-enum-types.h
+BUILT_SOURCES = $(ENUMFILES)
+
+gpsg-enum-types.h: stamp-gpsg-enum-types.h
+       @true
+stamp-gpsg-enum-types.h: $(source_h) Makefile
+       $(QUIET_GEN)( $(GLIB_MKENUMS) \
+               --template $(srcdir)/gpsg-enum-types.h.in \
+         $(source_h) ) >> xgen-ceth && \
+       (cmp -s xgen-ceth gpsg-enum-types.h || cp xgen-ceth gpsg-enum-types.h) && \
+       rm -f xgen-ceth && \
+       echo timestamp > $(@F)
+
+gpsg-enum-types.c: gpsg-enum-types.h
+       $(QUIET_GEN)( $(GLIB_MKENUMS) \
+               --template $(srcdir)/gpsg-enum-types.c.in \
+         $(source_h) ) >> xgen-cetc && \
+       cp xgen-cetc gpsg-enum-types.c && \
+       rm -f xgen-cetc
+
+DISTCLEANFILES = \
+       $(ENUMFILES)
+
+EXTRA_DIST = \
+       gpsg-enum-types.h.in \
+       gpsg-enum-types.c.in \
+       gpsg-sphere-vertex-shader.glsl
diff --git a/gps-globe/src/gpsg-enum-types.c.in b/gps-globe/src/gpsg-enum-types.c.in
new file mode 100644 (file)
index 0000000..b8d63bd
--- /dev/null
@@ -0,0 +1,41 @@
+/*** BEGIN file-header ***/
+#include "gpsg-enum-types.h"
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+#include "@filename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type (void)
+{
+  static volatile gsize g_enum_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_enum_type_id__volatile))
+    {
+      static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+        { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+        { 0, NULL, NULL }
+      };
+      GType g_enum_type_id;
+
+      g_enum_type_id =
+        g_@type@_register_static (g_intern_static_string ("@EnumName@"),
+                                  values);
+
+      g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
+    }
+
+  return g_enum_type_id__volatile;
+}
+/*** END value-tail ***/
diff --git a/gps-globe/src/gpsg-enum-types.h.in b/gps-globe/src/gpsg-enum-types.h.in
new file mode 100644 (file)
index 0000000..a8870d1
--- /dev/null
@@ -0,0 +1,26 @@
+/*** BEGIN file-header ***/
+#ifndef __GPSG_ENUM_TYPES_H__
+#define __GPSG_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* !__GPSG_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define GPSG_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+
+/*** END value-header ***/
+
diff --git a/gps-globe/src/gpsg-main.c b/gps-globe/src/gpsg-main.c
new file mode 100644 (file)
index 0000000..61f8ccf
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * gps-globe - A little app showing your position on a globe
+ * Copyright (C) 2009  Intel Corporation
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <clutter/clutter.h>
+
+#include "gpsg-sphere.h"
+
+static int tex_num;
+static int n_tex;
+static char **tex;
+
+static void
+on_paint (ClutterActor *actor)
+{
+  ClutterGeometry geom;
+
+  clutter_actor_get_allocation_geometry (actor, &geom);
+
+  cogl_set_source_color4ub (0, 0, 255, 255);
+}
+
+static gboolean
+set_tex (ClutterActor *sphere)
+{
+  if (n_tex > 0)
+    {
+      GError *error = NULL;
+
+      clutter_texture_set_from_file (CLUTTER_TEXTURE (sphere),
+                                     tex[tex_num++],
+                                     &error);
+
+      if (error)
+        {
+          g_warning ("%s", error->message);
+          g_error_free (error);
+        }
+
+      if (tex_num >= n_tex)
+        tex_num = 0;
+    }
+
+  return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+  ClutterActor *stage;
+  ClutterActor *sphere;
+  ClutterAnimation *anim;
+  ClutterVertex center = { 240, 240, 0 };
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+
+  sphere = gpsg_sphere_new ();
+  g_object_set (sphere,
+                "depth", 3,
+                "paint-flags", (GPSG_SPHERE_PAINT_LINES
+                                | GPSG_SPHERE_PAINT_TEXTURE),
+                NULL);
+  clutter_actor_set_size (sphere, 480, 480);
+  g_signal_connect_after (sphere, "paint",
+                          G_CALLBACK (on_paint), NULL);
+  clutter_actor_set_position (sphere,
+                              clutter_actor_get_width (stage) / 2.0 - 240,
+                              clutter_actor_get_height (stage) / 2.0 - 240);
+  anim = clutter_actor_animate (sphere, CLUTTER_LINEAR, 8000,
+                                "rotation-angle-y", 360.0,
+                                "fixed::rotation-center-y", &center,
+                                NULL);
+  clutter_animation_set_loop (anim, TRUE);
+
+  n_tex = argc - 1;
+  tex = argv + 1;
+  tex_num = 0;
+
+  set_tex (sphere);
+
+  g_signal_connect_swapped (stage, "button-press-event",
+                            G_CALLBACK (set_tex), sphere);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), sphere);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  return 0;
+}
diff --git a/gps-globe/src/gpsg-sphere-vertex-shader.glsl b/gps-globe/src/gpsg-sphere-vertex-shader.glsl
new file mode 100644 (file)
index 0000000..46d4f50
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * gps-globe - A little app showing your position on a globe
+ * Copyright (C) 2009  Intel Corporation
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 'flatness' should be a number from 0.0 -> 1.0. If it is 0.0 the
+   model will be rendered as a sphere, or if it is 1.0 it will be
+   rendered as a flat model. Otherwise it will be rendered somewhere
+   in-between the two. */
+uniform float flatness;
+
+/* size of the model when it is rendered completely flat */
+uniform float flat_width;
+uniform float flat_height;
+
+/* radius of the sphere */
+uniform float sphere_radius;
+
+void
+main ()
+{
+  vec3 sphere_position = gl_Vertex.xyz * sphere_radius;
+
+  vec3 flat_position;
+  flat_position.xyz = vec3 (vec2 (flat_width, flat_height)
+                            * (gl_MultiTexCoord0.xy - vec2 (0.5, 0.5)),
+                            0.0);
+
+  /* Linear interpolation between the flat position and sphere position */
+  vec4 lerp_position;
+  lerp_position = vec4 (mix (sphere_position, flat_position, flatness), 1.0);
+
+  gl_Position = gl_ModelViewProjectionMatrix * vec4 (lerp_position, 1.0);
+  gl_TexCoord[0] = gl_MultiTexCoord0;
+  gl_FrontColor = gl_Color;
+}
diff --git a/gps-globe/src/gpsg-sphere-vertex-shader.h b/gps-globe/src/gpsg-sphere-vertex-shader.h
new file mode 100644 (file)
index 0000000..4df21af
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * gps-globe - A little app showing your position on a globe
+ * Copyright (C) 2009  Intel Corporation
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GPSG_SPHERE_VERTEX_SHADER_H__
+#define __GPSG_SPHERE_VERTEX_SHADER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+extern const char gpsg_sphere_vertex_shader[];
+
+G_END_DECLS
+
+#endif /* __GPSG_SPHERE_VERTEX_SHADER_H__ */
diff --git a/gps-globe/src/gpsg-sphere.c b/gps-globe/src/gpsg-sphere.c
new file mode 100644 (file)
index 0000000..bfb9181
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ * gps-globe - A little app showing your position on a globe
+ * Copyright (C) 2009  Intel Corporation
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <clutter/clutter.h>
+#include <math.h>
+#include <string.h>
+
+#include "gpsg-sphere.h"
+#include "gpsg-enum-types.h"
+#include "gpsg-sphere-vertex-shader.h"
+
+#define GPSG_SPHERE_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GPSG_TYPE_SPHERE, GpsgSpherePrivate))
+
+G_DEFINE_TYPE (GpsgSphere, gpsg_sphere, CLUTTER_TYPE_TEXTURE);
+
+static void gpsg_sphere_paint (ClutterActor *self);
+static void gpsg_sphere_dispose (GObject *self);
+
+static void gpsg_sphere_set_property (GObject      *self,
+                                     guint         property_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec);
+static void gpsg_sphere_get_property (GObject    *self,
+                                     guint       property_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec);
+
+#define GPSG_SPHERE_GOLDEN_RATIO      1.61803398874989  /* φ = (1+√5) ÷ 2 */
+/* Amount to scale a vertex using the golden ratio so that it will
+   have a radius of one. */
+#define GPSG_SPHERE_NORM_ONE          0.525731112119134 /* = √(1 / (1 + φ²)) */
+#define GPSG_SPHERE_NORM_GOLDEN_RATIO (GPSG_SPHERE_GOLDEN_RATIO \
+                                       * GPSG_SPHERE_NORM_ONE)
+
+struct _GpsgSpherePrivate
+{
+  guint depth;
+  guint n_vertices, n_indices;
+  CoglHandle vertices, indices;
+  ClutterColor lines_color;
+  GpsgSpherePaintFlags paint_flags;
+
+  /* A shader program use to render the transition between a flat
+     texture and a sphere */
+  CoglHandle flat_program;
+  /* Set to true if shaders aren't available or it won't compile */
+  gboolean shader_failed;
+
+  gint flatness_uniform;
+  gint flat_width_uniform;
+  gint flat_height_uniform;
+  gint sphere_radius_uniform;
+
+  gfloat flatness;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_PAINT_FLAGS,
+  PROP_LINES_COLOR,
+  PROP_DEPTH,
+  PROP_FLATNESS
+};
+
+static void
+gpsg_sphere_class_init (GpsgSphereClass *klass)
+{
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  actor_class->paint = gpsg_sphere_paint;
+
+  object_class->dispose = gpsg_sphere_dispose;
+  object_class->set_property = gpsg_sphere_set_property;
+  object_class->get_property = gpsg_sphere_get_property;
+
+  g_type_class_add_private (klass, sizeof (GpsgSpherePrivate));
+
+  pspec = g_param_spec_uint ("depth", "Depth",
+                             "The number of times to subdivide each "
+                             "triangle. Higher numbers mean better looking "
+                             "spheres that consume more resources.",
+                             0, G_MAXUINT, 4,
+                             G_PARAM_READWRITE
+                             | G_PARAM_STATIC_NAME
+                             | G_PARAM_STATIC_NICK
+                             | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_DEPTH, pspec);
+
+  pspec = g_param_spec_float ("flatness", "Flatness",
+                              "A value between 0.0 and 1.0. Zero paints the "
+                              "texture normally and 1.0 paints it as a "
+                              "sphere. Other values mix between the two.",
+                              0.0f, 1.0f, 0.0f,
+                              G_PARAM_READWRITE
+                              | G_PARAM_STATIC_NAME
+                              | G_PARAM_STATIC_NICK
+                              | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_FLATNESS, pspec);
+
+  pspec = g_param_spec_flags ("paint-flags", "Paint flags",
+                              "A set of flags describing what parts of the "
+                              "sphere to paint.",
+                              GPSG_TYPE_SPHERE_PAINT_FLAGS,
+                              GPSG_SPHERE_PAINT_TEXTURE,
+                              G_PARAM_READWRITE
+                              | G_PARAM_STATIC_NAME
+                              | G_PARAM_STATIC_NICK
+                              | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_PAINT_FLAGS, pspec);
+
+  pspec = g_param_spec_boxed ("lines-color", "Lines color",
+                              "Color to use when painting a wireframe of the "
+                              "sphere.",
+                              CLUTTER_TYPE_COLOR,
+                              G_PARAM_READWRITE
+                              | G_PARAM_STATIC_NAME
+                              | G_PARAM_STATIC_NICK
+                              | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_LINES_COLOR, pspec);
+}
+
+static void
+gpsg_sphere_init (GpsgSphere *self)
+{
+  GpsgSpherePrivate *priv;
+
+  self->priv = priv = GPSG_SPHERE_GET_PRIVATE (self);
+
+  priv->depth = 4;
+  priv->vertices = COGL_INVALID_HANDLE;
+  priv->indices = COGL_INVALID_HANDLE;
+  priv->lines_color.alpha = 255;
+  priv->paint_flags = GPSG_SPHERE_PAINT_TEXTURE;
+}
+
+static void
+gpsg_sphere_set_property (GObject      *self,
+                         guint         property_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  GpsgSphere *sphere = GPSG_SPHERE (self);
+
+  switch (property_id)
+    {
+    case PROP_DEPTH:
+      gpsg_sphere_set_depth (sphere, g_value_get_uint (value));
+      break;
+
+    case PROP_FLATNESS:
+      gpsg_sphere_set_flatness (sphere, g_value_get_float (value));
+      break;
+
+    case PROP_PAINT_FLAGS:
+      gpsg_sphere_set_paint_flags (sphere, g_value_get_flags (value));
+      break;
+
+    case PROP_LINES_COLOR:
+      gpsg_sphere_set_lines_color (sphere, clutter_value_get_color (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gpsg_sphere_get_property (GObject    *self,
+                         guint       property_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  GpsgSphere *sphere = GPSG_SPHERE (self);
+
+  switch (property_id)
+    {
+    case PROP_DEPTH:
+      g_value_set_uint (value, gpsg_sphere_get_depth (sphere));
+      break;
+
+    case PROP_FLATNESS:
+      g_value_set_float (value, gpsg_sphere_get_flatness (sphere));
+      break;
+
+    case PROP_PAINT_FLAGS:
+      g_value_set_flags (value, gpsg_sphere_get_paint_flags (sphere));
+      break;
+
+    case PROP_LINES_COLOR:
+      {
+        ClutterColor color;
+        gpsg_sphere_get_lines_color (sphere, &color);
+        clutter_value_set_color (value, &color);
+      }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+      break;
+    }
+}
+
+ClutterActor *
+gpsg_sphere_new (void)
+{
+  return g_object_new (GPSG_TYPE_SPHERE, NULL);
+}
+
+typedef struct _GpsgSphereStackEntry
+{
+  /* Index of the three edges that make up the triangle */
+  guint16 e[3];
+  /* The recursion depth that was needed to add this entry */
+  guint8 depth;
+  /* A bit for each edge. If set then use v1, otherwise v0 */
+  guint8 direction;
+} GpsgSphereStackEntry;
+
+typedef struct _GpsgSphereVertex
+{
+  /* Vertex coordinates */
+  gfloat x, y, z;
+  /* Texture coordinates */
+  gfloat tx, ty;
+} GpsgSphereVertex;
+
+typedef struct _GpsgSphereEdge
+{
+  /* Index of the two vertices that make up this edge */
+  guint16 v0, v1;
+  /* Index of two edges that subdivide this edge, or -1 if it hasn't
+     been divided yet */
+  gint16 e0, e1;
+} GpsgSphereEdge;
+
+/* Initial edges needed to make an icosahedron */
+static const GpsgSphereEdge
+gpsg_sphere_ico_edges[] =
+{
+  { 0, 2, -1, -1 }, { 0, 4, -1, -1 }, { 0, 6, -1, -1 }, { 0, 8, -1, -1 },
+  { 0, 9, -1, -1 }, { 1, 3, -1, -1 }, { 1, 4, -1, -1 }, { 1, 6, -1, -1 },
+  { 1, 10, -1, -1 }, { 1, 11, -1, -1 }, { 2, 5, -1, -1 }, { 2, 7, -1, -1 },
+  { 2, 8, -1, -1 }, { 2, 9, -1, -1 }, { 3, 5, -1, -1 }, { 3, 7, -1, -1 },
+  { 3, 10, -1, -1 }, { 3, 11, -1, -1 }, { 4, 6, -1, -1 }, { 4, 8, -1, -1 },
+  { 4, 10, -1, -1 }, { 5, 7, -1, -1 }, { 5, 8, -1, -1 }, { 5, 10, -1, -1 },
+  { 6, 9, -1, -1 }, { 6, 11, -1, -1 }, { 7, 9, -1, -1 }, { 7, 11, -1, -1 },
+  { 8, 10, -1, -1 }, { 9, 11, -1, -1 }
+};
+
+/* Initial triangles needed to make an icosahedron with all the
+   vertices in anti-clockwise order */
+static const GpsgSphereStackEntry
+gpsg_sphere_ico_stack_entries[] =
+{
+  { { 17, 9, 5 }, 0, 2 }, { { 8, 16, 5 }, 0, 6 }, { { 14, 16, 23 }, 0, 5 },
+  { { 21, 15, 14 }, 0, 2 }, { { 27, 17, 15 }, 0, 2 }, { { 11, 21, 10 }, 0, 6 },
+  { { 12, 10, 22 }, 0, 1 }, { { 22, 23, 28 }, 0, 5 }, { { 19, 28, 20 }, 0, 4 },
+  { { 20, 8, 6 }, 0, 2 }, { { 18, 6, 7 }, 0, 3 }, { { 7, 9, 25 }, 0, 5 },
+  { { 24, 25, 29 }, 0, 5 }, { { 29, 27, 26 }, 0, 2 }, { { 26, 11, 13 }, 0, 3 },
+  { { 0, 4, 13 }, 0, 5 }, { { 4, 2, 24 }, 0, 1 }, { { 1, 18, 2 }, 0, 4 },
+  { { 3, 19, 1 }, 0, 6 }, { { 12, 3, 0 }, 0, 2 }
+};
+
+/* This helper macro is just used to abbreviate getting a vertex out
+   of the GArray */
+#define VERT(x) g_array_index (vertices, GpsgSphereVertex, (x))
+
+static void
+gpsg_sphere_ensure_vertices (GpsgSphere *sphere)
+{
+  GpsgSpherePrivate *priv = sphere->priv;
+  guint n_triangles;
+  guint n_indices;
+  guint n_edges;
+  GpsgSphereStackEntry *stack, *stack_pos, *max_stack_pos;
+  guint stack_size;
+  GArray *vertices;
+  GpsgSphereVertex *vertices_pos;
+  guint16 *indices, *indices_pos;
+  GpsgSphereEdge *edges, *edges_pos;
+  int i;
+
+  /* Don't do anything if we've already got the vertices */
+  if (priv->vertices != COGL_INVALID_HANDLE)
+    return;
+
+  n_triangles = 20 * powf (4, priv->depth) + 0.5f;
+  n_edges = 0;
+  for (i = 0; i <= priv->depth; i++)
+    n_edges += 30 * powf (4, i) + 0.5f;
+  n_indices = n_triangles * 3;
+  stack_size = priv->depth * 3 + 20;
+  stack = g_new (GpsgSphereStackEntry, stack_size);
+  indices_pos = indices = g_new (guint16, n_indices);
+  vertices = g_array_new (FALSE, FALSE, sizeof (GpsgSphereVertex));
+  edges = g_new (GpsgSphereEdge, n_edges + 100);
+
+  /* Add the initial 12 vertices needed to make an icosahedron */
+  g_array_set_size (vertices, 12);
+  vertices_pos = &VERT (0);
+  {
+    int unit, magic;
+
+    for (unit = -1; unit <= 1; unit += 2)
+      for (magic = -1; magic <= 1; magic += 2)
+        {
+          vertices_pos->x = 0;
+          vertices_pos->y = unit * GPSG_SPHERE_NORM_ONE;
+          vertices_pos->z = magic * GPSG_SPHERE_NORM_GOLDEN_RATIO;
+          vertices_pos++;
+        }
+    for (unit = -1; unit <= 1; unit += 2)
+      for (magic = -1; magic <= 1; magic += 2)
+        {
+          vertices_pos->x = unit * GPSG_SPHERE_NORM_ONE;
+          vertices_pos->y = magic * GPSG_SPHERE_NORM_GOLDEN_RATIO;
+          vertices_pos->z = 0;
+          vertices_pos++;
+        }
+    for (unit = -1; unit <= 1; unit += 2)
+      for (magic = -1; magic <= 1; magic += 2)
+        {
+          vertices_pos->x = magic * GPSG_SPHERE_NORM_GOLDEN_RATIO;
+          vertices_pos->y = 0;
+          vertices_pos->z = unit * GPSG_SPHERE_NORM_ONE;
+          vertices_pos++;
+        }
+  }
+
+  /* Add the initial edges */
+  memcpy (edges, gpsg_sphere_ico_edges, sizeof (gpsg_sphere_ico_edges));
+  edges_pos = edges + G_N_ELEMENTS (gpsg_sphere_ico_edges);
+  /* and stack entries */
+  memcpy (stack, gpsg_sphere_ico_stack_entries,
+          sizeof (gpsg_sphere_ico_stack_entries));
+  stack_pos = stack + G_N_ELEMENTS (gpsg_sphere_ico_stack_entries);
+
+  max_stack_pos = stack_pos;
+
+  /* While the stack is not empty */
+  while (stack_pos > stack)
+    {
+      /* Pop an entry off the stack */
+      GpsgSphereStackEntry entry = *(--stack_pos);
+
+      /* If we've reached the depth limit.. */
+      if (entry.depth >= priv->depth)
+        /* Add the triangle to the vertices */
+        for (i = 0; i < 3; i++)
+          *(indices_pos++) = ((entry.direction & (1 << i))
+                              ? edges[entry.e[i]].v1
+                              : edges[entry.e[i]].v0);
+      else
+        {
+          /* If the stack is not empty then add four more triangles
+             to split this one up */
+
+          /* Split each edge if it is not already split */
+          for (i = 0; i < 3; i++)
+            if (edges[entry.e[i]].e0 == -1)
+              {
+                g_array_set_size (vertices, vertices->len + 1);
+                vertices_pos = &VERT (vertices->len - 1);
+                vertices_pos->x = (VERT (edges[entry.e[i]].v0).x
+                                   + VERT (edges[entry.e[i]].v1).x) / 2.0;
+                vertices_pos->y = (VERT (edges[entry.e[i]].v0).y
+                                   + VERT (edges[entry.e[i]].v1).y) / 2.0;
+                vertices_pos->z = (VERT (edges[entry.e[i]].v0).z
+                                   + VERT (edges[entry.e[i]].v1).z) / 2.0;
+                edges[entry.e[i]].e0 = edges_pos - edges;
+                edges_pos->v0 = edges[entry.e[i]].v0;
+                edges_pos->v1 = vertices->len - 1;
+                edges_pos->e0 = -1;
+                edges_pos->e1 = -1;
+                edges_pos++;
+                edges[entry.e[i]].e1 = edges_pos - edges;
+                edges_pos->v0 = edges[entry.e[i]].v1;
+                edges_pos->v1 = vertices->len - 1;
+                edges_pos->e0 = -1;
+                edges_pos->e1 = -1;
+                edges_pos++;
+              }
+
+          /* Add each triangle */
+
+          /* Top triangle */
+          if ((entry.direction & 1))
+            stack_pos->e[0] = edges[entry.e[0]].e1;
+          else
+            stack_pos->e[0] = edges[entry.e[0]].e0;
+          stack_pos->e[1] = edges_pos - edges;
+          edges_pos->v0 = edges[edges[entry.e[0]].e0].v1;
+          edges_pos->v1 = edges[edges[entry.e[2]].e0].v1;
+          if (edges_pos->v0 > edges_pos->v1)
+            {
+              gint t = edges_pos->v0;
+              edges_pos->v0 = edges_pos->v1;
+              edges_pos->v1 = t;
+              stack_pos->direction = 6;
+            }
+          else
+            stack_pos->direction = 4;
+          edges_pos->e0 = -1;
+          edges_pos->e1 = -1;
+          edges_pos++;
+          if ((entry.direction & 4))
+            stack_pos->e[2] = edges[entry.e[2]].e0;
+          else
+            stack_pos->e[2] = edges[entry.e[2]].e1;
+          stack_pos->depth = entry.depth + 1;
+          stack_pos++;
+
+          /* Bottom left triangle */
+          if ((entry.direction & 1))
+            stack_pos->e[0] = edges[entry.e[0]].e0;
+          else
+            stack_pos->e[0] = edges[entry.e[0]].e1;
+          if ((entry.direction & 2))
+            stack_pos->e[1] = edges[entry.e[1]].e1;
+          else
+            stack_pos->e[1] = edges[entry.e[1]].e0;
+          stack_pos->e[2] = edges_pos - edges;
+          edges_pos->v0 = edges[edges[entry.e[1]].e0].v1;
+          edges_pos->v1 = edges[edges[entry.e[0]].e0].v1;
+          if (edges_pos->v0 > edges_pos->v1)
+            {
+              gint t = edges_pos->v0;
+              edges_pos->v0 = edges_pos->v1;
+              edges_pos->v1 = t;
+              stack_pos->direction = 5;
+            }
+          else
+            stack_pos->direction = 1;
+          edges_pos->e0 = -1;
+          edges_pos->e1 = -1;
+          edges_pos++;
+          stack_pos->depth = entry.depth + 1;
+          stack_pos++;
+
+          /* Bottom right triangle */
+          stack_pos->e[0] = edges_pos - edges;
+          edges_pos->v0 = edges[edges[entry.e[2]].e0].v1;
+          edges_pos->v1 = edges[edges[entry.e[1]].e0].v1;
+          if (edges_pos->v0 > edges_pos->v1)
+            {
+              gint t = edges_pos->v0;
+              edges_pos->v0 = edges_pos->v1;
+              edges_pos->v1 = t;
+              stack_pos->direction = 3;
+            }
+          else
+            stack_pos->direction = 2;
+          edges_pos->e0 = -1;
+          edges_pos->e1 = -1;
+          edges_pos++;
+          if ((entry.direction & 2))
+            stack_pos->e[1] = edges[entry.e[1]].e0;
+          else
+            stack_pos->e[1] = edges[entry.e[1]].e1;
+          if ((entry.direction & 4))
+            stack_pos->e[2] = edges[entry.e[2]].e1;
+          else
+            stack_pos->e[2] = edges[entry.e[2]].e0;
+          stack_pos->depth = entry.depth + 1;
+          stack_pos++;
+
+          /* Middle triangle */
+          stack_pos->e[0] = stack_pos[-1].e[0];
+          stack_pos->e[1] = stack_pos[-3].e[1];
+          stack_pos->e[2] = stack_pos[-2].e[2];
+          stack_pos->depth = entry.depth + 1;
+          stack_pos->direction = ((stack_pos[-1].direction & 1)
+                                  | (stack_pos[-3].direction & 2)
+                                  | (stack_pos[-2].direction & 4)) ^ 7;
+          stack_pos++;
+
+          /* This is just used for the assert below */
+          if (stack_pos > max_stack_pos)
+            max_stack_pos = stack_pos;
+        }
+    }
+
+  /* Normalise every vertex. The initial 12 are already normalised */
+  for (i = 12; i < vertices->len; i++)
+    {
+      gfloat length;
+
+      vertices_pos = &VERT (i);
+
+      length = sqrt (vertices_pos->x * vertices_pos->x
+                     + vertices_pos->y * vertices_pos->y
+                     + vertices_pos->z * vertices_pos->z);
+      vertices_pos->x /= length;
+      vertices_pos->y /= length;
+      vertices_pos->z /= length;
+    }
+
+  /* Calculate texture coordinates */
+  for (i = 0; i < vertices->len; i++)
+    {
+      vertices_pos = &VERT (i);
+
+      vertices_pos->tx = (atan2 (vertices_pos->x, vertices_pos->z)
+                          / G_PI / 2.0 + 0.5);
+      vertices_pos->ty = asin (vertices_pos->y) / G_PI + 0.5;
+    }
+
+  /* Fix all of the triangles along the seam. If a triangle contains
+     vertices with texture coordinates that wrap the long way from
+     0->1 then we need to duplicate one of them to extend the texture
+     coordinate past 1 so that it will vary across the span
+     correctly */
+  for (i = 0; i < n_indices; i += 3)
+    {
+      gfloat min_tx = G_MAXDOUBLE, max_tx = -G_MAXDOUBLE;
+      int v;
+
+      for (v = 0; v < 3; v++)
+        {
+          gfloat tx = VERT (indices[i + v]).tx;
+          if (tx < min_tx)
+            min_tx = tx;
+          if (tx > max_tx)
+            max_tx = tx;
+        }
+
+      /* If the span is greater than half of the texture then it would
+         be shorter to wrap around instead */
+      if (max_tx - min_tx > 0.5f)
+        {
+          int n_left = 0, n_right = 0, left, right;
+          gfloat tx_diff;
+
+          /* Find the odd one out */
+          for (v = 0; v < 3; v++)
+            if (VERT (indices[i + v]).tx < 0.5f)
+              {
+                n_left++;
+                left = v;
+              }
+            else
+              {
+                n_right++;
+                right = v;
+              }
+
+          /* Duplicate whichever side is the odd one out */
+          if (n_left == 1)
+            {
+              v = left;
+              tx_diff = 1.0f;
+            }
+          else
+            {
+              v = right;
+              tx_diff = -1.0f;
+            }
+
+          /* Duplicate it with a different tx */
+          g_array_set_size (vertices, vertices->len + 1);
+          vertices_pos = &VERT (vertices->len - 1);
+          *vertices_pos = VERT (indices[i + v]);
+          vertices_pos->tx += tx_diff;
+          indices[i + v] = vertices->len - 1;
+        }
+    }
+
+  /* Create the VBO */
+  vertices_pos = &VERT (0);
+  priv->vertices = cogl_vertex_buffer_new (vertices->len);
+  cogl_vertex_buffer_add (priv->vertices, "gl_Vertex", 3,
+                          COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
+                          sizeof (GpsgSphereVertex),
+                          &vertices_pos->x);
+  cogl_vertex_buffer_add (priv->vertices, "gl_MultiTexCoord0", 2,
+                          COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
+                          sizeof (GpsgSphereVertex),
+                          &vertices_pos->tx);
+  /* The normals are the same as the untransformed vertices */
+  cogl_vertex_buffer_add (priv->vertices, "gl_Normal", 3,
+                          COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
+                          sizeof (GpsgSphereVertex),
+                          &vertices_pos->x);
+  cogl_vertex_buffer_submit (priv->vertices);
+
+  priv->n_vertices = vertices->len;
+  priv->n_indices = n_indices;
+
+  priv->indices
+    = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
+                                      indices, n_indices);
+
+  /* Make sure that we allocated exactly the right amount of memory */
+  g_assert (edges_pos == edges + n_edges);
+  g_assert (indices_pos == indices + n_indices);
+  g_assert (max_stack_pos == stack + stack_size);
+
+  g_free (edges);
+  g_array_free (vertices, TRUE);
+  g_free (indices);
+  g_free (stack);
+}
+
+#undef VERT
+
+static gboolean
+gpsg_sphere_compile_program (GpsgSphere *sphere)
+{
+  GpsgSpherePrivate *priv = sphere->priv;
+  CoglHandle shader;
+  gboolean ret = TRUE;
+
+  /* If we've previously failed to create a shader then don't try
+     again */
+  if (priv->shader_failed)
+    ret = FALSE;
+  /* If we've already got the program then we don't need to do
+     anything */
+  else if (priv->flat_program == COGL_INVALID_HANDLE)
+    {
+      shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX);
+
+      if (shader == COGL_INVALID_HANDLE)
+        {
+          g_warning ("Failed to create shader");
+          priv->shader_failed = TRUE;
+          ret = FALSE;
+        }
+      else
+        {
+          cogl_shader_source (shader, gpsg_sphere_vertex_shader);
+          cogl_shader_compile (shader);
+
+          if (cogl_shader_is_compiled (shader))
+            {
+              priv->flat_program = cogl_create_program ();
+              cogl_program_attach_shader (priv->flat_program, shader);
+              cogl_program_link (priv->flat_program);
+
+              if ((priv->flatness_uniform
+                   = cogl_program_get_uniform_location (priv->flat_program,
+                                                        "flatness")) == -1
+                  || (priv->flat_width_uniform
+                      = cogl_program_get_uniform_location (priv->flat_program,
+                                                           "flat_width")) == -1
+                  || (priv->flat_height_uniform
+                      = cogl_program_get_uniform_location (priv->flat_program,
+                                                           "flat_height")) == -1
+                  || ((priv->sphere_radius_uniform
+                       = cogl_program_get_uniform_location (priv->flat_program,
+                                                            "sphere_radius"))
+                      == -1))
+                {
+                  g_warning ("Shader is missing some uniforms");
+                  cogl_handle_unref (priv->flat_program);
+                  priv->flat_program = COGL_INVALID_HANDLE;
+                  priv->shader_failed = TRUE;
+                  ret = FALSE;
+                }
+            }
+          else
+            {
+              gchar *info_log = cogl_shader_get_info_log (shader);
+              g_warning ("%s", info_log);
+              g_free (info_log);
+              priv->shader_failed = TRUE;
+              ret = FALSE;
+            }
+
+          cogl_handle_unref (shader);
+        }
+    }
+
+  return ret;
+}
+
+static void
+gpsg_sphere_paint (ClutterActor *self)
+{
+  GpsgSphere *sphere = GPSG_SPHERE (self);
+  GpsgSpherePrivate *priv = sphere->priv;
+
+  /* If the sphere is completely flat we can just use the regular
+     texture paint method */
+  if (priv->flatness >= 1.0f)
+    {
+      if (CLUTTER_ACTOR_CLASS (gpsg_sphere_parent_class)->paint)
+        CLUTTER_ACTOR_CLASS (gpsg_sphere_parent_class)->paint (self);
+    }
+  else
+    {
+      ClutterGeometry geom;
+      CoglHandle material;
+      gboolean backface_culling_was_enabled;
+      gfloat sphere_radius;
+      gboolean use_shader;
+      guint8 paint_opacity;
+
+      clutter_actor_get_allocation_geometry (self, &geom);
+      paint_opacity = clutter_actor_get_paint_opacity (self);
+
+      sphere_radius = MIN (geom.width, geom.height) / 2.0f;
+
+      gpsg_sphere_ensure_vertices (sphere);
+
+      backface_culling_was_enabled = cogl_get_backface_culling_enabled ();
+      cogl_set_backface_culling_enabled (TRUE);
+
+      use_shader = (priv->flatness > 0.0f
+                    && gpsg_sphere_compile_program (sphere));
+
+      cogl_push_matrix ();
+      cogl_translate (geom.width / 2.0f, geom.height / 2.0f, 0.0f);
+
+      if (use_shader)
+        {
+          cogl_program_use (priv->flat_program);
+          cogl_program_uniform_1f (priv->flatness_uniform, priv->flatness);
+          cogl_program_uniform_1f (priv->flat_width_uniform, geom.width);
+          cogl_program_uniform_1f (priv->flat_height_uniform, geom.height);
+          cogl_program_uniform_1f (priv->sphere_radius_uniform, sphere_radius);
+        }
+      else
+        cogl_scale (sphere_radius, sphere_radius, sphere_radius);
+
+      if ((priv->paint_flags & GPSG_SPHERE_PAINT_TEXTURE))
+        {
+          material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (self));
+
+          cogl_material_set_color4ub (material,
+                                      paint_opacity,
+                                      paint_opacity,
+                                      paint_opacity,
+                                      paint_opacity);
+
+          if (material != COGL_INVALID_HANDLE)
+            {
+              cogl_set_source (material);
+
+              cogl_vertex_buffer_draw_elements (priv->vertices,
+                                                COGL_VERTICES_MODE_TRIANGLES,
+                                                priv->indices,
+                                                0, priv->n_vertices - 1,
+                                                0, priv->n_indices);
+            }
+        }
+
+      if ((priv->paint_flags & GPSG_SPHERE_PAINT_LINES))
+        {
+          int i;
+          CoglColor color;
+
+          cogl_color_set_from_4ub (&color,
+                                   priv->lines_color.red,
+                                   priv->lines_color.green,
+                                   priv->lines_color.blue,
+                                   priv->lines_color.alpha
+                                   * paint_opacity / 255);
+          cogl_color_premultiply (&color);
+          cogl_set_source_color (&color);
+
+          /* If we could set the polygon mode this could be done with
+             triangles in a single call instead */
+          for (i = 0; i + 3 <= priv->n_indices; i += 3)
+            cogl_vertex_buffer_draw_elements (priv->vertices,
+                                              COGL_VERTICES_MODE_LINE_LOOP,
+                                              priv->indices,
+                                              0, priv->n_vertices - 1,
+                                              i, 3);
+        }
+
+      if (use_shader)
+        cogl_program_use (COGL_INVALID_HANDLE);
+
+      cogl_pop_matrix ();
+
+     cogl_set_backface_culling_enabled (backface_culling_was_enabled);
+    }
+}
+
+static void
+gpsg_sphere_forget_vertices (GpsgSphere *sphere)
+{
+  GpsgSpherePrivate *priv = sphere->priv;
+
+  if (priv->vertices != COGL_INVALID_HANDLE)
+    {
+      cogl_handle_unref (priv->vertices);
+      cogl_handle_unref (priv->indices);
+      priv->vertices = COGL_INVALID_HANDLE;
+      priv->indices = COGL_INVALID_HANDLE;
+    }
+}
+
+static void
+gpsg_sphere_dispose (GObject *self)
+{
+  GpsgSphere *sphere = GPSG_SPHERE (self);
+  GpsgSpherePrivate *priv = sphere->priv;
+
+  gpsg_sphere_forget_vertices (sphere);
+
+  if (priv->flat_program != COGL_INVALID_HANDLE)
+    {
+      cogl_handle_unref (priv->flat_program);
+      priv->flat_program = COGL_INVALID_HANDLE;
+    }
+
+  G_OBJECT_CLASS (gpsg_sphere_parent_class)->dispose (self);
+}
+
+guint
+gpsg_sphere_get_depth (GpsgSphere *sphere)
+{
+  g_return_val_if_fail (GPSG_IS_SPHERE (sphere), 0);
+
+  return sphere->priv->depth;
+}
+
+void
+gpsg_sphere_set_depth (GpsgSphere *sphere, guint depth)
+{
+  GpsgSpherePrivate *priv;
+
+  g_return_if_fail (GPSG_IS_SPHERE (sphere));
+
+  priv = sphere->priv;
+
+  if (depth != priv->depth)
+    {
+      gpsg_sphere_forget_vertices (sphere);
+      priv->depth = depth;
+      clutter_actor_queue_redraw (CLUTTER_ACTOR (sphere));
+      g_object_notify (G_OBJECT (sphere), "depth");
+    }
+}
+
+gfloat
+gpsg_sphere_get_flatness (GpsgSphere *sphere)
+{
+  g_return_val_if_fail (GPSG_IS_SPHERE (sphere), 0);
+
+  return sphere->priv->flatness;
+}
+
+void
+gpsg_sphere_set_flatness (GpsgSphere *sphere, gfloat flatness)
+{
+  GpsgSpherePrivate *priv;
+
+  g_return_if_fail (GPSG_IS_SPHERE (sphere));
+
+  priv = sphere->priv;
+
+  if (flatness != priv->flatness)
+    {
+      priv->flatness = flatness;
+      clutter_actor_queue_redraw (CLUTTER_ACTOR (sphere));
+      g_object_notify (G_OBJECT (sphere), "flatness");
+    }
+}
+
+GpsgSpherePaintFlags
+gpsg_sphere_get_paint_flags (GpsgSphere *sphere)
+{
+  g_return_val_if_fail (GPSG_IS_SPHERE (sphere), 0);
+
+  return sphere->priv->paint_flags;
+}
+
+void
+gpsg_sphere_set_paint_flags (GpsgSphere *sphere,
+                             GpsgSpherePaintFlags flags)
+{
+  GpsgSpherePrivate *priv;
+
+  g_return_if_fail (GPSG_IS_SPHERE (sphere));
+
+  priv = sphere->priv;
+
+  if (flags != priv->paint_flags)
+    {
+      priv->paint_flags = flags;
+      clutter_actor_queue_redraw (CLUTTER_ACTOR (sphere));
+      g_object_notify (G_OBJECT (sphere), "paint-flags");
+    }
+}
+
+void
+gpsg_sphere_get_lines_color (GpsgSphere *sphere,
+                             ClutterColor *color)
+{
+  g_return_if_fail (GPSG_IS_SPHERE (sphere));
+
+  *color = sphere->priv->lines_color;
+}
+
+void
+gpsg_sphere_set_lines_color (GpsgSphere *sphere,
+                             const ClutterColor *color)
+{
+  GpsgSpherePrivate *priv;
+
+  g_return_if_fail (GPSG_IS_SPHERE (sphere));
+
+  priv = sphere->priv;
+
+  if (!clutter_color_equal (color, &priv->lines_color))
+    {
+      priv->lines_color = *color;
+      if (priv->paint_flags & GPSG_SPHERE_PAINT_LINES)
+        clutter_actor_queue_redraw (CLUTTER_ACTOR (sphere));
+      g_object_notify (G_OBJECT (sphere), "lines-color");
+    }
+}
diff --git a/gps-globe/src/gpsg-sphere.h b/gps-globe/src/gpsg-sphere.h
new file mode 100644 (file)
index 0000000..0ff8b91
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * gps-globe - A little app showing your position on a globe
+ * Copyright (C) 2009  Intel Corporation
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GPSG_SPHERE_H__
+#define __GPSG_SPHERE_H__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define GPSG_TYPE_SPHERE (gpsg_sphere_get_type ())
+
+#define GPSG_SPHERE(obj)                                               \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GPSG_TYPE_SPHERE, GpsgSphere))
+#define GPSG_SPHERE_CLASS(klass)                                       \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GPSG_TYPE_SPHERE, GpsgSphereClass))
+#define GPSG_IS_SPHERE(obj)                                            \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GPSG_TYPE_SPHERE))
+#define GPSG_IS_SPHERE_CLASS(klass)                                    \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GPSG_TYPE_SPHERE))
+#define GPSG_SPHERE_GET_CLASS(obj)                                     \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GPSG_TYPE_SPHERE, GpsgSphereClass))
+
+typedef struct _GpsgSphere GpsgSphere;
+typedef struct _GpsgSpherePrivate GpsgSpherePrivate;
+typedef struct _GpsgSphereClass GpsgSphereClass;
+
+struct _GpsgSphere
+{
+  ClutterTexture parent_instance;
+
+  GpsgSpherePrivate *priv;
+};
+
+struct _GpsgSphereClass
+{
+  ClutterTextureClass parent_class;
+};
+
+typedef enum
+{
+  GPSG_SPHERE_PAINT_LINES   = (1 << 0),
+  GPSG_SPHERE_PAINT_TEXTURE = (1 << 1)
+} GpsgSpherePaintFlags;
+
+GType gpsg_sphere_get_type (void) G_GNUC_CONST;
+
+ClutterActor *gpsg_sphere_new (void);
+
+guint gpsg_sphere_get_depth (GpsgSphere *sphere);
+void gpsg_sphere_set_depth (GpsgSphere *sphere, guint depth);
+
+gfloat gpsg_sphere_get_flatness (GpsgSphere *sphere);
+void gpsg_sphere_set_flatness (GpsgSphere *sphere, gfloat flatness);
+
+GpsgSpherePaintFlags gpsg_sphere_get_paint_flags (GpsgSphere *sphere);
+void gpsg_sphere_set_paint_flags (GpsgSphere *sphere,
+                                  GpsgSpherePaintFlags flags);
+
+void gpsg_sphere_get_lines_color (GpsgSphere *sphere,
+                                  ClutterColor *color);
+void gpsg_sphere_set_lines_color (GpsgSphere *sphere,
+                                  const ClutterColor *color);
+
+G_END_DECLS
+
+
+#endif /* __GPSG_SPHERE_H__ */
diff --git a/nyancat/Makefile b/nyancat/Makefile
new file mode 100644 (file)
index 0000000..ac0e1ab
--- /dev/null
@@ -0,0 +1,83 @@
+# A generic buildfiles to build single executable directory projects depending
+# only on pkg-config ability to build. It automatically names the project on
+# the toplevel directory you're in.
+#
+# Setting additional CFLAGS like $ export CFLAGS=-Wall -Werror # can help you
+# track issues down better after compilation.
+#
+# 20071008
+# Øyvind Kolås (c) 2007 <pippin@gimp.org>  placed in the Public Domain.
+##
+
+PKGMODULES = clutter-1.0 
+
+# you only need to change the following if you want to change where the
+# generated tarball gets scp'd to:
+
+SCP_DESTINATION=
+
+BINARY=$(shell basename `pwd`)#
+PACKAGE=../$(BINARY).tar.bz2 # you can use both .gz and .bz2 as extension here
+
+
+##
+# end of template configuration.
+#
+
+# This makefile uses the current directory as the only target binary, and
+# expects a single of the .c files to contain a main function.
+
+
+
+all: $(BINARY)
+
+# The help available also contains brief information about the different
+# build rules supported.
+help: 
+       @echo ''
+       @echo 'Available targets in this make system'
+       @echo ''
+       @echo '  (none)   builds $(BINARY)'
+       @echo '  dist     create $(PACKAGE)'
+       @echo '  clean    rm *.o *~ and foo and bar'
+       @echo '  run      ./$(BINARY)'
+       @echo '  gdb      gdb ./$(BINARY)'
+       @echo '  gdb2     gdb ./$(BINARY) --g-fatal-warnings'
+       @echo '  scp      scp $(PACKAGE) $(SCP_DESTINATION)'
+       @echo '  help     this help'
+       @echo ''
+
+
+LIBS= $(shell pkg-config --libs $(PKGMODULES))
+INCS= $(shell pkg-config --cflags $(PKGMODULES))
+
+CFLAGS+=-Wall
+CFILES  = $(wildcard *.c)
+OBJECTS = $(subst ./,,$(CFILES:.c=.o))
+HFILES  = $(wildcard *.h)
+%.o: %.c $(HFILES)
+       $(CC) -g $(CFLAGS) $(INCS) -c $< -o$@
+$(BINARY): $(OBJECTS)
+       $(CC) -o $@ $(LIBS) $(OBJECTS)
+test: run
+run: $(BINARY)
+       ./$(BINARY)
+
+../$(BINARY).tar.gz: clean $(CFILES) $(HFILES)
+       cd ..;tar czvhf $(BINARY).tar.gz $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.gz
+../$(BINARY).tar.bz2: clean $(CFILES) $(HFILES)
+       cd ..;tar cjvhf $(BINARY).tar.bz2 $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.bz2
+
+dist: $(PACKAGE) 
+       echo $(PACKAGE) 
+scp: dist
+       scp $(PACKAGE) $(SCP_DESTINATION)
+
+gdb: all
+       gdb --args ./$(BINARY)
+gdb2: all
+       gdb --args ./$(BINARY) -demo --g-fatal-warnings
+clean:
+       rm -fvr *.o $(BINARY) *~ *.patch
diff --git a/nyancat/nyan.json b/nyancat/nyan.json
new file mode 100644 (file)
index 0000000..f52eda8
--- /dev/null
@@ -0,0 +1,1204 @@
+[
+   {
+      "type":"ClutterGroup",
+      "id":"nyancat",
+      "x":300,
+      "y":100,
+      "width":0,
+      "height":0,
+      "depth":0.000,
+      "opacity":255,
+      "scale-x":1.000,
+      "scale-y":1.000,
+      "rotation-angle-z":0.000,
+      "anchor-x":0.000,
+      "anchor-y":0.000,
+      "children":[
+         {
+            "type":"ClutterRectangle",
+            "id":"body",
+            "x":0,
+            "y":0,
+            "width":200,
+            "height":125,
+            "depth":-1.000,
+            "opacity":255,
+            "scale-x":1.000,
+            "scale-y":1.000,
+            "rotation-angle-z":0.000,
+            "anchor-x":0.000,
+            "anchor-y":0.000,
+            "color":"#FAD695",
+            "border-color":"#000000ff",
+            "border-width":5,
+            "has-border":true
+         },
+         {
+            "type":"ClutterGroup",
+            "id":"head",
+            "x":100,
+            "y":25,
+            "width":0,
+            "height":0,
+            "depth":0.000,
+            "opacity":255,
+            "scale-x":1.000,
+            "scale-y":1.000,
+            "rotation-angle-z":0.000,
+            "anchor-x":0.000,
+            "anchor-y":0.000,
+            "children":[
+               {
+                   "type":"ClutterRectangle",
+                   "id":"back_head",
+                   "x":0,
+                   "y":0,
+                   "width":170,
+                   "height":100,
+                   "depth":-2.000,
+                   "opacity":255,
+                   "scale-x":1.000,
+                   "scale-y":1.000,
+                   "rotation-angle-z":0.000,
+                   "anchor-x":0.000,
+                   "anchor-y":0.000,
+                   "color":"#A7A5AA",
+                   "border-color":"#000000ff",
+                   "border-width":5,
+                   "has-border":true
+               },
+               {
+                   "type":"ClutterRectangle",
+                   "id":"left_cheek",
+                   "x":30,
+                   "y":60,
+                   "width":15,
+                   "height":15,
+                   "depth":0.000,
+                   "opacity":255,
+                   "scale-x":1.000,
+                   "scale-y":1.000,
+                   "rotation-angle-z":0.000,
+                   "anchor-x":0.000,
+                   "anchor-y":0.000,
+                   "color":"#F7A4A3",
+                   "border-color":"#000000ff",
+                   "border-width":0,
+                   "has-border":false
+               },
+               {
+                   "type":"ClutterRectangle",
+                   "id":"right_cheek",
+                   "x":130,
+                   "y":60,
+                   "width":15,
+                   "height":15,
+                   "depth":0.000,
+                   "opacity":255,
+                   "scale-x":1.000,
+                   "scale-y":1.000,
+                   "rotation-angle-z":0.000,
+                   "anchor-x":0.000,
+                   "anchor-y":0.000,
+                   "color":"#F7A4A3",
+                   "border-color":"#000000ff",
+                   "border-width":0,
+                   "has-border":false
+               },
+               {
+                   "type":"ClutterGroup",
+                   "id":"left_eye",
+                   "x":50,
+                   "y":40,
+                   "width":0,
+                   "height":0,
+                   "depth":0.000,
+                   "opacity":255,
+                   "scale-x":1.000,
+                   "scale-y":1.000,
+                   "rotation-angle-z":0.000,
+                   "anchor-x":0.000,
+                   "anchor-y":0.000,
+                   "children":[
+                      {
+                         "type":"ClutterRectangle",
+                         "id":"back_left_eye",
+                         "x":0,
+                         "y":0,
+                         "width":15,
+                         "height":15,
+                         "depth":-2.000,
+                         "opacity":255,
+                         "scale-x":1.000,
+                         "scale-y":1.000,
+                         "rotation-angle-z":0.000,
+                         "anchor-x":0.000,
+                         "anchor-y":0.000,
+                         "color":"#000000",
+                         "border-color":"#000000ff",
+                         "border-width":0,
+                         "has-border":false
+                     },
+                     {
+                         "type":"ClutterRectangle",
+                         "id":"front_left_eye",
+                         "x":0,
+                         "y":0,
+                         "width":7,
+                         "height":7,
+                         "depth":0.000,
+                         "opacity":255,
+                         "scale-x":1.000,
+                         "scale-y":1.000,
+                         "rotation-angle-z":0.000,
+                         "anchor-x":0.000,
+                         "anchor-y":0.000,
+                         "color":"#ffffff",
+                         "border-color":"#000000ff",
+                         "border-width":0,
+                         "has-border":false
+                     }
+                  ]
+               },
+               {
+                  "type":"ClutterGroup",
+                  "id":"right_eye",
+                  "x":110,
+                  "y":40,
+                  "width":0,
+                  "height":0,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "children":[
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"back_right_eye",
+                        "x":0,
+                        "y":0,
+                        "width":15,
+                        "height":15,
+                        "depth":-2.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#000000",
+                        "border-color":"#000000ff",
+                        "border-width":0,
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"front_right_eye",
+                        "x":0,
+                        "y":0,
+                        "width":7,
+                        "height":7,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#ffffff",
+                        "border-color":"#000000ff",
+                        "border-width":0,
+                        "has-border":false
+                     }
+                  ]
+               },
+               {
+                  "type":"ClutterGroup",
+                  "id":"mounth",
+                  "x":50,
+                  "y":70,
+                  "width":0,
+                  "height":0,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "children":[
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"left_lip",
+                        "x":0,
+                        "y":0,
+                        "width":8,
+                        "height":15,
+                        "depth":-2.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#000000",
+                        "border-color":"#000000ff",
+                        "border-width":0,
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"right_lip",
+                        "x":67,
+                        "y":0,
+                        "width":8,
+                        "height":15,
+                        "depth":-2.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#000000",
+                        "border-color":"#000000ff",
+                        "border-width":0,
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"middle_lip",
+                        "x":35,
+                        "y":5,
+                        "width":8,
+                        "height":10,
+                        "depth":-2.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#000000",
+                        "border-color":"#000000ff",
+                        "border-width":0,
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"bottom_lip",
+                        "x":0,
+                        "y":15,
+                        "width":75,
+                        "height":5,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#000000",
+                        "border-color":"#000000ff",
+                        "border-width":0,
+                        "has-border":false
+                     }
+                  ]
+               }
+            ]
+         },
+         {
+            "type":"ClutterGroup",
+            "id":"legs",
+            "x":-20,
+            "y":0,
+            "width":0,
+            "height":0,
+            "depth":-3.000,
+            "opacity":255,
+            "scale-x":1.000,
+            "scale-y":1.000,
+            "rotation-angle-z":0.000,
+            "anchor-x":0.000,
+            "anchor-y":0.000,
+            "children":[
+               {
+                  "type":"ClutterRectangle",
+                  "id":"back_leg1",
+                  "x":0,
+                  "y":140,
+                  "width":50,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":-45.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true
+               },
+               {
+                  "type":"ClutterRectangle",
+                  "id":"back_leg2",
+                  "x":50,
+                  "y":140,
+                  "width":50,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":-45.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true
+               },
+               {
+                  "type":"ClutterRectangle",
+                  "id":"front_leg1",
+                  "x":150,
+                  "y":105,
+                  "width":50,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":45.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true
+               },
+               {
+                  "type":"ClutterRectangle",
+                  "id":"front_leg2",
+                  "x":200,
+                  "y":105,
+                  "width":50,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":45.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true
+               }
+            ]
+         },
+         {
+            "type":"ClutterGroup",
+            "id":"tail",
+            "x":-60,
+            "y":50,
+            "width":0,
+            "height":0,
+            "depth":-2.000,
+            "opacity":255,
+            "scale-x":1.000,
+            "scale-y":1.000,
+            "rotation-angle-z":0.000,
+            "anchor-x":0.000,
+            "anchor-y":0.000,
+            "children":[
+               {
+                  "type":"ClutterRectangle",
+                  "id":"tail1",
+                  "x":0,
+                  "y":0,
+                  "width":30,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true,
+                  "clip": [ 0, 0, 25, 30 ]
+               },
+               {
+                  "type":"ClutterRectangle",
+                  "id":"tail2",
+                  "x":20,
+                  "y":0,
+                  "width":30,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true,
+                  "clip": [ 5, 0, 20, 30 ]
+               },
+               {
+                  "type":"ClutterRectangle",
+                  "id":"tail3",
+                  "x":40,
+                  "y":0,
+                  "width":30,
+                  "height":30,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "color":"#A7A5AA",
+                  "border-color":"#000000ff",
+                  "border-width":5,
+                  "has-border":true,
+                  "clip": [ 5, 0, 20, 30 ]
+               }
+            ]
+         },
+         {
+            "type":"ClutterGroup",
+            "id":"rainbow",
+            "x":-380,
+            "y":0,
+            "width":0,
+            "height":0,
+            "depth":-4.000,
+            "opacity":255,
+            "scale-x":1.000,
+            "scale-y":1.000,
+            "rotation-angle-z":0.000,
+            "anchor-x":0.000,
+            "anchor-y":0.000,
+            "children":[
+               {
+                  "type":"ClutterGroup",
+                  "id":"rainbow1",
+                  "x":0,
+                  "y":0,
+                  "width":0,
+                  "height":0,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "children":[
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_red1",
+                        "x":0,
+                        "y":0,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#D91A12",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_orange1",
+                        "x":0,
+                        "y":20,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8960B",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_yellow1",
+                        "x":0,
+                        "y":40,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8E501",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_green1",
+                        "x":0,
+                        "y":60,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#54FE01",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_lightblue1",
+                        "x":0,
+                        "y":80,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#3BAAF2",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_darkblue1",
+                        "x":0,
+                        "y":100,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#6D3DF4",
+                        "has-border":false
+                     }
+                  ]
+               },
+               {
+                  "type":"ClutterGroup",
+                  "id":"rainbow2",
+                  "x":100,
+                  "y":10,
+                  "width":0,
+                  "height":0,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "children":[
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_red2",
+                        "x":0,
+                        "y":0,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#D91A12",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_orange2",
+                        "x":0,
+                        "y":20,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8960B",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_yellow2",
+                        "x":0,
+                        "y":40,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8E501",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_green2",
+                        "x":0,
+                        "y":60,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#54FE01",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_lightblue2",
+                        "x":0,
+                        "y":80,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#3BAAF2",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_darkblue2",
+                        "x":0,
+                        "y":100,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#6D3DF4",
+                        "has-border":false
+                     }
+                  ]
+               },
+               {
+                  "type":"ClutterGroup",
+                  "id":"rainbow3",
+                  "x":200,
+                  "y":0,
+                  "width":0,
+                  "height":0,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "children":[
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_red3",
+                        "x":0,
+                        "y":0,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#D91A12",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_orange3",
+                        "x":0,
+                        "y":20,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8960B",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_yellow3",
+                        "x":0,
+                        "y":40,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8E501",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_green3",
+                        "x":0,
+                        "y":60,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#54FE01",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_lightblue3",
+                        "x":0,
+                        "y":80,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#3BAAF2",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_darkblue3",
+                        "x":0,
+                        "y":100,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#6D3DF4",
+                        "has-border":false
+                     }
+                  ]
+               },
+               {
+                  "type":"ClutterGroup",
+                  "id":"rainbow4",
+                  "x":300,
+                  "y":10,
+                  "width":0,
+                  "height":0,
+                  "depth":0.000,
+                  "opacity":255,
+                  "scale-x":1.000,
+                  "scale-y":1.000,
+                  "rotation-angle-z":0.000,
+                  "anchor-x":0.000,
+                  "anchor-y":0.000,
+                  "children":[
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_red4",
+                        "x":0,
+                        "y":0,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#D91A12",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_orange4",
+                        "x":0,
+                        "y":20,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8960B",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_yellow4",
+                        "x":0,
+                        "y":40,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#F8E501",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_green4",
+                        "x":0,
+                        "y":60,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#54FE01",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_lightblue4",
+                        "x":0,
+                        "y":80,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#3BAAF2",
+                        "has-border":false
+                     },
+                     {
+                        "type":"ClutterRectangle",
+                        "id":"rainbow_brick_darkblue4",
+                        "x":0,
+                        "y":100,
+                        "width":100,
+                        "height":20,
+                        "depth":0.000,
+                        "opacity":255,
+                        "scale-x":1.000,
+                        "scale-y":1.000,
+                        "rotation-angle-z":0.000,
+                        "anchor-x":0.000,
+                        "anchor-y":0.000,
+                        "color":"#6D3DF4",
+                        "has-border":false
+                     }
+                  ]
+               }
+            ]
+         }
+      ]
+   },
+   {
+      "type":"ClutterState",
+      "id":"legs-tail-states",
+      "duration":200,
+      "transitions":[
+         {
+            "source":null,
+            "target":"legs-up",
+            "keys":[
+               [
+                  "rainbow1",
+                  "y",
+                  "linear",
+                  10.0,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "rainbow2",
+                  "y",
+                  "linear",
+                  -10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "rainbow3",
+                  "y",
+                  "linear",
+                  10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "rainbow4",
+                  "y",
+                  "linear",
+                  -10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "legs",
+                  "y",
+                  "linear",
+                  -10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "tail2",
+                  "y",
+                  "linear",
+                  10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "tail1",
+                  "y",
+                  "linear",
+                  20.000,
+                  0.000000,
+                  0.000000
+               ]
+            ]
+         },
+         {
+            "source":null,
+            "target":"legs-down",
+            "keys":[
+               [
+                  "rainbow1",
+                  "y",
+                  "linear",
+                  -10.0,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "rainbow2",
+                  "y",
+                  "linear",
+                  10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "rainbow3",
+                  "y",
+                  "linear",
+                  -10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "rainbow4",
+                  "y",
+                  "linear",
+                  10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "legs",
+                  "y",
+                  "linear",
+                  0.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "tail2",
+                  "y",
+                  "linear",
+                  -10.000,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "tail1",
+                  "y",
+                  "linear",
+                  -20.000,
+                  0.000000,
+                  0.000000
+               ]
+            ]
+         }
+      ]
+   },
+   {
+      "type":"ClutterState",
+      "id":"head-states",
+      "duration":100,
+      "transitions":[
+         {
+            "source":null,
+            "target":"head-up",
+            "keys":[
+               [
+                  "head",
+                  "x",
+                  "linear",
+                  100.0,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "head",
+                  "y",
+                  "linear",
+                  25.0,
+                  0.000000,
+                  0.000000
+               ]
+            ]
+         },
+         {
+            "source":null,
+            "target":"head-right",
+            "keys":[
+               [
+                  "head",
+                  "x",
+                  "linear",
+                  110.0,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "head",
+                  "y",
+                  "linear",
+                  30.0,
+                  0.000000,
+                  0.000000
+               ]
+            ]
+         },
+         {
+            "source":null,
+            "target":"head-down",
+            "keys":[
+               [
+                  "head",
+                  "x",
+                  "linear",
+                  100.0,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "head",
+                  "y",
+                  "linear",
+                  35.0,
+                  0.000000,
+                  0.000000
+               ]
+            ]
+         },
+         {
+            "source":null,
+            "target":"head-left",
+            "keys":[
+               [
+                  "head",
+                  "x",
+                  "linear",
+                  90.0,
+                  0.000000,
+                  0.000000
+               ],
+               [
+                  "head",
+                  "y",
+                  "linear",
+                  30.0,
+                  0.000000,
+                  0.000000
+               ]
+            ]
+         }
+      ]
+   }
+]
diff --git a/nyancat/nyancat.c b/nyancat/nyancat.c
new file mode 100644 (file)
index 0000000..8fde7b8
--- /dev/null
@@ -0,0 +1,181 @@
+#include <string.h>
+
+#include <clutter/clutter.h>
+
+#define SCALE_X_VARIANCE 0.3
+#define SCALE_Y_VARIANCE 0.2
+#define ROT_Z_VARIANCE 0.1
+#define ALPHA_VARIANCE 0.5
+#define ANIM_LENGTH 10000
+#define ANIM_VARIANCE 0.3
+#define OPACITY 0.60
+#define OPACITY_VARIANCE 0.33
+#define HEIGHT 0.85
+#define HEIGHT_VARIANCE 0.2
+#define HEIGHT_DROP 1.7
+
+static void
+legs_state_completed (ClutterState *state, gpointer data)
+{
+  const gchar *state_name = clutter_state_get_state (state);
+
+  if (!strcmp (state_name, "legs-up"))
+    clutter_state_set_state (state, "legs-down");
+  else
+    clutter_state_set_state (state, "legs-up");
+}
+
+static void
+head_state_completed (ClutterState *state, gpointer data)
+{
+  const gchar *state_name = clutter_state_get_state (state);
+
+  if (!strcmp (state_name, "head-up"))
+    clutter_state_set_state (state, "head-right");
+  else if (!strcmp (state_name, "head-right"))
+    clutter_state_set_state (state, "head-down");
+  else if (!strcmp (state_name, "head-down"))
+    clutter_state_set_state (state, "head-left");
+  else if (!strcmp (state_name, "head-left"))
+    clutter_state_set_state (state, "head-up");
+}
+
+static inline gdouble
+get_variance (gdouble value, gdouble constant)
+{
+  return value + value * (2.0 * g_random_double () - 1.0) * constant;
+}
+
+static gboolean
+create_cloud(ClutterActor *cloud_texture)
+{
+  ClutterPerspective perspective;
+  ClutterAnimator *animator;
+  ClutterTimeline *timeline;
+  guint8 opacity;
+  gfloat cloud_width;
+  gfloat stage_width, stage_height;
+
+  ClutterActor *stage = clutter_stage_get_default ();
+  ClutterActor *cloud = clutter_clone_new (cloud_texture);
+
+  stage_width = clutter_actor_get_width (stage);
+  stage_height = clutter_actor_get_height (stage);
+  cloud_width = clutter_actor_get_width (cloud);
+
+  clutter_actor_set_scale_with_gravity (cloud,
+                                        get_variance (1, SCALE_X_VARIANCE),
+                                        get_variance (1, SCALE_Y_VARIANCE),
+                                        CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_z_rotation_from_gravity (cloud,
+                                             get_variance (360, ROT_Z_VARIANCE),
+                                             CLUTTER_GRAVITY_CENTER);
+  clutter_actor_set_y (cloud,
+    g_random_double_range (-clutter_actor_get_height (cloud),
+                           stage_height));
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), cloud);
+  clutter_actor_lower_bottom (cloud);
+
+  clutter_actor_show (cloud);
+
+  clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
+
+  animator = clutter_animator_new();
+  opacity = (guint8)(get_variance (OPACITY, OPACITY_VARIANCE) * 255.0);
+  clutter_animator_set (animator,
+                        cloud, "x", CLUTTER_LINEAR, 0.0, stage_width,
+                        cloud, "opacity", CLUTTER_LINEAR, 0.0, 0,
+                        cloud, "opacity", CLUTTER_EASE_IN_CUBIC, 0.15, opacity,
+                        cloud, "opacity", CLUTTER_LINEAR, 0.85, opacity,
+                        cloud, "opacity", CLUTTER_EASE_OUT_CUBIC, 1.0, 0,
+                        cloud, "x", CLUTTER_LINEAR, 1.0, -cloud_width,
+                        NULL);
+
+  clutter_animator_set_duration (animator,
+                                 get_variance (ANIM_LENGTH, ANIM_VARIANCE));
+  timeline = clutter_animator_get_timeline (animator);
+  g_signal_connect_swapped (timeline, "completed",
+                            G_CALLBACK (clutter_actor_destroy), cloud);
+
+  g_object_weak_ref (G_OBJECT (cloud), (GWeakNotify)g_object_unref, animator);
+
+  clutter_animator_start (animator);
+
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  ClutterColor stage_color = { 0x1C, 0x41, 0x70, 0xff };
+  ClutterActor *nyancat, *stage, *cloud;
+  ClutterState *legs_states, *head_states;
+  ClutterScript *script;
+  guint source;
+  GError *error = NULL;
+
+  if (argc < 2)
+    {
+      g_warning ("%s file.json", argv[0]);
+      return 1;
+    }
+
+  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+    return 1;
+
+  stage = clutter_stage_get_default ();
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "Clutter Nyan Cat");
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  clutter_actor_set_size (stage, 800, 600);
+
+  script = clutter_script_new ();
+
+  clutter_script_load_from_file (script, argv[1], &error);
+  if (error)
+    {
+      g_warning ("Error while loading '%s': %s", argv[1], error->message);
+      g_error_free (error);
+      return 1;
+    }
+
+  /**/
+  nyancat = CLUTTER_ACTOR (clutter_script_get_object (script, "nyancat"));
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), nyancat);
+  clutter_actor_raise_top (nyancat);
+  legs_states = CLUTTER_STATE (clutter_script_get_object (script,
+                                                          "legs-tail-states"));
+  head_states = CLUTTER_STATE (clutter_script_get_object (script,
+                                                          "head-states"));
+  g_signal_connect (legs_states, "completed",
+                    G_CALLBACK (legs_state_completed), NULL);
+  g_signal_connect (head_states, "completed",
+                    G_CALLBACK (head_state_completed), NULL);
+
+  /**/
+  if (!(cloud = clutter_texture_new_from_file ("star.png", &error)))
+    {
+      g_warning ("Error loading image: %s", error->message);
+      g_error_free (error);
+      return -1;
+    }
+  clutter_actor_set_position (cloud,
+                              -clutter_actor_get_width (cloud),
+                              -clutter_actor_get_height (cloud));
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), cloud);
+
+  source = g_timeout_add_full (CLUTTER_PRIORITY_REDRAW, 1000,
+                               (GSourceFunc)create_cloud,
+                               cloud, NULL);
+
+  clutter_actor_show_all (stage);
+
+  clutter_state_set_state (legs_states, "legs-up");
+  clutter_state_set_state (head_states, "head-up");
+
+  clutter_main ();
+
+  g_source_remove (source);
+
+  return 0;
+}
diff --git a/nyancat/star.png b/nyancat/star.png
new file mode 100644 (file)
index 0000000..c614e79
Binary files /dev/null and b/nyancat/star.png differ
diff --git a/object-store/Makefile b/object-store/Makefile
new file mode 100644 (file)
index 0000000..73f083b
--- /dev/null
@@ -0,0 +1,36 @@
+
+PROGRAMS = \
+  object-store-example \
+  object-store-test \
+  $(NULL)
+
+example_SOURCES = \
+  foo-object-store.c \
+  foo-object-store.h \
+  foo-test-object.c \
+  foo-test-object.h \
+  object-store-example.c \
+  $(NULL)
+
+test_SOURCES = \
+  foo-object-store.c \
+  foo-object-store.h \
+  foo-test-object.c \
+  foo-test-object.h \
+  object-store-test.c \
+  $(NULL)
+
+PKGFLAGS = `pkg-config --cflags --libs clutter-1.0 mx-1.0`
+
+all: $(PROGRAMS)
+
+clean:
+       rm -f $(PROGRAMS)
+
+object-store-example: $(example_SOURCES)
+       $(CC) $(CPPLAGS) $(CFLAGS) $(PKGFLAGS) -o $@ $^
+
+object-store-test: $(test_SOURCES)
+       $(CC) $(CPPLAGS) $(CFLAGS) $(PKGFLAGS) -o $@ $^
+
+.PHONY: clean
diff --git a/object-store/foo-object-store-test b/object-store/foo-object-store-test
new file mode 100644 (file)
index 0000000..45bb03f
Binary files /dev/null and b/object-store/foo-object-store-test differ
diff --git a/object-store/foo-object-store.c b/object-store/foo-object-store.c
new file mode 100644 (file)
index 0000000..c11c498
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Rob Staudinger <robsta@linux.intel.com>
+ * Based on clutter-list-model.c
+ *    Copyright (C) 2006 OpenedHand, by
+ *    Matthew Allum  <mallum@openedhand.com>
+ *    Neil Jagdish Patel <njp@o-hand.com>
+ *    Emmanuele Bassi <ebassi@openedhand.com>
+ */
+
+/*
+  README
+
+  This is a ClutterModel subclass to proxy GObjects, instead of holding the
+  data itself, like ClutterListModel. The model has to be constructed so that
+  the object is held by column #0. All other colums can be mapped to the
+  objects' properties in any desired order.
+*/
+
+#include "foo-object-store.h"
+
+typedef struct FooObjectStoreIter_ FooObjectStoreIter;
+
+static void
+foo_object_store_object_property_notify (GObject         *object,
+                                         GParamSpec      *pspec,
+                                         FooObjectStore  *self);
+
+static void
+foo_object_store_detach_object          (FooObjectStore  *self,
+                                         GObject         *object);
+
+static void
+foo_object_store_attach_object          (FooObjectStore  *self,
+                                         GObject         *object);
+
+/*
+ * FooObjectStore declaration.
+ */
+
+G_DEFINE_TYPE (FooObjectStore, foo_object_store, CLUTTER_TYPE_MODEL)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FOO_TYPE_OBJECT_STORE, FooObjectStorePrivate))
+
+typedef struct
+{
+  GSequence           *sequence;
+  FooObjectStoreIter  *cached_iter;
+} FooObjectStorePrivate;
+
+/*
+ * FooObjectStoreIter.
+ */
+
+#define FOO_TYPE_OBJECT_STORE_ITER foo_object_store_iter_get_type()
+
+#define FOO_OBJECT_STORE_ITER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  FOO_TYPE_OBJECT_STORE_ITER, FooObjectStoreIter))
+
+#define FOO_OBJECT_STORE_ITER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  FOO_TYPE_OBJECT_STORE_ITER, FooObjectStoreIterClass))
+
+#define FOO_IS_OBJECT_STORE_ITER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  FOO_TYPE_OBJECT_STORE_ITER))
+
+#define FOO_IS_OBJECT_STORE_ITER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  FOO_TYPE_OBJECT_STORE_ITER))
+
+#define FOO_OBJECT_STORE_ITER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  FOO_TYPE_OBJECT_STORE_ITER, FooObjectStoreIterClass))
+
+struct FooObjectStoreIter_ {
+  ClutterModelIter   parent;
+  GSequenceIter     *seq_iter;  /* NULL means it's the end iter. */
+};
+
+typedef struct {
+  ClutterModelIterClass parent;
+} FooObjectStoreIterClass;
+
+GType foo_object_store_iter_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (FooObjectStoreIter, foo_object_store_iter, CLUTTER_TYPE_MODEL_ITER)
+
+static void
+foo_object_store_iter_get_value (ClutterModelIter *iter,
+                                 guint             column,
+                                 GValue           *value)
+{
+  FooObjectStoreIter  *self;
+  GObject             *object;
+  const gchar         *name;
+
+  g_return_if_fail (FOO_IS_OBJECT_STORE_ITER (iter));
+  g_return_if_fail (value);
+
+  self = FOO_OBJECT_STORE_ITER (iter);
+  if (!self->seq_iter)
+    return;
+  object = g_sequence_get (self->seq_iter);
+
+  if (column == 0)
+    {
+      g_value_set_object (value, object);
+    }
+  else
+    {
+      name = clutter_model_get_column_name (clutter_model_iter_get_model (iter),
+                                            column);
+      g_object_get_property (object, name, value);
+    }
+}
+
+static void
+foo_object_store_iter_set_value (ClutterModelIter *iter,
+                                 guint             column,
+                                 const GValue     *value)
+{
+  FooObjectStoreIter  *self;
+  ClutterModel        *model;
+  GObject             *object;
+
+  g_return_if_fail (FOO_IS_OBJECT_STORE_ITER (iter));
+  g_return_if_fail (value);
+
+  self = FOO_OBJECT_STORE_ITER (iter);
+  model = clutter_model_iter_get_model (iter);
+  object = g_sequence_get (self->seq_iter);
+
+  if (column == 0)
+    {
+      /* Set "master" column. NULL is legal since append() does an empty row. */
+      if (object)
+        {
+          foo_object_store_detach_object (FOO_OBJECT_STORE (model), object);
+          g_object_unref (object);
+        }
+
+      object = g_value_get_object (value);
+      g_sequence_set (self->seq_iter, g_object_ref (object));
+
+      /* Hook up "changed" notifications for the object's properties. */
+      foo_object_store_attach_object (FOO_OBJECT_STORE (model), object);
+    }
+  else if (object)
+    {
+      const gchar *name = clutter_model_get_column_name (model, column);
+      g_object_set_property (object, name, value);
+    }
+  else
+    {
+      g_warning ("%s Cannot set column %d on NULL object",
+                 G_STRLOC,
+                 column);
+    }
+}
+
+static gboolean
+foo_object_store_iter_is_first (ClutterModelIter *iter)
+{
+  FooObjectStoreIter    *self;
+  ClutterModel          *store;
+  FooObjectStorePrivate *priv;
+  FooObjectStoreIter    *cached_iter;
+  gboolean               is_seq_first;
+  gboolean               is_first = TRUE;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE_ITER (iter), FALSE);
+
+  self = FOO_OBJECT_STORE_ITER (iter);
+  store = clutter_model_iter_get_model (iter);
+  priv = GET_PRIVATE (store);
+  cached_iter = priv->cached_iter;
+
+  /* Go backwards from iter looking for non-filtered rows. */
+  for (is_seq_first = g_sequence_iter_is_begin (self->seq_iter),
+       cached_iter->seq_iter = g_sequence_iter_prev (self->seq_iter);
+       !is_seq_first;
+       is_seq_first = g_sequence_iter_is_begin (cached_iter->seq_iter),
+       cached_iter->seq_iter = g_sequence_iter_prev (cached_iter->seq_iter))
+    {
+      if (clutter_model_filter_iter (store, CLUTTER_MODEL_ITER (cached_iter)))
+        {
+          is_first = FALSE;
+          break;
+        }
+    }
+
+  return is_first;
+}
+
+static gboolean
+foo_object_store_iter_is_last (ClutterModelIter *iter)
+{
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE_ITER (iter), TRUE);
+  g_return_val_if_fail (FOO_OBJECT_STORE_ITER (iter)->seq_iter, TRUE);
+
+  return g_sequence_iter_is_end (FOO_OBJECT_STORE_ITER (iter)->seq_iter);
+}
+
+static ClutterModelIter *
+foo_object_store_iter_next (ClutterModelIter *iter)
+{
+  FooObjectStoreIter  *self;
+  ClutterModel        *store;
+  guint                row;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE_ITER (iter), NULL);
+
+  self = FOO_OBJECT_STORE_ITER (iter);
+  store = clutter_model_iter_get_model (iter);
+  row = clutter_model_iter_get_row (iter);
+
+  if (clutter_model_get_filter_set (store))
+    {
+      /* Look for next non-filtered row. */
+      for (self->seq_iter = g_sequence_iter_next (self->seq_iter);
+           !g_sequence_iter_is_end (self->seq_iter);
+           self->seq_iter = g_sequence_iter_next (self->seq_iter))
+        {
+          if (clutter_model_filter_iter (store, iter))
+            {
+              g_object_set (iter, "row", row + 1, NULL);
+              /* self->seq_iter already points to the correct row. */
+              break;
+            }
+        }
+    }
+  else if (!g_sequence_iter_is_end (self->seq_iter))
+    {
+      g_object_set (iter, "row", row + 1, NULL);
+      self->seq_iter = g_sequence_iter_next (self->seq_iter);
+    }
+
+  return iter;
+}
+
+static ClutterModelIter *
+foo_object_store_iter_prev (ClutterModelIter *iter)
+{
+  FooObjectStoreIter  *self;
+  ClutterModel        *store;
+  guint                row;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE_ITER (iter), NULL);
+
+  self = FOO_OBJECT_STORE_ITER (iter);
+  store = clutter_model_iter_get_model (iter);
+  row = clutter_model_iter_get_row (iter);
+
+  if (clutter_model_get_filter_set (store))
+    {
+      /* Look for prev non-filtered row. */
+      for (self->seq_iter = g_sequence_iter_prev (self->seq_iter);
+           !g_sequence_iter_is_begin (self->seq_iter);
+           self->seq_iter = g_sequence_iter_next (self->seq_iter))
+        {
+          if (clutter_model_filter_iter (store, iter))
+            {
+              g_object_set (iter, "row", row - 1, NULL);
+              /* self->seq_iter already points to the correct row. */
+              break;
+            }
+        }
+    }
+  else if (!g_sequence_iter_is_begin (self->seq_iter))
+    {
+      g_object_set (iter, "row", row - 1, NULL);
+      self->seq_iter = g_sequence_iter_prev (self->seq_iter);
+    }
+
+  return iter;
+}
+
+static ClutterModelIter *
+foo_object_store_iter_copy (ClutterModelIter *iter)
+{
+  FooObjectStoreIter  *self;
+  ClutterModelIter    *copy;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE_ITER (iter), NULL);
+
+  self = FOO_OBJECT_STORE_ITER (iter);
+  copy = g_object_new (FOO_TYPE_OBJECT_STORE_ITER,
+                       "model", clutter_model_iter_get_model (iter),
+                       "row", clutter_model_iter_get_row (iter),
+                       NULL);
+
+  /* this is safe, because the seq_iter pointer on the passed
+   * iterator will be always be overwritten in ::next or ::prev */
+  FOO_OBJECT_STORE_ITER (copy)->seq_iter = self->seq_iter;
+
+  return copy;
+}
+
+static void
+foo_object_store_iter_class_init (FooObjectStoreIterClass *klass)
+{
+  ClutterModelIterClass *iter_class = CLUTTER_MODEL_ITER_CLASS (klass);
+
+  iter_class->get_value = foo_object_store_iter_get_value;
+  iter_class->set_value = foo_object_store_iter_set_value;
+  iter_class->is_first  = foo_object_store_iter_is_first;
+  iter_class->is_last   = foo_object_store_iter_is_last;
+  iter_class->next      = foo_object_store_iter_next;
+  iter_class->prev      = foo_object_store_iter_prev;
+  iter_class->copy      = foo_object_store_iter_copy;
+}
+
+static void
+foo_object_store_iter_init (FooObjectStoreIter *iter)
+{
+  iter->seq_iter = NULL;
+}
+
+/*
+ * FooObjectStore.
+ */
+
+static void
+foo_object_store_finalize (GObject *gobject)
+{
+  FooObjectStorePrivate *priv = GET_PRIVATE (gobject);
+
+  g_sequence_free (priv->sequence);
+  priv->sequence = NULL;
+
+  G_OBJECT_CLASS (foo_object_store_parent_class)->finalize (gobject);
+}
+
+static void
+_detach_if_non_null (GObject        *object,
+                     FooObjectStore *self)
+{
+  if (G_IS_OBJECT (object))
+    foo_object_store_detach_object (self, object);
+}
+
+static void
+foo_object_store_dispose (GObject *gobject)
+{
+  FooObjectStorePrivate *priv = GET_PRIVATE (gobject);
+
+  g_sequence_foreach_range (g_sequence_get_begin_iter (priv->sequence),
+                            g_sequence_get_end_iter (priv->sequence),
+                            (GFunc) _detach_if_non_null,
+                            gobject);
+
+  g_sequence_remove_range (g_sequence_get_begin_iter (priv->sequence),
+                           g_sequence_get_end_iter (priv->sequence));
+
+  if (priv->cached_iter)
+    {
+      g_object_unref (priv->cached_iter);
+      priv->cached_iter = NULL;
+    }
+
+  G_OBJECT_CLASS (foo_object_store_parent_class)->dispose (gobject);
+}
+
+static ClutterModelIter *
+foo_object_store_get_iter_at_row (ClutterModel *self,
+                                  guint         row)
+{
+  FooObjectStorePrivate *priv;
+  FooObjectStoreIter    *cached_iter;
+  FooObjectStoreIter    *iter = NULL;
+  gint                   r = -1;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE (self), NULL);
+
+  priv = GET_PRIVATE (self);
+  cached_iter = priv->cached_iter;
+
+  /* Work the cached iter to defer object instantiation until success. */
+  if (clutter_model_get_filter_set (self))
+    {
+      /* Count matching rows. */
+      for (cached_iter->seq_iter = g_sequence_get_begin_iter (priv->sequence);
+           !g_sequence_iter_is_end (cached_iter->seq_iter);
+           cached_iter->seq_iter = g_sequence_iter_next (cached_iter->seq_iter))
+        {
+          if (clutter_model_filter_iter (self, CLUTTER_MODEL_ITER (cached_iter)))
+            {
+              r++;
+              if ((unsigned) r == row)
+                break;
+            }
+        }
+    }
+  else
+    {
+      r = row;
+      cached_iter->seq_iter = g_sequence_get_iter_at_pos (priv->sequence, row);
+    }
+
+  if (r > -1)
+    {
+      iter = g_object_new (FOO_TYPE_OBJECT_STORE_ITER,
+                            "model", self,
+                            "row", r,
+                            NULL);
+      iter->seq_iter = cached_iter->seq_iter;
+    }
+
+  return (ClutterModelIter *) iter;
+}
+
+static ClutterModelIter *
+foo_object_store_insert_row (ClutterModel *self,
+                             gint          index_)
+{
+  FooObjectStorePrivate *priv;
+  FooObjectStoreIter    *iter;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE (self), NULL);
+
+  priv = GET_PRIVATE (self);
+  iter = g_object_new (FOO_TYPE_OBJECT_STORE_ITER,
+                       "model", self,
+                       NULL);
+
+  if (index_ < 0)
+    {
+      iter->seq_iter = g_sequence_append (priv->sequence, NULL);
+      g_object_set (iter,
+                    "row", g_sequence_get_length (priv->sequence) - 1,
+                    NULL);
+    }
+  else
+    {
+      GSequenceIter *seq_iter;
+      seq_iter = g_sequence_get_iter_at_pos (priv->sequence, index_);
+      iter->seq_iter = g_sequence_insert_before (seq_iter, NULL);
+      g_object_set (iter,
+                    "row", index_,
+                    NULL);
+    }
+
+  return CLUTTER_MODEL_ITER (iter);
+}
+
+static void
+foo_object_store_remove_row (ClutterModel *self,
+                             guint         row)
+{
+  FooObjectStorePrivate *priv;
+  FooObjectStoreIter    *iter;
+
+  g_return_if_fail (FOO_IS_OBJECT_STORE (self));
+
+  priv = GET_PRIVATE (self);
+  iter = g_object_new (FOO_TYPE_OBJECT_STORE_ITER,
+                       "model", self,
+                       "row", row,
+                       NULL);
+  iter->seq_iter = g_sequence_get_iter_at_pos (priv->sequence, row);
+
+  /* the actual row is removed from the sequence inside
+   * the ::row-removed signal class handler, so that every
+   * handler connected to ::row-removed will still get
+   * a valid iterator, and every signal connected to
+   * ::row-removed with the AFTER flag will get an updated
+   * store */
+  g_signal_emit_by_name (self, "row-removed", iter);
+  g_object_unref (iter);
+}
+
+typedef struct
+{
+  ClutterModel          *store;
+  const gchar           *property_name;
+  ClutterModelSortFunc   func;
+  gpointer               data;
+} SortClosure;
+
+static gint
+sort_store_default (gconstpointer a,
+                    gconstpointer b,
+                    gpointer      data)
+{
+  SortClosure *closure = data;
+  GValue       p1 = { 0, };
+  GValue       p2 = { 0, };
+
+  if (a == NULL && b == NULL)
+    return 0;
+  else if (a == NULL)
+    return -1;
+  else if (b == NULL)
+    return 1;
+
+  g_object_get_property (G_OBJECT (a), closure->property_name, &p1);
+  g_object_get_property (G_OBJECT (b), closure->property_name, &p2);
+
+  return closure->func (closure->store, &p1, &p2, closure->data);
+}
+
+static void
+foo_object_store_resort (ClutterModel         *self,
+                         ClutterModelSortFunc  func,
+                         gpointer              data)
+{
+  FooObjectStorePrivate *priv;
+  SortClosure            closure;
+  gint                   column;
+
+  g_return_if_fail (FOO_IS_OBJECT_STORE (self));
+
+  priv = GET_PRIVATE (self);
+  column = clutter_model_get_sorting_column (self);
+
+  closure.store = self;
+  closure.property_name = clutter_model_get_column_name (self, column);
+  closure.func = func;
+  closure.data = data;
+
+  g_sequence_sort (priv->sequence, sort_store_default, &closure);
+}
+
+static void
+foo_object_store_row_removed (ClutterModel     *self,
+                              ClutterModelIter *iter_)
+{
+  FooObjectStoreIter  *iter;
+  GObject             *object;
+
+  iter = FOO_OBJECT_STORE_ITER (iter_);
+  object = g_sequence_get (iter->seq_iter);
+
+  if (G_IS_OBJECT (object))
+    {
+      foo_object_store_detach_object (FOO_OBJECT_STORE (self), object);
+      g_object_unref (object);
+    }
+
+  g_sequence_remove (iter->seq_iter);
+}
+
+static void
+foo_object_store_class_init (FooObjectStoreClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterModelClass *store_class = CLUTTER_MODEL_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (FooObjectStorePrivate));
+
+  gobject_class->dispose = foo_object_store_dispose;
+  gobject_class->finalize = foo_object_store_finalize;
+
+  store_class->get_iter_at_row = foo_object_store_get_iter_at_row;
+  store_class->insert_row      = foo_object_store_insert_row;
+  store_class->remove_row      = foo_object_store_remove_row;
+  store_class->resort          = foo_object_store_resort;
+
+  store_class->row_removed     = foo_object_store_row_removed;
+}
+
+/*
+ * The destroy function is called regardless of NULL data.
+ */
+static void
+_unref_if_non_null (GObject *object)
+{
+  if (G_IS_OBJECT (object))
+    g_object_unref (object);
+}
+
+static void
+foo_object_store_init (FooObjectStore *self)
+{
+  FooObjectStorePrivate *priv = GET_PRIVATE (self);
+
+  priv->sequence = g_sequence_new ((GDestroyNotify) _unref_if_non_null);
+  priv->cached_iter = g_object_new (FOO_TYPE_OBJECT_STORE_ITER,
+                                    "model", self,
+                                    NULL);
+}
+
+ClutterModel *
+foo_object_store_new (guint n_columns,
+                      ...)
+{
+  ClutterModel  *self;
+  GType          types[n_columns];
+  const gchar   *names[n_columns];
+  guint          i;
+  va_list        args;
+
+  g_return_val_if_fail (n_columns > 0, NULL);
+
+  self = g_object_new (FOO_TYPE_OBJECT_STORE, NULL);
+
+  va_start (args, n_columns);
+
+  for (i = 0; i < n_columns; i++)
+    {
+      types[i] = va_arg (args, GType);
+      names[i] = va_arg (args, gchar *);
+    }
+
+  va_end (args);
+
+  clutter_model_set_types (self, n_columns, types);
+  clutter_model_set_names (self, n_columns, names);
+
+  return self;
+}
+
+static void
+foo_object_store_object_property_notify (GObject         *object,
+                                         GParamSpec      *pspec,
+                                         FooObjectStore  *self)
+{
+  FooObjectStorePrivate *priv = GET_PRIVATE (self);
+  GSequenceIter         *seq_iter;
+  FooObjectStoreIter    *iter;
+  GSequenceIter         *notify_seq_iter = NULL;
+
+  /* Find corresponding row of changed object. */
+  for (seq_iter = g_sequence_get_begin_iter (priv->sequence);
+       !g_sequence_iter_is_end (seq_iter);
+       seq_iter = g_sequence_iter_next (seq_iter))
+    {
+      if (object == g_sequence_get (seq_iter))
+        {
+          notify_seq_iter = seq_iter;
+          break;
+        }
+    }
+
+  g_return_if_fail (notify_seq_iter);
+
+  iter = g_object_new (FOO_TYPE_OBJECT_STORE_ITER,
+                       "model", self,
+                       NULL);
+  iter->seq_iter = notify_seq_iter;
+  g_signal_emit_by_name (self, "row-changed", iter);
+  g_object_unref (iter);
+}
+
+static void
+foo_object_store_attach_object (FooObjectStore  *self,
+                                GObject         *object)
+{
+  guint        n_columns;
+  const gchar *column_name;
+  gchar       *signal_name;
+  guint        i;
+
+  /* Start at column 1 because 0 hold the actual object. */
+  n_columns = clutter_model_get_n_columns (CLUTTER_MODEL (self));
+  for (i = 1; i < n_columns; i++)
+    {
+      column_name = clutter_model_get_column_name (CLUTTER_MODEL (self), i);
+      signal_name = g_strdup_printf ("notify::%s", column_name);
+      g_signal_connect (object,
+                        signal_name,
+                        G_CALLBACK (foo_object_store_object_property_notify),
+                        self);
+      g_free (signal_name);
+    }
+}
+
+static void
+foo_object_store_detach_object (FooObjectStore  *self,
+                                GObject         *object)
+{
+  g_signal_handlers_disconnect_by_func (object,
+                                        foo_object_store_object_property_notify,
+                                        self);
+}
+
+void
+foo_object_store_foreach_unfiltered (FooObjectStore          *self,
+                                     ClutterModelForeachFunc  func,
+                                     gpointer                 user_data)
+{
+  FooObjectStorePrivate *priv;
+  GSequenceIter *seq_iter;
+
+  g_return_if_fail (FOO_IS_OBJECT_STORE (self));
+  g_return_if_fail (func);
+
+  priv = GET_PRIVATE (self);
+
+  for (seq_iter = g_sequence_get_begin_iter (priv->sequence);
+       !g_sequence_iter_is_end (seq_iter);
+       seq_iter = g_sequence_iter_next (seq_iter))
+    {
+      priv->cached_iter->seq_iter = seq_iter;
+      if (!func ((ClutterModel *) self,
+                 (ClutterModelIter *) priv->cached_iter,
+                 user_data))
+        {
+          break;
+        }
+    }
+}
+
+gint
+foo_object_store_remove (FooObjectStore  *self,
+                         GObject         *object)
+{
+  FooObjectStorePrivate *priv;
+  GSequenceIter *seq_iter;
+  gint           row = -1;
+
+  g_return_val_if_fail (FOO_IS_OBJECT_STORE (self), FALSE);
+  g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
+
+  priv = GET_PRIVATE (self);
+
+  for (seq_iter = g_sequence_get_begin_iter (priv->sequence);
+       !g_sequence_iter_is_end (seq_iter);
+       seq_iter = g_sequence_iter_next (seq_iter))
+    {
+      GObject *o = g_sequence_get (seq_iter);
+      row++;
+      if (o == object)
+        {
+          foo_object_store_remove_row (CLUTTER_MODEL (self), row);
+          break;
+        }
+    }
+
+  return row;
+}
+
diff --git a/object-store/foo-object-store.h b/object-store/foo-object-store.h
new file mode 100644 (file)
index 0000000..39f65b4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Rob Staudinger <robsta@linux.intel.com>
+ */
+
+#ifndef FOO_OBJECT_STORE_H
+#define FOO_OBJECT_STORE_H
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define FOO_TYPE_OBJECT_STORE foo_object_store_get_type()
+
+#define FOO_OBJECT_STORE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  FOO_TYPE_OBJECT_STORE, FooObjectStore))
+
+#define FOO_OBJECT_STORE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  FOO_TYPE_OBJECT_STORE, FooObjectStoreClass))
+
+#define FOO_IS_OBJECT_STORE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  FOO_TYPE_OBJECT_STORE))
+
+#define FOO_IS_OBJECT_STORE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  FOO_TYPE_OBJECT_STORE))
+
+#define FOO_OBJECT_STORE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  FOO_TYPE_OBJECT_STORE, FooObjectStoreClass))
+
+typedef struct FooObjectStore_        FooObjectStore;
+typedef struct FooObjectStoreClass_   FooObjectStoreClass;
+
+struct FooObjectStore_ {
+  ClutterModel parent;
+};
+
+struct FooObjectStoreClass_ {
+  ClutterModelClass parent;
+};
+
+GType foo_object_store_get_type (void) G_GNUC_CONST;
+
+ClutterModel * foo_object_store_new (guint n_columns,
+                                     ...);
+
+void foo_object_store_foreach_unfiltered (FooObjectStore          *self,
+                                          ClutterModelForeachFunc  func,
+                                          gpointer                 user_data);
+
+gint foo_object_store_remove (FooObjectStore  *self,
+                              GObject         *object);
+
+G_END_DECLS
+
+#endif /* FOO_OBJECT_STORE_H */
diff --git a/object-store/foo-test-object.c b/object-store/foo-test-object.c
new file mode 100644 (file)
index 0000000..e3fd109
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Rob Staudinger <robsta@linux.intel.com>
+ */
+
+#include "foo-test-object.h"
+
+G_DEFINE_TYPE (FooTestObject, foo_test_object, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FOO_TYPE_TEST_OBJECT, FooTestObjectPrivate))
+
+enum
+{
+  PROP_0,
+  PROP_NUMBER,
+  PROP_TEXT
+};
+
+typedef struct
+{
+  int   number;
+  char *text;
+} FooTestObjectPrivate;
+
+static void
+_get_property (GObject    *object,
+               unsigned    property_id,
+               GValue     *value,
+               GParamSpec *pspec)
+{
+  switch (property_id)
+  {
+  case PROP_NUMBER:
+    g_value_set_int (value,
+                     foo_test_object_get_number (
+                        FOO_TEST_OBJECT (object)));
+    break;
+  case PROP_TEXT:
+    g_value_set_string (value,
+                        foo_test_object_get_text (
+                          FOO_TEST_OBJECT (object)));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+_set_property (GObject      *object,
+               unsigned      property_id,
+               const GValue *value,
+               GParamSpec   *pspec)
+{
+  switch (property_id)
+  {
+  case PROP_NUMBER:
+    foo_test_object_set_number (FOO_TEST_OBJECT (object),
+                                g_value_get_int (value));
+    break;
+  case PROP_TEXT:
+    foo_test_object_set_text (FOO_TEST_OBJECT (object),
+                              g_value_get_string (value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (foo_test_object_parent_class)->finalize (object);
+}
+
+static void
+foo_test_object_class_init (FooTestObjectClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (FooTestObjectPrivate));
+
+  object_class->get_property = _get_property;
+  object_class->set_property = _set_property;
+  object_class->finalize = _finalize;
+
+  g_object_class_install_property (object_class,
+                                   PROP_NUMBER,
+                                   g_param_spec_int ("number", "", "",
+                                                     G_MININT32, G_MAXINT32, 0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_TEXT,
+                                   g_param_spec_string ("text", "", "",
+                                                        NULL,
+                                                        G_PARAM_READWRITE));
+}
+
+static void
+foo_test_object_init (FooTestObject *self)
+{
+}
+
+FooTestObject *
+foo_test_object_new (void)
+{
+  return g_object_new (FOO_TYPE_TEST_OBJECT, NULL);
+}
+
+int
+foo_test_object_get_number (FooTestObject *self)
+{
+  FooTestObjectPrivate *priv = GET_PRIVATE (self);
+
+  g_return_val_if_fail (FOO_IS_TEST_OBJECT (self), 0);
+
+  return priv->number;
+}
+
+void
+foo_test_object_set_number (FooTestObject *self,
+                            int            number)
+{
+  FooTestObjectPrivate *priv = GET_PRIVATE (self);
+
+  g_return_if_fail (FOO_IS_TEST_OBJECT (self));
+
+  if (number != priv->number)
+  {
+    priv->number = number;
+
+    g_object_notify (G_OBJECT (self), "number");
+  }
+}
+
+char const *
+foo_test_object_get_text (FooTestObject *self)
+{
+  FooTestObjectPrivate *priv = GET_PRIVATE (self);
+
+  g_return_val_if_fail (FOO_IS_TEST_OBJECT (self), NULL);
+
+  return priv->text;
+}
+
+void
+foo_test_object_set_text (FooTestObject *self,
+                          char const    *text)
+{
+  FooTestObjectPrivate *priv = GET_PRIVATE (self);
+
+  g_return_if_fail (FOO_IS_TEST_OBJECT (self));
+
+  if (0 != g_strcmp0 (text, priv->text))
+  {
+    if (priv->text)
+    {
+      g_free (priv->text);
+      priv->text = NULL;
+    }
+
+    if (text)
+    {
+      priv->text = g_strdup (text);
+    }
+
+    g_object_notify (G_OBJECT (self), "text");
+  }
+}
diff --git a/object-store/foo-test-object.h b/object-store/foo-test-object.h
new file mode 100644 (file)
index 0000000..5c53e3d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Rob Staudinger <robsta@linux.intel.com>
+ */
+
+#ifndef FOO_MODEL_OBJECT_H
+#define FOO_MODEL_OBJECT_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define FOO_TYPE_TEST_OBJECT foo_test_object_get_type()
+
+#define FOO_TEST_OBJECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_TEST_OBJECT, FooTestObject))
+
+#define FOO_TEST_OBJECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_TEST_OBJECT, FooTestObjectClass))
+
+#define FOO_IS_TEST_OBJECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_TEST_OBJECT))
+
+#define FOO_IS_TEST_OBJECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_TEST_OBJECT))
+
+#define FOO_TEST_OBJECT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_TEST_OBJECT, FooTestObjectClass))
+
+typedef struct
+{
+  GObject parent;
+} FooTestObject;
+
+typedef struct
+{
+  GObjectClass parent;
+} FooTestObjectClass;
+
+GType
+foo_test_object_get_type (void);
+
+FooTestObject *
+foo_test_object_new (void);
+
+int
+foo_test_object_get_number (FooTestObject *self);
+
+void
+foo_test_object_set_number (FooTestObject *self,
+                            int            number);
+
+char const *
+foo_test_object_get_text (FooTestObject *self);
+
+void
+foo_test_object_set_text (FooTestObject *self,
+                           char const   *text);
+
+G_END_DECLS
+
+#endif /* FOO_TEST_OBJECT_H */
diff --git a/object-store/object-store-example.c b/object-store/object-store-example.c
new file mode 100644 (file)
index 0000000..b8d78a3
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Rob Staudinger <robsta@linux.intel.com>
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <mx/mx.h>
+#include "foo-object-store.h"
+#include "foo-test-object.h"
+
+typedef struct
+{
+  ClutterActor  *view;
+  MxEntry       *entry;
+  ClutterModel  *store;
+} ObjectStoreTest;
+
+/*
+ * Look up item by index.
+ * Returned object needs to be g_object_unref'd.
+ * May return NULL.
+ */
+FooTestObject *
+store_get_object (ClutterModel *store,
+                  unsigned      index)
+{
+  ClutterModelIter  *iter;
+  FooTestObject     *object = NULL;
+
+  iter = clutter_model_get_iter_at_row (store, index);
+  if (iter &&
+      !clutter_model_iter_is_last (iter))
+  {
+    /* Column #0 of the model holds the actual object. */
+    clutter_model_iter_get (iter,
+                            0, &object,
+                            -1);
+  }
+
+  return object;
+}
+
+/*
+ * Add object to the store.
+ */
+static void
+store_add_object (ClutterModel  *store,
+                  char const    *text)
+{
+  FooTestObject *object;
+
+  object = foo_test_object_new ();
+  foo_test_object_set_text (object, text);
+
+  /* Column #0 holds the actual object, the other cols are mapped to
+   * its properties. */
+  clutter_model_append (store, 0, object, -1);
+  g_object_unref (object);
+}
+
+static void
+_update_clicked (MxButton         *button,
+                 ObjectStoreTest  *app)
+{
+  char const *input;
+
+  input = mx_entry_get_text (app->entry);
+  if (input == NULL ||
+      input[0] == '\0')
+  {
+    g_warning ("Please enter text");
+    return;
+
+  } else if (input[0] == '-') {
+
+    /* Remove item */
+    int index = g_ascii_isdigit (input[1]) ?
+                  atoi (&input[1]) :
+                  -1;
+    if (index < 0)
+    {
+      g_warning ("Invalid number, can not remove");
+      return;
+    }
+
+    clutter_model_remove (app->store, index);
+
+  } else if (g_ascii_isdigit (input[0])) {
+
+    /* Update item */
+    unsigned index = atoi (input);
+    char **tokens = g_strsplit (input, ":", 2);
+    char const *text = tokens[1];
+    FooTestObject *object = store_get_object (app->store, index);
+
+    if (object == NULL)
+    {
+      g_warning ("Failed to find object");
+      return;
+    }
+
+    foo_test_object_set_text (FOO_TEST_OBJECT (object), text);
+    g_object_unref (object);
+
+  } else {
+
+    /* Add item */
+    store_add_object (app->store, input);
+  }
+
+  mx_entry_set_text (app->entry, "");
+}
+
+static void
+_dump_clicked (MxButton         *button,
+               ObjectStoreTest  *app)
+{
+  ClutterModelIter *iter;
+
+  for (iter = clutter_model_get_first_iter (app->store);
+       !clutter_model_iter_is_last (iter);
+       iter = clutter_model_iter_next (iter))
+  {
+    FooTestObject *object = NULL;
+    char          *text = NULL;
+
+    clutter_model_iter_get (iter,
+                            0, &object,
+                            1, &text,
+                            -1);
+    g_debug ("%p %s\n", object, text);
+    g_object_unref (object);
+    g_free (text);
+  }
+}
+
+int
+main (int     argc,
+      char  **argv)
+{
+  ClutterActor    *stage;
+  MxBoxLayout     *vbox;
+  MxBoxLayout     *hbox;
+  ClutterActor    *button;
+  ClutterActor    *label;
+  ObjectStoreTest  app = { 0, };
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_set_size (stage, 320.0, 240.0);
+
+  vbox = (MxBoxLayout *) mx_box_layout_new ();
+  clutter_actor_set_size (CLUTTER_ACTOR (vbox), 320.0, 240.0);
+  mx_box_layout_set_orientation (vbox, MX_ORIENTATION_VERTICAL);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), CLUTTER_ACTOR (vbox));
+
+  /* Create model */
+  app.store = foo_object_store_new (2,
+                                    FOO_TYPE_TEST_OBJECT, "foo",  /* column #0 */
+                                    G_TYPE_STRING, "text");       /* column #1 */
+
+  /*
+   * Create view
+   */
+  app.view = mx_list_view_new ();
+
+  /* Use MxButton to render the model's items */
+  mx_list_view_set_item_type (MX_LIST_VIEW (app.view), MX_TYPE_BUTTON);
+
+  /* Map column #1 to attribute "label" of view's GtkButton */
+  mx_list_view_add_attribute (MX_LIST_VIEW (app.view), "label", 1);
+
+  /* Connect to model */
+  mx_list_view_set_model (MX_LIST_VIEW (app.view), app.store);
+
+  mx_box_layout_add_actor_with_properties (vbox, app.view, -1,
+                                           "expand", true,
+                                           "x-fill", true,
+                                           "y-fill", true,
+                                           NULL);
+
+  hbox = (MxBoxLayout *) mx_box_layout_new ();
+  mx_box_layout_set_orientation (hbox, MX_ORIENTATION_HORIZONTAL);
+  mx_box_layout_add_actor_with_properties (vbox, CLUTTER_ACTOR (hbox), -1,
+                                           "expand", false,
+                                           "x-fill", true,
+                                           NULL);
+
+  app.entry = (MxEntry *) mx_entry_new ();
+  mx_box_layout_add_actor_with_properties (hbox, CLUTTER_ACTOR (app.entry), -1,
+                                           "expand", true,
+                                           "x-fill", true,
+                                           NULL);
+
+  button = mx_button_new_with_label ("Update");
+  g_signal_connect (button, "clicked",
+                    G_CALLBACK (_update_clicked), &app);
+  clutter_container_add_actor (CLUTTER_CONTAINER (hbox), button);
+
+  button = mx_button_new_with_label ("Dump");
+  g_signal_connect (button, "clicked",
+                    G_CALLBACK (_dump_clicked), &app);
+  clutter_container_add_actor (CLUTTER_CONTAINER (hbox), button);
+
+  label = mx_label_new_with_text ("Enter text and update to add item\n"
+                                  "Enter <number>:<text> to change item <number>\n"
+                                  "Enter -<number> to delete item <number>");
+  clutter_container_add_actor (CLUTTER_CONTAINER (vbox), label);
+
+  clutter_actor_show_all (stage);
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}
diff --git a/object-store/object-store-test.c b/object-store/object-store-test.c
new file mode 100644 (file)
index 0000000..8a9b050
--- /dev/null
@@ -0,0 +1,364 @@
+#include <stdlib.h>
+#include <string.h>
+#include <clutter/clutter.h>
+#include "foo-object-store.h"
+#include "foo-test-object.h"
+
+typedef struct _ModelData
+{
+  ClutterModel *model;
+
+  guint n_row;
+} ModelData;
+
+enum
+{
+  COLUMN_OBJECT,  /* FOO_TYPE_OBJECT_STORE */
+  COLUMN_NUMBER,  /* G_TYPE_INT */
+  COLUMN_TEXT,    /* G_TYPE_STRING */
+
+  N_COLUMNS
+};
+
+static const struct {
+  const gchar *expected_foo;
+  gint expected_bar;
+} base_model[] = {
+  { "String 1", 1 },
+  { "String 2", 2 },
+  { "String 3", 3 },
+  { "String 4", 4 },
+  { "String 5", 5 },
+  { "String 6", 6 },
+  { "String 7", 7 },
+  { "String 8", 8 },
+  { "String 9", 9 },
+};
+
+static const struct {
+  const gchar *expected_foo;
+  gint expected_bar;
+} forward_base[] = {
+  { "String 1", 1 },
+  { "String 2", 2 },
+  { "String 3", 3 },
+  { "String 4", 4 },
+  { "String 5", 5 },
+  { "String 6", 6 },
+  { "String 7", 7 },
+  { "String 8", 8 },
+  { "String 9", 9 },
+};
+
+static const struct {
+  const gchar *expected_foo;
+  gint expected_bar;
+} backward_base[] = {
+  { "String 9", 9 },
+  { "String 8", 8 },
+  { "String 7", 7 },
+  { "String 6", 6 },
+  { "String 5", 5 },
+  { "String 4", 4 },
+  { "String 3", 3 },
+  { "String 2", 2 },
+  { "String 1", 1 },
+};
+
+static const struct {
+  const gchar *expected_foo;
+  gint expected_bar;
+} filter_odd[] = {
+  { "String 1", 1 },
+  { "String 3", 3 },
+  { "String 5", 5 },
+  { "String 7", 7 },
+  { "String 9", 9 },
+};
+
+static const struct {
+  const gchar *expected_foo;
+  gint expected_bar;
+} filter_even[] = {
+  { "String 8", 8 },
+  { "String 6", 6 },
+  { "String 4", 4 },
+  { "String 2", 2 },
+};
+
+static inline void
+compare_iter (ClutterModelIter *iter,
+              const gint        expected_row,
+              const gchar      *expected_foo,
+              const gint        expected_bar)
+{
+  gchar *foo = NULL;
+  gint bar = 0;
+  gint row = 0;
+
+  row = clutter_model_iter_get_row (iter);
+  clutter_model_iter_get (iter,
+                          COLUMN_TEXT, &foo,
+                          COLUMN_NUMBER, &bar,
+                          -1);
+
+  if (g_test_verbose ())
+    g_print ("Row %d => %d: Got [ '%s', '%d' ], expected [ '%s', '%d' ]\n",
+             row, expected_row,
+             foo, bar,
+             expected_foo, expected_bar);
+
+  g_assert_cmpint (row, ==, expected_row);
+  g_assert_cmpstr (foo, ==, expected_foo);
+  g_assert_cmpint (bar, ==, expected_bar);
+
+  g_free (foo);
+}
+
+static void
+on_row_added (ClutterModel     *model,
+              ClutterModelIter *iter,
+              gpointer          data)
+{
+  ModelData *model_data = data;
+
+  compare_iter (iter,
+                model_data->n_row,
+                base_model[model_data->n_row].expected_foo,
+                base_model[model_data->n_row].expected_bar);
+
+  model_data->n_row += 1;
+}
+
+static gboolean
+filter_even_rows (ClutterModel     *model,
+                  ClutterModelIter *iter,
+                  gpointer          dummy G_GNUC_UNUSED)
+{
+  gint bar_value;
+
+  clutter_model_iter_get (iter, COLUMN_NUMBER, &bar_value, -1);
+
+  if (bar_value % 2 == 0)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+filter_odd_rows (ClutterModel     *model,
+                 ClutterModelIter *iter,
+                 gpointer          dummy G_GNUC_UNUSED)
+{
+  gint bar_value;
+
+  clutter_model_iter_get (iter, COLUMN_NUMBER, &bar_value, -1);
+
+  if (bar_value % 2 != 0)
+    return TRUE;
+
+  return FALSE;
+}
+
+void
+test_list_model_filter (void)
+{
+  ModelData test_data = { NULL, 0 };
+  ClutterModelIter *iter;
+  gint i;
+
+  test_data.model = foo_object_store_new (N_COLUMNS,
+                                          FOO_TYPE_TEST_OBJECT, "object",
+                                          G_TYPE_INT,           "number",
+                                          G_TYPE_STRING,        "text");
+  test_data.n_row = 0;
+
+  for (i = 1; i < 10; i++)
+    {
+      gchar *foo = g_strdup_printf ("String %d", i);
+      GObject *object = g_object_new (FOO_TYPE_TEST_OBJECT,
+                                      "number", i,
+                                      "text", foo,
+                                      NULL);
+
+      clutter_model_append (test_data.model,
+                            COLUMN_OBJECT, object,
+                            -1);
+
+      g_object_unref (object);
+      g_free (foo);
+    }
+
+  if (g_test_verbose ())
+    g_print ("Forward iteration (filter odd)...\n");
+
+  clutter_model_set_filter (test_data.model, filter_odd_rows, NULL, NULL);
+
+  iter = clutter_model_get_first_iter (test_data.model);
+  g_assert (iter != NULL);
+
+  i = 0;
+  while (!clutter_model_iter_is_last (iter))
+    {
+      compare_iter (iter, i,
+                    filter_odd[i].expected_foo,
+                    filter_odd[i].expected_bar);
+
+      iter = clutter_model_iter_next (iter);
+      i += 1;
+    }
+
+  g_object_unref (iter);
+
+  if (g_test_verbose ())
+    g_print ("Backward iteration (filter even)...\n");
+
+  clutter_model_set_filter (test_data.model, filter_even_rows, NULL, NULL);
+
+  iter = clutter_model_get_last_iter (test_data.model);
+  g_assert (iter != NULL);
+
+  i = 0;
+  do
+    {
+      compare_iter (iter, G_N_ELEMENTS (filter_even) - i - 1,
+                    filter_even[i].expected_foo,
+                    filter_even[i].expected_bar);
+
+      iter = clutter_model_iter_prev (iter);
+      i += 1;
+    }
+  while (!clutter_model_iter_is_first (iter));
+
+  g_object_unref (iter);
+
+  g_object_unref (test_data.model);
+}
+
+void
+test_list_model_iterate (void)
+{
+  ModelData test_data = { NULL, 0 };
+  ClutterModelIter *iter;
+  gint i;
+
+  test_data.model = foo_object_store_new (N_COLUMNS,
+                                          FOO_TYPE_TEST_OBJECT, "object",
+                                          G_TYPE_INT,           "number",
+                                          G_TYPE_STRING,        "text");
+  test_data.n_row = 0;
+
+  g_signal_connect (test_data.model, "row-added",
+                    G_CALLBACK (on_row_added),
+                    &test_data);
+
+  for (i = 1; i < 10; i++)
+    {
+      gchar *foo = g_strdup_printf ("String %d", i);
+      GObject *object = g_object_new (FOO_TYPE_TEST_OBJECT,
+                                      "number", i,
+                                      "text", foo,
+                                      NULL);
+
+      clutter_model_append (test_data.model,
+                            COLUMN_OBJECT, object,
+                            -1);
+
+      g_object_unref (object);
+      g_free (foo);
+    }
+
+  if (g_test_verbose ())
+    g_print ("Forward iteration...\n");
+
+  iter = clutter_model_get_first_iter (test_data.model);
+  g_assert (iter != NULL);
+
+  i = 0;
+  while (!clutter_model_iter_is_last (iter))
+    {
+      compare_iter (iter, i,
+                    forward_base[i].expected_foo,
+                    forward_base[i].expected_bar);
+
+      iter = clutter_model_iter_next (iter);
+      i += 1;
+    }
+
+  g_object_unref (iter);
+
+  if (g_test_verbose ())
+    g_print ("Backward iteration...\n");
+
+  iter = clutter_model_get_last_iter (test_data.model);
+  g_assert (iter != NULL);
+
+  i = 0;
+  do
+    {
+      compare_iter (iter, G_N_ELEMENTS (backward_base) - i - 1,
+                    backward_base[i].expected_foo,
+                    backward_base[i].expected_bar);
+
+      iter = clutter_model_iter_prev (iter);
+      i += 1;
+    }
+  while (!clutter_model_iter_is_first (iter));
+
+  compare_iter (iter, G_N_ELEMENTS (backward_base) - i - 1,
+                backward_base[i].expected_foo,
+                backward_base[i].expected_bar);
+
+  g_object_unref (iter);
+
+  g_object_unref (test_data.model);
+}
+
+void
+test_list_model_populate (void)
+{
+  ModelData test_data = { NULL, 0 };
+  gint i;
+
+  test_data.model = foo_object_store_new (N_COLUMNS,
+                                          FOO_TYPE_TEST_OBJECT, "object",
+                                          G_TYPE_INT,           "number",
+                                          G_TYPE_STRING,        "text");
+  test_data.n_row = 0;
+
+  g_signal_connect (test_data.model, "row-added",
+                    G_CALLBACK (on_row_added),
+                    &test_data);
+
+  for (i = 1; i < 10; i++)
+    {
+      gchar *foo = g_strdup_printf ("String %d", i);
+      GObject *object = g_object_new (FOO_TYPE_TEST_OBJECT,
+                                      "number", i,
+                                      "text", foo,
+                                      NULL);
+
+      clutter_model_append (test_data.model,
+                            COLUMN_OBJECT, object,
+                            -1);
+
+      g_object_unref (object);
+      g_free (foo);
+    }
+
+  g_object_unref (test_data.model);
+}
+
+int
+main (int     argc,
+      char  **argv)
+{
+  clutter_init (&argc, &argv);
+
+  test_list_model_populate ();
+  test_list_model_iterate ();
+  test_list_model_filter ();
+
+  return EXIT_SUCCESS;
+}
\ No newline at end of file
diff --git a/odo/Makefile b/odo/Makefile
new file mode 100644 (file)
index 0000000..c46cffd
--- /dev/null
@@ -0,0 +1,14 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+CFLAGS="-lm"
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: odo
+
+odo: odo.o odo-texture.o odo-distort-funcs.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ odo.o odo-texture.o odo-distort-funcs.o $(LIBS)
+
+clean:
+       rm -f *.o odo
diff --git a/odo/README b/odo/README
new file mode 100644 (file)
index 0000000..487cebc
--- /dev/null
@@ -0,0 +1,8 @@
+This work has been superceded by the MxDeformTexture widget in the Mx
+toolkit. Mx is available from git,
+
+git://git.moblin.org/mx
+
+The effects here are all included in Mx, along with tweaks to improve
+their function, and the MxDeformTexture widget itself is better structured
+to allow for animating properties with clutter_actor_animate ().
diff --git a/odo/grid.png b/odo/grid.png
new file mode 100644 (file)
index 0000000..e72560a
Binary files /dev/null and b/odo/grid.png differ
diff --git a/odo/neghand.png b/odo/neghand.png
new file mode 100644 (file)
index 0000000..48e7d6a
Binary files /dev/null and b/odo/neghand.png differ
diff --git a/odo/odo-distort-funcs.c b/odo/odo-distort-funcs.c
new file mode 100644 (file)
index 0000000..3e66c73
--- /dev/null
@@ -0,0 +1,137 @@
+#include <math.h>
+#include "odo-distort-funcs.h"
+
+void
+cloth_func (OdoTexture *otex,
+            CoglTextureVertex *vertex,
+            gfloat             width,
+            gfloat             height,
+            gpointer           data)
+{
+  OdoDistortData *d = data;
+  gfloat cx, cy, rx, turn_angle, height_radius;
+  guint shade;
+
+  /* Rotate the point around the centre of the curl ray to align it with
+   * the y-axis.
+   */
+
+  cx = (1.f - d->turn) * width;
+  cy = (1.f - d->turn) * height;
+
+  rx = ((vertex->x - cx) * cos (-d->angle)) -
+       ((vertex->y - cy) * sin (-d->angle)) - d->radius;
+
+  /* Calculate the angle as a function of the distance from the curl ray */
+  turn_angle = ((rx / d->radius) * G_PI_2) - G_PI_2;
+
+  /* Add a gradient that makes it look like lighting and hides the switch
+   * between textures.
+   */
+  shade = (255 * (1.f - d->amplitude)) +
+          (((sin (turn_angle) * 96) + 159) * d->amplitude);
+  vertex->color.red = shade;
+  vertex->color.green = shade;
+  vertex->color.blue = shade;
+
+  /* Make the wave amplitude lower as its distance from the curl ray increases.
+   * Not really necessary, but looks a little nicer I think.
+   */
+  height_radius = (1 - rx / width) * d->radius;
+  vertex->z = height_radius * sin (turn_angle) * d->amplitude;
+}
+
+void
+bowtie_func (OdoTexture        *otex,
+             CoglTextureVertex *vertex,
+             gfloat             width,
+             gfloat             height,
+             gpointer           data)
+{
+  OdoDistortData *d = data;
+  gfloat cx, cy, rx, ry, turn_angle, height_radius;
+  guint shade;
+
+  cx = d->turn * (width + width/2);
+  cy = height/2;
+
+  rx = ((vertex->x - cx) * cos (0)) -
+       ((vertex->y - cy) * sin (0));
+  ry = ((vertex->x - cx) * sin (0)) +
+       ((vertex->y - cy) * cos (0));
+
+  /* Make angle as a function of distance from the curl ray */
+  turn_angle = MAX (-G_PI, MIN (0, (rx / (width/4)) * G_PI_2));
+
+  /* Add a gradient that makes it look like lighting */
+  shade = (cos (turn_angle * 2) * 96) + 159;
+  vertex->color.red = shade;
+  vertex->color.green = shade;
+  vertex->color.blue = shade;
+
+  /* Calculate the point on a cone (note, a cone, not a right cone) */
+  height_radius = ry;
+  /*ClutterFixed height_radius =
+    clutter_qmulx (clutter_qdivx (ry, height/2), height/2);*/
+
+  ry = height_radius * cos (turn_angle);
+  vertex->x = (rx * cos (0)) - (ry * sin (0)) + cx;
+  vertex->y = (rx * sin (0)) + (ry * cos (0)) + cy;
+  vertex->z = height_radius * sin (turn_angle);
+}
+
+void
+page_turn_func (OdoTexture        *otex,
+                CoglTextureVertex *vertex,
+                gfloat             width,
+                gfloat             height,
+                gpointer           data)
+{
+  OdoDistortData *d = data;
+  gfloat cx, cy, rx, ry;
+  gfloat turn_angle;
+  guint shade;
+
+  /* Rotate the point around the centre of the page-curl ray to align it with
+   * the y-axis.
+   */
+  cx = (1.f - d->turn) * width;
+  cy = (1.f - d->turn) * height;
+
+  rx = ((vertex->x - cx) * cos (-d->angle)) -
+       ((vertex->y - cy) * sin (-d->angle)) - d->radius;
+  ry = ((vertex->x - cx) * sin (-d->angle)) +
+       ((vertex->y - cy) * cos (-d->angle));
+
+  if (rx > -d->radius * 2)
+    {
+      /* Calculate the curl angle as a function from the distance of the curl
+       * ray (i.e. the page crease)
+       */
+      turn_angle = (rx / d->radius * G_PI_2) - G_PI_2;
+      shade = (sin (turn_angle) * 96) + 159;
+
+      /* Add a gradient that makes it look like lighting and hides the switch
+       * between textures.
+       */
+      vertex->color.red = shade;
+      vertex->color.green = shade;
+      vertex->color.blue = shade;
+    }
+
+  if (rx > 0)
+    {
+      /* Make the curl radius smaller as more circles are formed (stops
+       * z-fighting and looks cool)
+       */
+      gfloat small_radius = d->radius - (turn_angle * 2) / G_PI;
+
+      /* Calculate a point on a cylinder (maybe make this a cone at some point)
+       * and rotate it by the specified angle.
+       */
+      rx = (small_radius * cos (turn_angle)) + d->radius;
+      vertex->x = (rx * cos (d->angle)) - (ry * sin (d->angle)) + cx;
+      vertex->y = (rx * sin (d->angle)) + (ry * cos (d->angle)) + cy;
+      vertex->z = (small_radius * sin (turn_angle)) + d->radius;
+    }
+}
diff --git a/odo/odo-distort-funcs.h b/odo/odo-distort-funcs.h
new file mode 100644 (file)
index 0000000..ea8dcf6
--- /dev/null
@@ -0,0 +1,41 @@
+
+#ifndef ODO_DISTORT_FUNCS_H
+#define ODO_DISTORT_FUNCS_H
+
+#include <clutter/clutter.h>
+#include "odo-texture.h"
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+  gfloat           radius;
+  gfloat           angle;
+  gfloat           turn;
+  gfloat           amplitude;
+} OdoDistortData;
+
+void
+cloth_func (OdoTexture *otex,
+            CoglTextureVertex *vertex,
+            gfloat             width,
+            gfloat             height,
+            gpointer           data);
+
+void
+bowtie_func (OdoTexture        *otex,
+             CoglTextureVertex *vertex,
+             gfloat             width,
+             gfloat             height,
+             gpointer           data);
+
+void
+page_turn_func (OdoTexture        *otex,
+                CoglTextureVertex *vertex,
+                gfloat             width,
+                gfloat             height,
+                gpointer           data);
+
+G_END_DECLS
+
+#endif
diff --git a/odo/odo-texture.c b/odo/odo-texture.c
new file mode 100644 (file)
index 0000000..aea5bea
--- /dev/null
@@ -0,0 +1,641 @@
+/* odo-texture.c */
+
+#include "odo-texture.h"
+
+G_DEFINE_TYPE (OdoTexture, odo_texture, CLUTTER_TYPE_ACTOR)
+
+#define TEXTURE_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), ODO_TYPE_TEXTURE, OdoTexturePrivate))
+
+struct _OdoTexturePrivate
+{
+  gint                tiles_x;
+  gint                tiles_y;
+  OdoTextureCallback  callback;
+  gpointer            user_data;
+
+  CoglHandle          vbo;
+  gint                n_indices;
+  CoglHandle         *indices;
+  CoglHandle         *bf_indices;
+  CoglTextureVertex  *vertices;
+
+  ClutterTexture     *front_face;
+  ClutterTexture     *back_face;
+
+  gboolean            dirty;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_TILES_X,
+  PROP_TILES_Y,
+  PROP_FRONT_FACE,
+  PROP_BACK_FACE
+};
+
+static void
+odo_texture_get_property (GObject *object, guint property_id,
+                          GValue *value, GParamSpec *pspec)
+{
+  OdoTexturePrivate *priv = ODO_TEXTURE (object)->priv;
+
+  switch (property_id)
+    {
+    case PROP_TILES_X:
+      g_value_set_int (value, priv->tiles_x);
+      break;
+
+    case PROP_TILES_Y:
+      g_value_set_int (value, priv->tiles_y);
+      break;
+
+    case PROP_FRONT_FACE:
+      g_value_set_object (value, priv->front_face);
+      break;
+
+    case PROP_BACK_FACE:
+      g_value_set_object (value, priv->back_face);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+odo_texture_set_property (GObject *object, guint property_id,
+                          const GValue *value, GParamSpec *pspec)
+{
+  OdoTexture *texture = ODO_TEXTURE (object);
+  OdoTexturePrivate *priv = texture->priv;
+
+  switch (property_id)
+    {
+    case PROP_TILES_X:
+      odo_texture_set_resolution (texture,
+                                  g_value_get_int (value),
+                                  priv->tiles_y);
+      break;
+
+    case PROP_TILES_Y:
+      odo_texture_set_resolution (texture,
+                                  priv->tiles_x,
+                                  g_value_get_int (value));
+      break;
+
+    case PROP_FRONT_FACE:
+      odo_texture_set_textures (texture,
+                                g_value_get_object (value),
+                                priv->back_face);
+      break;
+
+    case PROP_BACK_FACE:
+      odo_texture_set_textures (texture,
+                                priv->front_face,
+                                g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+odo_texture_free_arrays (OdoTexture *self)
+{
+  OdoTexturePrivate *priv = self->priv;
+
+  if (priv->vbo)
+    {
+      cogl_handle_unref (priv->vbo);
+      priv->vbo = NULL;
+    }
+
+  if (priv->indices)
+    {
+      cogl_handle_unref (priv->indices);
+      priv->indices = NULL;
+    }
+
+  g_free (priv->vertices);
+  priv->vertices = NULL;
+}
+
+static void
+odo_texture_dispose (GObject *object)
+{
+  OdoTexture *self = ODO_TEXTURE (object);
+  OdoTexturePrivate *priv = self->priv;
+
+  odo_texture_free_arrays (self);
+
+  if (priv->front_face)
+    {
+      g_object_unref (priv->front_face);
+      priv->front_face = NULL;
+    }
+
+  if (priv->back_face)
+    {
+      g_object_unref (priv->back_face);
+      priv->back_face = NULL;
+    }
+
+  G_OBJECT_CLASS (odo_texture_parent_class)->dispose (object);
+}
+
+static void
+odo_texture_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (odo_texture_parent_class)->finalize (object);
+}
+
+static void
+odo_texture_paint (ClutterActor *actor)
+{
+  gint i, j;
+  CoglHandle material;
+  gboolean depth, cull;
+
+  OdoTexture *self = ODO_TEXTURE (actor);
+  OdoTexturePrivate *priv = self->priv;
+
+  if (priv->dirty)
+    {
+      guint opacity;
+      gfloat width, height;
+      ClutterActorBox box;
+
+      opacity = clutter_actor_get_paint_opacity (actor);
+      clutter_actor_get_allocation_box (actor, &box);
+      width = box.x2 - box.x1;
+      height = box.y2 - box.y1;
+
+      for (i = 0; i <= priv->tiles_y; i++)
+        {
+          for (j = 0; j <= priv->tiles_x; j++)
+            {
+              CoglTextureVertex *vertex =
+                &priv->vertices[(i * (priv->tiles_x + 1)) + j];
+
+              vertex->tx = j/(gfloat)priv->tiles_x;
+              vertex->ty = i/(gfloat)priv->tiles_y;
+              vertex->x = width * vertex->tx;
+              vertex->y = height * vertex->ty;
+              vertex->z = 0;
+              cogl_color_set_from_4ub (&vertex->color,
+                                       0xff, 0xff, 0xff, opacity);
+
+              if (priv->callback)
+                priv->callback (self, vertex, width, height, priv->user_data);
+            }
+        }
+
+      /* We add all three attributes again, although in an ideal case,
+       * we'd add only those that had changed. Because we provide the
+       * ability to change each, unless we had a 'changed' gboolean * in
+       * the function prototype, we have to upload all of it.
+       */
+      cogl_vertex_buffer_add (priv->vbo,
+                              "gl_Vertex",
+                              3,
+                              COGL_ATTRIBUTE_TYPE_FLOAT,
+                              FALSE,
+                              sizeof (CoglTextureVertex),
+                              &priv->vertices->x);
+      cogl_vertex_buffer_add (priv->vbo,
+                              "gl_MultiTexCoord0",
+                              2,
+                              COGL_ATTRIBUTE_TYPE_FLOAT,
+                              FALSE,
+                              sizeof (CoglTextureVertex),
+                              &priv->vertices->tx);
+      cogl_vertex_buffer_add (priv->vbo,
+                              "gl_Color",
+                              4,
+                              COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE,
+                              FALSE,
+                              sizeof (CoglTextureVertex),
+                              &priv->vertices->color);
+      cogl_vertex_buffer_submit (priv->vbo);
+
+      priv->dirty = FALSE;
+    }
+
+  depth = cogl_get_depth_test_enabled ();
+  if (!depth)
+    cogl_set_depth_test_enabled (TRUE);
+
+  cull = cogl_get_backface_culling_enabled ();
+  if (priv->back_face && !cull)
+    cogl_set_backface_culling_enabled (TRUE);
+  else if (!priv->back_face && cull)
+    cogl_set_backface_culling_enabled (FALSE);
+
+  if (priv->front_face)
+    {
+      material = clutter_texture_get_cogl_material (priv->front_face);
+      cogl_set_source (material);
+      cogl_vertex_buffer_draw_elements (priv->vbo,
+                                        COGL_VERTICES_MODE_TRIANGLE_STRIP,
+                                        priv->indices,
+                                        0,
+                                        (priv->tiles_x + 1) *
+                                        (priv->tiles_y + 1),
+                                        0,
+                                        priv->n_indices);
+    }
+
+  if (priv->back_face)
+    {
+      material = clutter_texture_get_cogl_material (priv->back_face);
+      cogl_set_source (material);
+      cogl_vertex_buffer_draw_elements (priv->vbo,
+                                        COGL_VERTICES_MODE_TRIANGLE_STRIP,
+                                        priv->bf_indices,
+                                        0,
+                                        (priv->tiles_x + 1) *
+                                        (priv->tiles_y + 1),
+                                        0,
+                                        priv->n_indices);
+    }
+
+  if (!depth)
+    cogl_set_depth_test_enabled (FALSE);
+  if (priv->back_face && !cull)
+    cogl_set_backface_culling_enabled (FALSE);
+  else if (!priv->back_face && cull)
+    cogl_set_backface_culling_enabled (TRUE);
+}
+
+static void
+odo_texture_get_preferred_width (ClutterActor *actor,
+                                 gfloat        for_height,
+                                 gfloat       *min_width_p,
+                                 gfloat       *natural_width_p)
+{
+  ClutterActor *proxy;
+  OdoTexturePrivate *priv = ODO_TEXTURE (actor)->priv;
+
+  if (priv->front_face)
+    proxy = CLUTTER_ACTOR (priv->front_face);
+  else if (priv->back_face)
+    proxy = CLUTTER_ACTOR (priv->back_face);
+  else
+    {
+      if (min_width_p)
+        *min_width_p = 0;
+      if (natural_width_p)
+        *natural_width_p = 0;
+
+      return;
+    }
+
+  clutter_actor_get_preferred_width (proxy,
+                                     for_height,
+                                     min_width_p,
+                                     natural_width_p);
+}
+
+static void
+odo_texture_get_preferred_height (ClutterActor *actor,
+                                  gfloat        for_width,
+                                  gfloat       *min_height_p,
+                                  gfloat       *natural_height_p)
+{
+  ClutterActor *proxy;
+  OdoTexturePrivate *priv = ODO_TEXTURE (actor)->priv;
+
+  if (priv->front_face)
+    proxy = CLUTTER_ACTOR (priv->front_face);
+  else if (priv->back_face)
+    proxy = CLUTTER_ACTOR (priv->back_face);
+  else
+    {
+      if (min_height_p)
+        *min_height_p = 0;
+      if (natural_height_p)
+        *natural_height_p = 0;
+
+      return;
+    }
+
+  clutter_actor_get_preferred_height (proxy,
+                                      for_width,
+                                      min_height_p,
+                                      natural_height_p);
+}
+/*
+static void
+odo_texture_allocate (ClutterActor           *actor,
+                      const ClutterActorBox  *box,
+                      ClutterAllocationFlags  flags)
+{
+}*/
+
+static void
+odo_texture_class_init (OdoTextureClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (OdoTexturePrivate));
+
+  object_class->get_property = odo_texture_get_property;
+  object_class->set_property = odo_texture_set_property;
+  object_class->dispose = odo_texture_dispose;
+  object_class->finalize = odo_texture_finalize;
+
+  actor_class->get_preferred_width = odo_texture_get_preferred_width;
+  actor_class->get_preferred_height = odo_texture_get_preferred_height;
+  /*actor_class->allocate = odo_texture_allocate;*/
+  actor_class->paint = odo_texture_paint;
+
+  g_object_class_install_property (object_class,
+                                   PROP_TILES_X,
+                                   g_param_spec_int ("tiles-x",
+                                                     "Horizontal tiles",
+                                                     "Amount of horizontal "
+                                                     "tiles to split the "
+                                                     "texture into.",
+                                                     1, G_MAXINT, 32,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_STATIC_NAME |
+                                                     G_PARAM_STATIC_NICK |
+                                                     G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+                                   PROP_TILES_Y,
+                                   g_param_spec_int ("tiles-y",
+                                                     "Vertical tiles",
+                                                     "Amount of vertical "
+                                                     "tiles to split the "
+                                                     "texture into.",
+                                                     1, G_MAXINT, 32,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_STATIC_NAME |
+                                                     G_PARAM_STATIC_NICK |
+                                                     G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+                                   PROP_FRONT_FACE,
+                                   g_param_spec_object ("front-face",
+                                                        "Front-face",
+                                                        "Front-face texture.",
+                                                        CLUTTER_TYPE_TEXTURE,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+                                   PROP_BACK_FACE,
+                                   g_param_spec_object ("back-face",
+                                                        "Back-face",
+                                                        "Back-face texture.",
+                                                        CLUTTER_TYPE_TEXTURE,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+}
+
+static void
+odo_texture_init_arrays (OdoTexture *self)
+{
+  GLushort *idx, *bf_idx;
+  gint x, y, direction;
+  GLushort *static_indices, *static_bf_indices;
+  OdoTexturePrivate *priv = self->priv;
+
+  odo_texture_free_arrays (self);
+
+  priv->n_indices = (2 + 2 * priv->tiles_x) *
+                    priv->tiles_y +
+                    (priv->tiles_y - 1);
+  static_indices = g_new (GLushort, priv->n_indices);
+  static_bf_indices = g_new (GLushort, priv->n_indices);
+
+#define MESH_INDEX(X, Y) (Y) * (priv->tiles_x + 1) + (X)
+
+  direction = 1;
+
+  idx = static_indices;
+  idx[0] = MESH_INDEX (0, 0);
+  idx[1] = MESH_INDEX (0, 1);
+  idx += 2;
+
+  bf_idx = static_bf_indices;
+  bf_idx[0] = MESH_INDEX (priv->tiles_x, 0);
+  bf_idx[1] = MESH_INDEX (priv->tiles_x, 1);
+  bf_idx += 2;
+
+  for (y = 0; y < priv->tiles_y; y++)
+    {
+      for (x = 0; x < priv->tiles_x; x++)
+        {
+          /* Add 2 triangles for a quad */
+          if (direction)
+            {
+              idx[0] = MESH_INDEX (x + 1, y);
+              idx[1] = MESH_INDEX (x + 1, y + 1);
+              bf_idx[0] = MESH_INDEX (priv->tiles_x - (x + 1), y);
+              bf_idx[1] = MESH_INDEX (priv->tiles_x - (x + 1), y + 1);
+            }
+          else
+            {
+              idx[0] = MESH_INDEX (priv->tiles_x - x - 1, y);
+              idx[1] = MESH_INDEX (priv->tiles_x - x - 1, y + 1);
+              bf_idx[0] = MESH_INDEX (x + 1, y);
+              bf_idx[1] = MESH_INDEX (x + 1, y + 1);
+            }
+          idx += 2;
+          bf_idx += 2;
+        }
+
+      /* Link rows together to draw in one call */
+      if (y == (priv->tiles_y - 1))
+        break;
+
+      if (direction)
+        {
+          idx[0] = MESH_INDEX (priv->tiles_x, y + 1);
+          idx[1] = MESH_INDEX (priv->tiles_x, y + 1);
+          idx[2] = MESH_INDEX (priv->tiles_x, y + 2);
+          bf_idx[0] = MESH_INDEX (0, y + 1);
+          bf_idx[1] = MESH_INDEX (0, y + 1);
+          bf_idx[2] = MESH_INDEX (0, y + 2);
+        }
+      else
+        {
+          idx[0] = MESH_INDEX (0, y + 1);
+          idx[1] = MESH_INDEX (0, y + 1);
+          idx[2] = MESH_INDEX (0, y + 2);
+          bf_idx[0] = MESH_INDEX (priv->tiles_x, y + 1);
+          bf_idx[1] = MESH_INDEX (priv->tiles_x, y + 1);
+          bf_idx[2] = MESH_INDEX (priv->tiles_x, y + 2);
+        }
+
+      idx += 3;
+      bf_idx += 3;
+      direction = !direction;
+    }
+
+  priv->indices =
+    cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
+                                    static_indices,
+                                    priv->n_indices);
+  priv->bf_indices =
+    cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
+                                    static_bf_indices,
+                                    priv->n_indices);
+  g_free (static_indices);
+  g_free (static_bf_indices);
+
+  priv->vertices = g_new (CoglTextureVertex,
+                          (priv->tiles_x + 1) * (priv->tiles_y + 1));
+
+  priv->vbo = cogl_vertex_buffer_new ((priv->tiles_x + 1) *
+                                      (priv->tiles_y + 1));
+}
+
+static void
+odo_texture_init (OdoTexture *self)
+{
+  OdoTexturePrivate *priv = self->priv = TEXTURE_PRIVATE (self);
+
+  priv->tiles_x = 32;
+  priv->tiles_y = 32;
+  odo_texture_init_arrays (self);
+}
+
+ClutterActor *
+odo_texture_new (void)
+{
+  return g_object_new (ODO_TYPE_TEXTURE, NULL);
+}
+
+ClutterActor *
+odo_texture_new_from_files (const gchar *front_face_filename,
+                            const gchar *back_face_filename)
+{
+  ClutterTexture *front_face, *back_face;
+
+  if (front_face_filename)
+    front_face = g_object_new (CLUTTER_TYPE_TEXTURE,
+                               "disable-slicing", TRUE,
+                               "filename", front_face_filename,
+                               NULL);
+  else
+    front_face = NULL;
+
+  if (back_face_filename)
+    back_face = g_object_new (CLUTTER_TYPE_TEXTURE,
+                              "disable-slicing", TRUE,
+                              "filename", back_face_filename,
+                              NULL);
+  else
+    back_face = NULL;
+
+  return odo_texture_new_with_textures (front_face, back_face);
+}
+
+ClutterActor *
+odo_texture_new_with_textures (ClutterTexture *front_face,
+                               ClutterTexture *back_face)
+{
+  return g_object_new (ODO_TYPE_TEXTURE,
+                       "front-face", front_face,
+                       "back-face", back_face,
+                       NULL);
+}
+
+void
+odo_texture_set_textures (OdoTexture     *texture,
+                          ClutterTexture *front_face,
+                          ClutterTexture *back_face)
+{
+  ClutterTexture *old_texture;
+  OdoTexturePrivate *priv = texture->priv;
+
+  old_texture = priv->front_face;
+  priv->front_face = front_face ? g_object_ref_sink (front_face) : NULL;
+  if (old_texture)
+    g_object_unref (old_texture);
+
+  old_texture = priv->back_face;
+  priv->back_face = back_face ? g_object_ref_sink (back_face) : NULL;
+  if (old_texture)
+    g_object_unref (old_texture);
+
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
+}
+
+void
+odo_texture_get_resolution (OdoTexture *texture,
+                            gint       *tiles_x,
+                            gint       *tiles_y)
+{
+  OdoTexturePrivate *priv = texture->priv;
+
+  if (tiles_x)
+    *tiles_x = priv->tiles_x;
+  if (tiles_y)
+    *tiles_y = priv->tiles_y;
+}
+
+void
+odo_texture_set_resolution (OdoTexture *texture,
+                            gint        tiles_x,
+                            gint        tiles_y)
+{
+  OdoTexturePrivate *priv = texture->priv;
+  gboolean changed = FALSE;
+
+  g_return_if_fail ((tiles_x > 0) && (tiles_y > 0));
+
+  if (priv->tiles_x != tiles_x)
+    {
+      priv->tiles_x = tiles_x;
+      changed = TRUE;
+      g_object_notify (G_OBJECT (texture), "tiles-x");
+    }
+
+  if (priv->tiles_y != tiles_y)
+    {
+      priv->tiles_y = tiles_y;
+      changed = TRUE;
+      g_object_notify (G_OBJECT (texture), "tiles-y");
+    }
+
+  if (changed)
+    {
+      odo_texture_init_arrays (texture);
+      odo_texture_invalidate (texture);
+    }
+}
+
+void
+odo_texture_set_callback (OdoTexture         *texture,
+                          OdoTextureCallback  callback,
+                          gpointer            user_data)
+{
+  OdoTexturePrivate *priv = texture->priv;
+
+  priv->callback = callback;
+  priv->user_data = user_data;
+
+  odo_texture_invalidate (texture);
+}
+
+void
+odo_texture_invalidate (OdoTexture *texture)
+{
+  OdoTexturePrivate *priv = texture->priv;
+  priv->dirty = TRUE;
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
+}
+
diff --git a/odo/odo-texture.h b/odo/odo-texture.h
new file mode 100644 (file)
index 0000000..5c2aae0
--- /dev/null
@@ -0,0 +1,84 @@
+/* odo-texture.h */
+
+#ifndef _ODO_TEXTURE_H
+#define _ODO_TEXTURE_H
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define ODO_TYPE_TEXTURE odo_texture_get_type()
+
+#define ODO_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  ODO_TYPE_TEXTURE, OdoTexture))
+
+#define ODO_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  ODO_TYPE_TEXTURE, OdoTextureClass))
+
+#define ODO_IS_TEXTURE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  ODO_TYPE_TEXTURE))
+
+#define ODO_IS_TEXTURE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  ODO_TYPE_TEXTURE))
+
+#define ODO_TEXTURE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  ODO_TYPE_TEXTURE, OdoTextureClass))
+
+typedef struct _OdoTexture OdoTexture;
+typedef struct _OdoTextureClass OdoTextureClass;
+typedef struct _OdoTexturePrivate OdoTexturePrivate;
+
+struct _OdoTexture
+{
+  ClutterActor parent;
+
+  OdoTexturePrivate *priv;
+};
+
+struct _OdoTextureClass
+{
+  ClutterActorClass parent_class;
+};
+
+GType odo_texture_get_type (void);
+
+typedef void (*OdoTextureCallback) (OdoTexture        *texture,
+                                    CoglTextureVertex *vertex,
+                                    gfloat             width,
+                                    gfloat             height,
+                                    gpointer           user_data);
+
+ClutterActor *odo_texture_new (void);
+ClutterActor *odo_texture_new_from_files (const gchar *front_face_filename,
+                                          const gchar *back_face_filename);
+ClutterActor *odo_texture_new_with_textures (ClutterTexture *front_face,
+                                             ClutterTexture *back_face);
+
+void odo_texture_get_resolution (OdoTexture *texture,
+                                 gint       *tiles_x,
+                                 gint       *tiles_y);
+
+void odo_texture_set_resolution (OdoTexture *texture,
+                                 gint        tiles_x,
+                                 gint        tiles_y);
+
+void odo_texture_set_callback (OdoTexture         *texture,
+                               OdoTextureCallback  callback,
+                               gpointer            user_data);
+
+void odo_texture_set_textures (OdoTexture     *texture,
+                               ClutterTexture *front_face,
+                               ClutterTexture *back_face);
+
+void odo_texture_invalidate (OdoTexture *texture);
+
+G_END_DECLS
+
+#endif /* _ODO_TEXTURE_H */
+
diff --git a/odo/odo.c b/odo/odo.c
new file mode 100644 (file)
index 0000000..91e0fb6
--- /dev/null
+++ b/odo/odo.c
@@ -0,0 +1,139 @@
+#include <math.h>
+#include <clutter/clutter.h>
+#include "odo-distort-funcs.h"
+#include "odo-texture.h"
+
+struct distort_data
+{
+  ClutterActor    *odo;
+  OdoDistortData   data;
+  ClutterTimeline *timeline;
+  ClutterAlpha    *alpha;
+};
+
+static gint func = 0;
+
+static void
+new_frame_cb (ClutterTimeline *timeline,
+              gint             msecs,
+              gpointer         data)
+{
+  /* Set the turn value to the alpha value and redraw */
+  struct distort_data *d = data;
+  d->data.turn = clutter_alpha_get_alpha (d->alpha);
+  d->data.amplitude = d->data.turn;
+
+  odo_texture_invalidate (ODO_TEXTURE (d->odo));
+}
+
+static void
+completed_cb (ClutterTimeline *timeline,
+              gpointer         data)
+{
+  struct distort_data *d = data;
+
+  /* Reverse direction and start again */
+  ClutterTimelineDirection dir = clutter_timeline_get_direction (timeline);
+  clutter_timeline_set_direction (timeline, 1 - dir);
+
+  if (dir == CLUTTER_TIMELINE_BACKWARD)
+    {
+      switch (func)
+        {
+        case 0:
+          odo_texture_set_callback (ODO_TEXTURE (d->odo),
+                                    bowtie_func,
+                                    &d->data);
+          func = 1;
+          break;
+
+        case 1:
+          odo_texture_set_callback (ODO_TEXTURE (d->odo),
+                                    cloth_func,
+                                    &d->data);
+          func = 2;
+          break;
+
+        case 2:
+          odo_texture_set_callback (ODO_TEXTURE (d->odo),
+                                    page_turn_func,
+                                    &d->data);
+          func = 0;
+          break;
+        }
+    }
+
+  clutter_timeline_start (timeline);
+}
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor        *stage;
+  ClutterColor         stage_color = { 0xcc, 0xcc, 0xcc, 0xff };
+  struct distort_data  data;
+
+  if (argc < 2)
+    {
+      printf ("Usage: %s <filename> [filename]\n", argv[0]);
+      return 1;
+    }
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+
+  /* Quit on key-press */
+  g_signal_connect (stage, "key-press-event",
+                    G_CALLBACK (clutter_main_quit), NULL);
+
+  /* Make a fullscreen stage */
+  clutter_stage_set_color (CLUTTER_STAGE (stage),
+                           &stage_color);
+  clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), TRUE);
+
+  /* Create the texture and set the deformation callback */
+  data.odo = odo_texture_new_from_files (argv[1], (argc > 2) ? argv[2] : NULL);
+  odo_texture_set_callback (ODO_TEXTURE (data.odo), page_turn_func, &data.data);
+
+  /* Make the subdivision dependent on image size */
+  odo_texture_set_resolution (ODO_TEXTURE (data.odo),
+                              clutter_actor_get_width (data.odo) / 10,
+                              clutter_actor_get_height (data.odo) / 10);
+
+  /* Put it in the centre of the stage and add a jaunty angle */
+  clutter_actor_set_rotation (data.odo, CLUTTER_Y_AXIS, 15, 0, 0, 0);
+  clutter_actor_set_rotation (data.odo, CLUTTER_X_AXIS, 15, 0, 0, 0);
+  clutter_actor_set_position (data.odo,
+                              (clutter_actor_get_width (stage) -
+                               clutter_actor_get_width (data.odo)) / 2,
+                              (clutter_actor_get_height (stage) -
+                               clutter_actor_get_height (data.odo)) / 2);
+  clutter_actor_set_depth (data.odo, -300.0);
+
+  /* Add it to the stage */
+  clutter_container_add (CLUTTER_CONTAINER (stage), data.odo, NULL);
+
+  /* Fill in the data required for the animation */
+  data.timeline = clutter_timeline_new (5000);
+  data.alpha = clutter_alpha_new_full (data.timeline,
+                                       CLUTTER_EASE_IN_OUT_SINE);
+  data.data.turn = 0;
+  data.data.radius = clutter_actor_get_width (data.odo) / 18;
+  data.data.angle = G_PI/6;
+  data.data.amplitude = 1.0;
+
+  /* Connect to timeline signals for progressing animation */
+  g_signal_connect (data.timeline, "new-frame",
+                    G_CALLBACK (new_frame_cb), &data);
+  g_signal_connect (data.timeline, "completed",
+                    G_CALLBACK (completed_cb), &data);
+
+  /* Begin */
+  clutter_actor_show (stage);
+  clutter_timeline_start (data.timeline);
+  clutter_main();
+
+  return 0;
+}
+
diff --git a/odo/oh-logo.png b/odo/oh-logo.png
new file mode 100644 (file)
index 0000000..677aa52
Binary files /dev/null and b/odo/oh-logo.png differ
diff --git a/odo/redhand.png b/odo/redhand.png
new file mode 100644 (file)
index 0000000..c07d8ac
Binary files /dev/null and b/odo/redhand.png differ
diff --git a/opt/.gitignore b/opt/.gitignore
new file mode 100644 (file)
index 0000000..c58cb6f
--- /dev/null
@@ -0,0 +1,17 @@
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/config.h
+/config.h.in
+/config.log
+/config.status
+/configure
+/depcomp
+/install-sh
+/missing
+/opt
+/stamp-h1
+
+*.o
+.deps
diff --git a/opt/AUTHORS b/opt/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/opt/ChangeLog b/opt/ChangeLog
new file mode 100644 (file)
index 0000000..5a9d28f
--- /dev/null
@@ -0,0 +1,365 @@
+2008-10-13  Matthew Allum  <mallum@openedhand.com>
+
+       * configure.ac:
+        Use clutter 0.8
+       * opt-show.c:
+       * opt-slide.c:
+        Dont hardcode number of channels when setting texture data,
+        use gdk_pixbuf_get_n_channels ()
+       * opt-transition.c: (fade_transition_frame_cb):
+        Fix fade. Timelines start from frame #1 now.
+
+2008-07-01  Emmanuele Bassi  <ebassi@openedhand.com>
+
+       * configure.ac:
+       * opt-config.c:
+       * opt-show.c:
+       * opt-slide.c:
+       * opt.c: Update to clutter-0.7 to test out the code base.
+
+2008-02-21  Øyvind Kolås  <pippin@o-hand.com>
+
+       * opt-config.c: (opt_config_load): permuted arguments of memset
+       to make it correct.
+
+2008-02-18  Chris Lord  <chris@openedhand.com>
+
+       * configure.ac:
+       Bump clutter version to 0.6
+
+2008-02-08  Chris Lord  <chris@openedhand.com>
+
+       * configure.ac:
+       * opt-menu.c: (opt_menu_new):
+       * opt-show.c: (transition_completed_cb):
+       * opt-transition.c: (yz_flip_transition_frame_cb),
+       (zoom_transition_frame_cb), (flip_transition_frame_cb),
+       (cube_transition_frame_cb), (page_transition_frame_cb):
+       Update to use 0.5
+
+2007-08-07  Matthew Allum  <mallum@openedhand.com>
+
+       * configure.ac:
+       Update to use 0.4
+
+2007-06-19  Matthew Allum  <mallum@openedhand.com>
+
+       * demo.xml:
+       Include cube transition
+
+       * opt-show.c:
+       Add png compression parameter and set at maximum
+
+       * opt.c:
+       Call clutter_init() with args
+
+2007-06-08  Matthew Allum  <mallum@openedhand.com>
+
+       * configure.ac:
+       * opt-menu.c:
+       * opt-show.c:
+       * opt-transition.c:
+       * opt.c: 
+       Update to 0.3 API, thanks to Johan Bilien  (#366).
+       Print error if offscreen stage unsupported.
+
+2007-04-16  Tomas Frydrych  <tf@openedhand.com>
+
+       * opt-menu.c:
+       Changed scaling gravity from SW to NW.
+       
+2007-03-29  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile:
+       Remove.
+       * Makefile.am:
+       * autogen.sh:
+       * configure.ac:
+       Autofooify.
+
+       * demo.xml:
+       Add a simple demo show with instructions.
+
+       * opt-show.c:
+       Improve export to generate simple XML.
+
+2007-02-28  Tomas Frydrych  <tf@openedhand.com>
+
+       * Makefile:
+       Put clutter version requirement back to 0.2
+       
+       * opt-menu.c:
+       Animated menu
+       
+2007-02-28  Tomas Frydrych  <tf@openedhand.com>
+
+       * opt-transition.h:
+       * opt-transition.c:
+       * opt-config.c:
+       Added new transition type 'page'
+
+       * Makefile:
+       * opt.h:
+       * opt-menu.h:
+       * opt-menu.c:
+       * opt-show.h:
+       * opt-show.c:
+       Added simple menu
+
+       * opt.c: (input_cb): 
+       Added 'm' to bring up menu, explicitely Right to advance, button 3
+       to retreat; ignore Up, Down, Return and buttons 2, 4, 5 used by
+       menu.
+       
+2007-01-26  Matthew Allum  <mallum@openedhand.com>
+
+       * opt.doap:
+       Add a doap file
+
+2007-01-17  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile:
+       * opt-show.c:
+       * opt-slide.c: (opt_slide_set_title), (opt_slide_add_bullet_text_item):
+       Update for 0.2 API changes.
+
+2006-07-03  Ross Burton  <ross@openedhand.com>
+
+       * opt-slide.c:
+       Remove unused constants.
+
+2006-07-03  Ross Burton  <ross@openedhand.com>
+
+       * opt-show.c:
+       Use somewhat better filenames when exporting. Should really count
+       slides to use the right number but this works for most
+       presentations.
+
+2006-07-03  Ross Burton  <ross@openedhand.com>
+
+       * opt.dtd:
+       Allow slides with only titles (Wouter Bolsterlee <uws@xs4all.nl>)
+
+2006-06-23  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-transition.c: (zoom_transition_frame_cb):
+       Fix zoom transition as to not leave next frame 180 degrees
+
+2006-06-22  Ross Burton  <ross@openedhand.com>
+
+       * Makefile:
+       Use clutter-0.1.
+
+       * opt.dtd:
+       Add zoom transition.
+
+2006-06-21  Emmanuele Bassi  <ebassi@openedhand.com>
+
+       * opt-show.h:
+       * opt-show.c (opt_show_update_position_label),
+       (transition_completed_cb), (opt_show_toggle_position): Toggle
+       an overlayed rectangle containing the current slide and the
+       total number of slides.
+
+       * opt.c (input_cb): Add binding for showing the slide number.
+
+2006-06-20  Ross Burton  <ross@openedhand.com>
+
+       * opt-transition.c:
+       Don't hard-code frame count anywhere but the creation, get it from
+       the timeline.
+
+2006-06-20  Ross Burton  <ross@openedhand.com>
+
+       * opt-transition.c:
+       Add a define for the transition midpoint frame, and hook up the
+       zoom transition.
+
+2006-06-20  Ross Burton  <ross@openedhand.com>
+
+       * opt-config.c:
+       Scale background images to the stage size when loading to avoid
+       scaling at runtime.
+
+2006-06-19  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-config.c:
+       * opt-show.c:
+       * opt-slide.c:
+       * opt-slide.h:
+       Integrate Mr Burtons per slide background patch.
+       Pre-realize textures before a transition.
+       Correctly bail on error if image cannot be loaded.
+
+2006-06-19  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-config.c:
+       * opt-transition.c: (yz_flip_transition_frame_cb):
+       * opt-transition.h:
+       * test.xml:
+       Add new zoom transition. 
+
+2006-06-19  Emmanuele Bassi  <ebassi@openedhand.com>
+
+       * opt-show.c:
+       Add support for the PgUp and PgDown keys, for skipping 5 slides
+       backward and forward the current position.
+
+2006-06-19  Ross Burton  <ross@openedhand.com>
+
+       * opt-show.c:
+       Marshal the background property as a GdkPixbuf object not a pointer.
+
+2006-06-19  Ross Burton  <ross@openedhand.com>
+
+       * hirez/oh-present.xcf:
+       Title the layers and remove empty/duplicate layers.
+
+2006-06-19  Ross Burton  <ross@openedhand.com>
+
+       * opt-transition.c:
+       Change the rotation of the cube when switching.
+
+2006-06-19  Ross Burton  <ross@openedhand.com>
+
+       * opt.dtd:
+       Image tags have no content.
+
+2006-06-15  Matthew Allum  <mallum@openedhand.com>
+
+       * opt.c: (input_cb):
+       Keep Tomas happy with support with mouse button 
+       slide forwards/back.
+
+2006-06-14  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-config.c:
+       * opt-show.c:
+       * opt-show.h:
+       Fix bullet symbol color.
+
+2006-06-14  Emmanuele Bassi  <ebassi@openedhand.com>
+
+       * opt.c (input_cb): Use clutter_main_quit() instead of
+       calling exit().
+
+2006-06-14  Ross Burton  <ross@openedhand.com>
+
+       * opt.dtd:
+       Remove img from <defaults> and set valid enumeration for symbol
+       and style.
+
+2006-06-13  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-config.c:
+       * opt.dtd:
+       * test.xml:
+       Add new style attribute to bullets.
+       Update text.xml with wrap test and code example.
+
+       * opt-show.c:
+       * opt-show.h:
+       * opt-slide.c:
+       * opt-slide.h:
+       * opt-transition.c:
+       Fix wrapping with bullet symbols
+       Add optional blank bullet
+       Increase FPS to 90
+
+2006-06-13  Ross Burton  <ross@openedhand.com>
+
+       * opt.dtd:
+       Add a DTD describing the OPT file format.
+
+       * test.xml:
+       Use the DTD.
+
+2006-06-13  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-config.c:
+       * opt-show.c:
+       * opt-slide.c:
+       * opt-slide.h:
+       * opt-transition.c:
+       * opt.c: 
+       Update for new element -> actor naming.
+
+2006-06-08  Matthew Allum  <mallum@openedhand.com>
+
+       * opt.c: 
+       * opt.h:
+       * opt-show.c:
+       Add command line opts.
+       Fix png exporting.
+       Make transitions work backwards and forwards.           
+
+       * opt-transition.c:
+       * opt-transition.h:
+       Add a direction parameter.
+
+2006-06-05  Matthew Allum  <mallum@openedhand.com>
+
+       * opt-config.c:
+       * opt-show.c:
+       * opt-slide.c:
+       * opt-slide.h:
+       * opt-transition.c:
+       * opt.c: 
+       Sync up with ebassi's clutter API changes.
+
+2006-06-02  Matthew Allum  <mallum@openedhand.com>
+
+       * test.xml:
+       * opt.c: (main):
+       * opt-config.c: 
+       * opt-show.c: 
+       * opt-show.h:
+       Add support for default <background> tag.
+       Attempt ( non working on fglfx at least ) slide export.
+
+       * opt-transition.c: 
+       * opt-transition.h:
+       Add another flip transition.
+
+2006-06-01  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile:
+       * opt.h:
+       * opt-transition.c:
+       * opt-transition.h:
+       * opt-config.c:
+       * opt-show.c:
+       * opt-show.h:
+       * opt-slide.c:
+       * opt-slide.h:
+       Redo transition handling.       
+
+       * opt.c: (input_cb), (main):
+       Handle back button now.
+       * test.xml:
+       Add some transition examples.
+
+2006-05-29  Matthew Allum  <mallum@openedhand.com>
+
+       * Makefile:
+       * opt.h:
+       * opt-config.c:
+       * test.xml:
+       Add initial basic XML config file loading. 
+       Regret using g_markup. 
+
+       * opt-show.c    
+       * opt-show.h:
+       Add props for default show 'style'
+
+       * opt-slide.c:
+       * opt-slide.h:
+       Add font and colour args.
+
+       * opt.c: (main):
+       Remove old manual slide building, use XML files instead.
+
+       * bg.png 
+        * hirez/oh-present.xcf
+        Add new OH template presentation background.
+
diff --git a/opt/Makefile.am b/opt/Makefile.am
new file mode 100644 (file)
index 0000000..6ce7cbd
--- /dev/null
@@ -0,0 +1,24 @@
+bin_PROGRAMS=opt
+
+AM_CFLAGS = $(DEPS_CFLAGS) $(GCC_FLAGS) -D_GNU_SOURCE
+
+opt_LDADD  = $(DEPS_LIBS)
+opt_SOURCES = opt.c            \
+             opt.h            \
+              opt-show.c       \
+             opt-show.h       \
+              opt-slide.c      \
+              opt-slide.h      \
+             opt-transition.h \
+             opt-transition.c \
+             opt-menu.c       \
+             opt-menu.h       \
+             opt-config.c 
+
+EXTRA_DIST=powers.png opt.dtd demo.xml bg.png
+
+MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub configure depcomp install-sh ltmain.sh Makefile.in missing
+
+snapshot:
+       $(MAKE) dist distdir=$(PACKAGE)-snap`date +"%Y%m%d"`
+
diff --git a/opt/NEWS b/opt/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/opt/README b/opt/README
new file mode 100644 (file)
index 0000000..9ba9a4c
--- /dev/null
@@ -0,0 +1,6 @@
+O.P.T - ' Openedhand Presentation Tool'
+======================================
+
+An experimental toy clutter based presentaion app..
+
+For more info, run './opt demo.xml'.
\ No newline at end of file
diff --git a/opt/autogen.sh b/opt/autogen.sh
new file mode 100755 (executable)
index 0000000..b1376df
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/opt/bg.png b/opt/bg.png
new file mode 100644 (file)
index 0000000..91a0d0e
Binary files /dev/null and b/opt/bg.png differ
diff --git a/opt/configure.ac b/opt/configure.ac
new file mode 100644 (file)
index 0000000..7cffba5
--- /dev/null
@@ -0,0 +1,24 @@
+AC_PREREQ(2.53)
+AC_INIT(opt, 0.1, [http://bugzilla.o-hand.com/enter_bug.cgi?product=woohaa])
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(opt.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+
+PKG_CHECK_MODULES(DEPS, gdk-pixbuf-2.0 clutter-0.9)
+AC_SUBST(DEPS_CFLAGS)
+AC_SUBST(DEPS_LIBS)
+
+if test "x$GCC" = "xyes"; then
+        GCC_FLAGS="-g -Wall"
+fi
+
+AC_SUBST(GCC_FLAGS)
+
+AC_OUTPUT([
+Makefile
+])
diff --git a/opt/demo.xml b/opt/demo.xml
new file mode 100644 (file)
index 0000000..36a5840
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!DOCTYPE opt SYSTEM "opt.dtd">
+<opt>
+
+  <defaults>
+    <title  color="#444444ff" font="VistaSansMed 50" />
+    <bullet color="#444444ff" font="VistaSansMed 40" /> 
+    <transition style="flip" />  
+    <background src="bg.png" />
+  </defaults>
+
+  <slide>
+    <title>Hello!</title>
+    <bullet>This is a simple 'OPT' demo presentation</bullet> 
+    <bullet>OPT is a simple presentation program built with Clutter by folks at OH.</bullet> 
+    <bullet>Presentations are built with simple XML files.</bullet> 
+    <bullet>Press any key to go on...</bullet> 
+    <transition style="cube" />        
+  </slide>
+
+  <slide>
+    <title>Navigating with OPT.</title>
+    <bullet>Any key to advance to next slide.</bullet>
+    <bullet>'r' or left arrow to go back.</bullet>
+    <bullet>'m' for menu, 'q' quits.</bullet>
+    <bullet>You can also use mouse buttons.</bullet>
+
+    <transition style="fade" />        
+  </slide>
+
+  <slide>
+    <title>Features 1</title>
+    <bullet>You can embed images;</bullet>
+    <img src="powers.png" /> 
+    <bullet>And have different transition effects.</bullet>
+
+    <transition style="zoom" />        
+  </slide>
+
+  <slide>
+    <title>Features 2</title>
+    <bullet>You can display source code</bullet>
+    <bullet font="mono 20" symbol="none">clutter_label_set_text_extents (CLUTTER_LABEL(bullet),
+                                 width - symbol_width,
+                                 0);
+
+clutter_actor_set_position (bullet, x, y);
+clutter_group_add (CLUTTER_GROUP(slide), bullet);
+
+clutter_actor_show(bullet);
+clutter_actor_show(symbol);
+</bullet>
+
+  </slide>
+
+  <slide>
+    <title color="#ff4444ff">Features 3</title>
+    <bullet>You can change</bullet>
+    <bullet color="#4444ffff">colors</bullet>
+    <bullet font="mono 40">and fonts</bullet>
+  </slide>
+
+  <slide>
+    <title>Thats all folks.</title>
+    <bullet>Dont forget to check the demo.xml source for making your own presentations.</bullet>
+    <bullet>And send patches to improve OPT further!</bullet>
+  </slide>
+
+</opt>
\ No newline at end of file
diff --git a/opt/hirez/oh-present.xcf b/opt/hirez/oh-present.xcf
new file mode 100644 (file)
index 0000000..1525386
Binary files /dev/null and b/opt/hirez/oh-present.xcf differ
diff --git a/opt/kitten.jpg b/opt/kitten.jpg
new file mode 100644 (file)
index 0000000..6232fb7
Binary files /dev/null and b/opt/kitten.jpg differ
diff --git a/opt/kitten2.jpg b/opt/kitten2.jpg
new file mode 100644 (file)
index 0000000..cfb4453
Binary files /dev/null and b/opt/kitten2.jpg differ
diff --git a/opt/opt-config.c b/opt/opt-config.c
new file mode 100644 (file)
index 0000000..963ce12
--- /dev/null
@@ -0,0 +1,759 @@
+#include "opt.h"
+#include <stdio.h>             /* for scanf */
+#include <string.h>            /* for strcmp */
+
+/* 
+  <opt>
+  <defaults>
+    <bullet font="" color="">
+    <title font="" color="">
+    <offsets border="" title-spacing="" bullet-border="" bullet-spacing=""/>
+    <background img="" | color= "" />
+    <transition style="cube|flip|fade" />
+  </defualts>
+  <slide>
+    <background img="" | color= "" />
+    <title font="" color=""></title>
+    <bullet font="" color="" symbol="none"></bullet>
+    <img src="" />
+    <code width="xx"></code>
+    <transition style="cube|flip|fade" />
+  </slide>
+  <transition type=""/>
+  ....
+
+  </opt>
+ */
+
+typedef struct OptParseInfo OptParseInfo;
+
+typedef enum 
+{
+  INITIAL,
+  IN_OPT,
+  IN_DEFAULTS,
+  IN_DEFAULTS_TITLE,
+  IN_DEFAULTS_BULLET,
+  IN_DEFAULTS_TRANS,
+  IN_DEFAULTS_BG,
+  IN_FONTS,
+  IN_OFFSETS,
+  IN_SLIDE,
+  IN_TITLE,
+  IN_BULLET,
+  IN_TRANS,
+  IN_IMG,
+  IN_BG,
+  FINAL
+} 
+OptParseState;
+
+
+typedef enum 
+{
+  TAG_UNKNOWN = 0,
+  TAG_OPT,
+  TAG_DEFAULTS,
+  TAG_DEFAULTS_TITLE,
+  TAG_DEFAULTS_BULLET,
+  TAG_DEFAULTS_TRANS,
+  TAG_DEFAULTS_BG,
+  TAG_SLIDE,
+  TAG_TITLE,
+  TAG_BULLET,
+  TAG_TRANS,
+  TAG_IMG,
+  TAG_BG
+
+} OptParseTag;
+
+const struct { gchar *name; OptTransitionStyle style; } _style_lookup[] = 
+  {
+    { "cube", OPT_TRANSITION_CUBE },
+    { "page", OPT_TRANSITION_PAGE },
+    { "flip", OPT_TRANSITION_FLIP },
+    { "zoom", OPT_TRANSITION_ZOOM },
+    { "yzflip", OPT_TRANSITION_YZ_FLIP },
+    { "fade", OPT_TRANSITION_FADE },
+    { NULL, 0 }
+  };
+
+
+struct OptParseInfo
+{
+  OptShow           *show;
+  OptParseState      state;
+  OptSlide          *slide;
+
+  GdkPixbuf *default_bg;
+
+  GString           *title_buf;
+  gchar             *title_font;
+  ClutterColor       title_color;
+  ClutterColor       title_default_color;
+
+  GString           *bullet_buf;
+  gchar             *bullet_font;
+  ClutterColor       bullet_color;
+  ClutterColor       bullet_default_color;
+  OptSlideBulletSymbol bullet_sym;
+
+  OptTransitionStyle style_default;
+};
+
+static void 
+color_from_string (const gchar *spec, ClutterColor *color)
+{
+  if (spec[0] == '#' && strlen(spec) == 9)
+    {
+      guint32 result;
+      if (sscanf (spec+1, "%x", &result))
+       {
+         color->red   = result >> 24 & 0xff;
+         color->green = (result >> 16) & 0xff;
+         color->blue  = (result >> 8) & 0xff;
+         color->alpha = result & 0xff;
+         return;
+       }
+    }
+  
+  g_warning("unable to parse '%s' as a color in format #RRGGBBAA", spec);
+}
+
+static OptTransitionStyle
+lookup_style (const gchar *name)
+{
+  gint i = 0;
+
+  while (_style_lookup[i].name != NULL)
+    {
+      if (!strcmp(name, _style_lookup[i].name))
+       return _style_lookup[i].style;
+
+      i++;
+    }
+
+  return OPT_TRANSITION_ANY;
+}
+
+static int
+expect_tag (GMarkupParseContext *context,
+           const gchar         *actor_name,
+           GError             **error,
+           ...)
+{
+  va_list vap;
+  const char *expected;
+  int n_expected = 0;
+  
+  va_start (vap, error);
+  expected = va_arg (vap, const char *);
+  while (expected)
+    {
+      int value = va_arg (vap, int);
+      n_expected++;
+      
+      if (strcmp (expected, actor_name) == 0)
+       return value;
+      
+      expected = va_arg (vap, const char *);
+    }
+  
+  va_end (vap);
+
+  if (n_expected == 0)
+    {
+      g_set_error (error,
+                  G_MARKUP_ERROR,
+                  G_MARKUP_ERROR_INVALID_CONTENT,
+                  "Unexpected tag '%s', no tags expected",
+                  actor_name);
+    }
+  else
+    {
+      GString *tag_string = g_string_new (NULL);
+
+      va_start (vap, error);
+      expected = va_arg (vap, const char *);
+      while (expected)
+       {
+         va_arg (vap, int);
+
+         if (tag_string->len)
+           g_string_append (tag_string, ", ");
+         g_string_append (tag_string, expected);
+           
+         expected = va_arg (vap, const char *);
+       }
+  
+      va_end (vap);
+
+      if (n_expected == 1)
+       g_set_error (error,
+                    G_MARKUP_ERROR,
+                    G_MARKUP_ERROR_INVALID_CONTENT,
+                    "Unexpected tag '%s', expected '%s'",
+                    actor_name, tag_string->str);
+      else
+       g_set_error (error,
+                    G_MARKUP_ERROR,
+                    G_MARKUP_ERROR_INVALID_CONTENT,
+                    "Unexpected tag '%s', expected one of: %s",
+                    actor_name, tag_string->str);
+
+      g_string_free (tag_string, TRUE);
+    }
+  
+  return 0;
+}
+
+static gboolean
+extract_attrs (GMarkupParseContext *context,
+              const gchar        **attribute_names,
+              const gchar        **attribute_values,
+              GError             **error,
+              ...)
+{
+  va_list vap;
+  const char *name;
+  gboolean *attr_map;
+  gboolean nattrs = 0;
+  int i;
+
+  for (i = 0; attribute_names[i]; i++)
+    nattrs++;
+
+  attr_map = g_new0 (gboolean, nattrs);
+
+  va_start (vap, error);
+  name = va_arg (vap, const char *);
+  while (name)
+    {
+      gboolean mandatory = va_arg (vap, gboolean);
+      const char **loc = va_arg (vap, const char **);
+      gboolean found = FALSE;
+
+      for (i = 0; attribute_names[i]; i++)
+       {
+         if (!attr_map[i] && strcmp (attribute_names[i], name) == 0)
+           {
+             if (found)
+               {
+                 g_set_error (error,
+                              G_MARKUP_ERROR,
+                              G_MARKUP_ERROR_INVALID_CONTENT,
+                              "Duplicate attribute '%s'", name);
+                 return FALSE;
+               }
+               
+             *loc = attribute_values[i];
+             found = TRUE;
+             attr_map[i] = TRUE;
+           }
+       }
+      
+      if (!found && mandatory)
+       {
+         g_set_error (error,
+                      G_MARKUP_ERROR,
+                      G_MARKUP_ERROR_INVALID_CONTENT,
+                      "Missing attribute '%s'", name);
+         return FALSE;
+       }
+      
+      name = va_arg (vap, const char *);
+    }
+
+  for (i = 0; i < nattrs; i++)
+    if (!attr_map[i])
+      {
+       g_set_error (error,
+                    G_MARKUP_ERROR,
+                    G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                    "Unknown attribute '%s'", attribute_names[i]);
+       return FALSE;
+      }
+
+  return TRUE;
+}
+
+
+static void 
+opt_parse_on_start_actor (GMarkupParseContext *context,
+                           const gchar         *actor_name,
+                           const gchar        **attr_names,
+                           const gchar        **attr_values,
+                           gpointer             user_data,
+                           GError             **error)
+{
+  OptParseTag   tag;
+  OptParseInfo *info = user_data;
+
+  switch (info->state)
+    {
+    case INITIAL:
+      if (expect_tag (context, actor_name, error, "opt", TAG_OPT, NULL) 
+         && extract_attrs (context, attr_names, attr_values, error, NULL))
+       info->state = IN_OPT;
+      break;
+
+      /***** Top level, just defaults and slide *****/
+
+    case IN_OPT:
+      tag = expect_tag (context, actor_name, error, 
+                       "defaults", TAG_DEFAULTS, 
+                       "slide", TAG_SLIDE,
+                       NULL); 
+      switch (tag)
+       {
+       case TAG_DEFAULTS:
+         info->state = IN_DEFAULTS;
+         break;
+       case TAG_SLIDE:
+         {
+           OptTransition *trans;
+
+           info->state = IN_SLIDE;
+           info->slide = opt_slide_new (info->show);
+
+           g_object_set (info->show, "background", info->default_bg, NULL);
+
+           trans = opt_transition_new (info->style_default); 
+           opt_transition_set_from (trans, info->slide);
+           opt_slide_set_transition (info->slide, trans);
+         }
+         break;
+       default:
+         break;
+       }
+      break;
+
+      /*****  Default tags *****/
+
+    case IN_DEFAULTS:
+      tag = expect_tag (context, actor_name, error, 
+                       "title",  TAG_DEFAULTS_TITLE, 
+                       "bullet", TAG_DEFAULTS_BULLET,
+                       "transition", TAG_DEFAULTS_TRANS,
+                       "background", TAG_DEFAULTS_BG,
+                       NULL); 
+      switch (tag)
+       {
+       case TAG_DEFAULTS_TRANS:
+         {
+           const char *style_str = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "style", FALSE, &style_str,
+                              NULL))
+             {
+               info->style_default = lookup_style (style_str);
+             }
+         }
+         info->state = IN_DEFAULTS_TRANS;
+         break;
+       case TAG_DEFAULTS_TITLE:
+         {
+           const char *color = NULL;
+           const char *font = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "font", FALSE, &font,
+                              "color",  FALSE, &color,
+                              NULL))
+             {
+               if (font)
+                 g_object_set(info->show,
+                              "title-font", font,
+                              NULL);
+
+               if (color)
+                 {
+                   color_from_string (color, &info->title_default_color);
+                 }
+             }
+         }
+         info->state = IN_DEFAULTS_TITLE;
+         break;
+
+       case TAG_DEFAULTS_BULLET:
+         {
+           const char *color = NULL;
+           const char *font = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "font", FALSE, &font,
+                              "color",  FALSE, &color,
+
+                              NULL))
+             {
+               if (font)
+                 g_object_set(info->show,
+                              "bullet-font", font,
+                              NULL);
+
+               if (color)
+                 {
+                   color_from_string (color, &info->bullet_default_color);
+
+                   opt_show_set_bullet_color (info->show,
+                                              &info->bullet_default_color);
+                 }
+             }
+         }
+         info->state = IN_DEFAULTS_BULLET;
+         break;
+       case TAG_DEFAULTS_BG:
+         {
+           const char *src = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "src", TRUE, &src,
+                              NULL))
+             {
+               GdkPixbuf *pic;
+               
+               pic = gdk_pixbuf_new_from_file_at_size (src,
+                                                        CLUTTER_STAGE_WIDTH(),
+                                                        CLUTTER_STAGE_HEIGHT(),
+                                                        NULL);
+
+               if (pic == NULL)
+                 {
+                   g_set_error (error,
+                                G_MARKUP_ERROR,
+                                G_MARKUP_ERROR_INVALID_CONTENT,
+                                "Unable to load '%s'", src);
+                 }
+               
+               info->default_bg = pic;
+             }
+         }
+         info->state = IN_DEFAULTS_BG;
+         break;
+       default:
+         g_assert_not_reached ();
+         break;
+       }
+      
+      break;
+
+      /*****  Slide Tags *****/
+
+    case IN_SLIDE:
+      tag = expect_tag (context, actor_name, error, 
+                       "title",      TAG_TITLE, 
+                       "bullet",     TAG_BULLET,
+                       "img",        TAG_IMG,
+                       "transition", TAG_TRANS,
+                       "background", TAG_BG,
+                       NULL); 
+      switch (tag)
+       {
+       case TAG_BG:
+         {
+           const char *src = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "src", TRUE, &src,
+                              NULL))
+             {
+               GdkPixbuf *pic = NULL;
+
+               pic = gdk_pixbuf_new_from_file_at_size (src,
+                                                        CLUTTER_STAGE_WIDTH(),
+                                                        CLUTTER_STAGE_HEIGHT(),
+                                                        NULL);
+
+               if (pic == NULL)
+                 {
+                   g_set_error (error,
+                                G_MARKUP_ERROR,
+                                G_MARKUP_ERROR_INVALID_CONTENT,
+                                "Unable to load '%s'", src);
+                 }
+               
+               opt_slide_set_background_pixbuf (info->slide, pic);
+
+               g_object_unref (pic);
+             }
+           info->state = IN_BG;
+         }
+         break;
+       case TAG_TRANS:
+         {
+           const char *style_str = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "style", TRUE, &style_str,
+                              NULL))
+             {
+               OptTransitionStyle style;
+               OptTransition     *trans;
+
+               style = lookup_style (style_str);
+               
+               trans = opt_slide_get_transition (info->slide);
+               opt_transition_set_style (trans, style);
+             }
+           info->state = IN_TRANS;
+         }
+         break;
+       case TAG_IMG:
+         {
+           gchar *img_path = NULL;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "src", TRUE, &img_path,
+                              NULL))
+             {
+               GdkPixbuf    *pix = NULL;
+               ClutterActor *pic = NULL;
+
+               pix = gdk_pixbuf_new_from_file (img_path, NULL);
+
+               if (pix == NULL)
+                 {
+                   g_set_error (error,
+                                G_MARKUP_ERROR,
+                                G_MARKUP_ERROR_INVALID_CONTENT,
+                                "Unable to load '%s'", img_path);
+                 }
+               else
+                 {
+                   pic = clutter_texture_new ();
+                    clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (pic),
+                                     gdk_pixbuf_get_pixels (pix),
+                                     gdk_pixbuf_get_has_alpha (pix),
+                                     gdk_pixbuf_get_width (pix),
+                                     gdk_pixbuf_get_height (pix),
+                                     gdk_pixbuf_get_rowstride (pix),
+                                     4, 0,
+                                     NULL);
+
+                   opt_slide_add_bullet (info->slide, pic);
+                 }
+             }
+           info->state = IN_IMG;
+         }
+         break;
+
+       case TAG_TITLE:
+         {
+           const char *color = NULL;
+           const char *font = NULL;
+
+           info->state      = IN_TITLE;
+           info->title_buf  = g_string_new("");
+           info->title_font = NULL;
+           info->title_color = info->title_default_color;
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "font", FALSE, &font,
+                              "color",  FALSE, &color,
+                              NULL))
+             {
+               if (font)
+                 info->title_font = g_strdup(font);
+
+               if (color)
+                 color_from_string(color, &info->title_color);
+                 
+             }
+         }
+         break;
+
+       case TAG_BULLET:
+         {
+           const char *color = NULL;
+           const char *font = NULL;
+           const char *sym  = NULL;
+           
+           info->state        = IN_BULLET;
+           info->bullet_buf   = g_string_new("");
+           info->bullet_font  = NULL;
+           info->bullet_color = info->bullet_default_color;
+           info->bullet_sym   = OPT_BULLET_REGULAR;        
+
+           if (extract_attrs (context, attr_names, attr_values, error,
+                              "font", FALSE, &font,
+                              "color",  FALSE, &color,
+                              "symbol", FALSE, &sym,
+                              NULL))
+             {
+               if (font)
+                 info->bullet_font = g_strdup(font);
+               
+               if (color)
+                 color_from_string(color, &info->bullet_color);
+               
+               if (sym && !strcmp(sym, "none"))
+                 info->bullet_sym = OPT_BULLET_NONE;
+             }
+         }
+         break;
+       default:
+         break;
+       }
+    default:
+      break;
+    }      
+}
+
+static void 
+opt_parse_on_end_actor (GMarkupParseContext *context,
+                         const gchar         *actor_name,
+                         gpointer             user_data,
+                         GError             **error)
+{
+  OptParseInfo *info = user_data;
+
+  switch (info->state)
+    {
+    case INITIAL:
+      g_assert_not_reached ();
+      break;
+    case IN_OPT:
+      info->state = FINAL;
+      break;
+    case IN_SLIDE:
+      opt_show_add_slide (info->show, info->slide);
+      info->state = IN_OPT;
+      info->slide = NULL;
+      break;
+    case IN_DEFAULTS:
+      info->state = IN_OPT;
+      break;
+    case IN_DEFAULTS_TITLE:
+    case IN_DEFAULTS_BULLET:
+    case IN_DEFAULTS_TRANS:
+    case IN_DEFAULTS_BG:
+      info->state = IN_DEFAULTS;
+      break;
+    case IN_BG:
+    case IN_IMG:
+      info->state = IN_SLIDE;
+      break;
+    case IN_TITLE:
+      opt_slide_set_title (info->slide, 
+                          info->title_buf->str,
+                          info->title_font,
+                          &info->title_color);
+      g_string_free (info->title_buf, TRUE);
+
+      if (info->title_font)
+       g_free (info->title_font);
+      info->title_font  = NULL;
+      info->bullet_buf  = NULL;
+      info->state       = IN_SLIDE;
+      break;
+    case IN_BULLET:
+      opt_slide_add_bullet_text_item (info->slide, 
+                                     info->bullet_buf->str,
+                                     info->bullet_font,
+                                     info->bullet_sym,
+                                     &info->bullet_color);
+      g_string_free (info->bullet_buf, TRUE);
+      if (info->bullet_font)
+       g_free (info->bullet_font);
+      info->bullet_font  = NULL;
+      info->bullet_buf = NULL;
+      info->state = IN_SLIDE;
+      break;
+    case IN_TRANS:
+      info->state = IN_SLIDE;
+      break;
+    case FINAL:
+      g_assert_not_reached ();
+      break;
+    default:
+      break;
+    }
+}
+
+
+static void 
+opt_parse_on_text (GMarkupParseContext *context,
+                  const gchar         *text,
+                  gsize                text_len,  
+                  gpointer             user_data,
+                  GError             **error)
+{
+  int           i;
+  OptParseInfo *info = user_data;
+
+  switch (info->state)
+    {
+    case IN_TITLE:
+      g_string_append_len (info->title_buf, text, text_len);
+      break;
+    case IN_BULLET:
+      g_string_append_len (info->bullet_buf, text, text_len);
+      break;
+    case INITIAL:
+    case IN_IMG:
+    case IN_OPT:
+    case IN_DEFAULTS:
+    case IN_DEFAULTS_TITLE:
+    case IN_DEFAULTS_BULLET:
+    case IN_DEFAULTS_TRANS:
+    case IN_DEFAULTS_BG:
+    case IN_FONTS:
+    case IN_OFFSETS:
+    case IN_SLIDE:
+    case IN_BG:
+    case IN_TRANS:
+    case FINAL:
+      for (i = 0; i < text_len; i++)
+       if (!g_ascii_isspace (text[i]))
+         {
+           g_set_error (error,
+                        G_MARKUP_ERROR,
+                        G_MARKUP_ERROR_INVALID_CONTENT,
+                        "Unexpected text '%s' in presentation file",
+                        text);
+           return;
+         }
+      break;
+    }
+}
+
+
+gboolean
+opt_config_load (OptShow     *show, 
+                const gchar *filename,
+                GError     **error)
+{
+  GMarkupParseContext *context;
+  OptParseInfo         info;
+  char                *contents;
+  gsize                len;
+  gboolean             result;
+
+  const GMarkupParser parser = 
+    {
+      opt_parse_on_start_actor,
+      opt_parse_on_end_actor,
+      opt_parse_on_text,
+      NULL,
+      NULL
+    };
+
+  memset (&info, 0, sizeof(OptParseInfo));
+
+  info.state = INITIAL; 
+  info.show  = show;
+  /*
+  info.bullet_default_color = { 0, 0, 0, 0xff };
+  info.title_default_color  = { 0, 0, 0, 0xff };
+  */
+  info.style_default        = OPT_TRANSITION_FADE;
+
+  if (!g_file_get_contents (filename, &contents, &len, error))
+    return FALSE;
+
+  context = g_markup_parse_context_new (&parser, 0, &info, NULL);
+  result  = g_markup_parse_context_parse (context, contents, len, error);
+
+  return result;
+}
diff --git a/opt/opt-menu.c b/opt/opt-menu.c
new file mode 100644 (file)
index 0000000..5560dd2
--- /dev/null
@@ -0,0 +1,496 @@
+/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "opt.h"
+
+#define DEFAULT_FONT_SIZE 20
+#define DEFAULT_FONT "Sans Bold 20"
+#define ITEM_HEIGHT 24
+#define TEXT_BORDER 4
+#define MENU_BORDER 1
+
+G_DEFINE_TYPE (OptMenu, opt_menu, CLUTTER_TYPE_GROUP);
+
+static void opt_menu_up (OptMenu * menu);
+static void opt_menu_down (OptMenu * menu);
+static void opt_menu_activate (OptMenu * menu);
+static void opt_menu_select_item (OptMenu * menu, gint slide_no);
+
+struct OptMenuPrivate
+{
+  guint             height;
+  gint              current_slide;
+  gint              active_item;
+  gint              item_count;
+  
+  ClutterColor      color_normal;
+  ClutterColor      color_sel;
+  ClutterColor      color_bg;
+
+  OptShow          *show;
+  ClutterActor     *background;
+  ClutterActor     *selection;
+
+  ClutterTimeline  *timeline;
+  ClutterAlpha     *alpha;
+  ClutterBehaviour *behaviour_s;
+  ClutterBehaviour *behaviour_o;
+  
+  gboolean          size_set;
+  gboolean          hiding;
+  guint             timeout_id;
+  gulong            button_release_signal_id;
+  gulong            key_release_signal_id;
+};
+
+/* Set sizes for background and selection -- called once the
+ * menu is fully populated
+ */
+static void
+opt_menu_init_size (OptMenu * menu)
+{
+  guint width, height;
+  clutter_actor_get_size (CLUTTER_ACTOR (menu), &width, &height);
+
+  width += 2 * TEXT_BORDER;
+  
+  clutter_actor_set_size (CLUTTER_ACTOR (menu),
+                          width, height);
+  
+  clutter_actor_set_size (CLUTTER_ACTOR (menu->priv->background),
+                          width, height);
+
+  clutter_actor_set_size (CLUTTER_ACTOR (menu->priv->selection),
+                          width - 2 * MENU_BORDER, ITEM_HEIGHT);
+
+  menu->priv->height = height;
+  menu->priv->size_set = TRUE;
+}
+
+/* Input callbacks
+ */
+static void 
+opt_menu_key_release_cb (ClutterStage          *stage,
+                         ClutterKeyEvent       *kev,
+                         gpointer               user_data)
+{
+  OptMenu  *menu = OPT_MENU (user_data);
+
+  if (!CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (menu)))
+    return;
+
+  switch (clutter_key_event_symbol (kev))
+    {
+      case CLUTTER_Up:
+          opt_menu_up (menu);
+          break;
+      case CLUTTER_Down:
+          opt_menu_down (menu);
+          break;
+      case CLUTTER_Return:
+          opt_menu_activate (menu);
+          break;
+
+      default:
+          opt_menu_popdown (menu);
+          break;
+    }
+}
+
+static void
+opt_menu_button_release_cb (ClutterStage       *stage,
+                            ClutterButtonEvent *bev,
+                            gpointer            user_data)
+{
+  OptMenu  *menu = OPT_MENU (user_data);
+
+  if (!CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (menu)))
+    return;
+
+  /* Allow a mouse wheel to control the menu (cannot handle
+   * buttons 1 and 3 here, because those are used to control the slides).
+   */
+
+  if (bev->button == 4)
+    opt_menu_up (menu);
+  else if (bev->button == 5)
+    opt_menu_down (menu);
+  else if (bev->button == 2)
+    opt_menu_activate (menu);
+}
+
+static void 
+opt_menu_finalize (GObject *object)
+{
+  OptMenu *self = OPT_MENU(object); 
+
+  g_object_unref (G_OBJECT (self->priv->behaviour_s));
+  g_object_unref (G_OBJECT (self->priv->behaviour_o));
+  g_object_unref (G_OBJECT (self->priv->timeline));
+  
+  if (self->priv)
+    {
+      g_free(self->priv);
+      self->priv = NULL;
+    }
+
+  G_OBJECT_CLASS (opt_menu_parent_class)->finalize (object);
+}
+
+static void
+opt_menu_class_init (OptMenuClass *klass)
+{
+  GObjectClass * object_class = (GObjectClass*) klass;
+  object_class->finalize = opt_menu_finalize;
+}
+
+static void
+opt_menu_init (OptMenu *self)
+{
+  OptMenuPrivate *priv = g_new0 (OptMenuPrivate, 1);
+  self->priv = priv;
+}
+
+static void
+opt_menu_hide_cb (ClutterTimeline * timeline, gpointer data)
+{
+  OptMenu  *menu = OPT_MENU (data);
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (menu)) &&
+      menu->priv->hiding)
+    {
+      ClutterActor * stage = clutter_stage_get_default();
+
+      clutter_actor_hide_all (CLUTTER_ACTOR (menu));
+      clutter_group_remove (CLUTTER_GROUP (stage), CLUTTER_ACTOR (menu));
+      opt_menu_select_item (menu, 0);
+      menu->priv->hiding = FALSE;
+      
+      if (menu->priv->timeout_id)
+        {
+          g_source_remove (menu->priv->timeout_id);
+          menu->priv->timeout_id = 0;
+        }
+    }
+}
+
+OptMenu*
+opt_menu_new (OptShow * show)
+{
+  OptMenu *menu = g_object_new (OPT_TYPE_MENU, NULL);
+
+  /* TODO -- maybe allow these to be customised
+   */
+  menu->priv->color_normal.red   = 0xff;
+  menu->priv->color_normal.green = 0xff;
+  menu->priv->color_normal.blue  = 0xff;
+  menu->priv->color_normal.alpha = 0xff;
+
+  menu->priv->color_sel.red   = 0;
+  menu->priv->color_sel.green = 0;
+  menu->priv->color_sel.blue  = 0;
+  menu->priv->color_sel.alpha = 0xff;
+
+  menu->priv->color_bg.red   = 0x7f;
+  menu->priv->color_bg.green = 0x7f;
+  menu->priv->color_bg.blue  = 0x7f;
+  menu->priv->color_bg.alpha = 0xcf;
+
+  menu->priv->show = show;
+
+  menu->priv->background =
+    clutter_rectangle_new_with_color (&menu->priv->color_bg);
+  
+  clutter_rectangle_set_border_color(CLUTTER_RECTANGLE(menu->priv->background),
+                                     &menu->priv->color_normal);
+  clutter_rectangle_set_border_width(CLUTTER_RECTANGLE(menu->priv->background),
+                                     1);
+  
+  clutter_group_add (CLUTTER_GROUP (menu),
+                     CLUTTER_ACTOR (menu->priv->background));
+
+  menu->priv->selection =
+    clutter_rectangle_new_with_color (&menu->priv->color_normal);
+
+  clutter_group_add (CLUTTER_GROUP (menu),
+                     CLUTTER_ACTOR (menu->priv->selection));
+  clutter_actor_set_position (CLUTTER_ACTOR (menu->priv->selection),
+                              MENU_BORDER, 0);
+
+  menu->priv->timeline = clutter_timeline_new (10, 26);
+
+  g_signal_connect (menu->priv->timeline, "completed",
+                    G_CALLBACK (opt_menu_hide_cb), menu);
+  
+  menu->priv->alpha = clutter_alpha_new_full (menu->priv->timeline,
+                                              CLUTTER_LINEAR);
+
+  menu->priv->behaviour_s =
+    clutter_behaviour_scale_new (menu->priv->alpha,
+                                 0.0, 0.0, 1.0, 1.0); 
+
+  clutter_behaviour_apply (menu->priv->behaviour_s, CLUTTER_ACTOR (menu));
+
+  menu->priv->behaviour_o =
+    clutter_behaviour_opacity_new (menu->priv->alpha, 0x00, 0xff); 
+
+  clutter_behaviour_apply (menu->priv->behaviour_o, CLUTTER_ACTOR (menu));
+  
+  return menu;
+}
+
+/*
+ * Adjusts the postition of the menu if the selected item is
+ * off screen
+ */
+static void
+opt_menu_adjust_postion (OptMenu * menu)
+{
+  if (menu->priv->height > CLUTTER_STAGE_HEIGHT ())
+    {
+      gint x           = clutter_actor_get_x (CLUTTER_ACTOR (menu));
+      gint y           = clutter_actor_get_y (CLUTTER_ACTOR (menu));
+      gint item_offset = menu->priv->active_item * ITEM_HEIGHT + y;
+
+      if (item_offset < 0)
+        {
+          /* attemp to shift the item to the middle of screen, but no so that
+           * the the menu would detach from the top of stage
+           */
+          gint screen_itms = CLUTTER_STAGE_HEIGHT () / ITEM_HEIGHT;
+          gint shift = ITEM_HEIGHT * screen_itms / 2 - item_offset;
+
+          y += shift;
+
+          if (shift > 0)
+            y = 0;
+        }
+      else if (item_offset > CLUTTER_STAGE_HEIGHT () - ITEM_HEIGHT)
+        {
+          /* attemp to shift the item to the middle of screen, but no so that
+           * the the menu would detach from the bottom of stage
+           */
+          gint screen_itms = CLUTTER_STAGE_HEIGHT () / ITEM_HEIGHT;
+          gint shift = ITEM_HEIGHT * screen_itms / 2 + item_offset;
+          gint max_shft = (menu->priv->item_count - screen_itms)*ITEM_HEIGHT;
+          
+          if (shift > max_shft)
+            shift = max_shft;
+          
+          y -= shift;
+        }
+
+      clutter_actor_set_position (CLUTTER_ACTOR (menu), x, y);
+    }
+}
+
+/*
+ * Selects nth item in the menu
+ */
+static void
+opt_menu_select_item (OptMenu * menu, gint slide_no)
+{
+  if (slide_no < 0 || slide_no >= menu->priv->item_count)
+    return;
+  
+  if (menu->priv->active_item != slide_no)
+    {
+      /* Plus two, because the first two children are the background
+       * and selection rectangles
+       */
+      ClutterActor * active =
+        clutter_group_get_nth_child (CLUTTER_GROUP (menu),
+                                     menu->priv->active_item + 2);
+  
+      clutter_text_set_color (CLUTTER_TEXT (active),
+                              &menu->priv->color_normal);
+
+      active = clutter_group_get_nth_child (CLUTTER_GROUP (menu),
+                                            slide_no + 2);
+  
+      clutter_text_set_color (CLUTTER_TEXT (active), &menu->priv->color_sel);
+
+      clutter_actor_set_position (CLUTTER_ACTOR (menu->priv->selection),
+                                  MENU_BORDER, slide_no * ITEM_HEIGHT);
+      
+      menu->priv->active_item = slide_no;
+
+      opt_menu_adjust_postion (menu);
+    }
+}
+
+/*
+ * Callback to automatically close the menu after given period of inactivity
+ */
+static gboolean
+opt_menu_timeout_cb (gpointer data)
+{
+  OptMenu * menu = data;
+
+  opt_menu_popdown (menu);
+  menu->priv->timeout_id = 0;
+  
+  return FALSE;
+}
+
+/*
+ * move one item up in the menu
+ */
+static void
+opt_menu_up (OptMenu * menu)
+{
+  opt_menu_select_item (menu, menu->priv->active_item - 1);
+
+  if (menu->priv->timeout_id)
+    {
+      g_source_remove (menu->priv->timeout_id);
+      menu->priv->timeout_id = g_timeout_add (5000, opt_menu_timeout_cb, menu);
+    }
+}
+
+/* move one item down in the menu */
+static void
+opt_menu_down (OptMenu * menu)
+{
+  opt_menu_select_item (menu, menu->priv->active_item + 1);
+
+  if (menu->priv->timeout_id)
+    {
+      g_source_remove (menu->priv->timeout_id);
+      menu->priv->timeout_id = g_timeout_add (5000, opt_menu_timeout_cb, menu);
+    }
+}
+
+/*
+ * Jump to the slide represented by the active menu item
+ */
+static void
+opt_menu_activate (OptMenu * menu)
+{
+  int step = menu->priv->active_item - menu->priv->current_slide;
+
+  opt_menu_popdown (menu);
+  
+  if (step)
+    opt_show_skip (menu->priv->show, step);
+}
+
+/*
+ *  Called when we mode to a different slide
+ */
+void
+opt_menu_set_current_slide (OptMenu * menu, gint slide_no)
+{
+  opt_menu_select_item (menu, slide_no);
+  menu->priv->current_slide = slide_no;
+}
+
+/*
+ * Adds a slide to the menu
+ */
+void
+opt_menu_add_slide (OptMenu * menu, OptSlide * slide)
+{
+  static gint y = 0;
+  
+  gchar              * text = NULL;
+  const gchar        * font = DEFAULT_FONT;
+  const ClutterText  * title = CLUTTER_TEXT (opt_slide_get_title (slide));
+  ClutterActor       * label;
+  
+  if (title)
+    text = g_strdup_printf ("Slide %d: %s", menu->priv->item_count + 1,
+                            clutter_text_get_text ((ClutterText*)title));
+  else
+    text = g_strdup_printf ("Slide %d", menu->priv->item_count + 1);
+
+  if (!menu->priv->item_count)
+    label = clutter_text_new_full (font, text, &menu->priv->color_sel);
+  else
+    label = clutter_text_new_full (font, text, &menu->priv->color_normal);
+  
+  g_free (text);
+  
+  clutter_actor_set_position (label, TEXT_BORDER, y);
+  y += ITEM_HEIGHT;
+      
+  clutter_group_add (CLUTTER_GROUP (menu), label);
+  menu->priv->item_count++;
+}
+
+/*
+ * Shows menu
+ */
+void
+opt_menu_pop (OptMenu * menu)
+{
+  if (!CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (menu)))
+    {
+      guint width, height;
+      
+      ClutterActor * stage = clutter_stage_get_default();
+
+      if (!menu->priv->size_set)
+        opt_menu_init_size (menu);
+      
+      clutter_actor_get_size (CLUTTER_ACTOR (menu), &width, &height);
+
+      clutter_actor_set_scale (CLUTTER_ACTOR (menu), 0.0, 0.0);
+      clutter_timeline_set_direction (menu->priv->timeline,
+                                      CLUTTER_TIMELINE_FORWARD);
+      
+      clutter_group_add (CLUTTER_GROUP(stage), CLUTTER_ACTOR(menu));
+
+      clutter_actor_set_position (CLUTTER_ACTOR (menu), 0, 0);
+
+      /* Connect up for input event */
+      menu->priv->button_release_signal_id =
+        g_signal_connect (stage, "button-release-event",
+                          G_CALLBACK (opt_menu_button_release_cb), menu);
+      menu->priv->key_release_signal_id =
+        g_signal_connect (stage, "key-release-event",
+                          G_CALLBACK (opt_menu_key_release_cb), menu);
+
+      opt_menu_select_item (menu, menu->priv->current_slide);
+      clutter_actor_show_all (CLUTTER_ACTOR (menu));
+
+      menu->priv->timeout_id = g_timeout_add (5000, opt_menu_timeout_cb, menu);
+      menu->priv->hiding = FALSE;
+      clutter_timeline_rewind (menu->priv->timeline);
+      clutter_timeline_start (menu->priv->timeline);
+    }
+}
+
+/*
+ * Hides menu, if shown
+ */
+void
+opt_menu_popdown (OptMenu * menu)
+{
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (menu)))
+  {
+    ClutterActor * stage = clutter_stage_get_default();
+
+    if (menu->priv->button_release_signal_id)
+      {
+        g_signal_handler_disconnect (stage,
+                                     menu->priv->button_release_signal_id);
+        menu->priv->button_release_signal_id = 0;
+      }
+
+    if (menu->priv->key_release_signal_id)
+      {
+        g_signal_handler_disconnect (stage,
+                                     menu->priv->key_release_signal_id);
+        menu->priv->key_release_signal_id = 0;
+      }
+  
+    clutter_actor_set_scale (CLUTTER_ACTOR (menu), 1.0, 1.0);
+    clutter_timeline_set_direction (menu->priv->timeline,
+                                    CLUTTER_TIMELINE_BACKWARD);
+    
+    menu->priv->hiding = TRUE;
+    clutter_timeline_rewind (menu->priv->timeline);
+    clutter_timeline_start (menu->priv->timeline);
+  }
+}
+
diff --git a/opt/opt-menu.h b/opt/opt-menu.h
new file mode 100644 (file)
index 0000000..91ae7ca
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _HAVE_OPT_MENU_H
+#define _HAVE_OPT_MENU_H
+
+#include <glib-object.h>
+
+#include "opt.h"
+
+G_BEGIN_DECLS
+
+#define OPT_TYPE_MENU opt_menu_get_type()
+
+#define OPT_MENU(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  OPT_TYPE_MENU, OptMenu))
+
+#define OPT_MENU_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  OPT_TYPE_MENU, OptMenuClass))
+
+#define OPT_IS_MENU(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  OPT_TYPE_MENU))
+
+#define OPT_IS_MENU_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  OPT_TYPE_MENU))
+
+#define OPT_MENU_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  OPT_TYPE_MENU, OptMenuClass))
+
+typedef struct OptMenuPrivate OptMenuPrivate;
+typedef struct _OptMenuClass  OptMenuClass;
+struct _OptMenu
+{
+  ClutterGroup    parent;
+  OptMenuPrivate *priv;
+};
+
+struct _OptMenuClass
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+};
+
+OptMenu *opt_menu_new (OptShow * show);
+void opt_menu_add_slide (OptMenu * menu, OptSlide * slide);
+void opt_menu_set_current_slide (OptMenu * menu, gint slide_no);
+void opt_menu_pop (OptMenu * menu);
+void opt_menu_popdown (OptMenu * menu);
+
+G_END_DECLS
+
+#endif
diff --git a/opt/opt-show.c b/opt/opt-show.c
new file mode 100644 (file)
index 0000000..50fa126
--- /dev/null
@@ -0,0 +1,695 @@
+
+#include "opt.h"
+
+G_DEFINE_TYPE (OptShow, opt_show, G_TYPE_OBJECT);
+
+#define TITLE_BORDER_SIZE    8  /* all round */
+#define TITLE_BULLET_PAD     5  /* between title and bullet */
+#define BULLET_BORDER_SIZE  10  /* sides */
+#define BULLET_PAD    5  /* between bullets */
+
+#define TITLE_FONT "VistaSansMed 50"
+#define BULLET_FONT "VistaSansMed 40"
+
+struct OptShowPrivate
+{
+  GList           *slides;
+  gint             current_slide_num;
+  guint            num_slides;
+
+  gint             title_border_size;
+  gint             title_bullet_pad;
+  gint             bullet_border_size;
+  gint             bullet_pad;
+  gchar*           title_font;
+  gchar*           bullet_font;
+  ClutterActor    *bullet_texture;
+  GdkPixbuf       *background;
+
+  ClutterActor    *position_label;
+  ClutterActor    *position_rect;
+  guint            position_label_visible;
+  
+  ClutterTimeline *transition;
+  ClutterActor    *bg;
+
+  gulong           trans_signal_id;
+
+  OptMenu         *menu;
+};
+
+enum
+{
+  PROP_0,
+  PROP_TITLE_BORDER_SIZE,
+  PROP_TITLE_BULLET_PAD,  
+  PROP_BULLET_BORDER_SIZE,
+  PROP_BULLET_PAD,  
+  PROP_TITLE_FONT,
+  PROP_BULLET_FONT,
+  PROP_BACKGROUND
+};
+
+
+static void 
+opt_show_dispose (GObject *object)
+{
+  OptShow *self = OPT_SHOW(object); 
+
+  if (self->priv)
+    {
+
+    }
+
+  G_OBJECT_CLASS (opt_show_parent_class)->dispose (object);
+}
+
+static void 
+opt_show_finalize (GObject *object)
+{
+  OptShow *self = OPT_SHOW(object); 
+
+  g_object_unref (G_OBJECT (self->priv->menu));
+  
+  if (self->priv)
+    {
+      g_free(self->priv);
+      self->priv = NULL;
+    }
+
+  G_OBJECT_CLASS (opt_show_parent_class)->finalize (object);
+}
+
+static void 
+opt_show_set_property (GObject      *object, 
+                      guint         prop_id,
+                      const GValue *value, 
+                      GParamSpec   *pspec)
+{
+
+  OptShow *show = OPT_SHOW(object);
+  OptShowPrivate *priv;
+
+  priv = show->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_TITLE_BORDER_SIZE:
+      priv->title_border_size = g_value_get_int (value);
+      break;
+    case PROP_TITLE_BULLET_PAD:
+      priv->title_bullet_pad = g_value_get_int (value);
+      break;
+    case PROP_BULLET_BORDER_SIZE:
+      priv->bullet_border_size = g_value_get_int (value);
+      break;
+    case PROP_BULLET_PAD:
+      priv->bullet_pad = g_value_get_int (value);
+      break;
+    case PROP_TITLE_FONT:
+      if (priv->title_font) g_free (priv->title_font);
+      priv->title_font = g_value_dup_string (value);
+      break;
+    case PROP_BULLET_FONT:
+      if (priv->bullet_font) g_free (priv->bullet_font);
+      priv->bullet_font = g_value_dup_string (value);
+      break;
+    case PROP_BACKGROUND:
+      priv->background = g_value_get_object (value);
+
+      clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (priv->bg),
+                                         gdk_pixbuf_get_pixels (priv->background),
+                                         gdk_pixbuf_get_has_alpha (priv->background),
+                                         gdk_pixbuf_get_width (priv->background),
+                                         gdk_pixbuf_get_height (priv->background),
+                                         gdk_pixbuf_get_rowstride (priv->background),
+                                         gdk_pixbuf_get_n_channels (priv->background), 
+                                         0,
+                                         NULL);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void 
+opt_show_get_property (GObject    *object, 
+                      guint       prop_id,
+                      GValue     *value, 
+                      GParamSpec *pspec)
+{
+  OptShow *show = OPT_SHOW(object);
+  OptShowPrivate *priv;
+
+  priv = show->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_TITLE_BORDER_SIZE:
+      g_value_set_int (value, priv->title_border_size);
+      break;
+    case PROP_TITLE_BULLET_PAD:
+      g_value_set_int (value, priv->title_bullet_pad);
+      break;
+    case PROP_BULLET_BORDER_SIZE:
+      g_value_set_int (value, priv->bullet_border_size);
+      break;
+    case PROP_BULLET_PAD:
+      g_value_set_int (value, priv->bullet_pad);
+      break;
+    case PROP_TITLE_FONT:
+      g_value_set_string (value, priv->title_font);
+      break;
+    case PROP_BULLET_FONT:
+      g_value_set_string (value, priv->bullet_font);
+      break;
+    case PROP_BACKGROUND:
+      g_value_set_object (value, priv->background);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+opt_show_class_init (OptShowClass *klass)
+{
+  GObjectClass        *object_class;
+
+  object_class = (GObjectClass*) klass;
+
+  /* GObject */
+  object_class->finalize     = opt_show_finalize;
+  object_class->dispose      = opt_show_dispose;
+  object_class->set_property = opt_show_set_property;
+  object_class->get_property = opt_show_get_property;
+
+  g_object_class_install_property
+    (object_class, PROP_TITLE_BORDER_SIZE,
+     g_param_spec_int ("title-border-size",
+                      "percentage",
+                      "percentage",
+                      0,
+                      100,
+                      TITLE_BORDER_SIZE,
+                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (object_class, PROP_TITLE_BULLET_PAD,
+     g_param_spec_int ("title-bullet-pad",
+                      "percentage",
+                      "percentage",
+                      0,
+                      100,
+                      TITLE_BULLET_PAD,
+                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (object_class, PROP_BULLET_BORDER_SIZE,
+     g_param_spec_int ("bullet-border-size",
+                      "percentage",
+                      "percentage",
+                      0,
+                      100,
+                      BULLET_BORDER_SIZE,
+                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (object_class, PROP_BULLET_PAD,
+     g_param_spec_int ("bullet-pad",
+                      "percentage",
+                      "percentage",
+                      0,
+                      100,
+                      BULLET_PAD,
+                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (object_class, PROP_BULLET_FONT,
+     g_param_spec_string ("bullet-font",
+                         "bullet font name",
+                         "bullet font name",
+                         BULLET_FONT,
+                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (object_class, PROP_TITLE_FONT,
+     g_param_spec_string ("title-font",
+                         "title font name",
+                         "title font name",
+                         TITLE_FONT,
+                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property
+    (object_class, PROP_BACKGROUND,
+     g_param_spec_object ("background",
+                         "Pixbuf source for default show background.",
+                         "Pixbuf source for default show background.",
+                         GDK_TYPE_PIXBUF, G_PARAM_READWRITE));
+}
+
+static void
+opt_show_init (OptShow *self)
+{
+  OptShowPrivate *priv;
+
+  priv           = g_new0 (OptShowPrivate, 1);
+
+  self->priv  = priv;
+}
+
+OptShow*
+opt_show_new (void)
+{
+  OptShow       *show;
+  ClutterColor col = { 0, 0, 0, 0xff };
+
+  show = g_object_new (OPT_TYPE_SHOW, NULL);
+
+  show->priv->bullet_texture 
+    = clutter_text_new_with_text (show->priv->bullet_font, "•");
+  clutter_text_set_color (CLUTTER_TEXT(show->priv->bullet_texture), &col);
+
+  show->priv->bg = g_object_new (CLUTTER_TYPE_TEXTURE, NULL);
+
+  show->priv->menu = opt_menu_new (show);
+  g_object_ref (G_OBJECT (show->priv->menu));
+  
+  return show;
+}
+
+/* bullet hacks, needs redoing */
+ClutterActor*
+opt_show_bullet_clone (OptShow *show)
+{
+  return clutter_text_new_with_text (show->priv->bullet_font, "•");
+}
+
+void
+opt_show_set_bullet_color (OptShow *show, ClutterColor *col)
+{
+  clutter_text_set_color (CLUTTER_TEXT(show->priv->bullet_texture), col);
+}
+
+void
+opt_show_add_slide (OptShow *self, OptSlide *slide)
+{
+  ClutterActor   *bg, *stage;
+
+  self->priv->slides = g_list_append(self->priv->slides, slide);
+  self->priv->num_slides++;
+
+  stage = clutter_stage_get_default();
+
+  bg = CLUTTER_ACTOR(opt_slide_get_background_texture (slide));
+
+  if (bg == NULL)
+    bg = clutter_clone_new(self->priv->bg);
+
+  clutter_actor_set_size (bg, 
+                          clutter_actor_get_width (stage),
+                          clutter_actor_get_height (stage));
+  
+
+  clutter_group_add (CLUTTER_GROUP(slide), bg);
+
+  clutter_actor_lower_bottom(bg);
+  clutter_actor_show(bg);
+
+  opt_menu_add_slide (self->priv->menu, slide);
+}
+
+void
+opt_show_run (OptShow *self)
+{
+  OptSlide       *slide;
+  OptShowPrivate *priv;
+  ClutterActor *stage;
+  ClutterColor    col = { 0x22, 0x22, 0x22, 0xff };
+
+  priv = self->priv;
+  priv->current_slide_num = 0;
+
+  slide = g_list_nth_data (priv->slides, 0);
+  stage = clutter_stage_get_default();
+
+  clutter_stage_set_color (CLUTTER_STAGE(stage), &col);
+  clutter_group_add (CLUTTER_GROUP(stage), CLUTTER_ACTOR(slide));
+  clutter_actor_show_all (stage);
+}
+
+static void
+opt_show_update_position_label (OptShow *show)
+{
+  OptShowPrivate *priv = show->priv;
+  ClutterActor *stage;
+  ClutterGeometry stage_geom;
+  ClutterGeometry rect_geom;
+  gint label_width, label_height;
+  gchar *pos;
+  
+  if (!priv->position_label)
+    return;
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_get_geometry (stage, &stage_geom);
+  
+  pos = g_strdup_printf ("%d/%d",
+                        priv->current_slide_num + 1,
+                        priv->num_slides);
+
+  clutter_text_set_text (CLUTTER_TEXT (priv->position_label), pos);
+  clutter_texture_get_base_size (CLUTTER_TEXTURE (priv->position_label),
+                                &label_width,
+                                &label_height);
+
+  rect_geom.width = label_width + 50;
+  rect_geom.height = label_height + 20;
+  rect_geom.x = (stage_geom.width / 2) - (rect_geom.width / 2);
+  rect_geom.y = stage_geom.height - rect_geom.height - 10;
+  
+  clutter_actor_set_geometry (priv->position_rect, &rect_geom);
+  clutter_actor_set_position (priv->position_label,
+                             rect_geom.x + 25,
+                             rect_geom.y + 10);
+  
+  g_free (pos);
+}
+
+static void
+transition_completed_cb (OptTransition   *trans,
+                        gpointer         data)
+{
+  OptShow        *show = (OptShow *)data;
+  OptSlide       *from;
+  OptShowPrivate *priv;
+  ClutterActor *stage;
+
+  priv = show->priv;
+
+  from = opt_transition_get_from (trans);
+  stage = clutter_stage_get_default();
+
+  /* Remove as to free up resources. */
+
+  clutter_actor_hide_all (CLUTTER_ACTOR(from));
+  clutter_container_remove_actor (CLUTTER_CONTAINER(stage),
+                                  CLUTTER_ACTOR(from));
+
+
+  /* Reset any tranforms to be safe */
+  clutter_actor_set_rotation (CLUTTER_ACTOR(from), CLUTTER_X_AXIS, 0, 0, 0, 0);
+  clutter_actor_set_rotation (CLUTTER_ACTOR(from), CLUTTER_Y_AXIS, 0, 0, 0, 0);
+  clutter_actor_set_rotation (CLUTTER_ACTOR(from), CLUTTER_Z_AXIS, 0, 0, 0, 0);
+
+  /* If needed, update the position */
+  if (priv->position_label_visible)
+    opt_show_update_position_label (show);
+  
+  /* Disconnect the handler */
+  g_signal_handler_disconnect (trans, priv->trans_signal_id);
+  priv->trans_signal_id = 0;
+}
+
+void
+opt_show_step (OptShow *self, gint step)
+{
+  OptSlide       *from, *to;
+  OptShowPrivate *priv;
+  OptTransition  *trans;
+  ClutterActor *stage;
+
+  priv = self->priv;
+
+  /* transition already running */
+  if (priv->trans_signal_id != 0)
+    return;
+
+  stage = clutter_stage_get_default();
+
+  from = g_list_nth_data (priv->slides, priv->current_slide_num);
+  to   = g_list_nth_data (priv->slides, priv->current_slide_num + step);
+
+  if (from == NULL)
+    from = priv->slides->data;
+  
+  /* Nowhere to go */
+  if (to == NULL)
+    return;
+
+  /* Add next slide to stage */
+  clutter_group_add (CLUTTER_GROUP(stage), CLUTTER_ACTOR(to));
+
+  trans = opt_slide_get_transition ( step < 0 ? to : from);
+
+  /* 
+   * Make sure any textures are loaded before the transitions is started .
+  */
+  clutter_container_foreach (CLUTTER_CONTAINER (to), 
+                             (ClutterCallback)clutter_actor_realize,
+                             NULL);
+
+  if (trans != NULL)
+    {
+      if (step < 0)
+       opt_transition_set_direction (trans, OPT_TRANSITION_BACKWARD);
+      else
+       opt_transition_set_direction (trans, OPT_TRANSITION_FORWARD);
+
+      /* Set up transition and start it */
+      opt_transition_set_to (trans, to);
+      opt_transition_set_from (trans, from);
+
+      priv->trans_signal_id 
+       = g_signal_connect (trans,
+                           "completed",  
+                           G_CALLBACK (transition_completed_cb), 
+                           self);
+
+      /* lower it out of view */
+      clutter_actor_lower_bottom (CLUTTER_ACTOR(to));
+
+      clutter_timeline_start (CLUTTER_TIMELINE(trans));
+    }
+  else
+    {
+      /* No transition just hide current slide*/
+      clutter_group_remove (CLUTTER_GROUP(stage), CLUTTER_ACTOR(from));
+      clutter_actor_hide_all (CLUTTER_ACTOR(from));
+    }
+  
+  /* Advance */
+    priv->current_slide_num += step;
+
+  priv->current_slide_num = 
+      CLAMP(priv->current_slide_num, 0, priv->num_slides-1);
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (priv->menu)))
+      opt_menu_popdown (priv->menu);
+  
+  opt_menu_set_current_slide (priv->menu, priv->current_slide_num);
+}
+
+void
+opt_show_advance (OptShow *self)
+{
+  opt_show_step (self, 1);
+}
+
+void
+opt_show_retreat (OptShow *self)
+{
+  opt_show_step (self, -1);
+}
+
+void
+opt_show_skip (OptShow *self, gint n_slides)
+{
+  opt_show_step (self, n_slides);
+}
+
+static void
+free_data (guchar *pixels,
+           gpointer data)
+{
+  g_free (pixels);
+}
+
+gboolean
+opt_show_export (OptShow *self, const char *path, GError **error)
+{
+#define HTML "<html><head><title>Slide %i</title></head>\n"       \
+             "<body><p><center><img src=\"%s\"></center></p>\n"   \
+             "<p><center><strong>%s%s</strong></center></p>\n"    \
+             "</body></html>"
+
+  GList          *slide;
+  OptShowPrivate *priv;
+  ClutterActor   *stage;
+  gint            i = 0;
+
+  priv = self->priv;
+
+  stage = clutter_stage_get_default();
+
+  g_object_set (stage, "offscreen", TRUE, NULL);
+
+  clutter_actor_show_all (stage);
+
+  slide = priv->slides;
+
+  while (slide)
+    {
+      ClutterActor *e;
+      guchar       *data;
+      GdkPixbuf    *pixb = NULL;
+      gchar         name[32];
+      gchar        *filename = NULL;
+      gchar         html[2048], html_next[512], html_prev[512];
+
+      e = CLUTTER_ACTOR(slide->data);
+
+      clutter_container_add_actor (CLUTTER_CONTAINER(stage), e);
+      clutter_actor_show_all (stage);
+      clutter_actor_show_all (e);
+
+      // clutter_redraw (CLUTTER_STAGE (stage));
+      
+      data = clutter_stage_read_pixels (CLUTTER_STAGE(stage),
+                                       0,
+                                       0,
+                                       clutter_actor_get_width (stage),
+                                       clutter_actor_get_height (stage));
+      if (!data)
+       {
+         g_warning("Failed to grab pixels from stage");
+         return FALSE;
+       }
+
+      pixb = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE, 8,
+                                       clutter_actor_get_width (stage),
+                                       clutter_actor_get_height (stage),
+                                       clutter_actor_get_width (stage) * 4,
+                                       free_data,
+                                       NULL);
+
+      g_snprintf (name, 32, "slide-%02i.png", i);
+
+      filename = g_build_filename(path, name, NULL);
+
+      if (!gdk_pixbuf_save (pixb, filename, "png", error, 
+                           "compression", "9", /* Really compress */
+                           NULL))
+       {
+         if (filename) g_free (filename);
+          g_object_unref (pixb);
+         return FALSE;
+       }
+
+      html_next[0] = html_prev[0] = '\0';
+      
+      if (i > 0)
+       snprintf(html_prev, 512, 
+                "<a href=\"slide-%02i.html\">Prev</a> |", i-1);
+
+      if (slide->next)
+       snprintf(html_next, 512, 
+                " <a href=\"slide-%02i.html\">Next</a>", i+1);
+
+      g_snprintf(html, 2048, HTML, i, name, html_prev, html_next);
+      g_snprintf(name, 32, "slide-%02i.html", i);
+      g_free (filename);
+
+      filename = g_build_filename(path, name, NULL);
+
+      g_file_set_contents (filename, html, -1, NULL);
+
+      g_print ("wrote '%s'\n", filename);
+
+      clutter_actor_hide_all (e);
+      clutter_group_remove (CLUTTER_GROUP(stage), e);
+
+      if (filename) g_free (filename);
+      slide = slide->next;
+      i++;
+
+      g_object_unref (pixb);
+    }
+
+  return TRUE;
+}
+
+void
+opt_show_toggle_position (OptShow *show)
+{
+  OptShowPrivate *priv;
+  ClutterActor *stage;
+  ClutterGeometry stage_geom;
+  
+  g_return_if_fail (OPT_IS_SHOW (show));
+
+  priv = show->priv;
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_get_geometry (stage, &stage_geom);
+
+  if (!priv->position_label)
+    {
+      ClutterActor *rect;
+      ClutterActor *label;
+      ClutterColor rect_color = { 0x00, 0x00, 0x00, 0x33 };
+      ClutterColor label_color = { 0xff, 0xff, 0xff, 0xee };
+      ClutterGeometry rect_geom;
+
+      rect = clutter_rectangle_new ();
+      clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect),
+                                  &rect_color);
+
+      rect_geom.width = 102;
+      rect_geom.height = 77;
+      rect_geom.x = stage_geom.width / 2 - rect_geom.width / 2;
+      rect_geom.y = stage_geom.height - rect_geom.height - 20;
+
+      clutter_actor_set_geometry (rect, &rect_geom);
+
+      label = clutter_text_new_with_text ("Sans Bold 20", "0/0");
+      clutter_text_set_color (CLUTTER_TEXT (label),
+                              &label_color);
+      clutter_actor_set_position (label, rect_geom.x + 10, rect_geom.y + 10);
+
+      clutter_group_add_many (CLUTTER_GROUP (stage),
+                             rect,
+                             label,
+                             NULL);
+      
+      priv->position_label = label;
+      priv->position_rect = rect;
+      priv->position_label_visible = FALSE;
+    }
+
+  if (!priv->position_label_visible)
+    {
+      priv->position_label_visible = TRUE;
+
+      opt_show_update_position_label (show);
+      
+      clutter_actor_show (priv->position_rect);
+      clutter_actor_show (priv->position_label);
+    }
+  else
+    {
+      clutter_actor_hide (priv->position_label);
+      clutter_actor_hide (priv->position_rect);
+
+      priv->position_label_visible = FALSE;
+    }
+}
+
+void
+opt_show_pop_menu (OptShow *show)
+{
+    opt_menu_pop (show->priv->menu);
+}
+
diff --git a/opt/opt-show.h b/opt/opt-show.h
new file mode 100644 (file)
index 0000000..27cfdd6
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef _HAVE_OPT_SHOW_H
+#define _HAVE_OPT_SHOW_H
+
+#include <glib-object.h>
+
+#include "opt.h"
+
+G_BEGIN_DECLS
+
+#define OPT_TYPE_SHOW opt_show_get_type()
+
+#define OPT_SHOW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  OPT_TYPE_SHOW, OptShow))
+
+#define OPT_SHOW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  OPT_TYPE_SHOW, OptShowClass))
+
+#define OPT_IS_SHOW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  OPT_TYPE_SHOW))
+
+#define OPT_IS_SHOW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  OPT_TYPE_SHOW))
+
+#define OPT_SHOW_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  OPT_TYPE_SHOW, OptShowClass))
+
+typedef struct OptShowPrivate OptShowPrivate;
+typedef struct _OptShowClass  OptShowClass;
+struct _OptShow
+{
+  GObject              parent;
+  OptShowPrivate      *priv;
+};
+
+struct _OptShowClass
+{
+  GObjectClass         parent_class;
+};
+
+GType opt_show_get_type (void);
+
+OptShow* 
+opt_show_new (void);
+
+void
+opt_show_add_slide (OptShow *self, OptSlide *slide);
+
+void
+opt_show_run (OptShow *self);
+
+void
+opt_show_advance (OptShow *self);
+
+void
+opt_show_retreat (OptShow *self);
+
+void
+opt_show_skip (OptShow *self, gint n_slides);
+
+gboolean
+opt_show_export (OptShow *self, const char *path, GError **error);
+
+ClutterActor*
+opt_show_bullet_clone (OptShow *show);
+
+void
+opt_show_set_bullet_color (OptShow *show, ClutterColor *col);
+
+void
+opt_show_toggle_position (OptShow *show);
+
+void
+opt_show_pop_menu (OptShow *show);
+
+G_END_DECLS
+
+#endif
diff --git a/opt/opt-slide.c b/opt/opt-slide.c
new file mode 100644 (file)
index 0000000..fd62491
--- /dev/null
@@ -0,0 +1,319 @@
+#include "opt.h"
+
+G_DEFINE_TYPE (OptSlide, opt_slide, CLUTTER_TYPE_GROUP);
+
+#define PERCENT_TO_PIXELS(p) \
+   (( (p) * CLUTTER_STAGE_WIDTH() ) / 100)
+
+struct OptSlidePrivate
+{
+  ClutterActor   *background;
+  ClutterActor   *title;
+  ClutterActor   *bg;
+  GList          *bullets;
+  OptShow        *show;
+  OptTransition  *trans;
+};
+
+static void 
+opt_slide_dispose (GObject *object)
+{
+  OptSlide *self = OPT_SLIDE(object); 
+
+  if (self->priv)
+    {
+      if (self->priv->trans != NULL)
+       g_object_unref(self->priv->trans);
+      self->priv->trans = NULL;
+    }
+
+  G_OBJECT_CLASS (opt_slide_parent_class)->dispose (object);
+}
+
+
+static void 
+opt_slide_finalize (GObject *object)
+{
+  OptSlide *self = OPT_SLIDE(object); 
+
+  if (self->priv)
+    {
+      g_free(self->priv);
+      self->priv = NULL;
+    }
+
+  G_OBJECT_CLASS (opt_slide_parent_class)->finalize (object);
+}
+
+static void
+opt_slide_class_init (OptSlideClass *klass)
+{
+  GObjectClass        *object_class;
+  ClutterActorClass *actor_class;
+
+  object_class = (GObjectClass*) klass;
+  actor_class = (ClutterActorClass*)klass;
+
+  /* GObject */
+  object_class->finalize     = opt_slide_finalize;
+  object_class->dispose      = opt_slide_dispose;
+}
+
+static void
+opt_slide_init (OptSlide *self)
+{
+  OptSlidePrivate *priv;
+
+  priv = g_new0 (OptSlidePrivate, 1);
+
+  self->priv  = priv;
+}
+
+OptSlide*
+opt_slide_new (OptShow *show)
+{
+  OptSlide *slide;
+
+  g_return_val_if_fail(OPT_IS_SHOW(show), NULL);
+
+  slide = g_object_new (OPT_TYPE_SLIDE, NULL);
+
+  slide->priv->show = show; 
+
+  return slide;
+}
+
+void
+opt_slide_set_title (OptSlide     *slide, 
+                    const gchar  *title,
+                    const gchar  *font,
+                    ClutterColor *col)
+{
+  OptSlidePrivate *priv;
+  gint             avail_w, border;
+  gint             title_border_size;
+  ClutterActor    *stage;
+
+  g_return_if_fail(OPT_IS_SLIDE(slide));
+
+  priv = slide->priv;
+
+  if (priv->title != NULL)
+    {
+      clutter_group_remove (CLUTTER_GROUP(slide), priv->title);
+      g_object_unref (priv->title);
+    }
+
+  if (font == NULL)
+    {
+      gchar *default_font = NULL;
+      g_object_get (priv->show, "title-font", &default_font, NULL);
+      priv->title = clutter_text_new_with_text (default_font, title);
+      g_free (default_font);
+    }
+  else
+    priv->title = clutter_text_new_with_text (font, title);
+
+  clutter_group_add (CLUTTER_GROUP(slide), priv->title);
+
+  g_object_get (priv->show, 
+               "title-border-size", &title_border_size,
+               NULL);
+
+  stage = clutter_stage_get_default ();
+
+  border = PERCENT_TO_PIXELS (title_border_size);
+
+  avail_w = clutter_actor_get_width (stage) - (2 * border) ; 
+
+  clutter_actor_set_size (CLUTTER_ACTOR(priv->title), avail_w, -1);
+
+  clutter_text_set_color (CLUTTER_TEXT(priv->title), col);
+
+  clutter_actor_set_position (priv->title, border, border);
+
+  clutter_actor_show (priv->title);
+}
+
+void
+get_next_bullet_offsets (OptSlide *slide,
+                        gint     *x,
+                        gint     *y,
+                        gint     *max_width)
+{
+  OptSlidePrivate *priv;
+  GList           *last_bullet_item;
+  gint             title_bullet_pad, bullet_border_size, bullet_pad;
+
+  priv = slide->priv;
+
+  g_object_get (priv->show, 
+               "title-bullet-pad", &title_bullet_pad,
+               "bullet-pad", &bullet_pad,
+               "bullet-border-size", &bullet_border_size,
+               NULL);
+
+  if ((last_bullet_item = g_list_last (priv->bullets)) == NULL)
+    {
+      *y = clutter_actor_get_y (priv->title)
+        + clutter_actor_get_height (priv->title);
+
+      *y += PERCENT_TO_PIXELS (title_bullet_pad);
+    }
+  else
+    {
+      ClutterActor *last_bullet = CLUTTER_ACTOR(last_bullet_item->data);
+
+      *y = clutter_actor_get_y (last_bullet)
+        + clutter_actor_get_height (last_bullet);
+
+      *y += PERCENT_TO_PIXELS (bullet_pad);
+    }
+
+  *x = PERCENT_TO_PIXELS (bullet_border_size);
+
+  *max_width = CLUTTER_STAGE_WIDTH() 
+                  - (2 * PERCENT_TO_PIXELS (bullet_border_size)) ; 
+}
+
+void
+opt_slide_add_bullet_text_item (OptSlide            *slide, 
+                               const gchar         *title,
+                               const gchar         *font,
+                               OptSlideBulletSymbol sym,
+                               ClutterColor        *col)
+{
+  OptSlidePrivate *priv;
+  ClutterActor  *bullet, *symbol = NULL;
+  gint             x, y, width, symbol_width = 0;
+
+  priv = slide->priv;
+
+  if (font == NULL)
+    {
+      gchar *default_font = NULL;
+
+      g_object_get (priv->show, "bullet-font", &default_font, NULL);
+      bullet = clutter_text_new_with_text (default_font, title);
+      g_free (default_font);
+    }
+  else
+    bullet = clutter_text_new_with_text (font, title);
+
+  clutter_text_set_color (CLUTTER_TEXT(bullet), col);
+  clutter_text_set_line_wrap (CLUTTER_TEXT (bullet), TRUE);
+
+  get_next_bullet_offsets (slide, &x, &y, &width);
+
+  symbol       = opt_show_bullet_clone (priv->show);
+  symbol_width = 2 * clutter_actor_get_width (symbol);
+
+  if (sym != OPT_BULLET_NONE)
+    {
+      clutter_group_add (CLUTTER_GROUP(slide), symbol);
+      clutter_actor_set_position (symbol, x, y);
+      clutter_actor_show(symbol);
+    }
+
+  x += symbol_width;
+
+  clutter_actor_set_size (CLUTTER_ACTOR(bullet), width - symbol_width, -1);
+
+  clutter_actor_set_position (bullet, x, y);
+  clutter_group_add (CLUTTER_GROUP(slide), bullet);
+
+  clutter_actor_show(bullet);
+
+
+  priv->bullets = g_list_append(priv->bullets, bullet);
+}
+
+void
+opt_slide_add_bullet (OptSlide *slide, ClutterActor *actor)
+{
+  OptSlidePrivate *priv;
+  gint             x, y, width;
+
+  priv = slide->priv;
+
+  get_next_bullet_offsets (slide, &x, &y, &width);
+
+  priv->bullets = g_list_append(priv->bullets, actor);
+
+  clutter_group_add (CLUTTER_GROUP(slide), actor);
+
+  clutter_actor_set_position (actor, 
+                               x + (width -clutter_actor_get_width(actor))
+                                                     /2, 
+                               y);
+
+  clutter_actor_show(actor);
+}
+
+const ClutterActor*
+opt_slide_get_title (OptSlide *slide)
+{
+  return slide->priv->title;
+}
+
+GList*
+opt_slide_get_bullets (OptSlide *slide)
+{
+  return slide->priv->bullets;
+}
+
+void
+opt_slide_set_transition (OptSlide *slide, OptTransition *trans)
+{
+  OptSlidePrivate *priv;
+
+  priv = slide->priv;
+
+  if (priv->trans == trans)
+    return;
+
+  if (priv->trans != NULL)
+    g_object_unref(priv->trans);
+
+  if (trans)
+    {
+      priv->trans = trans;
+      g_object_ref(slide);
+    }
+}
+
+OptTransition*
+opt_slide_get_transition (OptSlide *slide)
+{
+  return slide->priv->trans;
+}
+
+void
+opt_slide_set_background_pixbuf (OptSlide *slide, GdkPixbuf *background)
+{
+  OptSlidePrivate *priv;
+
+  g_return_if_fail (background != NULL);
+
+  priv = slide->priv;
+
+  if (priv->background != NULL)
+    clutter_actor_destroy (priv->background);
+
+  priv->background = clutter_texture_new ();
+  clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (priv->background),
+                                     gdk_pixbuf_get_pixels (background),
+                                     gdk_pixbuf_get_has_alpha (background),
+                                     gdk_pixbuf_get_width (background),
+                                     gdk_pixbuf_get_height (background),
+                                     gdk_pixbuf_get_rowstride (background),
+                                     gdk_pixbuf_get_n_channels (background), 
+                                     0,
+                                     NULL);
+}
+
+ClutterActor *
+opt_slide_get_background_texture (OptSlide *slide)
+{
+  return slide->priv->background;
+}
diff --git a/opt/opt-slide.h b/opt/opt-slide.h
new file mode 100644 (file)
index 0000000..dda8893
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef _HAVE_OPT_SLIDE_H
+#define _HAVE_OPT_SLIDE_H
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "opt.h"
+
+G_BEGIN_DECLS
+
+#define OPT_TYPE_SLIDE opt_slide_get_type()
+
+#define OPT_SLIDE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  OPT_TYPE_SLIDE, OptSlide))
+
+#define OPT_SLIDE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  OPT_TYPE_SLIDE, OptSlideClass))
+
+#define OPT_IS_SLIDE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  OPT_TYPE_SLIDE))
+
+#define OPT_IS_SLIDE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   OPT_TYPE_SLIDE))
+
+#define OPT_SLIDE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  OPT_TYPE_SLIDE, OptSlideClass))
+
+typedef struct OptSlidePrivate OptSlidePrivate;
+typedef struct _OptSlideClass  OptSlideClass;
+struct _OptSlide
+{
+  ClutterGroup          parent;
+  OptSlidePrivate      *priv;
+};
+
+struct _OptSlideClass
+{
+  ClutterGroupClass     parent_class;
+};
+
+typedef enum OptSlideBulletSymbol
+{
+  OPT_BULLET_REGULAR = 0,
+  OPT_BULLET_NONE
+}
+OptSlideBulletSymbol;
+
+GType opt_slide_get_type (void);
+
+OptSlide* 
+opt_slide_new (OptShow *show);
+
+void
+opt_slide_set_title (OptSlide     *slide, 
+                    const gchar  *title,
+                    const gchar  *font,
+                    ClutterColor *col);
+
+void
+opt_slide_add_bullet_text_item (OptSlide            *slide, 
+                               const gchar         *title,
+                               const gchar         *font,
+                               OptSlideBulletSymbol sym,
+                               ClutterColor        *col);
+
+void
+opt_slide_add_bullet (OptSlide *slide, ClutterActor *actor);
+
+const ClutterActor*
+opt_slide_get_title (OptSlide *slide);
+
+GList*
+opt_slide_get_bullets (OptSlide *slide);
+
+void
+opt_slide_set_transition (OptSlide *slide, OptTransition *trans);
+
+OptTransition*
+opt_slide_get_transition (OptSlide *slide);
+
+void
+opt_slide_set_background_pixbuf (OptSlide *slide, GdkPixbuf *pixbuf);
+
+ClutterActor*
+opt_slide_get_background_texture (OptSlide *slide);
+
+G_END_DECLS
+
+#endif
diff --git a/opt/opt-transition.c b/opt/opt-transition.c
new file mode 100644 (file)
index 0000000..89b5d82
--- /dev/null
@@ -0,0 +1,459 @@
+#include "opt.h"
+
+#define FPS    90
+#define FRAMES 30
+
+G_DEFINE_TYPE (OptTransition, opt_transition, CLUTTER_TYPE_TIMELINE);
+
+struct OptTransitionPrivate
+{
+  OptTransitionStyle      style;
+  OptSlide               *from, *to;
+  gulong                  signal_id;
+  OptTransitionDirection  direction;
+};
+
+static void
+yz_flip_transition_frame_cb (OptTransition   *trans,
+                            gint             frame_num,
+                            gpointer         data)
+{
+  OptSlide             *from, *to;
+  OptTransitionPrivate *priv;
+  ClutterActor         *stage;
+  gint                  n_frames = 0; 
+
+  priv = trans->priv;
+
+  from  = opt_transition_get_from (trans);
+  to    = opt_transition_get_to (trans);
+  stage = clutter_stage_get_default();
+
+  n_frames = clutter_timeline_get_n_frames (CLUTTER_TIMELINE(trans));
+
+  if (frame_num > n_frames/2)
+    {
+      clutter_actor_hide (CLUTTER_ACTOR(from));
+      clutter_actor_show_all (CLUTTER_ACTOR(to));
+      clutter_actor_set_depth (CLUTTER_ACTOR(to), 
+                              -1 * ((n_frames * 2000) - (frame_num * 2000)));
+
+      clutter_actor_set_rotation (CLUTTER_ACTOR(to),
+            CLUTTER_Z_AXIS,
+            frame_num * (360/n_frames/2),
+            CLUTTER_STAGE_WIDTH()/2,
+            CLUTTER_STAGE_HEIGHT()/2,
+            0);
+    }
+  else
+    {
+      clutter_actor_hide (CLUTTER_ACTOR(to));
+      clutter_actor_set_depth (CLUTTER_ACTOR(from), -2000 * frame_num);
+
+      clutter_actor_set_rotation (CLUTTER_ACTOR(from),
+            CLUTTER_Z_AXIS,
+            frame_num * (360/n_frames/2),
+            CLUTTER_STAGE_WIDTH()/2,
+            CLUTTER_STAGE_HEIGHT()/2,
+            0);
+    }
+}
+
+static void
+zoom_transition_frame_cb (OptTransition   *trans,
+                         gint             frame_num,
+                         gpointer         data)
+{
+  OptSlide             *from, *to;
+  OptTransitionPrivate *priv;
+  ClutterActor         *stage;
+  gint                  n_frames = 0; 
+
+  priv = trans->priv;
+
+  from  = opt_transition_get_from (trans);
+  to    = opt_transition_get_to (trans);
+  stage = clutter_stage_get_default();
+
+  n_frames = clutter_timeline_get_n_frames (CLUTTER_TIMELINE(trans));
+
+  if (frame_num > n_frames/2)
+    {
+      clutter_actor_hide (CLUTTER_ACTOR(from));
+      clutter_actor_show_all (CLUTTER_ACTOR(to));
+      clutter_actor_set_depth (CLUTTER_ACTOR(to), 
+                              -1 * ((n_frames * 2000) - (frame_num * 2000)));
+
+      clutter_actor_set_rotation (CLUTTER_ACTOR(to),
+            CLUTTER_Z_AXIS,
+            frame_num * ((360*2)/n_frames),
+            CLUTTER_STAGE_WIDTH()/2,
+            CLUTTER_STAGE_HEIGHT()/2,
+            0);
+    }
+  else
+    {
+      clutter_actor_hide (CLUTTER_ACTOR(to));
+      clutter_actor_set_depth (CLUTTER_ACTOR(from), -2000 * frame_num);
+
+      clutter_actor_set_rotation (CLUTTER_ACTOR(from),
+            CLUTTER_Z_AXIS,
+            frame_num * ((360*2)/n_frames),
+            CLUTTER_STAGE_WIDTH()/2,
+            CLUTTER_STAGE_HEIGHT()/2,
+            0);
+    }
+}
+
+static void
+flip_transition_frame_cb (OptTransition   *trans,
+                         gint             frame_num,
+                         gpointer         data)
+{
+  OptSlide             *from, *to;
+  OptTransitionPrivate *priv;
+  ClutterColor          color = { 0x22, 0x22, 0x22, 0xff };
+  ClutterActor       *stage;
+  gint                  mult, n_frames;
+
+  priv = trans->priv;
+
+  from = opt_transition_get_from (trans);
+  to   = opt_transition_get_to (trans);
+  stage = clutter_stage_get_default();
+
+  clutter_actor_show_all (CLUTTER_ACTOR(to));
+
+  mult = priv->direction ? 1 : -1;
+
+  n_frames = clutter_timeline_get_n_frames (CLUTTER_TIMELINE(trans));
+
+  if (frame_num > n_frames/2)
+    {
+      /* Fix Z ordering */
+      clutter_actor_lower_bottom (CLUTTER_ACTOR(from));
+    }
+
+  clutter_stage_set_color (CLUTTER_STAGE(stage), &color);
+
+  clutter_actor_set_rotation (CLUTTER_ACTOR(from),
+                              CLUTTER_Y_AXIS,
+                              - (float)frame_num * 6 * mult,
+                              CLUTTER_STAGE_WIDTH ()/2,
+                              0,
+                              0);
+
+  clutter_actor_set_rotation (CLUTTER_ACTOR(to),
+                              CLUTTER_Y_AXIS,
+                              180 - (frame_num * 6) * mult,
+                              CLUTTER_STAGE_WIDTH()/2,
+                              0,
+                              0);
+}
+
+static void
+cube_transition_frame_cb (OptTransition   *trans,
+                         gint             frame_num,
+                         gpointer         data)
+{
+  OptSlide             *from, *to;
+  ClutterActor       *stage;
+  ClutterColor          color = { 0x22, 0x22, 0x22, 0xff };
+  OptTransitionPrivate *priv;
+  gint                  mult, n_frames;
+
+  priv = trans->priv;
+
+  from  = opt_transition_get_from (trans);
+  to    = opt_transition_get_to (trans);
+  stage = clutter_stage_get_default();
+
+  clutter_actor_show_all (CLUTTER_ACTOR(to));
+
+  mult = priv->direction ? -1 : 1;
+
+  n_frames = clutter_timeline_get_n_frames (CLUTTER_TIMELINE(trans));
+
+  if (frame_num > n_frames/2)
+    {
+      /* Fix Z ordering */
+      clutter_actor_lower_bottom (CLUTTER_ACTOR(from));
+    }
+
+  clutter_stage_set_color (CLUTTER_STAGE(stage), &color);
+
+  clutter_actor_set_rotation (CLUTTER_ACTOR(from),
+                              CLUTTER_Y_AXIS,
+                              - (float)frame_num * 3 * mult,
+                              CLUTTER_STAGE_WIDTH()/2,
+                              0,
+                              -1 * (CLUTTER_STAGE_WIDTH()/2));
+
+  clutter_actor_set_rotation (CLUTTER_ACTOR(to),
+                              CLUTTER_Y_AXIS,
+                              (mult * 90) - (frame_num * 3 * mult),
+                              CLUTTER_STAGE_WIDTH()/2,
+                              0,
+                              -1 * (CLUTTER_STAGE_WIDTH()/2));
+}
+
+static void
+page_transition_frame_cb (OptTransition   *trans,
+                            gint             frame_num,
+                            gpointer         data)
+{
+  OptSlide             *from, *to;
+  ClutterActor       *stage;
+  ClutterColor          color = { 0x22, 0x22, 0x22, 0xff };
+  OptTransitionPrivate *priv;
+  gint                  mult, n_frames;
+
+  priv = trans->priv;
+
+  from  = opt_transition_get_from (trans);
+  to    = opt_transition_get_to (trans);
+  stage = clutter_stage_get_default();
+
+  clutter_actor_show_all (CLUTTER_ACTOR(to));
+
+  mult = priv->direction ? -1 : 1;
+
+  n_frames = clutter_timeline_get_n_frames (CLUTTER_TIMELINE(trans));
+
+  if (frame_num > n_frames/2)
+    {
+      /* Fix Z ordering */
+      clutter_actor_lower_bottom (CLUTTER_ACTOR(from));
+    }
+
+  clutter_stage_set_color (CLUTTER_STAGE(stage), &color);
+
+  clutter_actor_set_rotation (CLUTTER_ACTOR(from),
+                              CLUTTER_Y_AXIS,
+                              - (float)frame_num * 2 * mult,
+                              CLUTTER_STAGE_WIDTH()*3/2,
+                              0,
+                              -1 * (CLUTTER_STAGE_WIDTH()/2));
+
+  clutter_actor_set_rotation (CLUTTER_ACTOR(to),
+                              CLUTTER_Y_AXIS,
+                              (mult * 60) - (frame_num * 2 * mult),
+                              CLUTTER_STAGE_WIDTH()*3/2,
+                              0,
+                              -1 * (CLUTTER_STAGE_WIDTH()/2));
+}
+
+static void
+fade_transition_frame_cb (OptTransition   *trans,
+                         gint             frame_num,
+                         gpointer         data)
+{
+  OptSlide             *from, *to;
+  OptTransitionPrivate *priv;
+  gint                  opacity;
+
+  priv = trans->priv;
+
+  from = opt_transition_get_from (trans);
+  to   = opt_transition_get_to (trans);
+
+  if (frame_num == 1)
+    {
+      clutter_actor_show_all (CLUTTER_ACTOR(to));
+      clutter_actor_raise_top (CLUTTER_ACTOR(to));
+    }
+
+  opacity = (frame_num * 255 ) 
+                  / clutter_timeline_get_n_frames (CLUTTER_TIMELINE(trans));
+
+  clutter_actor_set_opacity (CLUTTER_ACTOR(to), opacity);
+
+  /* clutter_actor_set_depth (CLUTTER_ACTOR(from), - opacity/10 ); */
+}
+
+static void 
+opt_transition_dispose (GObject *object)
+{
+  OptTransition *self = OPT_TRANSITION(object); 
+
+  if (self->priv)
+    {
+      opt_transition_set_from (self, NULL);
+      opt_transition_set_to (self, NULL);
+    }
+
+  G_OBJECT_CLASS (opt_transition_parent_class)->dispose (object);
+}
+
+static void 
+opt_transition_finalize (GObject *object)
+{
+  OptTransition *self = OPT_TRANSITION(object); 
+
+  if (self->priv)
+    {
+      g_free(self->priv);
+      self->priv = NULL;
+    }
+
+  G_OBJECT_CLASS (opt_transition_parent_class)->finalize (object);
+}
+
+static void
+opt_transition_class_init (OptTransitionClass *klass)
+{
+  GObjectClass        *object_class;
+
+  object_class = (GObjectClass*) klass;
+
+  object_class->finalize     = opt_transition_finalize;
+  object_class->dispose      = opt_transition_dispose;
+}
+
+static void
+opt_transition_init (OptTransition *self)
+{
+  OptTransitionPrivate *priv;
+
+  priv  = g_new0 (OptTransitionPrivate, 1);
+
+  self->priv = priv;
+
+}
+
+OptTransition*
+opt_transition_new (OptTransitionStyle style)
+{
+  OptTransition *trans;
+
+  trans = g_object_new (OPT_TYPE_TRANSITION, 
+                      "fps", FPS, 
+                      "num-frames", FRAMES, 
+                       NULL);
+
+  opt_transition_set_style (trans, style);
+
+  return trans;
+}
+
+OptTransitionStyle
+opt_transition_get_style (OptTransition     *trans)
+{
+  return trans->priv->style;
+}
+
+void
+opt_transition_set_style (OptTransition     *trans,
+                         OptTransitionStyle style)
+{
+  OptTransitionPrivate *priv;
+
+  priv = trans->priv;
+
+  if (priv->signal_id)
+    g_signal_handler_disconnect (trans, priv->signal_id);
+
+  switch (style)
+    {
+    case OPT_TRANSITION_CUBE:
+      priv->signal_id 
+       = g_signal_connect (trans,
+                           "new-frame",  
+                           G_CALLBACK (cube_transition_frame_cb), 
+                           trans);
+      break;
+    case OPT_TRANSITION_PAGE:
+      priv->signal_id 
+       = g_signal_connect (trans,
+                           "new-frame",  
+                           G_CALLBACK (page_transition_frame_cb), 
+                           trans);
+      break;
+    case OPT_TRANSITION_FLIP:
+      priv->signal_id 
+       = g_signal_connect (trans,
+                           "new-frame",  
+                           G_CALLBACK (flip_transition_frame_cb), 
+                           trans);
+      break;
+    case OPT_TRANSITION_YZ_FLIP:
+      priv->signal_id 
+       = g_signal_connect (trans,
+                           "new-frame",  
+                           G_CALLBACK (yz_flip_transition_frame_cb), 
+                           trans);
+      break;
+    case OPT_TRANSITION_ZOOM:
+      priv->signal_id 
+       = g_signal_connect (trans,
+                           "new-frame",  
+                           G_CALLBACK (zoom_transition_frame_cb), 
+                           trans);
+      break;
+    case OPT_TRANSITION_FADE:
+    default:
+      priv->signal_id 
+       = g_signal_connect (trans,
+                           "new-frame",  
+                           G_CALLBACK (fade_transition_frame_cb), 
+                           trans);
+      break;
+    }
+
+  trans->priv->style = style;
+}
+
+void
+opt_transition_set_from (OptTransition *trans, OptSlide *slide)
+{
+  OptTransitionPrivate *priv;
+
+  priv = trans->priv;
+
+  if (priv->from == slide)
+    return;
+
+  if (priv->from != NULL)
+    g_object_unref(priv->from);
+
+  priv->from = slide;
+  if (slide != NULL)
+    g_object_ref(slide);
+}
+
+void
+opt_transition_set_to (OptTransition *trans, OptSlide *slide)
+{
+  OptTransitionPrivate *priv;
+
+  priv = trans->priv;
+
+  if (priv->to == slide)
+    return;
+
+  if (priv->to != NULL)
+    g_object_unref(priv->to);
+
+  priv->to = slide;
+  if (slide != NULL)
+    g_object_ref(slide);
+}
+
+OptSlide*
+opt_transition_get_from (OptTransition *trans)
+{
+  return trans->priv->from;
+}
+
+OptSlide*
+opt_transition_get_to (OptTransition *trans)
+{
+  return trans->priv->to;
+}
+
+void
+opt_transition_set_direction (OptTransition           *trans, 
+                             OptTransitionDirection   direction)
+{
+  trans->priv->direction = direction;
+}
diff --git a/opt/opt-transition.h b/opt/opt-transition.h
new file mode 100644 (file)
index 0000000..629fe16
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef _HAVE_OPT_TRANSITION_H
+#define _HAVE_OPT_TRANSITION_H
+
+#include <glib-object.h>
+
+#include "opt.h"
+
+G_BEGIN_DECLS
+
+#define OPT_TYPE_TRANSITION opt_transition_get_type()
+
+#define OPT_TRANSITION(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  OPT_TYPE_TRANSITION, OptTransition))
+
+#define OPT_TRANSITION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  OPT_TYPE_TRANSITION, OptTransitionClass))
+
+#define OPT_IS_TRANSITION(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  OPT_TYPE_TRANSITION))
+
+#define OPT_IS_TRANSITION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  OPT_TYPE_TRANSITION))
+
+#define OPT_TRANSITION_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  OPT_TYPE_TRANSITION, OptTransitionClass))
+
+typedef enum OptTransitionStyle
+{
+  OPT_TRANSITION_ANY,
+  OPT_TRANSITION_CUBE,
+  OPT_TRANSITION_PAGE,
+  OPT_TRANSITION_FLIP,
+  OPT_TRANSITION_ZOOM,
+  OPT_TRANSITION_YZ_FLIP,
+  OPT_TRANSITION_FADE
+}
+OptTransitionStyle;
+
+typedef enum OptTransitionDirection
+{
+  OPT_TRANSITION_FORWARD,
+  OPT_TRANSITION_BACKWARD,
+}
+OptTransitionDirection;
+
+typedef struct OptTransitionPrivate OptTransitionPrivate;
+typedef struct _OptTransitionClass  OptTransitionClass;
+struct _OptTransition
+{
+  ClutterTimeline       parent;
+  OptTransitionPrivate *priv;
+};
+
+struct _OptTransitionClass
+{
+  ClutterTimelineClass         parent_class;
+};
+
+GType opt_transition_get_type (void);
+
+OptTransition*
+opt_transition_new (OptTransitionStyle style);
+
+OptTransitionStyle
+opt_transition_get_style (OptTransition     *trans);
+
+void
+opt_transition_set_style (OptTransition     *trans,
+                         OptTransitionStyle style);
+
+void
+opt_transition_set_direction (OptTransition           *trans, 
+                             OptTransitionDirection   direction);
+void
+opt_transition_set_from (OptTransition *trans, OptSlide *slide);
+
+void
+opt_transition_set_to (OptTransition *trans, OptSlide *slide);
+
+OptSlide*
+opt_transition_get_from (OptTransition *trans);
+
+OptSlide*
+opt_transition_get_to (OptTransition *trans);
+
+G_END_DECLS
+
+#endif
diff --git a/opt/opt.c b/opt/opt.c
new file mode 100644 (file)
index 0000000..7962e28
--- /dev/null
+++ b/opt/opt.c
@@ -0,0 +1,225 @@
+#include "opt.h"
+#include <stdlib.h>            /* for exit() */
+
+static OptShow *opt_show = NULL;
+
+static gboolean 
+key_release_cb (ClutterStage           *stage,
+                ClutterKeyEvent        *kev,
+                gpointer                user_data)
+{
+  OptShow *show = OPT_SHOW (user_data);
+
+  switch (clutter_key_event_symbol (kev))
+    {
+      case CLUTTER_m:
+          opt_show_pop_menu (show);
+          break;
+      case CLUTTER_s:
+          opt_show_toggle_position (show);
+          break;
+      case CLUTTER_q:
+          clutter_main_quit ();
+          break;
+      case CLUTTER_r:
+      case CLUTTER_Left:
+          opt_show_retreat (show);
+          break;
+      case CLUTTER_Page_Down:
+          opt_show_skip (show, 5);
+          break;
+      case CLUTTER_Page_Up:
+          opt_show_skip (show, -5);
+          break;
+
+      case CLUTTER_Up:
+      case CLUTTER_Down:
+      case CLUTTER_Return:
+          /* menu keys -- ignore */
+          break;
+
+      case CLUTTER_Right:
+      default:
+          opt_show_advance (show);
+          break;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+button_release_cb (ClutterStage        *stage,
+                   ClutterButtonEvent  *bev,
+                   gpointer             user_data)
+{
+  OptShow  *show = OPT_SHOW (user_data);
+
+  if (bev->button == 1)
+    opt_show_advance (show);
+  else if (bev->button == 3)
+    opt_show_retreat (show);
+
+  return FALSE;
+}
+
+static void
+on_fullscreen (ClutterStage *stage,
+               const gchar  *filename)
+{
+  GError *error = NULL;
+
+  if (opt_show)
+    return;
+
+  opt_show = opt_show_new ();
+
+  if (!opt_config_load (opt_show, filename, &error))
+    {
+      /* Cleanup */
+      g_printerr ("Could not load presentation:\n\t%s\n", error->message);
+      g_error_free (error);
+      exit (EXIT_FAILURE);
+    }
+
+  opt_show_run (opt_show);
+
+  /* Connect up for input event */
+  g_signal_connect (stage,
+                    "key-release-event", G_CALLBACK (key_release_cb),
+                    opt_show);
+  g_signal_connect (stage,
+                    "button-release-event", G_CALLBACK (button_release_cb),
+                    opt_show);
+}
+
+static int
+usage (const char *msg)
+{
+  g_printerr ("Usage: %s [OPTIONS..] <FILE>\n", msg);
+
+  return EXIT_FAILURE;
+}
+
+int 
+main(int argc, char **argv)
+{
+  GError        *error = NULL; 
+  ClutterActor  *stage;
+  gchar        **opt_filename = NULL;
+  gchar         *opt_export = NULL;
+  gchar         *opt_size = NULL;
+
+  GOptionEntry options[] = {
+    { "export", 
+      'e', 
+      0, 
+      G_OPTION_ARG_STRING, 
+      &opt_export, 
+      "Export PNG slides to PATH", 
+      "PATH" },
+
+    { "size", 
+      's', 
+      0, 
+      G_OPTION_ARG_STRING, 
+      &opt_size, 
+      "Presentation display dimentions.", 
+      "WxH" },
+
+    { G_OPTION_REMAINING, 
+      0, 
+      0, 
+      G_OPTION_ARG_FILENAME_ARRAY, 
+      &opt_filename, 
+      "Presentation XML filename to load", 
+      "FILE" },
+
+    { NULL }
+  };
+
+  if (argc == 1)
+    return usage (argv[0]);
+
+  clutter_init_with_args (&argc, &argv, "- OH Presentation tool",
+                          options, NULL,
+                          NULL);
+
+  stage = clutter_stage_get_default();
+
+  /* Need to set this early on */
+  if (opt_export != NULL)
+    {
+      gboolean offscreen_supported;
+
+      g_object_set (stage, "offscreen", TRUE, NULL);
+
+      /* Actually check offscreen works - recent Mesas appear not to
+       * like rendering to Pixmaps. 
+      */
+      g_object_get (stage, "offscreen", &offscreen_supported, NULL);
+      if (offscreen_supported == FALSE)
+       {
+         g_print ("Could not export presentation:\n"
+                  "\tOffscreen rendering not supported by Clutter backend\n");
+         return EXIT_FAILURE;
+       }
+    }
+
+  if (opt_size != NULL)
+    {
+      gint w, h;
+
+      if (!sscanf (opt_size, "%dx%d", &w, &h) || w <= 0 || h <= 0)
+       return usage (argv[0]);
+
+      opt_show = opt_show_new ();
+
+      clutter_actor_set_size (stage, w, h);
+
+      if (!opt_config_load (opt_show, opt_filename[0], &error))
+        {
+          /* Cleanup */
+          g_printerr ("Could not load presentation:\n\t%s\n", error->message);
+          g_error_free (error);
+          return EXIT_FAILURE;
+        }
+
+      /* Connect up for input event */
+      g_signal_connect (stage,
+                        "key-release-event", G_CALLBACK (key_release_cb),
+                        opt_show);
+      g_signal_connect (stage,
+                        "button-release-event", G_CALLBACK (button_release_cb),
+                        opt_show);
+
+      opt_show_run (opt_show);
+    }
+  else
+    {
+      g_signal_connect (stage,
+                        "fullscreen", G_CALLBACK (on_fullscreen),
+                        opt_filename[0]);
+
+      clutter_stage_fullscreen (CLUTTER_STAGE (stage));
+      clutter_stage_hide_cursor (CLUTTER_STAGE (stage));
+      clutter_actor_show (stage);
+    }
+
+  if (opt_export)
+    {
+      if (!opt_show_export (opt_show, opt_export, &error))
+        {
+          /* Cleanup */
+          g_printerr ("Could not export presentation:\n\t%s\n",
+                      error->message);
+          g_error_free (error);
+         return EXIT_FAILURE;
+       }
+
+      return EXIT_SUCCESS;
+    }
+  else
+    clutter_main ();
+
+  return EXIT_SUCCESS;
+}
diff --git a/opt/opt.doap b/opt/opt.doap
new file mode 100644 (file)
index 0000000..ec82f85
--- /dev/null
@@ -0,0 +1,41 @@
+<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+       xmlns:foaf="http://xmlns.com/foaf/0.1/"
+       xmlns="http://usefulinc.com/ns/doap#">
+
+       <name>OpenedHand Presentation Tool</name>
+       <shortname>opt</shortname>
+       <created>2006-21-11</created>
+
+       <shortdesc xml:lang="en">'OPT' is a simple application for creating presentations.</shortdesc>
+
+       <description xml:lang="en"> 
+
+       </description>
+
+       <license rdf:resource="http://usefulinc.com/doap/licenses/gpl" />
+        <os>linux</os>
+        <programming-language>C</programming-language>
+        <category rdf:resource="http://labs.o-hand.com/doap/category/clutter"/>
+        <category rdf:resource="http://labs.o-hand.com/doap/category/graphics"/>
+        <category rdf:resource="http://labs.o-hand.com/doap/category/application"/>
+
+       <maintainer>
+               <foaf:Person>
+                       <foaf:name>Matthew Allum</foaf:name>
+               </foaf:Person>
+       </maintainer>
+
+       <author>
+               <foaf:Person>
+                       <foaf:name>Matthew Allum</foaf:name>
+               </foaf:Person>
+       </author>
+
+        <repository>
+               <SVNRepository>
+                       <browse rdf:resource="http://svn.o-hand.com/view/clutter/trunk/toys/opt"/>
+                       <location rdf:resource="https://svn.o-hand.com/repos/clutter/trunk/toys/opt"/>
+               </SVNRepository>
+        </repository>
+
+</Project>
diff --git a/opt/opt.dtd b/opt/opt.dtd
new file mode 100644 (file)
index 0000000..f8a9329
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!ELEMENT opt (defaults?,slide+)>
+
+<!ELEMENT defaults (title, (background|bullet|transition)+)>
+
+<!ELEMENT slide (title, (bullet|img|transition)*)>
+
+<!ELEMENT title (#PCDATA)>
+<!ATTLIST title
+          color CDATA #IMPLIED
+          font CDATA #IMPLIED
+>
+
+<!ELEMENT background (#PCDATA)>
+<!ATTLIST background
+          src CDATA #REQUIRED
+>
+
+<!ELEMENT bullet (#PCDATA)>
+<!ATTLIST bullet
+          color CDATA #IMPLIED
+          font CDATA #IMPLIED
+          symbol (none) #IMPLIED
+>
+
+<!ELEMENT img EMPTY>
+<!ATTLIST img
+          src CDATA #REQUIRED
+>
+
+<!ELEMENT transition (#PCDATA)>
+<!ATTLIST transition
+          style (cube|flip|yzflip|fade|zoom) #REQUIRED
+>
+
diff --git a/opt/opt.h b/opt/opt.h
new file mode 100644 (file)
index 0000000..52ba5bb
--- /dev/null
+++ b/opt/opt.h
@@ -0,0 +1,22 @@
+#ifndef _HAVE_OPT_H
+#define _HAVE_OPT_H
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+typedef struct _OptSlide OptSlide;
+typedef struct _OptShow OptShow;
+typedef struct _OptTransition OptTransition;
+typedef struct _OptMenu OptMenu;
+
+#include "opt-show.h"
+#include "opt-slide.h"
+#include "opt-transition.h"
+#include "opt-menu.h"
+
+gboolean
+opt_config_load (OptShow     *show, 
+                const gchar *filename,
+                GError     **error);
+
+#endif
diff --git a/opt/powers.png b/opt/powers.png
new file mode 100644 (file)
index 0000000..25c0423
Binary files /dev/null and b/opt/powers.png differ
diff --git a/opt/test.xml b/opt/test.xml
new file mode 100644 (file)
index 0000000..f47ff31
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<!DOCTYPE opt SYSTEM "opt.dtd">
+<opt>
+
+  <defaults>
+    <title  color="#444444ff" font="VistaSansMed 50" />
+    <bullet color="#444444ff" font="VistaSansMed 40" /> 
+    <transition style="flip" />  
+    <background src="bg.png" />
+  </defaults>
+
+  <slide>
+    <title>Hello slide 1</title>
+    <bullet>See test.xml</bullet>
+    <bullet>q quit, r or left back</bullet>
+    <bullet>Any key to advance.</bullet>
+    <transition style="zoom" />        
+  </slide>
+
+  <slide>
+    <title>Hello slide 2</title>
+    <bullet>Checking wr-wr-wr-wr-wr-wrapping, check check one two three four Checking wr-wr-wr-wr-wr-wrapping, check check one two three four</bullet>
+    <img src="kitten.jpg" /> 
+    <bullet>bullet 4</bullet>
+
+    <transition style="fade" />        
+  </slide>
+
+  <slide>
+    <title>Hello slide 3</title>
+    <bullet>Some code</bullet>
+    <bullet font="mono 20" symbol="none">clutter_label_set_text_extents (CLUTTER_LABEL(bullet),
+                                 width - symbol_width,
+                                 0);
+
+clutter_actor_set_position (bullet, x, y);
+clutter_group_add (CLUTTER_GROUP(slide), bullet);
+
+clutter_actor_show(bullet);
+clutter_actor_show(symbol);
+</bullet>
+
+  </slide>
+
+  <slide>
+    <title>Hello slide 4</title>
+    <bullet>Foo foo </bullet>
+    <bullet>bullet 4</bullet>
+    <transition style="flip" />        
+  </slide>
+
+  <slide>
+    <title color="#ff4444ff">Hello slide 5 ( colors! )</title>
+    <bullet color="#44ff44ff">Foo foo </bullet>
+    <bullet color="#4444ffff">bullet 4</bullet>
+    <bullet font="mono 40">and fonts</bullet>
+  </slide>
+
+</opt>
\ No newline at end of file
diff --git a/packaging/clutter-toys.spec b/packaging/clutter-toys.spec
new file mode 100644 (file)
index 0000000..b3f99cc
--- /dev/null
@@ -0,0 +1,86 @@
+Name:       clutter-toys
+Summary:    Clutter sample applications
+Version:    0.1
+Release:    1
+Group:      System/Libraries
+License:    LGPLv2+
+URL:        http://www.clutter-project.org/
+Source0:    %{name}-%{version}.tar.gz
+Patch1:     fix-colors.patch
+Patch2:     fix-image-path.patch
+Patch3:     map-escape-key-to-quit.patch
+BuildRequires:  pkgconfig(clutter-1.0)
+BuildRequires:  pkgconfig(gl)
+
+%description
+Clutter toy sample applications.
+
+
+%prep
+%setup -q -n %{name}-%{version}
+
+#make color easier to see
+%patch1 -p1
+
+#set image path to installed data directory
+%patch2 -p1
+
+#map escape key to quit apps
+%patch3 -p1
+
+%build
+cd arc-clock
+make -j8
+cd ..
+
+cd circles
+make -j8
+cd ..
+
+cd courasel
+make -j8
+cd ..
+
+cd foofone
+make -j8
+cd ..
+
+cd pong
+make -j8
+cd ..
+
+cd ripples
+make -j8
+cd ..
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}%{_bindir}
+mkdir -p %{buildroot}%{_datadir}/clutter-toys
+mkdir -p %{buildroot}%{_datadir}/clutter-toys/courasel
+mkdir -p %{buildroot}%{_datadir}/clutter-toys/foofone
+mkdir -p %{buildroot}%{_datadir}/clutter-toys/pong
+
+
+install -m 755 arc-clock/arc-clock $RPM_BUILD_ROOT%{_bindir}
+
+install -m 755 circles/circles $RPM_BUILD_ROOT%{_bindir}
+
+install -m 755 courasel/courasel $RPM_BUILD_ROOT%{_bindir}
+install -m 644 courasel/*.png $RPM_BUILD_ROOT%{_datadir}/clutter-toys/courasel/
+
+install -m 755 foofone/foofone $RPM_BUILD_ROOT%{_bindir}
+install -m 644 foofone/*.png $RPM_BUILD_ROOT%{_datadir}/clutter-toys/foofone/
+
+install -m 755 pong/pong2 $RPM_BUILD_ROOT%{_bindir}
+
+install -m 755 ripples/ripples $RPM_BUILD_ROOT%{_bindir}
+
+%clean
+rm -rf "$RPM_BUILD_ROOT"
+
+%files
+%defattr(-,root,root,-)
+%{_bindir}/*
+%{_datadir}/clutter-toys
+
diff --git a/patches/fix-colors.patch b/patches/fix-colors.patch
new file mode 100644 (file)
index 0000000..59e6935
--- /dev/null
@@ -0,0 +1,24 @@
+diff -Naur clutter-toys-0.1/circles/circles.c clutter-toys-0.1-new/circles/circles.c
+--- clutter-toys-0.1/circles/circles.c 2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/circles/circles.c     2012-03-20 13:48:21.092969742 -0700
+@@ -16,7 +16,7 @@
+ static void
+ circle_paint_cb (ClutterActor *actor)
+ {
+-  const CoglColor fill_color = { 0xff, 0xff, 0xff, 0x80 };
++  const CoglColor fill_color = { 0x00, 0xff, 0xff, 0x80 };
+   gint i;
+   gdouble angle;
+   guint radius = clutter_actor_get_width (actor) / 2;
+diff -Naur clutter-toys-0.1/ripples/ripples.c clutter-toys-0.1-new/ripples/ripples.c
+--- clutter-toys-0.1/ripples/ripples.c 2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/ripples/ripples.c     2012-03-20 13:49:20.216971928 -0700
+@@ -19,7 +19,7 @@
+   float radius = clutter_actor_get_width (actor) / 2;
+   cogl_color_set_from_4ub (&fill_color,
+-                           255,
++                           0,
+                            255,
+                            255,
+                            clutter_actor_get_paint_opacity (actor));
diff --git a/patches/fix-image-path.patch b/patches/fix-image-path.patch
new file mode 100644 (file)
index 0000000..a919175
--- /dev/null
@@ -0,0 +1,56 @@
+diff -Naur clutter-toys-0.1/courasel/courasel.c clutter-toys-0.1-new/courasel/courasel.c
+--- clutter-toys-0.1/courasel/courasel.c       2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/courasel/courasel.c   2012-03-20 14:05:16.361007303 -0700
+@@ -10,14 +10,14 @@
+ struct { gchar *img; gchar *title; } ItemDetails[] =
+ {
+-  { "accessories-text-editor.png", "Text Editor" },
+-  { "applications-games.png", "Game" },
+-  { "dates.png", "Dates" },
+-  { "im-client.png", "Chat" },
+-  { "preferences-desktop-theme.png", "Preferences" },
+-  { "tasks.png", "Todo List" },
+-  { "utilities-terminal.png", "Terminal" },
+-  { "web-browser.png", "Browser"},
++  { "/usr/share/clutter-toys/courasel/accessories-text-editor.png", "Text Editor" },
++  { "/usr/share/clutter-toys/courasel/applications-games.png", "Game" },
++  { "/usr/share/clutter-toys/courasel/dates.png", "Dates" },
++  { "/usr/share/clutter-toys/courasel/im-client.png", "Chat" },
++  { "/usr/share/clutter-toys/courasel/preferences-desktop-theme.png", "Preferences" },
++  { "/usr/share/clutter-toys/courasel/tasks.png", "Todo List" },
++  { "/usr/share/clutter-toys/courasel/utilities-terminal.png", "Terminal" },
++  { "/usr/share/clutter-toys/courasel/web-browser.png", "Browser"},
+ };
+ typedef struct Item
+diff -Naur clutter-toys-0.1/foofone/foofone.c clutter-toys-0.1-new/foofone/foofone.c
+--- clutter-toys-0.1/foofone/foofone.c 2012-03-19 13:20:31.285711498 -0700
++++ clutter-toys-0.1-new/foofone/foofone.c     2012-03-20 14:06:26.841009909 -0700
+@@ -277,7 +277,7 @@
+                 rect_color = { 0, 0, 0, 0x99 },
+                 black_color = { 0, 0, 0, 0xff };
+-  button_texture =  clutter_texture_new_from_file ("button.png", NULL);
++  button_texture =  clutter_texture_new_from_file ("/usr/share/clutter-toys/foofone/button.png", NULL);
+   xpad = (CSW-(3*clutter_actor_get_width(button_texture)))/4;
+   x = xinit = xpad;
+@@ -301,7 +301,7 @@
+   app->dpy = clutter_group_new();
+-  a = clutter_texture_new_from_file ("display.png", NULL);
++  a = clutter_texture_new_from_file ("/usr/share/clutter-toys/foofone/display.png", NULL);
+   clutter_group_add (CLUTTER_GROUP(app->dpy), a);
+   app->dpyx = xdpy = x;
+   app->dpyy = ydpy = (y - clutter_actor_get_height(app->dpy))/2;
+@@ -393,7 +393,7 @@
+   clutter_actor_set_size (a, CSW, CSH);
+   clutter_group_add (CLUTTER_GROUP(app->screen_dial), a);
+-  a = clutter_texture_new_from_file ("call-background.png", NULL);
++  a = clutter_texture_new_from_file ("/usr/share/clutter-toys/foofone/call-background.png", NULL);
+   clutter_group_add (CLUTTER_GROUP(app->screen_dial), a);
+   a = clutter_rectangle_new_with_color (&rect_color);
diff --git a/patches/map-escape-key-to-quit.patch b/patches/map-escape-key-to-quit.patch
new file mode 100644 (file)
index 0000000..e5a8ab7
--- /dev/null
@@ -0,0 +1,142 @@
+diff -Naur clutter-toys-0.1/arc-clock/arc-clock.c clutter-toys-0.1-new/arc-clock/arc-clock.c
+--- clutter-toys-0.1/arc-clock/arc-clock.c     2012-03-19 13:20:31.285711498 -0700
++++ clutter-toys-0.1-new/arc-clock/arc-clock.c 2012-03-20 14:41:44.137088242 -0700
+@@ -128,6 +128,17 @@
+   { NULL }
+ };
++static void
++on_key_release (ClutterActor *stage,
++  ClutterEvent *event,
++  gpointer      user_data)
++{
++  if (clutter_event_get_key_symbol (event) == CLUTTER_Escape)
++  {
++     clutter_main_quit();
++  }
++}
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -179,6 +190,11 @@
+   g_timeout_add_seconds ((hide_seconds ? 60 : 1), update_slices, NULL);
++  g_signal_connect (stage,
++                  "key-release-event",
++                  G_CALLBACK (on_key_release),
++                  NULL);
++
+   update_slices (NULL);
+   clutter_actor_show (stage);
+diff -Naur clutter-toys-0.1/circles/circles.c clutter-toys-0.1-new/circles/circles.c
+--- clutter-toys-0.1/circles/circles.c 2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/circles/circles.c     2012-03-20 14:42:22.033089645 -0700
+@@ -42,6 +42,17 @@
+     }
+ }
++static void
++on_key_release (ClutterActor *stage,
++  ClutterEvent *event,
++  gpointer      user_data)
++{
++  if (clutter_event_get_key_symbol (event) == CLUTTER_Escape)
++  {
++     clutter_main_quit();
++  }
++}
++
+ int
+ main (int argc, char **argv)
+ {
+@@ -98,6 +109,11 @@
+                                            0);
+       clutter_behaviour_apply (behaviour, actor);
+     }
++
++  g_signal_connect (stage,
++                  "key-release-event",
++                  G_CALLBACK (on_key_release),
++                  NULL);
+   
+   clutter_actor_show_all (stage);
+   
+diff -Naur clutter-toys-0.1/courasel/courasel.c clutter-toys-0.1-new/courasel/courasel.c
+--- clutter-toys-0.1/courasel/courasel.c       2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/courasel/courasel.c   2012-03-20 14:32:09.885066996 -0700
+@@ -188,7 +188,7 @@
+         break;
+       case CLUTTER_Return:
+         break;
+-      case CLUTTER_q:
++      case CLUTTER_Escape:
+         clutter_main_quit();
+         break;
+       default:
+diff -Naur clutter-toys-0.1/foofone/foofone.c clutter-toys-0.1-new/foofone/foofone.c
+--- clutter-toys-0.1/foofone/foofone.c 2012-03-19 13:20:31.285711498 -0700
++++ clutter-toys-0.1-new/foofone/foofone.c     2012-03-20 14:36:49.769077348 -0700
+@@ -264,6 +264,13 @@
+       return TRUE;
+     }
++  else if (event->type == CLUTTER_KEY_RELEASE)
++  {
++    if (clutter_event_get_key_symbol (event) == CLUTTER_Escape)
++      {
++        clutter_main_quit();
++      }
++  }
+   return FALSE;
+ }
+diff -Naur clutter-toys-0.1/pong/pong2.c clutter-toys-0.1-new/pong/pong2.c
+--- clutter-toys-0.1/pong/pong2.c      2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/pong/pong2.c  2012-03-20 14:38:27.749080976 -0700
+@@ -309,6 +309,10 @@
+           case CLUTTER_m:
+               data->down2 = FALSE;
+               break;
++          case CLUTTER_Escape:
++              data->down2 = FALSE;
++              clutter_main_quit();
++              break;
+           default:
+               break;
+       }
+diff -Naur clutter-toys-0.1/ripples/ripples.c clutter-toys-0.1-new/ripples/ripples.c
+--- clutter-toys-0.1/ripples/ripples.c 2012-03-19 13:20:31.309711495 -0700
++++ clutter-toys-0.1-new/ripples/ripples.c     2012-03-20 14:43:46.533092770 -0700
+@@ -104,6 +104,17 @@
+   return FALSE;
+ }
++static void
++on_key_release (ClutterActor *stage,
++  ClutterEvent *event,
++  gpointer      user_data)
++{
++  if (clutter_event_get_key_symbol (event) == CLUTTER_Escape)
++  {
++     clutter_main_quit();
++  }
++}
++
+ int
+ main (int argc, char **argv)
+ {
+@@ -124,6 +135,11 @@
+                     "button-press-event", G_CALLBACK (stage_clicked_cb),
+                     NULL);
++  g_signal_connect (stage,
++                  "key-release-event",
++                  G_CALLBACK (on_key_release),
++                  NULL);
++
+   clutter_main ();
+   
+   return EXIT_SUCCESS;
diff --git a/pong/Makefile b/pong/Makefile
new file mode 100644 (file)
index 0000000..3555e3f
--- /dev/null
@@ -0,0 +1,15 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+CFLAGS="-lm"
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: pong2
+
+
+pong2: pong2.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ pong2.o $(LIBS)
+
+clean:
+       rm -fr *.o pong2
diff --git a/pong/pong-ball.png b/pong/pong-ball.png
new file mode 100644 (file)
index 0000000..d80af4c
Binary files /dev/null and b/pong/pong-ball.png differ
diff --git a/pong/pong-bat.png b/pong/pong-bat.png
new file mode 100644 (file)
index 0000000..1415dd3
Binary files /dev/null and b/pong/pong-bat.png differ
diff --git a/pong/pong2.c b/pong/pong2.c
new file mode 100644 (file)
index 0000000..3a57c34
--- /dev/null
@@ -0,0 +1,412 @@
+#include <clutter/clutter.h>
+#include <cairo/cairo.h>
+#include <math.h>
+
+#define PADDLE_SIZE 48.0
+#define PADDLE_THICKNESS 8.0
+#define PADDLE_SPEED 4
+#define BALL_SIZE 12.0
+#define DASH_LENGTH 12.0
+#define ARENA_WIDTH 320.0
+#define ARENA_HEIGHT 240.0
+#define FPS 60.0
+#define MINPOS (PADDLE_THICKNESS * 2)
+#define MAXPOS (ARENA_HEIGHT - PADDLE_SIZE - (PADDLE_THICKNESS * 2))
+
+/*
+ * NOTE: This is a completely brain-dead way to implement pong, but helped
+ *       me familiarise with Clutter paths and such.
+ */
+
+static const ClutterColor green = { 0x0, 0xff, 0x0, 0xff };
+
+typedef struct {
+       /* First paddle */
+       gint score1;
+       gint position1;
+       ClutterActor *paddle1;
+       gboolean up1;
+       gboolean down1;
+       
+       /* Second paddle */
+       gint score2;
+       gint position2;
+       ClutterActor *paddle2;
+       gboolean up2;
+       gboolean down2;
+       
+       /* Paddle independent */
+       gdouble angle;
+       gdouble speed;
+       ClutterActor *ball;
+       ClutterActor *arena;
+       ClutterTimeline *timeline;
+       ClutterAlpha *alpha;
+       ClutterBehaviour *behaviour;
+       ClutterPath *path;
+       ClutterKnot start;
+       ClutterKnot end;
+       gboolean pause;
+} PongData;
+
+static ClutterActor *
+pong_arena_actor_create (PongData *data)
+{
+       ClutterActor *group, *actor;
+       ClutterGeometry geom;
+       gint i;
+       
+       group = clutter_group_new ();
+       
+       /* Top border */
+       actor = clutter_rectangle_new_with_color (&green);
+       geom.x = 0; geom.y = 0;
+       geom.width = ARENA_WIDTH; geom.height = PADDLE_THICKNESS;
+       clutter_actor_set_geometry (actor, &geom);
+       clutter_actor_show (actor);
+       clutter_group_add (CLUTTER_GROUP (group), actor);
+       
+       /* Bottom border */
+       actor = clutter_rectangle_new_with_color (&green);
+       geom.y = ARENA_HEIGHT - PADDLE_THICKNESS;
+       clutter_actor_set_geometry (actor, &geom);
+       clutter_actor_show (actor);
+       clutter_group_add (CLUTTER_GROUP (group), actor);
+       
+       /* Dotted line down the middle */
+       geom.x = (ARENA_WIDTH / 2) - (PADDLE_THICKNESS / 2);
+       geom.width = PADDLE_THICKNESS;
+       geom.height = PADDLE_THICKNESS * 2;
+       for (i = 0; i < ARENA_HEIGHT / (PADDLE_THICKNESS * 2); i+= 2) {
+               geom.y = i * PADDLE_THICKNESS * 2;
+               actor = clutter_rectangle_new_with_color (&green);
+               clutter_actor_set_geometry (actor, &geom);
+               clutter_actor_show (actor);
+               clutter_group_add (CLUTTER_GROUP (group), actor);
+       }
+       
+       return group;
+}
+
+static ClutterActor *
+pong_ball_actor_create (PongData *data)
+{
+       ClutterActor *actor, *group;
+       cairo_t *cr;
+       
+       actor = clutter_cairo_texture_new (BALL_SIZE, BALL_SIZE);
+       cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (actor));
+       
+       /* Clear */
+       cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+       cairo_paint(cr);
+       
+       cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+       cairo_set_source_rgba (cr, 0, 1.0, 0, 1.0);
+       
+       cairo_new_path (cr);
+       cairo_arc (cr, BALL_SIZE/2.0, BALL_SIZE/2.0,
+               BALL_SIZE/2.0, 0, 2*M_PI);
+       cairo_fill (cr);
+       
+       cairo_destroy (cr);
+
+       group = clutter_group_new ();
+       clutter_group_add (CLUTTER_GROUP (group), actor);
+       clutter_actor_set_position (actor, -BALL_SIZE/2, -BALL_SIZE/2);
+       clutter_actor_show (actor);
+
+       return group;
+}
+
+static ClutterActor *
+pong_paddle_actor_create (PongData *data)
+{
+       ClutterGeometry geom;
+       ClutterActor *actor;
+
+       actor = clutter_rectangle_new_with_color (&green);
+       geom.x = 0; geom.y = 0;
+       geom.width = PADDLE_THICKNESS;
+       geom.height = PADDLE_SIZE;
+       clutter_actor_set_geometry (actor, &geom);
+       
+       return actor;
+}
+
+static void
+pong_ball_path_calculate (PongData *data, gdouble ax, gdouble ay, gdouble w,
+                         gdouble h)
+{
+       gdouble x, y, dx, dy, angle;
+       
+       x = clutter_actor_get_x (data->ball);
+       y = clutter_actor_get_y (data->ball);
+       
+       data->start.x = x;
+       data->start.y = y;
+
+       /* Work out destination */
+       if (data->angle < M_PI * 0.5) {
+               /* Travelling up-right */
+               dx = x + (tan (data->angle) * (y - ay - (BALL_SIZE/2)));
+               if (dx > w - (BALL_SIZE/2)) {
+                       dx = w - (BALL_SIZE/2);
+                       dy = y - ((dx - x) / tan (data->angle));
+               } else {
+                       dy = ay + (BALL_SIZE / 2);
+               }
+       } else if (data->angle < M_PI) {
+               /* Travelling down-right */
+               angle = M_PI - data->angle;
+               dx = x + (tan (angle) * (h - y));
+               if (dx > w - (BALL_SIZE/2)) {
+                       dx = w - (BALL_SIZE/2);
+                       dy = y + ((dx - x) / tan (angle));
+               } else {
+                       dy = h - (BALL_SIZE/2);
+               }
+       } else if (data->angle < M_PI * 1.5) {
+               /* Travelling down-left */
+               angle = data->angle - M_PI;
+               dx = x - (tan (angle) * (h - y));
+               if (dx < (BALL_SIZE/2)) {
+                       dx = (BALL_SIZE/2);
+                       dy = y + ((x - ax) / tan (angle));
+               } else {
+                       dy = h - (BALL_SIZE/2);
+               }
+       } else {
+               /* Travelling up-left */
+               angle = (M_PI * 2) - data->angle;
+               dx = x - (tan (angle) * (y - ay - (BALL_SIZE/2)));
+               if (dx <  (BALL_SIZE/2)) {
+                       dx = (BALL_SIZE/2);
+                       dy = y - ((x - ax) / tan (angle));
+               } else {
+                       dy = ay + (BALL_SIZE / 2);
+               }
+       }
+       
+       clutter_timeline_set_duration (data->timeline, MAX (1000/FPS,
+               (guint)(1000 * (ABS (dx - x)/w) * data->speed)));
+       data->end.x = (gint)dx;
+       data->end.y = (gint)dy;
+}
+
+static void
+pong_path_end_cb (ClutterTimeline *timeline,
+                     PongData *data)
+{
+       /* Figure out the new angle of the ball after a collision */
+               gint x, y;
+
+               x = clutter_actor_get_x (data->ball);
+               y = clutter_actor_get_y (data->ball);
+               
+               /*g_debug ("%d, %d, %lf", x, y, data->angle);*/
+               
+               /* Work out new travel angle after collisions */
+               if ((x >= (ARENA_WIDTH - (BALL_SIZE/2))) ||
+                   (x <= (BALL_SIZE/2)))
+                       data->angle = -data->angle;
+
+               while (data->angle > M_PI*2) data->angle -= M_PI*2;
+               while (data->angle < 0) data->angle += M_PI*2;
+
+               if (y <= PADDLE_THICKNESS + (BALL_SIZE/2)) {
+                       if (data->angle < M_PI * 0.5) {
+                               data->angle = M_PI - data->angle;
+                       } else if (data->angle > M_PI * 1.5) {
+                               data->angle = M_PI +
+                                       ((M_PI * 2.0) - data->angle);
+                       }
+               } else if (y >= ARENA_HEIGHT - PADDLE_THICKNESS -
+                          (BALL_SIZE/2)) {
+                       if (data->angle < M_PI) {
+                               data->angle = M_PI - data->angle;
+                       } else if (data->angle < M_PI * 1.5) {
+                               data->angle = (M_PI * 2.0) -
+                                       (data->angle - M_PI);
+                       }
+               }
+               
+               while (data->angle > M_PI*2) { data->angle -= M_PI*2; }
+               while (data->angle < 0) { data->angle += M_PI*2; }
+               
+               pong_ball_path_calculate (data,
+                       0, PADDLE_THICKNESS,
+                       ARENA_WIDTH,
+                       ARENA_HEIGHT - PADDLE_THICKNESS);
+               
+       clutter_path_clear (data->path);
+       clutter_path_add_move_to (data->path, data->start.x, data->start.y);
+       clutter_path_add_line_to (data->path, data->end.x,   data->end.y  );
+
+       clutter_timeline_start (data->timeline);
+
+               /*g_debug ("%d, %d, %lf", data->end.x,
+                       data->end.y, data->angle);*/
+}
+
+static void
+pong_key_press_event_cb (ClutterStage *stage, ClutterEvent *event,
+                        PongData *data)
+{
+       guint key_symbol = clutter_event_get_key_symbol (event);
+
+       if ((key_symbol != CLUTTER_p) && (data->pause)) {
+               data->pause = FALSE;
+               clutter_timeline_start (data->timeline);
+       }
+               
+       switch (key_symbol)
+       {
+           case CLUTTER_Escape:
+           case CLUTTER_q:
+               clutter_main_quit ();
+               break;
+           case CLUTTER_a:
+               data->up1 = TRUE;
+               break;
+           case CLUTTER_z:
+               data->down1 = TRUE;
+               break;
+           case CLUTTER_k:
+               data->up2 = TRUE;
+               break;
+           case CLUTTER_m:
+               data->down2 = TRUE;
+               break;
+           case CLUTTER_p:
+               data->pause = !data->pause;
+               if (data->pause) {
+                       clutter_timeline_pause (data->timeline);
+               } else
+                       clutter_timeline_start (data->timeline);
+           default:
+               break;
+       }
+}
+
+static void
+pong_key_release_event_cb (ClutterStage *stage, ClutterEvent *event,
+                          PongData *data)
+{
+       guint key_symbol = clutter_event_get_key_symbol (event);
+
+       switch (key_symbol)
+       {
+           case CLUTTER_a:
+               data->up1 = FALSE;
+               break;
+           case CLUTTER_z:
+               data->down1 = FALSE;
+               break;
+           case CLUTTER_k:
+               data->up2 = FALSE;
+               break;
+           case CLUTTER_m:
+               data->down2 = FALSE;
+               break;
+           default:
+               break;
+       }
+}
+
+static void
+pong_new_frame_cb (ClutterTimeline *timeline, gint frame_num,
+                              PongData *data)
+{
+       if (data->up1 ^ data->down1) {
+               data->position1 = MAX (MINPOS, MIN (MAXPOS, data->position1 +
+                       (data->down1 ? PADDLE_SPEED : 0) -
+                       (data->up1 ? PADDLE_SPEED : 0)));
+               clutter_actor_set_position (data->paddle1, PADDLE_THICKNESS,
+                       data->position1);
+       }
+
+       if (data->up2 ^ data->down2) {
+               data->position2 = MAX (MINPOS, MIN (MAXPOS, data->position2 +
+                       (data->down2 ? PADDLE_SPEED : 0) -
+                       (data->up2 ? PADDLE_SPEED : 0)));
+               clutter_actor_set_position (data->paddle2, ARENA_WIDTH -
+                       (PADDLE_THICKNESS * 2), data->position2);
+       }
+}
+
+int
+main (int argc, char **argv)
+{
+       PongData data;
+       ClutterActor *stage;
+       const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
+       
+       clutter_init (&argc, &argv);
+       
+       data.arena = pong_arena_actor_create (&data);
+       data.paddle1 = pong_paddle_actor_create (&data);
+       data.paddle2 = pong_paddle_actor_create (&data);
+       data.ball = pong_ball_actor_create (&data);
+       
+       clutter_actor_set_position (data.paddle1, PADDLE_THICKNESS,
+               PADDLE_THICKNESS * 2);
+       clutter_actor_set_position (data.paddle2,
+               ARENA_WIDTH - (PADDLE_THICKNESS * 2),
+               PADDLE_THICKNESS * 2);
+       
+       data.up1 = FALSE;
+       data.down1 = FALSE;
+       data.up2 = FALSE;
+       data.down2 = FALSE;
+       data.pause = TRUE;
+       data.position1 = 0;
+       data.position2 = 0;
+       
+       data.timeline = clutter_timeline_new (2000);
+       data.alpha = clutter_alpha_new_full (data.timeline, CLUTTER_LINEAR);
+       data.path = clutter_path_new();
+       data.behaviour = clutter_behaviour_path_new (data.alpha, data.path);
+       
+       data.angle = ((M_PI * 1.8));
+       data.speed = 2;
+       
+       clutter_actor_set_position (data.ball, ARENA_WIDTH/2, ARENA_HEIGHT/2);
+       
+       stage = clutter_stage_get_default ();
+       clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+       
+       clutter_group_add (CLUTTER_GROUP (stage), data.arena);
+       clutter_group_add (CLUTTER_GROUP (stage), data.paddle1);
+       clutter_group_add (CLUTTER_GROUP (stage), data.paddle2);
+       clutter_group_add (CLUTTER_GROUP (stage), data.ball);
+       
+       clutter_actor_show_all (CLUTTER_ACTOR (stage));
+       clutter_actor_set_scale (CLUTTER_ACTOR (stage),
+               CLUTTER_STAGE_WIDTH () / ARENA_WIDTH,
+               CLUTTER_STAGE_HEIGHT () / ARENA_HEIGHT);
+       
+       pong_ball_path_calculate (&data,
+                       0, PADDLE_THICKNESS,
+                       ARENA_WIDTH,
+                       ARENA_HEIGHT - PADDLE_THICKNESS);
+       clutter_behaviour_apply (data.behaviour, data.ball);
+       
+       clutter_path_add_move_to (data.path, data.start.x, data.start.y);
+       clutter_path_add_line_to (data.path, data.end.x,   data.end.y  );
+
+       g_signal_connect_after (data.timeline, "completed",
+               G_CALLBACK (pong_path_end_cb), &data);
+       g_signal_connect (data.timeline, "new_frame",
+               G_CALLBACK (pong_new_frame_cb), &data);
+
+       g_signal_connect (stage, "key-press-event",
+               G_CALLBACK (pong_key_press_event_cb), &data);
+       g_signal_connect (stage, "key-release-event",
+               G_CALLBACK (pong_key_release_event_cb), &data);
+
+       clutter_main ();
+
+       return 0;
+}
+
diff --git a/ripples/Makefile b/ripples/Makefile
new file mode 100644 (file)
index 0000000..b92ab06
--- /dev/null
@@ -0,0 +1,13 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+
+.c.o:
+       $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: ripples
+
+ripples: ripples.o
+       $(CC) -g -Wall $(CFLAGS) -o $@ ripples.o $(LIBS)
+
+clean:
+       rm -fr *.o ripples
diff --git a/ripples/ripples.c b/ripples/ripples.c
new file mode 100644 (file)
index 0000000..bdd9a17
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdlib.h>
+#include <cogl/cogl.h>
+#include <clutter/clutter.h>
+
+#define RIPPLE_S 3000    /* speed */
+#define RIPPLE_W 8       /* width */
+#define RIPPLE_G 2       /* gap */
+#define RIPPLE_N 6       /* Max amount of ripple circles */
+#define RIPPLE_MIND 500  /* Minimum delay between ripples */
+#define RIPPLE_MAXD 2000 /* Maximum delay */
+
+#define SCREEN_W 640
+#define SCREEN_H 480
+
+static void
+circle_paint_cb (ClutterActor *actor)
+{
+  CoglColor fill_color;
+  float radius = clutter_actor_get_width (actor) / 2;
+
+  cogl_color_set_from_4ub (&fill_color,
+                           255,
+                           255,
+                           255,
+                           clutter_actor_get_paint_opacity (actor));
+
+  cogl_set_source_color (&fill_color);
+  cogl_path_move_to (radius, radius);
+  cogl_path_arc (radius, radius,
+                 radius, radius,
+                 0.0, 360.0);
+  cogl_path_line_to (radius - RIPPLE_W / 2, radius);
+  cogl_path_arc (radius, radius,
+                 radius - RIPPLE_W / 2, radius - RIPPLE_W / 2,
+                 0.0,
+                 360.0);
+  cogl_path_close ();
+  cogl_path_fill ();
+}
+
+void
+ripple (ClutterActor *stage,
+        gfloat        x,
+        gfloat        y)
+{
+  const ClutterColor transp = { 0x00, 0x00, 0x00, 0x00 };
+  gfloat scale_x, scale_y;
+  gint i, n;
+
+  n = g_random_int_range (1, RIPPLE_N);
+
+  scale_x = clutter_actor_get_width (stage) / RIPPLE_W,
+  scale_y = clutter_actor_get_width (stage) / RIPPLE_W;
+
+  for (i = 0; i < n; i++)
+    {
+      ClutterActor *actor = clutter_rectangle_new_with_color (&transp);
+      gfloat size;
+
+      size = ((RIPPLE_W * 2) * (i + 1)) + (RIPPLE_G * i);
+      clutter_actor_set_size (actor, size, size);
+      clutter_actor_set_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER);
+      clutter_actor_set_position (actor, x, y);
+      clutter_actor_set_opacity (actor, 0x80);
+
+      g_signal_connect (actor, "paint", G_CALLBACK (circle_paint_cb), NULL);
+
+      clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
+
+      clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, RIPPLE_S / 2,
+                             "scale-x", scale_x,
+                             "scale-y", scale_y,
+                             "opacity", 0,
+                             "signal-swapped-after::completed",
+                               clutter_actor_destroy, actor,
+                             NULL);
+    }
+}
+
+static gboolean
+stage_clicked_cb (ClutterActor *stage, ClutterEvent *event)
+{
+  gfloat event_x, event_y;
+
+  clutter_event_get_coords (event, &event_x, &event_y);
+  ripple (stage, event_x, event_y);
+
+  return TRUE;
+}
+
+static gboolean
+random_ripple_cb (gpointer data)
+{
+  ClutterActor *stage = data;
+
+  ripple (stage,
+          g_random_double_range (0, clutter_actor_get_width (stage)),
+          g_random_double_range (0, clutter_actor_get_height (stage)));
+
+  g_timeout_add (g_random_int_range (RIPPLE_MIND, RIPPLE_MAXD),
+                 random_ripple_cb,
+                 stage);
+
+  return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+  const ClutterColor bg_color = { 0xe0, 0xf2, 0xfc, 0xff };
+  ClutterActor *stage;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_set_size (stage, SCREEN_W, SCREEN_H);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &bg_color);
+
+  clutter_actor_show (stage);
+
+  random_ripple_cb (stage);
+
+  g_signal_connect (stage,
+                    "button-press-event", G_CALLBACK (stage_clicked_cb),
+                    NULL);
+
+  clutter_main ();
+  
+  return EXIT_SUCCESS;
+}
+
diff --git a/script-viewer/.gitignore b/script-viewer/.gitignore
new file mode 100644 (file)
index 0000000..514a634
--- /dev/null
@@ -0,0 +1,2 @@
+script-viewer
+script-viewer.o
diff --git a/script-viewer/COPYING b/script-viewer/COPYING
new file mode 100644 (file)
index 0000000..b1e3f5a
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/script-viewer/ChangeLog b/script-viewer/ChangeLog
new file mode 100644 (file)
index 0000000..5d9b665
--- /dev/null
@@ -0,0 +1,48 @@
+2008-08-11  Emmanuele Bassi  <ebassi@openedhand.com>
+
+       * Makefile:
+       * script-viewer.c: Update to use clutter-0.8.
+
+       * behaviours.json:
+       * test-script.json:
+       * text.json: Update examples.
+
+2008-02-08  Chris Lord  <chris@openedhand.com>
+
+       * test-script.json:
+       Change 'angle-begin' to 'angle-start' on rotation behaviour
+
+2008-01-24  Øyvind Kolås  <pippin@gimp.org>
+
+       * alphas.json: changed duration.
+       * behaviours.json: updaed scale behaviours properties.
+
+2007-10-25  Øyvind Kolås  <pippin@o-hand.com>
+
+       * behaviours.json: updated the names used for properties to reflect
+       the new naming convention of foo-start, foo-end.
+
+2007-10-25  Øyvind Kolås  <pippin@o-hand.com>
+
+       * script-viewer.c: add the error label actor to stage and show it upon
+       errors.
+
+2007-10-25  Øyvind Kolås  <pippin@o-hand.com>
+
+       * alphas.json: added illustrations of all alphas going along a
+       horizontal path simultanously.
+
+2007-10-25  Øyvind Kolås  <pippin@o-hand.com>
+
+       * behaviours.json: updated with path, bspline and fixed ellipse
+       after updates to ClutterScript.
+
+2007-10-23  Øyvind Kolås  <pippin@o-hand.com>
+
+       * behaviours.json: added a sample animating text labels using scale,
+       rotate, opacity, depth and ellipse behaviours, with some BUG comments
+       sprinkled around the code.
+
+2007-10-23  Øyvind Kolås  <pippin@o-hand.com>
+
+       Initial import to svn.
diff --git a/script-viewer/Makefile b/script-viewer/Makefile
new file mode 100644 (file)
index 0000000..ac0e1ab
--- /dev/null
@@ -0,0 +1,83 @@
+# A generic buildfiles to build single executable directory projects depending
+# only on pkg-config ability to build. It automatically names the project on
+# the toplevel directory you're in.
+#
+# Setting additional CFLAGS like $ export CFLAGS=-Wall -Werror # can help you
+# track issues down better after compilation.
+#
+# 20071008
+# Øyvind Kolås (c) 2007 <pippin@gimp.org>  placed in the Public Domain.
+##
+
+PKGMODULES = clutter-1.0 
+
+# you only need to change the following if you want to change where the
+# generated tarball gets scp'd to:
+
+SCP_DESTINATION=
+
+BINARY=$(shell basename `pwd`)#
+PACKAGE=../$(BINARY).tar.bz2 # you can use both .gz and .bz2 as extension here
+
+
+##
+# end of template configuration.
+#
+
+# This makefile uses the current directory as the only target binary, and
+# expects a single of the .c files to contain a main function.
+
+
+
+all: $(BINARY)
+
+# The help available also contains brief information about the different
+# build rules supported.
+help: 
+       @echo ''
+       @echo 'Available targets in this make system'
+       @echo ''
+       @echo '  (none)   builds $(BINARY)'
+       @echo '  dist     create $(PACKAGE)'
+       @echo '  clean    rm *.o *~ and foo and bar'
+       @echo '  run      ./$(BINARY)'
+       @echo '  gdb      gdb ./$(BINARY)'
+       @echo '  gdb2     gdb ./$(BINARY) --g-fatal-warnings'
+       @echo '  scp      scp $(PACKAGE) $(SCP_DESTINATION)'
+       @echo '  help     this help'
+       @echo ''
+
+
+LIBS= $(shell pkg-config --libs $(PKGMODULES))
+INCS= $(shell pkg-config --cflags $(PKGMODULES))
+
+CFLAGS+=-Wall
+CFILES  = $(wildcard *.c)
+OBJECTS = $(subst ./,,$(CFILES:.c=.o))
+HFILES  = $(wildcard *.h)
+%.o: %.c $(HFILES)
+       $(CC) -g $(CFLAGS) $(INCS) -c $< -o$@
+$(BINARY): $(OBJECTS)
+       $(CC) -o $@ $(LIBS) $(OBJECTS)
+test: run
+run: $(BINARY)
+       ./$(BINARY)
+
+../$(BINARY).tar.gz: clean $(CFILES) $(HFILES)
+       cd ..;tar czvhf $(BINARY).tar.gz $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.gz
+../$(BINARY).tar.bz2: clean $(CFILES) $(HFILES)
+       cd ..;tar cjvhf $(BINARY).tar.bz2 $(BINARY)/*
+       @ls -slah ../$(BINARY).tar.bz2
+
+dist: $(PACKAGE) 
+       echo $(PACKAGE) 
+scp: dist
+       scp $(PACKAGE) $(SCP_DESTINATION)
+
+gdb: all
+       gdb --args ./$(BINARY)
+gdb2: all
+       gdb --args ./$(BINARY) -demo --g-fatal-warnings
+clean:
+       rm -fvr *.o $(BINARY) *~ *.patch
diff --git a/script-viewer/README b/script-viewer/README
new file mode 100644 (file)
index 0000000..3b0fb6a
--- /dev/null
@@ -0,0 +1,56 @@
+ClutterScriptViewer
+===================
+
+ClutterScriptViewer, a minimalistic hacker editing tool for authoring and
+experimenting with ClutterScript. Compile by typing make, if that worked well.
+You can now start using script-viewer. The main use of script-viewer is editing
+and tweaking layouts in your favourite editor whilst script-viewer provides a
+live preview.
+
+Documentation
+-------------
+
+The core documentation for script-viewer is the usage shown when no commands
+are passed in, default values are shown in paranthesises after each option,
+by adding -h to the end of your list of options the script-viewer will show
+the parsed values for different options.
+
+$ ./script-viewer -h
+
+Usage: ./script-viewer [options] <clutterscript>
+
+  -s <widthXheight>       stage size                  (640x480)
+  -fs                     run fullscreen              (FALSE)
+  -bg <color>             stage color                 (gray)
+  -id <actor id>          which actor id to show      (root)
+  -timeline <timeline id> a timeline to play          (NULL)
+  -o <file.png>           write screenshot, then quit (NULL)
+  -h                      this help
+
+Examples
+--------
+
+Load the file foo.json and show the actor/group with id 'root' on stage.
+
+$ ./script-viewer foo.json
+
+
+Load the file foo.json and show the actor/group with id 'bar' on a stage
+with a black background.
+
+$ ./script-viewer foo.json -id 'bar' -bg black
+
+
+Load the file foo.json and show the actor/group with id 'bar' to a stage size
+400x300 and save a screenshot to the file screenshot.png, note that the stage
+itself will appear transparent in the screenshot even when it has a color on
+screen.
+
+$ ./script-viewer foo.json -id 'bar' -o screenshot.png -s 400x300
+
+
+Load the file foo.json and show the actor/group with id 'bar' to stage
+and start playing the timeline with id 'baz'
+
+$ ./script-viewer foo.json -id 'bar' -timeline 'baz'
+
diff --git a/script-viewer/alphas.json b/script-viewer/alphas.json
new file mode 100644 (file)
index 0000000..7026a27
--- /dev/null
@@ -0,0 +1,186 @@
+[
+  {
+    "id" : "animation",
+    "type" : "ClutterTimeline",
+    "duration" : 5000,
+    "loop" : true
+  },
+  {
+    "id" : "root",
+    "type" : "ClutterGroup",
+    "x": 0,
+    "y": 0,
+    "children" : [
+
+      {
+        "type": "ClutterText",
+        "text": "linear",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"  : "ClutterBehaviourPath",
+              "path" : "M 20,10 L 400,10",
+              "alpha" : {"timeline"  : "animation", "mode" : "linear"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "ramp-dec",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 40], [400, 40]],
+              "alpha" : {"timeline"  : "animation", "function"  : "ramp-dec"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "sine-inc",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 60], [400, 60]],
+              "alpha" : {"timeline"  : "animation", "function"  : "sine-inc"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "sine-dec",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 80], [400, 80]],
+              "alpha" : {"timeline"  : "animation", "function"  : "sine-dec"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "sine",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 100], [400, 100]],
+              "alpha" : {"timeline"  : "animation", "function"  : "sine"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "ramp",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 120], [400, 120]],
+              "alpha" : {"timeline"  : "animation", "function"  : "ramp"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "ramp",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 140], [400, 140]],
+              "alpha" : {"timeline"  : "animation", "function"  : "square"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "exp-inc",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 160], [400, 160]],
+              "alpha" : {"timeline"  : "animation", "function"  : "exp-inc"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "exp-dec",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 180], [400, 180]],
+              "alpha" : {"timeline"  : "animation", "function"  : "exp-dec"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "sine-half",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 200], [400, 200]],
+              "alpha" : {"timeline"  : "animation", "function"  : "sine-half"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "smoothstep-inc",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 220], [400, 220]],
+              "alpha" : {"timeline"  : "animation", "function"  : "smoothstep-inc"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "smoothstep-dec",
+        "font-name": "Sans 20px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourPath",
+              "knots" : [[20, 240], [400, 240]],
+              "alpha" : {"timeline"  : "animation", "function"  : "smoothstep-dec"}
+            }
+          ]
+      },
+
+    ]
+  }
+]
diff --git a/script-viewer/behaviours.json b/script-viewer/behaviours.json
new file mode 100644 (file)
index 0000000..816f919
--- /dev/null
@@ -0,0 +1,140 @@
+# there are inconsistencies in the naming of the nicks of the
+# properties: 
+
+[
+  {
+    "id" : "animation",
+    "type" : "ClutterTimeline",
+    "num-frames" : 300,
+    "fps" : 60,
+    "loop" : true
+  },
+  {
+    "id" : "root",
+    "type" : "ClutterGroup",
+    "x": 0,
+    "y": 0
+    "children" : [
+      {
+        "type": "ClutterLabel",
+        "text": "Scale",
+        "font-name": "Sans 30px",
+        "visible":true,
+        "x":50,
+        "y":100,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourScale",
+              "x-scale-start"   : 1.0,
+              "x-scale-end"     : 0.5,
+              "y-scale-start"   : 1.0,
+              "y-scale-end"     : 0.5,
+              "alpha"         : {"timeline"  : "animation", "function"  : "sine"}
+            },
+          ]
+      },
+
+      {
+        "type": "ClutterLabel",
+        "text": "Rotate",
+        "font-name": "Sans 30px",
+        "color": "blue",
+        "visible":true,
+        "x":250,
+        "y":100,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourRotate",
+              "angle-start"   : 0.0,
+              "angle-end"     : 359.0,
+              "alpha"         : {"timeline"  : "animation", "function"  : "sine"}
+            },
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "Opacity",
+        "font-name": "Sans 30px",
+        "visible":true,
+        "x":400,
+        "y":100,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourOpacity",
+              "opacity-start" : 100,
+              "opacity-end"   : 255,
+              "alpha"         : {"timeline"  : "animation", "function"  : "sine"}
+            }
+          ]
+      },
+      {
+        "type": "ClutterLabel",
+        "text": "Depth",
+        "font-name": "Sans 30px",
+        "visible":true,
+        "x":100,
+        "y":200,
+        "behaviours" : [
+            {
+              "type"          : "ClutterBehaviourDepth",
+              "depth-start"   : 50,
+              "depth-end"     : -1000, 
+              "alpha"         : {"timeline"  : "animation", "function"  : "sine"}
+            }
+          ]
+      } ,
+
+      {
+        "type": "ClutterLabel",
+        "text": "Ellipse",
+        "font-name": "Sans 30px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"       : "ClutterBehaviourEllipse",
+              "center"     : [150, 200],
+              "width"      : 100,
+              "height"     : 100,
+              "angle-start": 90.0,
+              "angle-end"  : 180.0,
+              "alpha"      : {"timeline"  : "animation", "function"  : "sine"}
+            }
+          ]
+      },
+
+      {
+        "type": "ClutterLabel",
+        "text": "Path",
+        "font-name": "Sans 30px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"  : "ClutterBehaviourPath",
+              "knots" : [[300, 200], [400,230], [300,150], [300,200]],
+              "alpha" : {"timeline"  : "animation", "function"  : "sine-inc"}
+            }
+          ]
+      },
+
+      {
+        "type": "ClutterLabel",
+        "text": "BSpline",
+        "font-name": "Sans 30px",
+        "visible":true,
+        "wrap":false,
+        "behaviours" : [
+            {
+              "type"  : "ClutterBehaviourBSpline",
+              "knots" : [[100, 300], [200,300], [300,300],
+                         [400, 400], [450, 400], [450, 400],
+                         [500, 400]],
+              "alpha" : {"timeline"  : "animation", "function"  : "ramp-dec"}
+            }
+          ]
+      }
+
+    ]
+  }
+]
diff --git a/script-viewer/redhand.png b/script-viewer/redhand.png
new file mode 100644 (file)
index 0000000..c07d8ac
Binary files /dev/null and b/script-viewer/redhand.png differ
diff --git a/script-viewer/script-viewer.c b/script-viewer/script-viewer.c
new file mode 100644 (file)
index 0000000..afaa84e
--- /dev/null
@@ -0,0 +1,239 @@
+/* ClutterScript viewer, a viewer for displaying clutter scripts or fragments
+ * of clutterscript.
+ *
+ * Copyright 2007 OpenedHand Ltd
+ * Copyright 2010 Intel Corp
+ *
+ * Authored by Øyvind Kolås <pippin@o-hand.com>
+ *
+ * Licensed under the GPL v2 or greater.
+ */
+
+#include <clutter/clutter.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+
+/* Global structure containing information parsed from commandline parameters */
+static struct
+{
+  gboolean  fullscreen;
+  gchar    *bg_color;
+  gint      width, height;
+  gchar    *path;
+  gchar    *id;
+  gchar    *timeline;
+  gchar    *png;
+}
+args =
+{
+  FALSE,
+  "gray",
+  640,    480,
+  NULL,
+  "root",
+  NULL,
+  NULL
+};
+
+/* using global variables, this is needed at least for the ClutterScript to avoid
+ * possible behaviours to be destroyed when the script is destroyed.
+ */
+static ClutterActor    *stage;
+static ClutterActor    *actor    = NULL;
+static ClutterTimeline *timeline = NULL;
+static ClutterScript   *script   = NULL;
+
+gboolean
+parse_args (gchar **argv)
+{
+  gchar **arg = argv + 1;
+
+  while (*arg)
+    {
+      if (g_str_equal (*arg, "-h") ||
+          g_str_equal (*arg, "--help"))
+        {
+usage:
+          g_print ("\nUsage: %s [options] %s\n\n",
+                   argv[0], args.path ? args.path : "<clutterscript>");
+          g_print ("  -s <widthXheight>       stage size                  (%ix%i)\n",
+                   args.width, args.height);
+          g_print ("  -fs                     run fullscreen              (%s)\n",
+                   args.fullscreen ? "TRUE" : "FALSE");
+          g_print ("  -bg <color>             stage color                 (%s)\n",
+                   args.bg_color);
+          g_print ("  -id <actor id>          which actor id to show      (%s)\n",
+                   args.id ? args.id : "NULL");
+          g_print ("  -timeline <timeline id> a timeline to play          (%s)\n",
+                   args.timeline ? args.timeline : "NULL");
+          g_print ("  -o <file.png>           write screenshot, then quit (%s)\n",
+                   args.png? args.png: "NULL");
+          g_print ("  -h                      this help\n\n");
+          return FALSE;
+        }
+      else if (g_str_equal (*arg, "-s"))
+        {
+          arg++; g_assert (*arg);
+          args.width = atoi (*arg);
+          if (strstr (*arg, "x"))
+            args.height = atoi (strstr (*arg, "x") + 1);
+        }
+      else if (g_str_equal (*arg, "-bg"))
+        {
+          arg++; g_assert (*arg);
+          args.bg_color = *arg;
+        }
+      else if (g_str_equal (*arg, "-id"))
+        {
+          arg++; g_assert (*arg);
+          args.id = *arg;
+        }
+      else if (g_str_equal (*arg, "-timeline"))
+        {
+          arg++; g_assert (*arg);
+          args.timeline = *arg;
+        }
+      else if (g_str_equal (*arg, "-o"))
+        {
+          arg++; g_assert (*arg);
+          args.png = *arg;
+        }
+      else if (g_str_equal (*arg, "-fs"))
+        {
+          args.fullscreen = TRUE;
+        }
+      else
+        {
+          args.path = *arg;
+        }
+      arg++;
+    }
+  if (args.path == NULL)
+    {
+      g_print ("Error parsing commandline: no clutterscript provided\n");
+      goto usage;
+    }
+  return TRUE;
+}
+
+static ClutterActor *
+initialize_stage ()
+{
+  ClutterActor *stage;
+  ClutterColor  color;
+
+  stage = clutter_stage_get_default ();
+
+  clutter_actor_set_size (stage, args.width, args.height);
+
+  clutter_color_from_string (&color, args.bg_color);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &color);
+
+  clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), args.fullscreen);
+
+  return stage;
+}
+
+
+static void
+load_script (const gchar *path)
+{
+  GError        *error = NULL;
+
+  g_assert (CLUTTER_IS_SCRIPT (script));
+  clutter_script_load_from_file (script, path, &error);
+
+  if (error)
+    {
+      ClutterColor error_color = { 0xff, 0, 0, 0xff };
+
+      actor = clutter_text_new_with_text ("Sans 20px", error->message);
+      clutter_text_set_color (CLUTTER_TEXT (actor), &error_color);
+
+      clutter_actor_set_size (actor, clutter_actor_get_width (stage), 200);
+
+      g_print ("%s\n", error->message);
+
+      clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
+      clutter_actor_show_all (stage);
+
+      g_clear_error (&error);
+
+      return;
+    }
+
+  actor = CLUTTER_ACTOR (clutter_script_get_object (script, args.id));
+
+  if (actor == NULL)
+    {
+      ClutterColor error_color = { 0xff, 0, 0, 0xff };
+      gchar        message[256];
+
+      g_sprintf (message, "No actor with \"id\"=\"%s\" found", args.id);
+      actor = clutter_text_new_with_text ("Sans 30px", message);
+      clutter_text_set_color (CLUTTER_TEXT (actor), &error_color);
+    }
+  else
+    {
+      clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
+      clutter_actor_show_all (stage);
+
+      if (args.timeline != NULL)
+        {
+          timeline = CLUTTER_TIMELINE (clutter_script_get_object (
+                                       script, args.timeline));
+          if (timeline)
+            clutter_timeline_start (timeline);
+        }
+    }
+}
+
+static gboolean watch_file (gpointer data)
+{
+  static struct stat   stat_buf;
+  static time_t        previous_ctime = 0;
+
+  g_stat (args.path, &stat_buf);
+
+  if (stat_buf.st_ctime != previous_ctime)
+    {
+      if (script != NULL)
+        g_object_unref (script);
+
+      script = clutter_script_new ();
+      if (actor != NULL)
+        {
+          clutter_actor_destroy (actor);
+        }
+      if (timeline != NULL)
+        {
+          timeline = NULL;
+        }
+
+      load_script (args.path);
+    }
+
+  previous_ctime = stat_buf.st_ctime;
+  return TRUE;
+}
+
+gint
+main (gint    argc,
+      gchar **argv)
+{
+  clutter_init (&argc, &argv);
+
+  if (!parse_args (argv))
+    return -1;
+
+  stage = initialize_stage ();
+
+  g_timeout_add (1000, watch_file, NULL);
+
+  clutter_main ();
+  return 0;
+}
diff --git a/script-viewer/test-script.json b/script-viewer/test-script.json
new file mode 100644 (file)
index 0000000..52c81f2
--- /dev/null
@@ -0,0 +1,70 @@
+[
+  {
+    "id" : "main-timeline",
+    "type" : "ClutterTimeline",
+    "num-frames" : 600,
+    "fps" : 60,
+    "loop" : true
+  },
+  {
+    "id"          : "rotate-behaviour",
+    "type"        : "ClutterBehaviourRotate",
+    "angle-start" : 0.0,
+    "angle-end"   : 360.0,
+    "axis"        : "y-axis",
+    "alpha"       : {
+      "timeline" : "main-timeline",
+      "function" : "sine"
+    }
+  },
+  {
+    "id"            : "fade-behaviour",
+    "type"          : "ClutterBehaviourOpacity",
+    "opacity-start" : 255,
+    "opacity-end"   : 0,
+    "alpha"         : {
+      "timeline" : "main-timeline",
+      "function" : "ramp-inc"
+    }
+  },
+  {
+    "id" : "root",
+    "type" : "ClutterGroup",
+    "width" : 500,
+    "height" : 200,
+    "children" : [
+
+      {
+        "id" : "red-button",
+        "type" : "ClutterRectangle",
+        "color" : "#ff0000ff",
+        "x" : 50,
+        "y" : 50,
+        "width" : 100,
+        "height" : 100,
+        "visible" : true,
+      },
+      {
+        "id" : "green-button",
+        "type" : "ClutterRectangle",
+        "color" : "#00ff00ff",
+        "x" : 200,
+        "y" : 50,
+        "width" : 100,
+        "height" : 100,
+        "visible" : true,
+        "behaviours" : [ "fade-behaviour"]
+      }, 
+      {
+        "id" : "red-hand",
+        "type" : "ClutterTexture",
+        "filename" : "redhand.png",
+        "x" : 50,
+        "y" : 50,
+        "opacity" : 100,
+        "visible" : true,
+        "behaviours" : [ "rotate-behaviour", "fade-behaviour" ]
+      }
+    ]
+  }
+]
diff --git a/script-viewer/text.json b/script-viewer/text.json
new file mode 100644 (file)
index 0000000..c1b0514
--- /dev/null
@@ -0,0 +1,102 @@
+[
+  {
+    "id" : "animation",
+    "type" : "ClutterTimeline",
+    "duration" : 5000,
+    "loop" : true
+  },
+  {
+    "id" : "root",
+    "type" : "ClutterGroup",
+    "x" : 50,
+    "y" : 40,
+    "children" : [
+      {
+        "type" : "ClutterTexture",
+        "filename" : "redhand.png",
+        "visible" : true,
+        "x" : 200,
+        "y" : 200,
+        "behaviours" : [
+          {
+            "type" : "ClutterBehaviourRotate",
+            "alpha" : { "timeline" : "animation", "mode" : "linear" }
+          }
+        ]
+      },
+      {
+        "type" : "ClutterText",
+        "text" : "Clutter",
+        "font-name" : "Sans 60px",
+        "visible" : true,
+        "x" : 100,
+        "y" : 100,
+        "behaviours" : [
+          {
+            "type" : "ClutterBehaviourScale",
+            "x-scale-start" : 1.0,
+            "y-scale-start" : 1.0,
+            "x-scale-end" : 0.5,
+            "y-scale-end" : 0.5,
+            "alpha" : { "timeline" : "animation", "mode" : "easeOutSine" }
+          },
+          {
+            "type" : "ClutterBehaviourOpacity",
+            "opacity-start" : 100,
+            "opacity-end" : 255,
+            "alpha" : { "timeline" : "animation", "mode" : "linear" }
+          }
+        ]
+      },
+      {
+        "type" : "ClutterText",
+        "text" : "Script",
+        "font-name" : "Sans 60px",
+        "color" : "blue",
+        "visible" : true,
+        "x" : 160,
+        "y" : 130,
+        "behaviours" : [
+          {
+            "type" : "ClutterBehaviourScale",
+            "x-scale-start" : 0.5,
+            "y-scale-start" : 0.5,
+            "x-scale-end" : 1.0,
+            "y-scale-end" : 1.0,
+            "alpha" : {"timeline" : "animation", "mode" : "easeInSine" }
+          },
+          {
+            "type" : "ClutterBehaviourOpacity",
+            "opacity-start" : 100,
+            "opacity-end" : 255,
+            "alpha" : { "timeline" : "animation", "mode" : "linear"}
+          }
+        ]
+      },
+      {
+        "type" : "ClutterText",
+        "text" : "Viewer",
+        "font-name" : "Sans 60px",
+        "visible" : true,
+        "x" : 200,
+        "y" : 170,
+        "behaviours" : [
+          {
+            "type" : "ClutterBehaviourScale",
+            "x-scale-start" : 1.0,
+            "y-scale-start" : 1.0,
+            "x-scale-end" : 0.5,
+            "y-scale-end" : 0.5,
+            "alpha" : { "timeline" : "animation", "mode" : "easeOutSine" }
+          },
+          {
+            "type" : "ClutterBehaviourOpacity",
+            "opacity-start" : 100,
+            "opacity-end" : 255,
+            "alpha" : { "timeline" : "animation", "mode" : "linear" }
+          }
+        ]
+      },
+    ]
+  }
+]