summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README32
-rw-r--r--arc-clock/Makefile17
-rw-r--r--arc-clock/arc-clock.c189
-rw-r--r--attic/aaina/AUTHORS1
-rw-r--r--attic/aaina/ChangeLog713
-rw-r--r--attic/aaina/Makefile.am7
-rw-r--r--attic/aaina/NEWS0
-rw-r--r--attic/aaina/README0
-rw-r--r--attic/aaina/TODO0
-rwxr-xr-xattic/aaina/autogen.sh3
-rw-r--r--attic/aaina/configure.ac29
-rw-r--r--attic/aaina/libaaina/Makefile.am28
-rw-r--r--attic/aaina/libaaina/aaina-behave.c124
-rw-r--r--attic/aaina/libaaina/aaina-behave.h74
-rw-r--r--attic/aaina/libaaina/aaina-library.c375
-rw-r--r--attic/aaina/libaaina/aaina-library.h111
-rw-r--r--attic/aaina/libaaina/aaina-photo.c803
-rw-r--r--attic/aaina/libaaina/aaina-photo.h117
-rw-r--r--attic/aaina/libaaina/aaina-source.c49
-rw-r--r--attic/aaina/libaaina/aaina-source.h81
-rw-r--r--attic/aaina/libaaina/clutter-texture-label.c718
-rw-r--r--attic/aaina/libaaina/clutter-texture-label.h105
-rw-r--r--attic/aaina/libaaina/eggsequence.c1709
-rw-r--r--attic/aaina/libaaina/eggsequence.h120
-rw-r--r--attic/aaina/libnflick/Makefile.am75
-rw-r--r--attic/aaina/libnflick/nflick-api-request-private.h58
-rw-r--r--attic/aaina/libnflick/nflick-api-request.c396
-rw-r--r--attic/aaina/libnflick/nflick-api-request.h62
-rw-r--r--attic/aaina/libnflick/nflick-api-response-private.h58
-rw-r--r--attic/aaina/libnflick/nflick-api-response.c337
-rw-r--r--attic/aaina/libnflick/nflick-api-response.h58
-rw-r--r--attic/aaina/libnflick/nflick-auth-worker-private.h60
-rw-r--r--attic/aaina/libnflick/nflick-auth-worker.c278
-rw-r--r--attic/aaina/libnflick/nflick-auth-worker.h50
-rw-r--r--attic/aaina/libnflick/nflick-flickr.h73
-rw-r--r--attic/aaina/libnflick/nflick-get-sizes-response-private.h51
-rw-r--r--attic/aaina/libnflick/nflick-get-sizes-response.c304
-rw-r--r--attic/aaina/libnflick/nflick-get-sizes-response.h55
-rw-r--r--attic/aaina/libnflick/nflick-gft-response-private.h62
-rw-r--r--attic/aaina/libnflick/nflick-gft-response.c281
-rw-r--r--attic/aaina/libnflick/nflick-gft-response.h49
-rw-r--r--attic/aaina/libnflick/nflick-info-response-private.h66
-rw-r--r--attic/aaina/libnflick/nflick-info-response.c272
-rw-r--r--attic/aaina/libnflick/nflick-info-response.h55
-rw-r--r--attic/aaina/libnflick/nflick-info-worker-private.h63
-rw-r--r--attic/aaina/libnflick/nflick-info-worker.c275
-rw-r--r--attic/aaina/libnflick/nflick-info-worker.h59
-rw-r--r--attic/aaina/libnflick/nflick-no-set-response-private.h51
-rw-r--r--attic/aaina/libnflick/nflick-no-set-response.c199
-rw-r--r--attic/aaina/libnflick/nflick-no-set-response.h52
-rw-r--r--attic/aaina/libnflick/nflick-photo-data.c75
-rw-r--r--attic/aaina/libnflick/nflick-photo-data.h44
-rw-r--r--attic/aaina/libnflick/nflick-photo-list-response-private.h51
-rw-r--r--attic/aaina/libnflick/nflick-photo-list-response.c195
-rw-r--r--attic/aaina/libnflick/nflick-photo-list-response.h52
-rw-r--r--attic/aaina/libnflick/nflick-photo-list-worker-private.h54
-rw-r--r--attic/aaina/libnflick/nflick-photo-list-worker.c240
-rw-r--r--attic/aaina/libnflick/nflick-photo-list-worker.h52
-rw-r--r--attic/aaina/libnflick/nflick-photo-search-response-private.h51
-rw-r--r--attic/aaina/libnflick/nflick-photo-search-response.c207
-rw-r--r--attic/aaina/libnflick/nflick-photo-search-response.h51
-rw-r--r--attic/aaina/libnflick/nflick-photo-search-worker-private.h64
-rw-r--r--attic/aaina/libnflick/nflick-photo-search-worker.c324
-rw-r--r--attic/aaina/libnflick/nflick-photo-search-worker.h62
-rw-r--r--attic/aaina/libnflick/nflick-photo-set-private.h59
-rw-r--r--attic/aaina/libnflick/nflick-photo-set.c242
-rw-r--r--attic/aaina/libnflick/nflick-photo-set.h53
-rw-r--r--attic/aaina/libnflick/nflick-pixbuf-fetch-private.h37
-rw-r--r--attic/aaina/libnflick/nflick-pixbuf-fetch.c172
-rw-r--r--attic/aaina/libnflick/nflick-pixbuf-fetch.h40
-rw-r--r--attic/aaina/libnflick/nflick-set-list-response-private.h51
-rw-r--r--attic/aaina/libnflick/nflick-set-list-response.c212
-rw-r--r--attic/aaina/libnflick/nflick-set-list-response.h52
-rw-r--r--attic/aaina/libnflick/nflick-set-list-worker-private.h54
-rw-r--r--attic/aaina/libnflick/nflick-set-list-worker.c362
-rw-r--r--attic/aaina/libnflick/nflick-set-list-worker.h55
-rw-r--r--attic/aaina/libnflick/nflick-show-worker-private.h57
-rw-r--r--attic/aaina/libnflick/nflick-show-worker.c264
-rw-r--r--attic/aaina/libnflick/nflick-show-worker.h54
-rw-r--r--attic/aaina/libnflick/nflick-types.h591
-rw-r--r--attic/aaina/libnflick/nflick-worker-private.h74
-rw-r--r--attic/aaina/libnflick/nflick-worker.c454
-rw-r--r--attic/aaina/libnflick/nflick-worker.h70
-rw-r--r--attic/aaina/libnflick/nflick.h34
-rw-r--r--attic/aaina/sources/Makefile.am24
-rw-r--r--attic/aaina/sources/aaina-source-directory.c100
-rw-r--r--attic/aaina/sources/aaina-source-directory.h82
-rw-r--r--attic/aaina/sources/aaina-source-flickr.c447
-rw-r--r--attic/aaina/sources/aaina-source-flickr.h85
-rw-r--r--attic/aaina/src/Makefile.am20
-rw-r--r--attic/aaina/src/aaina-slide-show.c507
-rw-r--r--attic/aaina/src/aaina-slide-show.h91
-rw-r--r--attic/aaina/src/main.c233
-rw-r--r--attic/astro-desktop/AUTHORS1
-rw-r--r--attic/astro-desktop/ChangeLog761
-rw-r--r--attic/astro-desktop/Makefile.am7
-rw-r--r--attic/astro-desktop/NEWS0
-rw-r--r--attic/astro-desktop/README0
-rw-r--r--attic/astro-desktop/applets/Makefile.am11
-rw-r--r--attic/astro-desktop/applets/cal.json32
-rw-r--r--attic/astro-desktop/applets/cal.pngbin0 -> 2378 bytes
-rw-r--r--attic/astro-desktop/applets/clock.json33
-rw-r--r--attic/astro-desktop/applets/clock.pngbin0 -> 5876 bytes
-rw-r--r--attic/astro-desktop/applets/clouds.pngbin0 -> 4358 bytes
-rw-r--r--attic/astro-desktop/applets/mail.json31
-rw-r--r--attic/astro-desktop/applets/mail.pngbin0 -> 3390 bytes
-rw-r--r--attic/astro-desktop/applets/weather.json47
-rw-r--r--attic/astro-desktop/applications/Makefile.am1
-rw-r--r--attic/astro-desktop/applications/contacts/Makefile.am31
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contact-row.c371
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contact-row.h82
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contacts-details.c145
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contacts-details.h81
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contacts-window.c591
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contacts-window.h85
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contacts.c152
-rw-r--r--attic/astro-desktop/applications/contacts/astro-contacts.h77
-rw-r--r--attic/astro-desktop/applications/contacts/astro-reflection.c258
-rw-r--r--attic/astro-desktop/applications/contacts/astro-reflection.h79
-rw-r--r--attic/astro-desktop/applications/contacts/astro-texture-group.c189
-rw-r--r--attic/astro-desktop/applications/contacts/astro-texture-group.h82
-rw-r--r--attic/astro-desktop/applications/contacts/clutter-reflect-texture.c346
-rw-r--r--attic/astro-desktop/applications/contacts/clutter-reflect-texture.h84
-rw-r--r--attic/astro-desktop/applications/contacts/init.c26
-rw-r--r--attic/astro-desktop/applications/example/Makefile.am26
-rw-r--r--attic/astro-desktop/applications/example/astro-example.c156
-rw-r--r--attic/astro-desktop/applications/example/astro-example.h77
-rw-r--r--attic/astro-desktop/applications/example/init.c25
-rw-r--r--attic/astro-desktop/applications/images/Makefile.am28
-rw-r--r--attic/astro-desktop/applications/images/astro-images-window.c71
-rw-r--r--attic/astro-desktop/applications/images/astro-images-window.h76
-rw-r--r--attic/astro-desktop/applications/images/astro-images.c152
-rw-r--r--attic/astro-desktop/applications/images/astro-images.h77
-rw-r--r--attic/astro-desktop/applications/images/clutter-reflect-texture.c346
-rw-r--r--attic/astro-desktop/applications/images/clutter-reflect-texture.h84
-rw-r--r--attic/astro-desktop/applications/images/init.c26
-rw-r--r--attic/astro-desktop/applications/music/Makefile.am30
-rw-r--r--attic/astro-desktop/applications/music/astro-music-window.c491
-rw-r--r--attic/astro-desktop/applications/music/astro-music-window.h79
-rw-r--r--attic/astro-desktop/applications/music/astro-music.c152
-rw-r--r--attic/astro-desktop/applications/music/astro-music.h77
-rw-r--r--attic/astro-desktop/applications/music/astro-reflection.c272
-rw-r--r--attic/astro-desktop/applications/music/astro-reflection.h79
-rw-r--r--attic/astro-desktop/applications/music/astro-songs.c280
-rw-r--r--attic/astro-desktop/applications/music/astro-songs.h78
-rw-r--r--attic/astro-desktop/applications/music/clutter-reflect-texture.c346
-rw-r--r--attic/astro-desktop/applications/music/clutter-reflect-texture.h84
-rw-r--r--attic/astro-desktop/applications/music/init.c25
-rwxr-xr-xattic/astro-desktop/autogen.sh3
-rw-r--r--attic/astro-desktop/configure.ac37
-rw-r--r--attic/astro-desktop/data/Makefile.am12
-rw-r--r--attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpgbin0 -> 16410 bytes
-rw-r--r--attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpgbin0 -> 19285 bytes
-rw-r--r--attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpgbin0 -> 91746 bytes
-rw-r--r--attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpgbin0 -> 21734 bytes
-rw-r--r--attic/astro-desktop/data/albums/Makefile.am10
-rwxr-xr-xattic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpgbin0 -> 59693 bytes
-rw-r--r--attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpgbin0 -> 94541 bytes
-rwxr-xr-xattic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpgbin0 -> 229321 bytes
-rw-r--r--attic/astro-desktop/data/applet_bg.pngbin0 -> 714 bytes
-rw-r--r--attic/astro-desktop/data/background.svgbin0 -> 59181 bytes
-rw-r--r--attic/astro-desktop/data/contact-bar.svg447
-rw-r--r--attic/astro-desktop/data/contact.pngbin0 -> 11748 bytes
-rw-r--r--attic/astro-desktop/data/disc_bg.svg1028
-rw-r--r--attic/astro-desktop/data/face.pngbin0 -> 1862 bytes
-rw-r--r--attic/astro-desktop/data/icons/Makefile.am11
-rw-r--r--attic/astro-desktop/data/icons/bt.pngbin0 -> 400 bytes
-rw-r--r--attic/astro-desktop/data/icons/close.pngbin0 -> 1467 bytes
-rw-r--r--attic/astro-desktop/data/icons/contacts.pngbin0 -> 9708 bytes
-rw-r--r--attic/astro-desktop/data/icons/exec.pngbin0 -> 8688 bytes
-rw-r--r--attic/astro-desktop/data/icons/home.pngbin0 -> 3140 bytes
-rw-r--r--attic/astro-desktop/data/icons/images.pngbin0 -> 8617 bytes
-rw-r--r--attic/astro-desktop/data/icons/music.pngbin0 -> 7889 bytes
-rw-r--r--attic/astro-desktop/data/icons/nm.pngbin0 -> 307 bytes
-rw-r--r--attic/astro-desktop/data/info_bg.pngbin0 -> 744 bytes
-rw-r--r--attic/astro-desktop/libastro-desktop/Makefile.am20
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-application.c198
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-application.h94
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-behave.c89
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-behave.h79
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-defines.h40
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-utils.c14
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-utils.h34
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-window.c154
-rw-r--r--attic/astro-desktop/libastro-desktop/astro-window.h79
-rw-r--r--attic/astro-desktop/libastro-desktop/astro.h30
-rw-r--r--attic/astro-desktop/libastro-desktop/tidy-private.h40
-rw-r--r--attic/astro-desktop/libastro-desktop/tidy-texture-frame.c378
-rw-r--r--attic/astro-desktop/libastro-desktop/tidy-texture-frame.h82
-rw-r--r--attic/astro-desktop/src/Makefile.am35
-rw-r--r--attic/astro-desktop/src/astro-appicon.c190
-rw-r--r--attic/astro-desktop/src/astro-appicon.h82
-rw-r--r--attic/astro-desktop/src/astro-applet-manager.c216
-rw-r--r--attic/astro-desktop/src/astro-applet-manager.h75
-rw-r--r--attic/astro-desktop/src/astro-applet.c116
-rw-r--r--attic/astro-desktop/src/astro-applet.h79
-rw-r--r--attic/astro-desktop/src/astro-appview.c357
-rw-r--r--attic/astro-desktop/src/astro-appview.h84
-rw-r--r--attic/astro-desktop/src/astro-desktop.c316
-rw-r--r--attic/astro-desktop/src/astro-desktop.h75
-rw-r--r--attic/astro-desktop/src/astro-example.c156
-rw-r--r--attic/astro-desktop/src/astro-example.h77
-rw-r--r--attic/astro-desktop/src/astro-panel.c222
-rw-r--r--attic/astro-desktop/src/astro-panel.h83
-rw-r--r--attic/astro-desktop/src/astro-systray.c131
-rw-r--r--attic/astro-desktop/src/astro-systray.h76
-rw-r--r--attic/astro-desktop/src/main.c110
-rw-r--r--attic/fluttr/AUTHORS1
-rw-r--r--attic/fluttr/COPYING340
-rw-r--r--attic/fluttr/ChangeLog740
-rw-r--r--attic/fluttr/INSTALL236
-rw-r--r--attic/fluttr/Makefile.am7
-rw-r--r--attic/fluttr/NEWS0
-rw-r--r--attic/fluttr/README69
-rw-r--r--attic/fluttr/TODO1
-rwxr-xr-xattic/fluttr/autogen.sh3
l---------attic/fluttr/config.guess1
l---------attic/fluttr/config.sub1
-rw-r--r--attic/fluttr/configure.ac28
-rw-r--r--attic/fluttr/data/Makefile.am12
-rw-r--r--attic/fluttr/data/background.svg88
-rw-r--r--attic/fluttr/data/message.svg158
-rw-r--r--attic/fluttr/data/picture.svg950
-rw-r--r--attic/fluttr/data/spinner.svg179
-rw-r--r--attic/fluttr/libnflick/Makefile.am62
-rw-r--r--attic/fluttr/libnflick/nflick-api-request-private.h58
-rw-r--r--attic/fluttr/libnflick/nflick-api-request.c396
-rw-r--r--attic/fluttr/libnflick/nflick-api-request.h62
-rw-r--r--attic/fluttr/libnflick/nflick-api-response-private.h58
-rw-r--r--attic/fluttr/libnflick/nflick-api-response.c337
-rw-r--r--attic/fluttr/libnflick/nflick-api-response.h58
-rw-r--r--attic/fluttr/libnflick/nflick-auth-worker-private.h60
-rw-r--r--attic/fluttr/libnflick/nflick-auth-worker.c278
-rw-r--r--attic/fluttr/libnflick/nflick-auth-worker.h50
-rw-r--r--attic/fluttr/libnflick/nflick-flickr.h69
-rw-r--r--attic/fluttr/libnflick/nflick-get-sizes-response-private.h51
-rw-r--r--attic/fluttr/libnflick/nflick-get-sizes-response.c304
-rw-r--r--attic/fluttr/libnflick/nflick-get-sizes-response.h55
-rw-r--r--attic/fluttr/libnflick/nflick-gft-response-private.h62
-rw-r--r--attic/fluttr/libnflick/nflick-gft-response.c281
-rw-r--r--attic/fluttr/libnflick/nflick-gft-response.h49
-rw-r--r--attic/fluttr/libnflick/nflick-no-set-response-private.h51
-rw-r--r--attic/fluttr/libnflick/nflick-no-set-response.c199
-rw-r--r--attic/fluttr/libnflick/nflick-no-set-response.h52
-rw-r--r--attic/fluttr/libnflick/nflick-photo-data.c75
-rw-r--r--attic/fluttr/libnflick/nflick-photo-data.h44
-rw-r--r--attic/fluttr/libnflick/nflick-photo-list-response-private.h51
-rw-r--r--attic/fluttr/libnflick/nflick-photo-list-response.c195
-rw-r--r--attic/fluttr/libnflick/nflick-photo-list-response.h52
-rw-r--r--attic/fluttr/libnflick/nflick-photo-list-worker-private.h54
-rw-r--r--attic/fluttr/libnflick/nflick-photo-list-worker.c240
-rw-r--r--attic/fluttr/libnflick/nflick-photo-list-worker.h52
-rw-r--r--attic/fluttr/libnflick/nflick-photo-set-private.h59
-rw-r--r--attic/fluttr/libnflick/nflick-photo-set.c242
-rw-r--r--attic/fluttr/libnflick/nflick-photo-set.h53
-rw-r--r--attic/fluttr/libnflick/nflick-pixbuf-fetch-private.h37
-rw-r--r--attic/fluttr/libnflick/nflick-pixbuf-fetch.c172
-rw-r--r--attic/fluttr/libnflick/nflick-pixbuf-fetch.h40
-rw-r--r--attic/fluttr/libnflick/nflick-set-list-response-private.h51
-rw-r--r--attic/fluttr/libnflick/nflick-set-list-response.c212
-rw-r--r--attic/fluttr/libnflick/nflick-set-list-response.h52
-rw-r--r--attic/fluttr/libnflick/nflick-set-list-worker-private.h54
-rw-r--r--attic/fluttr/libnflick/nflick-set-list-worker.c362
-rw-r--r--attic/fluttr/libnflick/nflick-set-list-worker.h55
-rw-r--r--attic/fluttr/libnflick/nflick-show-worker-private.h57
-rw-r--r--attic/fluttr/libnflick/nflick-show-worker.c264
-rw-r--r--attic/fluttr/libnflick/nflick-show-worker.h54
-rw-r--r--attic/fluttr/libnflick/nflick-types.h514
-rw-r--r--attic/fluttr/libnflick/nflick-worker-private.h74
-rw-r--r--attic/fluttr/libnflick/nflick-worker.c454
-rw-r--r--attic/fluttr/libnflick/nflick-worker.h70
-rw-r--r--attic/fluttr/libnflick/nflick.h32
l---------attic/fluttr/ltmain.sh1
-rw-r--r--attic/fluttr/src/Makefile.am42
-rw-r--r--attic/fluttr/src/eggsequence.c1709
-rw-r--r--attic/fluttr/src/eggsequence.h120
-rw-r--r--attic/fluttr/src/fluttr-auth.c433
-rw-r--r--attic/fluttr/src/fluttr-auth.h73
-rw-r--r--attic/fluttr/src/fluttr-behave.c124
-rw-r--r--attic/fluttr/src/fluttr-behave.h74
-rw-r--r--attic/fluttr/src/fluttr-library-row.c222
-rw-r--r--attic/fluttr/src/fluttr-library-row.h69
-rw-r--r--attic/fluttr/src/fluttr-library.c294
-rw-r--r--attic/fluttr/src/fluttr-library.h99
-rw-r--r--attic/fluttr/src/fluttr-list-view.c526
-rw-r--r--attic/fluttr/src/fluttr-list-view.h92
-rw-r--r--attic/fluttr/src/fluttr-list.c622
-rw-r--r--attic/fluttr/src/fluttr-list.h75
-rw-r--r--attic/fluttr/src/fluttr-photo.c983
-rw-r--r--attic/fluttr/src/fluttr-photo.h96
-rw-r--r--attic/fluttr/src/fluttr-set-view.c281
-rw-r--r--attic/fluttr/src/fluttr-set-view.h94
-rw-r--r--attic/fluttr/src/fluttr-set.c554
-rw-r--r--attic/fluttr/src/fluttr-set.h106
-rw-r--r--attic/fluttr/src/fluttr-settings.c197
-rw-r--r--attic/fluttr/src/fluttr-settings.h69
-rw-r--r--attic/fluttr/src/fluttr-spinner.c149
-rw-r--r--attic/fluttr/src/fluttr-spinner.h68
-rw-r--r--attic/fluttr/src/fluttr-viewer.c524
-rw-r--r--attic/fluttr/src/fluttr-viewer.h80
-rw-r--r--attic/fluttr/src/main.c695
-rw-r--r--attic/gcr/Makefile88
-rw-r--r--attic/gcr/README28
-rw-r--r--attic/gcr/custom-cursor.c392
-rw-r--r--attic/gcr/custom-cursor.h77
-rw-r--r--attic/gcr/gcr.c206
-rw-r--r--attic/gcr/gcr.h10
-rw-r--r--attic/gcr/test.c27
-rw-r--r--attic/mallums-magic-browser/Makefile86
-rw-r--r--attic/mallums-magic-browser/README-mozilla16
-rwxr-xr-xattic/mallums-magic-browser/assets/back.pngbin0 -> 2587 bytes
-rwxr-xr-xattic/mallums-magic-browser/assets/bground.pngbin0 -> 6200 bytes
-rw-r--r--attic/mallums-magic-browser/assets/document-new.pngbin0 -> 1008 bytes
-rwxr-xr-xattic/mallums-magic-browser/assets/forward.pngbin0 -> 2593 bytes
-rw-r--r--attic/mallums-magic-browser/assets/go-next.pngbin0 -> 1849 bytes
-rw-r--r--attic/mallums-magic-browser/assets/go-previous.pngbin0 -> 1841 bytes
-rwxr-xr-xattic/mallums-magic-browser/assets/tabs.pngbin0 -> 4587 bytes
-rw-r--r--attic/mallums-magic-browser/assets/toolbar-bg.pngbin0 -> 26595 bytes
-rw-r--r--attic/mallums-magic-browser/popup-factory.c118
-rw-r--r--attic/mallums-magic-browser/popup-factory.h31
-rw-r--r--attic/mallums-magic-browser/scroll-frame.c362
-rw-r--r--attic/mallums-magic-browser/scroll-frame.h33
-rw-r--r--attic/mallums-magic-browser/web-browser-mozilla.c952
-rw-r--r--attic/mallums-magic-browser/web-browser-mozilla.h32
-rw-r--r--attic/mallums-magic-browser/web-browser.c901
-rw-r--r--attic/mallums-magic-browser/web-browser.h32
-rw-r--r--attic/sqlite-model/Makefile13
-rw-r--r--attic/sqlite-model/clutter-sqlite-model.c1110
-rw-r--r--attic/sqlite-model/clutter-sqlite-model.h97
-rw-r--r--attic/sqlite-model/test-sqlite-model.c248
-rw-r--r--attic/table/Makefile14
-rw-r--r--attic/table/clutter-dominatrix.c1008
-rw-r--r--attic/table/clutter-dominatrix.h89
-rw-r--r--attic/table/clutter-video-player.c374
-rw-r--r--attic/table/clutter-video-player.h81
-rw-r--r--attic/table/hand0.pngbin0 -> 6451 bytes
-rw-r--r--attic/table/hand1.pngbin0 -> 6605 bytes
-rw-r--r--attic/table/hand2.pngbin0 -> 7130 bytes
-rw-r--r--attic/table/hand3.pngbin0 -> 6719 bytes
-rw-r--r--attic/table/hand4.pngbin0 -> 6737 bytes
-rw-r--r--attic/table/hand5.pngbin0 -> 6691 bytes
-rw-r--r--attic/table/hand6.pngbin0 -> 7115 bytes
-rw-r--r--attic/table/hand7.pngbin0 -> 7101 bytes
-rw-r--r--attic/table/hand8.pngbin0 -> 7009 bytes
-rw-r--r--attic/table/pause_png.h431
-rw-r--r--attic/table/play_png.h540
-rw-r--r--attic/table/table.c446
-rw-r--r--attic/widgets/Makefile14
-rw-r--r--attic/widgets/clutter-reflect-texture.c340
-rw-r--r--attic/widgets/clutter-reflect-texture.h84
-rw-r--r--attic/widgets/test.c45
-rw-r--r--attic/woohaa/AUTHORS0
-rw-r--r--attic/woohaa/ChangeLog271
-rw-r--r--attic/woohaa/Makefile.am41
-rw-r--r--attic/woohaa/NEWS0
-rw-r--r--attic/woohaa/README25
-rwxr-xr-xattic/woohaa/autogen.sh3
-rw-r--r--attic/woohaa/configure.ac43
-rw-r--r--attic/woohaa/data/Makefile.am4
-rw-r--r--attic/woohaa/data/arrow-down.svg63
-rw-r--r--attic/woohaa/data/arrow-next.svg63
-rw-r--r--attic/woohaa/data/arrow-prev.svg63
-rw-r--r--attic/woohaa/data/arrow-up.svg63
-rw-r--r--attic/woohaa/data/bg.pngbin0 -> 6154 bytes
-rw-r--r--attic/woohaa/data/busy.pngbin0 -> 5716 bytes
-rw-r--r--attic/woohaa/data/default-thumb.pngbin0 -> 1423 bytes
-rw-r--r--attic/woohaa/data/header.svg101
-rw-r--r--attic/woohaa/data/play.svg50
-rw-r--r--attic/woohaa/data/selected.svg122
-rw-r--r--attic/woohaa/data/spinner.svg74
-rw-r--r--attic/woohaa/eggsequence.c1709
-rw-r--r--attic/woohaa/eggsequence.h120
-rw-r--r--attic/woohaa/totem-resources.c121
-rw-r--r--attic/woohaa/totem-resources.h33
-rw-r--r--attic/woohaa/util.c76
-rw-r--r--attic/woohaa/util.h51
-rw-r--r--attic/woohaa/wh-busy.c443
-rw-r--r--attic/woohaa/wh-busy.h62
-rw-r--r--attic/woohaa/wh-db.c648
-rw-r--r--attic/woohaa/wh-db.h54
-rw-r--r--attic/woohaa/wh-screen-video.c706
-rw-r--r--attic/woohaa/wh-screen-video.h58
-rw-r--r--attic/woohaa/wh-slider-menu.c518
-rw-r--r--attic/woohaa/wh-slider-menu.h73
-rw-r--r--attic/woohaa/wh-theme.c78
-rw-r--r--attic/woohaa/wh-theme.h27
-rw-r--r--attic/woohaa/wh-video-model-row.c468
-rw-r--r--attic/woohaa/wh-video-model-row.h103
-rw-r--r--attic/woohaa/wh-video-model.c298
-rw-r--r--attic/woohaa/wh-video-model.h91
-rw-r--r--attic/woohaa/wh-video-row-renderer.c373
-rw-r--r--attic/woohaa/wh-video-row-renderer.h52
-rw-r--r--attic/woohaa/wh-video-thumbnailer.c157
-rw-r--r--attic/woohaa/wh-video-view.c543
-rw-r--r--attic/woohaa/wh-video-view.h93
-rw-r--r--attic/woohaa/woohaa.c782
-rw-r--r--attic/youhaa/AUTHORS0
-rw-r--r--attic/youhaa/ChangeLog106
-rw-r--r--attic/youhaa/Makefile.am7
-rw-r--r--attic/youhaa/NEWS0
-rw-r--r--attic/youhaa/README0
-rwxr-xr-xattic/youhaa/autogen.sh3
-rw-r--r--attic/youhaa/configure.ac36
-rw-r--r--attic/youhaa/data/Makefile.am6
-rw-r--r--attic/youhaa/data/go-next.svg191
-rw-r--r--attic/youhaa/data/go-previous.svg852
-rw-r--r--attic/youhaa/libcurl.m4236
-rw-r--r--attic/youhaa/src/Makefile.am20
-rw-r--r--attic/youhaa/src/glibcurl.c546
-rw-r--r--attic/youhaa/src/glibcurl.h80
-rw-r--r--attic/youhaa/src/yh-main.c377
-rw-r--r--attic/youhaa/src/yh-theme.c14
-rw-r--r--attic/youhaa/src/yh-theme.h24
-rw-r--r--attic/youhaa/src/yh-youtube-browser.c828
-rw-r--r--attic/youhaa/src/yh-youtube-browser.h58
-rw-r--r--attic/youhaa/src/yh-youtube.c826
-rw-r--r--attic/youhaa/src/yh-youtube.h81
-rw-r--r--circles/Makefile13
-rw-r--r--circles/circles.c109
-rw-r--r--courasel/Makefile14
-rw-r--r--courasel/accessories-text-editor.pngbin0 -> 3953 bytes
-rw-r--r--courasel/applications-games.pngbin0 -> 5529 bytes
-rw-r--r--courasel/courasel.c309
-rw-r--r--courasel/dates.pngbin0 -> 4656 bytes
-rw-r--r--courasel/im-client.pngbin0 -> 3934 bytes
-rw-r--r--courasel/preferences-desktop-theme.pngbin0 -> 7306 bytes
-rw-r--r--courasel/tasks.pngbin0 -> 5053 bytes
-rw-r--r--courasel/utilities-terminal.pngbin0 -> 1971 bytes
-rw-r--r--courasel/web-browser.pngbin0 -> 10151 bytes
-rw-r--r--foofone/Makefile14
-rw-r--r--foofone/button.pngbin0 -> 683 bytes
-rw-r--r--foofone/call-background.pngbin0 -> 123785 bytes
-rw-r--r--foofone/display.pngbin0 -> 734 bytes
-rw-r--r--foofone/foofone.c446
-rw-r--r--gps-globe/.gitignore23
-rw-r--r--gps-globe/AUTHORS0
-rw-r--r--gps-globe/COPYING674
-rw-r--r--gps-globe/ChangeLog0
-rw-r--r--gps-globe/INSTALL291
-rw-r--r--gps-globe/Makefile.am1
-rw-r--r--gps-globe/NEWS0
-rw-r--r--gps-globe/README13
-rwxr-xr-xgps-globe/autogen.sh14
-rw-r--r--gps-globe/configure.ac20
-rw-r--r--gps-globe/data/visible-earth.jpgbin0 -> 67099 bytes
-rw-r--r--gps-globe/src/Makefile.am54
-rw-r--r--gps-globe/src/gpsg-enum-types.c.in41
-rw-r--r--gps-globe/src/gpsg-enum-types.h.in26
-rw-r--r--gps-globe/src/gpsg-main.c111
-rw-r--r--gps-globe/src/gpsg-sphere-vertex-shader.glsl49
-rw-r--r--gps-globe/src/gpsg-sphere-vertex-shader.h30
-rw-r--r--gps-globe/src/gpsg-sphere.c940
-rw-r--r--gps-globe/src/gpsg-sphere.h83
-rw-r--r--nyancat/Makefile83
-rw-r--r--nyancat/nyan.json1204
-rw-r--r--nyancat/nyancat.c181
-rw-r--r--nyancat/star.pngbin0 -> 1538 bytes
-rw-r--r--object-store/Makefile36
-rw-r--r--object-store/foo-object-store-testbin0 -> 12855268 bytes
-rw-r--r--object-store/foo-object-store.c749
-rw-r--r--object-store/foo-object-store.h75
-rw-r--r--object-store/foo-test-object.c184
-rw-r--r--object-store/foo-test-object.h76
-rw-r--r--object-store/object-store-example.c230
-rw-r--r--object-store/object-store-test.c364
-rw-r--r--odo/Makefile14
-rw-r--r--odo/README8
-rw-r--r--odo/grid.pngbin0 -> 839 bytes
-rw-r--r--odo/neghand.pngbin0 -> 8315 bytes
-rw-r--r--odo/odo-distort-funcs.c137
-rw-r--r--odo/odo-distort-funcs.h41
-rw-r--r--odo/odo-texture.c641
-rw-r--r--odo/odo-texture.h84
-rw-r--r--odo/odo.c139
-rw-r--r--odo/oh-logo.pngbin0 -> 11993 bytes
-rw-r--r--odo/redhand.pngbin0 -> 8250 bytes
-rw-r--r--opt/.gitignore17
-rw-r--r--opt/AUTHORS0
-rw-r--r--opt/ChangeLog365
-rw-r--r--opt/Makefile.am24
-rw-r--r--opt/NEWS0
-rw-r--r--opt/README6
-rwxr-xr-xopt/autogen.sh3
-rw-r--r--opt/bg.pngbin0 -> 122701 bytes
-rw-r--r--opt/configure.ac24
-rw-r--r--opt/demo.xml69
-rw-r--r--opt/hirez/oh-present.xcfbin0 -> 1474567 bytes
-rw-r--r--opt/kitten.jpgbin0 -> 3941 bytes
-rw-r--r--opt/kitten2.jpgbin0 -> 22802 bytes
-rw-r--r--opt/opt-config.c759
-rw-r--r--opt/opt-menu.c496
-rw-r--r--opt/opt-menu.h55
-rw-r--r--opt/opt-show.c695
-rw-r--r--opt/opt-show.h83
-rw-r--r--opt/opt-slide.c319
-rw-r--r--opt/opt-slide.h94
-rw-r--r--opt/opt-transition.c459
-rw-r--r--opt/opt-transition.h94
-rw-r--r--opt/opt.c225
-rw-r--r--opt/opt.doap41
-rw-r--r--opt/opt.dtd36
-rw-r--r--opt/opt.h22
-rw-r--r--opt/powers.pngbin0 -> 29901 bytes
-rw-r--r--opt/test.xml59
-rw-r--r--packaging/clutter-toys.spec86
-rw-r--r--patches/fix-colors.patch24
-rw-r--r--patches/fix-image-path.patch56
-rw-r--r--patches/map-escape-key-to-quit.patch142
-rw-r--r--pong/Makefile15
-rw-r--r--pong/pong-ball.pngbin0 -> 1089 bytes
-rw-r--r--pong/pong-bat.pngbin0 -> 972 bytes
-rw-r--r--pong/pong2.c412
-rw-r--r--ripples/Makefile13
-rw-r--r--ripples/ripples.c131
-rw-r--r--script-viewer/.gitignore2
-rw-r--r--script-viewer/COPYING504
-rw-r--r--script-viewer/ChangeLog48
-rw-r--r--script-viewer/Makefile83
-rw-r--r--script-viewer/README56
-rw-r--r--script-viewer/alphas.json186
-rw-r--r--script-viewer/behaviours.json140
-rw-r--r--script-viewer/redhand.pngbin0 -> 8250 bytes
-rw-r--r--script-viewer/script-viewer.c239
-rw-r--r--script-viewer/test-script.json70
-rw-r--r--script-viewer/text.json102
525 files changed, 79663 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
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
index 0000000..620bbd9
--- /dev/null
+++ b/arc-clock/Makefile
@@ -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
index 0000000..b455752
--- /dev/null
+++ b/arc-clock/arc-clock.c
@@ -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
index 0000000..efdbb94
--- /dev/null
+++ b/attic/aaina/AUTHORS
@@ -0,0 +1 @@
+Neil J. Patel <njp@o-hand.com>
diff --git a/attic/aaina/ChangeLog b/attic/aaina/ChangeLog
new file mode 100644
index 0000000..07e5bc5
--- /dev/null
+++ b/attic/aaina/ChangeLog
@@ -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
index 0000000..c777c14
--- /dev/null
+++ b/attic/aaina/Makefile.am
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/aaina/NEWS
diff --git a/attic/aaina/README b/attic/aaina/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/attic/aaina/README
diff --git a/attic/aaina/TODO b/attic/aaina/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/attic/aaina/TODO
diff --git a/attic/aaina/autogen.sh b/attic/aaina/autogen.sh
new file mode 100755
index 0000000..b1376df
--- /dev/null
+++ b/attic/aaina/autogen.sh
@@ -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
index 0000000..6e18348
--- /dev/null
+++ b/attic/aaina/configure.ac
@@ -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
index 0000000..db9f285
--- /dev/null
+++ b/attic/aaina/libaaina/Makefile.am
@@ -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
index 0000000..24c5936
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-behave.c
@@ -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
index 0000000..dee6649
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-behave.h
@@ -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
index 0000000..0b6aedf
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-library.c
@@ -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
index 0000000..725fd96
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-library.h
@@ -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
index 0000000..664a4b8
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-photo.c
@@ -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
index 0000000..ec3d7db
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-photo.h
@@ -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
index 0000000..e51f340
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-source.c
@@ -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
index 0000000..707f4b3
--- /dev/null
+++ b/attic/aaina/libaaina/aaina-source.h
@@ -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
index 0000000..4c90101
--- /dev/null
+++ b/attic/aaina/libaaina/clutter-texture-label.c
@@ -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
index 0000000..eada401
--- /dev/null
+++ b/attic/aaina/libaaina/clutter-texture-label.h
@@ -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
index 0000000..979a512
--- /dev/null
+++ b/attic/aaina/libaaina/eggsequence.c
@@ -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
index 0000000..107db47
--- /dev/null
+++ b/attic/aaina/libaaina/eggsequence.h
@@ -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
index 0000000..344968d
--- /dev/null
+++ b/attic/aaina/libnflick/Makefile.am
@@ -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
index 0000000..99f84dd
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-api-request-private.h
@@ -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
index 0000000..9986143
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-api-request.c
@@ -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
index 0000000..8853e46
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-api-request.h
@@ -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
index 0000000..38bb074
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-api-response-private.h
@@ -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
index 0000000..244cd81
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-api-response.c
@@ -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
index 0000000..9778872
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-api-response.h
@@ -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
index 0000000..dfdbdac
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-auth-worker-private.h
@@ -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
index 0000000..c23d610
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-auth-worker.c
@@ -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
index 0000000..807e4ec
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-auth-worker.h
@@ -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
index 0000000..67d88d1
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-flickr.h
@@ -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
index 0000000..4853bd5
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-get-sizes-response-private.h
@@ -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
index 0000000..d7cf12a
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-get-sizes-response.c
@@ -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
index 0000000..bf2a304
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-get-sizes-response.h
@@ -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
index 0000000..dd8a54d
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-gft-response-private.h
@@ -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
index 0000000..a38e04d
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-gft-response.c
@@ -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
index 0000000..cd67b4a
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-gft-response.h
@@ -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
index 0000000..f2c7fbf
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-info-response-private.h
@@ -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
index 0000000..dc94fa9
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-info-response.c
@@ -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
index 0000000..5de6787
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-info-response.h
@@ -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
index 0000000..104da49
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-info-worker-private.h
@@ -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
index 0000000..9c211d2
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-info-worker.c
@@ -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
index 0000000..92ce505
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-info-worker.h
@@ -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
index 0000000..e71c6aa
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-no-set-response-private.h
@@ -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
index 0000000..b215c4e
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-no-set-response.c
@@ -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
index 0000000..623c42f
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-no-set-response.h
@@ -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
index 0000000..9954732
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-data.c
@@ -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
index 0000000..5a156d2
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-data.h
@@ -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
index 0000000..c8920ab
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-list-response-private.h
@@ -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
index 0000000..0941181
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-list-response.c
@@ -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
index 0000000..2b6b3f7
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-list-response.h
@@ -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
index 0000000..b2b84ab
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-list-worker-private.h
@@ -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
index 0000000..9d75c17
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-list-worker.c
@@ -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
index 0000000..03de657
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-list-worker.h
@@ -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
index 0000000..64cd6bd
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-search-response-private.h
@@ -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
index 0000000..130119a
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-search-response.c
@@ -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
index 0000000..7a7227a
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-search-response.h
@@ -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
index 0000000..c07f371
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-search-worker-private.h
@@ -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
index 0000000..f21adbd
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-search-worker.c
@@ -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
index 0000000..6d8764b
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-search-worker.h
@@ -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
index 0000000..4c6e745
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-set-private.h
@@ -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
index 0000000..5bd4483
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-set.c
@@ -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
index 0000000..a322962
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-photo-set.h
@@ -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
index 0000000..460b369
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-pixbuf-fetch-private.h
@@ -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
index 0000000..8892907
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-pixbuf-fetch.c
@@ -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
index 0000000..8def879
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-pixbuf-fetch.h
@@ -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
index 0000000..0634c58
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-set-list-response-private.h
@@ -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
index 0000000..abaa761
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-set-list-response.c
@@ -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
index 0000000..6e0d45d
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-set-list-response.h
@@ -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
index 0000000..7dc1742
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-set-list-worker-private.h
@@ -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
index 0000000..024ab1f
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-set-list-worker.c
@@ -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
index 0000000..d7105c7
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-set-list-worker.h
@@ -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
index 0000000..417fa75
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-show-worker-private.h
@@ -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
index 0000000..e2ab692
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-show-worker.c
@@ -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
index 0000000..a17faf9
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-show-worker.h
@@ -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
index 0000000..11566cd
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-types.h
@@ -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
index 0000000..884f364
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-worker-private.h
@@ -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
index 0000000..b618a72
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-worker.c
@@ -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
index 0000000..b1c1a4f
--- /dev/null
+++ b/attic/aaina/libnflick/nflick-worker.h
@@ -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
index 0000000..027ea59
--- /dev/null
+++ b/attic/aaina/libnflick/nflick.h
@@ -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
index 0000000..d6c2b13
--- /dev/null
+++ b/attic/aaina/sources/Makefile.am
@@ -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
index 0000000..8a73039
--- /dev/null
+++ b/attic/aaina/sources/aaina-source-directory.c
@@ -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
index 0000000..fe19ed1
--- /dev/null
+++ b/attic/aaina/sources/aaina-source-directory.h
@@ -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
index 0000000..2fec200
--- /dev/null
+++ b/attic/aaina/sources/aaina-source-flickr.c
@@ -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
index 0000000..0821435
--- /dev/null
+++ b/attic/aaina/sources/aaina-source-flickr.h
@@ -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
index 0000000..f1e696d
--- /dev/null
+++ b/attic/aaina/src/Makefile.am
@@ -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
index 0000000..6a9f490
--- /dev/null
+++ b/attic/aaina/src/aaina-slide-show.c
@@ -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
index 0000000..5fffe9f
--- /dev/null
+++ b/attic/aaina/src/aaina-slide-show.h
@@ -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
index 0000000..32ca421
--- /dev/null
+++ b/attic/aaina/src/main.c
@@ -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
index 0000000..8ec34a6
--- /dev/null
+++ b/attic/astro-desktop/AUTHORS
@@ -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
index 0000000..9032ae9
--- /dev/null
+++ b/attic/astro-desktop/ChangeLog
@@ -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
index 0000000..bb184fd
--- /dev/null
+++ b/attic/astro-desktop/Makefile.am
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/astro-desktop/NEWS
diff --git a/attic/astro-desktop/README b/attic/astro-desktop/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/attic/astro-desktop/README
diff --git a/attic/astro-desktop/applets/Makefile.am b/attic/astro-desktop/applets/Makefile.am
new file mode 100644
index 0000000..9294d8a
--- /dev/null
+++ b/attic/astro-desktop/applets/Makefile.am
@@ -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
index 0000000..697867f
--- /dev/null
+++ b/attic/astro-desktop/applets/cal.json
@@ -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
index 0000000..fca6460
--- /dev/null
+++ b/attic/astro-desktop/applets/cal.png
Binary files differ
diff --git a/attic/astro-desktop/applets/clock.json b/attic/astro-desktop/applets/clock.json
new file mode 100644
index 0000000..26c58bd
--- /dev/null
+++ b/attic/astro-desktop/applets/clock.json
@@ -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
index 0000000..13bb265
--- /dev/null
+++ b/attic/astro-desktop/applets/clock.png
Binary files differ
diff --git a/attic/astro-desktop/applets/clouds.png b/attic/astro-desktop/applets/clouds.png
new file mode 100644
index 0000000..87e1db0
--- /dev/null
+++ b/attic/astro-desktop/applets/clouds.png
Binary files differ
diff --git a/attic/astro-desktop/applets/mail.json b/attic/astro-desktop/applets/mail.json
new file mode 100644
index 0000000..fb76c26
--- /dev/null
+++ b/attic/astro-desktop/applets/mail.json
@@ -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
index 0000000..5ad6e41
--- /dev/null
+++ b/attic/astro-desktop/applets/mail.png
Binary files differ
diff --git a/attic/astro-desktop/applets/weather.json b/attic/astro-desktop/applets/weather.json
new file mode 100644
index 0000000..c9556b0
--- /dev/null
+++ b/attic/astro-desktop/applets/weather.json
@@ -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
index 0000000..14da3fd
--- /dev/null
+++ b/attic/astro-desktop/applications/Makefile.am
@@ -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
index 0000000..14679e0
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/Makefile.am
@@ -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
index 0000000..a1b3556
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contact-row.c
@@ -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
index 0000000..e84f271
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contact-row.h
@@ -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
index 0000000..93f3490
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contacts-details.c
@@ -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
index 0000000..a475e06
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contacts-details.h
@@ -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
index 0000000..aeb8b55
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contacts-window.c
@@ -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
index 0000000..7050392
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contacts-window.h
@@ -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
index 0000000..73d8510
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contacts.c
@@ -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
index 0000000..a755262
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-contacts.h
@@ -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
index 0000000..a9feb43
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-reflection.c
@@ -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
index 0000000..1d71ea9
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-reflection.h
@@ -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
index 0000000..fa1d616
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-texture-group.c
@@ -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
index 0000000..1efb939
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/astro-texture-group.h
@@ -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
index 0000000..5689d49
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/clutter-reflect-texture.c
@@ -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
index 0000000..9ba7353
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/clutter-reflect-texture.h
@@ -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
index 0000000..d693877
--- /dev/null
+++ b/attic/astro-desktop/applications/contacts/init.c
@@ -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
index 0000000..5e008b9
--- /dev/null
+++ b/attic/astro-desktop/applications/example/Makefile.am
@@ -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
index 0000000..fadb7c6
--- /dev/null
+++ b/attic/astro-desktop/applications/example/astro-example.c
@@ -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
index 0000000..a452ecb
--- /dev/null
+++ b/attic/astro-desktop/applications/example/astro-example.h
@@ -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
index 0000000..4d54fdd
--- /dev/null
+++ b/attic/astro-desktop/applications/example/init.c
@@ -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
index 0000000..1eee4a5
--- /dev/null
+++ b/attic/astro-desktop/applications/images/Makefile.am
@@ -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
index 0000000..7919147
--- /dev/null
+++ b/attic/astro-desktop/applications/images/astro-images-window.c
@@ -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
index 0000000..f3995ea
--- /dev/null
+++ b/attic/astro-desktop/applications/images/astro-images-window.h
@@ -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
index 0000000..e4e8d47
--- /dev/null
+++ b/attic/astro-desktop/applications/images/astro-images.c
@@ -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
index 0000000..012d58b
--- /dev/null
+++ b/attic/astro-desktop/applications/images/astro-images.h
@@ -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
index 0000000..5689d49
--- /dev/null
+++ b/attic/astro-desktop/applications/images/clutter-reflect-texture.c
@@ -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
index 0000000..9ba7353
--- /dev/null
+++ b/attic/astro-desktop/applications/images/clutter-reflect-texture.h
@@ -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
index 0000000..4fab13f
--- /dev/null
+++ b/attic/astro-desktop/applications/images/init.c
@@ -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
index 0000000..98b669f
--- /dev/null
+++ b/attic/astro-desktop/applications/music/Makefile.am
@@ -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
index 0000000..8a25165
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-music-window.c
@@ -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
index 0000000..fc590e9
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-music-window.h
@@ -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
index 0000000..4f1594b
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-music.c
@@ -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
index 0000000..05c5d5a
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-music.h
@@ -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
index 0000000..87e9cc5
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-reflection.c
@@ -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
index 0000000..1d71ea9
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-reflection.h
@@ -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
index 0000000..dcdd774
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-songs.c
@@ -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
index 0000000..21fa78c
--- /dev/null
+++ b/attic/astro-desktop/applications/music/astro-songs.h
@@ -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
index 0000000..5689d49
--- /dev/null
+++ b/attic/astro-desktop/applications/music/clutter-reflect-texture.c
@@ -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
index 0000000..9ba7353
--- /dev/null
+++ b/attic/astro-desktop/applications/music/clutter-reflect-texture.h
@@ -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
index 0000000..7d17570
--- /dev/null
+++ b/attic/astro-desktop/applications/music/init.c
@@ -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
index 0000000..b1376df
--- /dev/null
+++ b/attic/astro-desktop/autogen.sh
@@ -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
index 0000000..10f06a0
--- /dev/null
+++ b/attic/astro-desktop/configure.ac
@@ -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
index 0000000..7a73690
--- /dev/null
+++ b/attic/astro-desktop/data/Makefile.am
@@ -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
index 0000000..36e2745
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpg
Binary files 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
index 0000000..7dab931
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg
Binary files 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
index 0000000..133687e
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg
Binary files 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
index 0000000..5ce60bd
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpg
Binary files differ
diff --git a/attic/astro-desktop/data/albums/Makefile.am b/attic/astro-desktop/data/albums/Makefile.am
new file mode 100644
index 0000000..a804798
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Makefile.am
@@ -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
index 0000000..04de882
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg
Binary files 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
index 0000000..ad75622
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg
Binary files 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
index 0000000..216fbcc
--- /dev/null
+++ b/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg
Binary files differ
diff --git a/attic/astro-desktop/data/applet_bg.png b/attic/astro-desktop/data/applet_bg.png
new file mode 100644
index 0000000..9d25c90
--- /dev/null
+++ b/attic/astro-desktop/data/applet_bg.png
Binary files differ
diff --git a/attic/astro-desktop/data/background.svg b/attic/astro-desktop/data/background.svg
new file mode 100644
index 0000000..03d9b16
--- /dev/null
+++ b/attic/astro-desktop/data/background.svg
Binary files differ
diff --git a/attic/astro-desktop/data/contact-bar.svg b/attic/astro-desktop/data/contact-bar.svg
new file mode 100644
index 0000000..a3f549e
--- /dev/null
+++ b/attic/astro-desktop/data/contact-bar.svg
@@ -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
index 0000000..9749d8b
--- /dev/null
+++ b/attic/astro-desktop/data/contact.png
Binary files differ
diff --git a/attic/astro-desktop/data/disc_bg.svg b/attic/astro-desktop/data/disc_bg.svg
new file mode 100644
index 0000000..eb0731c
--- /dev/null
+++ b/attic/astro-desktop/data/disc_bg.svg
@@ -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
index 0000000..5fca186
--- /dev/null
+++ b/attic/astro-desktop/data/face.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/Makefile.am b/attic/astro-desktop/data/icons/Makefile.am
new file mode 100644
index 0000000..afaa4d1
--- /dev/null
+++ b/attic/astro-desktop/data/icons/Makefile.am
@@ -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
index 0000000..2b29dc5
--- /dev/null
+++ b/attic/astro-desktop/data/icons/bt.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/close.png b/attic/astro-desktop/data/icons/close.png
new file mode 100644
index 0000000..f17b36c
--- /dev/null
+++ b/attic/astro-desktop/data/icons/close.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/contacts.png b/attic/astro-desktop/data/icons/contacts.png
new file mode 100644
index 0000000..d37e990
--- /dev/null
+++ b/attic/astro-desktop/data/icons/contacts.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/exec.png b/attic/astro-desktop/data/icons/exec.png
new file mode 100644
index 0000000..7c4abdb
--- /dev/null
+++ b/attic/astro-desktop/data/icons/exec.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/home.png b/attic/astro-desktop/data/icons/home.png
new file mode 100644
index 0000000..f165f03
--- /dev/null
+++ b/attic/astro-desktop/data/icons/home.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/images.png b/attic/astro-desktop/data/icons/images.png
new file mode 100644
index 0000000..0432e78
--- /dev/null
+++ b/attic/astro-desktop/data/icons/images.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/music.png b/attic/astro-desktop/data/icons/music.png
new file mode 100644
index 0000000..637be83
--- /dev/null
+++ b/attic/astro-desktop/data/icons/music.png
Binary files differ
diff --git a/attic/astro-desktop/data/icons/nm.png b/attic/astro-desktop/data/icons/nm.png
new file mode 100644
index 0000000..a3d973e
--- /dev/null
+++ b/attic/astro-desktop/data/icons/nm.png
Binary files differ
diff --git a/attic/astro-desktop/data/info_bg.png b/attic/astro-desktop/data/info_bg.png
new file mode 100644
index 0000000..b9f5fcc
--- /dev/null
+++ b/attic/astro-desktop/data/info_bg.png
Binary files differ
diff --git a/attic/astro-desktop/libastro-desktop/Makefile.am b/attic/astro-desktop/libastro-desktop/Makefile.am
new file mode 100644
index 0000000..354f018
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/Makefile.am
@@ -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
index 0000000..cf907e6
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-application.c
@@ -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
index 0000000..4ae43df
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-application.h
@@ -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
index 0000000..00b7c56
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-behave.c
@@ -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
index 0000000..164495d
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-behave.h
@@ -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
index 0000000..705a1f4
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-defines.h
@@ -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
index 0000000..26c872a
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-utils.c
@@ -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
index 0000000..f8528fc
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-utils.h
@@ -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
index 0000000..54bc88c
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-window.c
@@ -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
index 0000000..73c3ab6
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro-window.h
@@ -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
index 0000000..2fa048c
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/astro.h
@@ -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
index 0000000..5f17d93
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/tidy-private.h
@@ -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
index 0000000..8bc91c0
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/tidy-texture-frame.c
@@ -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
index 0000000..87d2d04
--- /dev/null
+++ b/attic/astro-desktop/libastro-desktop/tidy-texture-frame.h
@@ -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
index 0000000..2228260
--- /dev/null
+++ b/attic/astro-desktop/src/Makefile.am
@@ -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
index 0000000..9ce40ff
--- /dev/null
+++ b/attic/astro-desktop/src/astro-appicon.c
@@ -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
index 0000000..a33b938
--- /dev/null
+++ b/attic/astro-desktop/src/astro-appicon.h
@@ -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
index 0000000..380d782
--- /dev/null
+++ b/attic/astro-desktop/src/astro-applet-manager.c
@@ -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
index 0000000..dd07ce2
--- /dev/null
+++ b/attic/astro-desktop/src/astro-applet-manager.h
@@ -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
index 0000000..d897758
--- /dev/null
+++ b/attic/astro-desktop/src/astro-applet.c
@@ -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
index 0000000..2ad9705
--- /dev/null
+++ b/attic/astro-desktop/src/astro-applet.h
@@ -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
index 0000000..b65f27d
--- /dev/null
+++ b/attic/astro-desktop/src/astro-appview.c
@@ -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
index 0000000..2e5c7b5
--- /dev/null
+++ b/attic/astro-desktop/src/astro-appview.h
@@ -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
index 0000000..4129743
--- /dev/null
+++ b/attic/astro-desktop/src/astro-desktop.c
@@ -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
index 0000000..ea6d539
--- /dev/null
+++ b/attic/astro-desktop/src/astro-desktop.h
@@ -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
index 0000000..ff73340
--- /dev/null
+++ b/attic/astro-desktop/src/astro-example.c
@@ -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
index 0000000..87c06a5
--- /dev/null
+++ b/attic/astro-desktop/src/astro-example.h
@@ -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
index 0000000..df600ce
--- /dev/null
+++ b/attic/astro-desktop/src/astro-panel.c
@@ -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
index 0000000..ec81149
--- /dev/null
+++ b/attic/astro-desktop/src/astro-panel.h
@@ -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
index 0000000..449cb4c
--- /dev/null
+++ b/attic/astro-desktop/src/astro-systray.c
@@ -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
index 0000000..5042636
--- /dev/null
+++ b/attic/astro-desktop/src/astro-systray.h
@@ -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
index 0000000..a7f3fec
--- /dev/null
+++ b/attic/astro-desktop/src/main.c
@@ -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
index 0000000..8ec34a6
--- /dev/null
+++ b/attic/fluttr/AUTHORS
@@ -0,0 +1 @@
+Neil J. Patel <njp@o-hand.com>
diff --git a/attic/fluttr/COPYING b/attic/fluttr/COPYING
new file mode 100644
index 0000000..623b625
--- /dev/null
+++ b/attic/fluttr/COPYING
@@ -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.
+
+ 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.)
+
+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.
+
+ 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.
+
+ 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
+
+ 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
index 0000000..7c71cb1
--- /dev/null
+++ b/attic/fluttr/ChangeLog
@@ -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
index 0000000..23e5f25
--- /dev/null
+++ b/attic/fluttr/INSTALL
@@ -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
index 0000000..7dba0bf
--- /dev/null
+++ b/attic/fluttr/Makefile.am
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/fluttr/NEWS
diff --git a/attic/fluttr/README b/attic/fluttr/README
new file mode 100644
index 0000000..b21d2e7
--- /dev/null
+++ b/attic/fluttr/README
@@ -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
index 0000000..8b13789
--- /dev/null
+++ b/attic/fluttr/TODO
@@ -0,0 +1 @@
+
diff --git a/attic/fluttr/autogen.sh b/attic/fluttr/autogen.sh
new file mode 100755
index 0000000..b1376df
--- /dev/null
+++ b/attic/fluttr/autogen.sh
@@ -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
index 0000000..d0bb19b
--- /dev/null
+++ b/attic/fluttr/config.guess
@@ -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
index 0000000..31a57ca
--- /dev/null
+++ b/attic/fluttr/config.sub
@@ -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
index 0000000..02fcd08
--- /dev/null
+++ b/attic/fluttr/configure.ac
@@ -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
index 0000000..4754dd6
--- /dev/null
+++ b/attic/fluttr/data/Makefile.am
@@ -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
index 0000000..b3e1b2a
--- /dev/null
+++ b/attic/fluttr/data/background.svg
@@ -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
index 0000000..64daef9
--- /dev/null
+++ b/attic/fluttr/data/message.svg
@@ -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
index 0000000..7d17d9f
--- /dev/null
+++ b/attic/fluttr/data/picture.svg
@@ -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
index 0000000..62e6a18
--- /dev/null
+++ b/attic/fluttr/data/spinner.svg
@@ -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
index 0000000..faf1134
--- /dev/null
+++ b/attic/fluttr/libnflick/Makefile.am
@@ -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
index 0000000..99f84dd
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-api-request-private.h
@@ -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
index 0000000..9986143
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-api-request.c
@@ -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
index 0000000..8853e46
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-api-request.h
@@ -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
index 0000000..38bb074
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-api-response-private.h
@@ -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
index 0000000..1313a9d
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-api-response.c
@@ -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
index 0000000..9778872
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-api-response.h
@@ -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
index 0000000..dfdbdac
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-auth-worker-private.h
@@ -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
index 0000000..c23d610
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-auth-worker.c
@@ -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
index 0000000..807e4ec
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-auth-worker.h
@@ -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
index 0000000..2183262
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-flickr.h
@@ -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
index 0000000..4853bd5
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-get-sizes-response-private.h
@@ -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
index 0000000..d7cf12a
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-get-sizes-response.c
@@ -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
index 0000000..bf2a304
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-get-sizes-response.h
@@ -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
index 0000000..dd8a54d
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-gft-response-private.h
@@ -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
index 0000000..a38e04d
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-gft-response.c
@@ -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
index 0000000..cd67b4a
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-gft-response.h
@@ -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
index 0000000..e71c6aa
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-no-set-response-private.h
@@ -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
index 0000000..b215c4e
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-no-set-response.c
@@ -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
index 0000000..623c42f
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-no-set-response.h
@@ -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
index 0000000..9954732
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-data.c
@@ -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
index 0000000..5a156d2
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-data.h
@@ -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
index 0000000..c8920ab
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-list-response-private.h
@@ -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
index 0000000..0941181
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-list-response.c
@@ -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
index 0000000..2b6b3f7
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-list-response.h
@@ -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
index 0000000..b2b84ab
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-list-worker-private.h
@@ -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
index 0000000..9d75c17
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-list-worker.c
@@ -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
index 0000000..03de657
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-list-worker.h
@@ -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
index 0000000..4c6e745
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-set-private.h
@@ -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
index 0000000..5bd4483
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-set.c
@@ -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
index 0000000..a322962
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-photo-set.h
@@ -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
index 0000000..460b369
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-pixbuf-fetch-private.h
@@ -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
index 0000000..8892907
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-pixbuf-fetch.c
@@ -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
index 0000000..8def879
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-pixbuf-fetch.h
@@ -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
index 0000000..0634c58
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-set-list-response-private.h
@@ -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
index 0000000..abaa761
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-set-list-response.c
@@ -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
index 0000000..6e0d45d
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-set-list-response.h
@@ -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
index 0000000..7dc1742
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-set-list-worker-private.h
@@ -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
index 0000000..024ab1f
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-set-list-worker.c
@@ -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
index 0000000..d7105c7
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-set-list-worker.h
@@ -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
index 0000000..417fa75
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-show-worker-private.h
@@ -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
index 0000000..10bc3d5
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-show-worker.c
@@ -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
index 0000000..a17faf9
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-show-worker.h
@@ -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
index 0000000..61b0e46
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-types.h
@@ -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
index 0000000..884f364
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-worker-private.h
@@ -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
index 0000000..b618a72
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-worker.c
@@ -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
index 0000000..b1c1a4f
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick-worker.h
@@ -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
index 0000000..3769917
--- /dev/null
+++ b/attic/fluttr/libnflick/nflick.h
@@ -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
index 0000000..72940b6
--- /dev/null
+++ b/attic/fluttr/ltmain.sh
@@ -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
index 0000000..aee400c
--- /dev/null
+++ b/attic/fluttr/src/Makefile.am
@@ -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
index 0000000..979a512
--- /dev/null
+++ b/attic/fluttr/src/eggsequence.c
@@ -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
index 0000000..107db47
--- /dev/null
+++ b/attic/fluttr/src/eggsequence.h
@@ -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
index 0000000..9507012
--- /dev/null
+++ b/attic/fluttr/src/fluttr-auth.c
@@ -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
index 0000000..f46a267
--- /dev/null
+++ b/attic/fluttr/src/fluttr-auth.h
@@ -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
index 0000000..c676f70
--- /dev/null
+++ b/attic/fluttr/src/fluttr-behave.c
@@ -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
index 0000000..c4b7629
--- /dev/null
+++ b/attic/fluttr/src/fluttr-behave.h
@@ -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
index 0000000..315d2d3
--- /dev/null
+++ b/attic/fluttr/src/fluttr-library-row.c
@@ -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
index 0000000..e5012db
--- /dev/null
+++ b/attic/fluttr/src/fluttr-library-row.h
@@ -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
index 0000000..394f6ea
--- /dev/null
+++ b/attic/fluttr/src/fluttr-library.c
@@ -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
index 0000000..42c9bef
--- /dev/null
+++ b/attic/fluttr/src/fluttr-library.h
@@ -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
index 0000000..7e05f83
--- /dev/null
+++ b/attic/fluttr/src/fluttr-list-view.c
@@ -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
index 0000000..901e6c3
--- /dev/null
+++ b/attic/fluttr/src/fluttr-list-view.h
@@ -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
index 0000000..0fe38ee
--- /dev/null
+++ b/attic/fluttr/src/fluttr-list.c
@@ -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
index 0000000..7cd14cf
--- /dev/null
+++ b/attic/fluttr/src/fluttr-list.h
@@ -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
index 0000000..061c901
--- /dev/null
+++ b/attic/fluttr/src/fluttr-photo.c
@@ -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
index 0000000..c952f69
--- /dev/null
+++ b/attic/fluttr/src/fluttr-photo.h
@@ -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
index 0000000..6d0f849
--- /dev/null
+++ b/attic/fluttr/src/fluttr-set-view.c
@@ -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
index 0000000..a316bfe
--- /dev/null
+++ b/attic/fluttr/src/fluttr-set-view.h
@@ -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
index 0000000..f54b1b4
--- /dev/null
+++ b/attic/fluttr/src/fluttr-set.c
@@ -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
index 0000000..8171518
--- /dev/null
+++ b/attic/fluttr/src/fluttr-set.h
@@ -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
index 0000000..75b6623
--- /dev/null
+++ b/attic/fluttr/src/fluttr-settings.c
@@ -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
index 0000000..59604ab
--- /dev/null
+++ b/attic/fluttr/src/fluttr-settings.h
@@ -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
index 0000000..b31066c
--- /dev/null
+++ b/attic/fluttr/src/fluttr-spinner.c
@@ -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
index 0000000..7bfb364
--- /dev/null
+++ b/attic/fluttr/src/fluttr-spinner.h
@@ -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
index 0000000..fa1c367
--- /dev/null
+++ b/attic/fluttr/src/fluttr-viewer.c
@@ -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
index 0000000..43cb9ba
--- /dev/null
+++ b/attic/fluttr/src/fluttr-viewer.h
@@ -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
index 0000000..c394c3f
--- /dev/null
+++ b/attic/fluttr/src/main.c
@@ -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
index 0000000..7e88452
--- /dev/null
+++ b/attic/gcr/Makefile
@@ -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
index 0000000..4843649
--- /dev/null
+++ b/attic/gcr/README
@@ -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
index 0000000..dfda6e7
--- /dev/null
+++ b/attic/gcr/custom-cursor.c
@@ -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
index 0000000..f40f830
--- /dev/null
+++ b/attic/gcr/custom-cursor.h
@@ -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
index 0000000..68888e3
--- /dev/null
+++ b/attic/gcr/gcr.c
@@ -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
index 0000000..a0f56e8
--- /dev/null
+++ b/attic/gcr/gcr.h
@@ -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
index 0000000..95f3490
--- /dev/null
+++ b/attic/gcr/test.c
@@ -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
index 0000000..875a5dd
--- /dev/null
+++ b/attic/mallums-magic-browser/Makefile
@@ -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
index 0000000..a033441
--- /dev/null
+++ b/attic/mallums-magic-browser/README-mozilla
@@ -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
index 0000000..a7617db
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/back.png
Binary files differ
diff --git a/attic/mallums-magic-browser/assets/bground.png b/attic/mallums-magic-browser/assets/bground.png
new file mode 100755
index 0000000..0d5b4c3
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/bground.png
Binary files 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
index 0000000..e6d64bb
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/document-new.png
Binary files differ
diff --git a/attic/mallums-magic-browser/assets/forward.png b/attic/mallums-magic-browser/assets/forward.png
new file mode 100755
index 0000000..266200d
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/forward.png
Binary files 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
index 0000000..036e432
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/go-next.png
Binary files 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
index 0000000..895ce33
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/go-previous.png
Binary files differ
diff --git a/attic/mallums-magic-browser/assets/tabs.png b/attic/mallums-magic-browser/assets/tabs.png
new file mode 100755
index 0000000..f872e21
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/tabs.png
Binary files 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
index 0000000..21fbd7d
--- /dev/null
+++ b/attic/mallums-magic-browser/assets/toolbar-bg.png
Binary files differ
diff --git a/attic/mallums-magic-browser/popup-factory.c b/attic/mallums-magic-browser/popup-factory.c
new file mode 100644
index 0000000..985416d
--- /dev/null
+++ b/attic/mallums-magic-browser/popup-factory.c
@@ -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
index 0000000..0ec3d41
--- /dev/null
+++ b/attic/mallums-magic-browser/popup-factory.h
@@ -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
index 0000000..27ac97a
--- /dev/null
+++ b/attic/mallums-magic-browser/scroll-frame.c
@@ -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
index 0000000..6577a63
--- /dev/null
+++ b/attic/mallums-magic-browser/scroll-frame.h
@@ -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
index 0000000..a4ea56e
--- /dev/null
+++ b/attic/mallums-magic-browser/web-browser-mozilla.c
@@ -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
index 0000000..9d39ad0
--- /dev/null
+++ b/attic/mallums-magic-browser/web-browser-mozilla.h
@@ -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
index 0000000..75fbaa4
--- /dev/null
+++ b/attic/mallums-magic-browser/web-browser.c
@@ -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
index 0000000..9d39ad0
--- /dev/null
+++ b/attic/mallums-magic-browser/web-browser.h
@@ -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
index 0000000..9389842
--- /dev/null
+++ b/attic/sqlite-model/Makefile
@@ -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
index 0000000..0a4c624
--- /dev/null
+++ b/attic/sqlite-model/clutter-sqlite-model.c
@@ -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
index 0000000..815af58
--- /dev/null
+++ b/attic/sqlite-model/clutter-sqlite-model.h
@@ -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
index 0000000..0cc2750
--- /dev/null
+++ b/attic/sqlite-model/test-sqlite-model.c
@@ -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
index 0000000..385061e
--- /dev/null
+++ b/attic/table/Makefile
@@ -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
index 0000000..79e2991
--- /dev/null
+++ b/attic/table/clutter-dominatrix.c
@@ -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
index 0000000..d99e510
--- /dev/null
+++ b/attic/table/clutter-dominatrix.h
@@ -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
index 0000000..2f62e0a
--- /dev/null
+++ b/attic/table/clutter-video-player.c
@@ -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
index 0000000..f2ec2e2
--- /dev/null
+++ b/attic/table/clutter-video-player.h
@@ -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
index 0000000..5b71eeb
--- /dev/null
+++ b/attic/table/hand0.png
Binary files differ
diff --git a/attic/table/hand1.png b/attic/table/hand1.png
new file mode 100644
index 0000000..2cf1b78
--- /dev/null
+++ b/attic/table/hand1.png
Binary files differ
diff --git a/attic/table/hand2.png b/attic/table/hand2.png
new file mode 100644
index 0000000..ac5243a
--- /dev/null
+++ b/attic/table/hand2.png
Binary files differ
diff --git a/attic/table/hand3.png b/attic/table/hand3.png
new file mode 100644
index 0000000..83c7c07
--- /dev/null
+++ b/attic/table/hand3.png
Binary files differ
diff --git a/attic/table/hand4.png b/attic/table/hand4.png
new file mode 100644
index 0000000..2d289ee
--- /dev/null
+++ b/attic/table/hand4.png
Binary files differ
diff --git a/attic/table/hand5.png b/attic/table/hand5.png
new file mode 100644
index 0000000..f0fb783
--- /dev/null
+++ b/attic/table/hand5.png
Binary files differ
diff --git a/attic/table/hand6.png b/attic/table/hand6.png
new file mode 100644
index 0000000..7a50ab7
--- /dev/null
+++ b/attic/table/hand6.png
Binary files differ
diff --git a/attic/table/hand7.png b/attic/table/hand7.png
new file mode 100644
index 0000000..d0dfd4f
--- /dev/null
+++ b/attic/table/hand7.png
Binary files differ
diff --git a/attic/table/hand8.png b/attic/table/hand8.png
new file mode 100644
index 0000000..21236ce
--- /dev/null
+++ b/attic/table/hand8.png
Binary files differ
diff --git a/attic/table/pause_png.h b/attic/table/pause_png.h
new file mode 100644
index 0000000..7971cf9
--- /dev/null
+++ b/attic/table/pause_png.h
@@ -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
index 0000000..e76dd0b
--- /dev/null
+++ b/attic/table/play_png.h
@@ -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
index 0000000..69f7d16
--- /dev/null
+++ b/attic/table/table.c
@@ -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
index 0000000..d52c9f1
--- /dev/null
+++ b/attic/widgets/Makefile
@@ -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
index 0000000..9fd86a1
--- /dev/null
+++ b/attic/widgets/clutter-reflect-texture.c
@@ -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
index 0000000..9ba7353
--- /dev/null
+++ b/attic/widgets/clutter-reflect-texture.h
@@ -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
index 0000000..362b35a
--- /dev/null
+++ b/attic/widgets/test.c
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/woohaa/AUTHORS
diff --git a/attic/woohaa/ChangeLog b/attic/woohaa/ChangeLog
new file mode 100644
index 0000000..1663d7f
--- /dev/null
+++ b/attic/woohaa/ChangeLog
@@ -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
index 0000000..b275de1
--- /dev/null
+++ b/attic/woohaa/Makefile.am
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/woohaa/NEWS
diff --git a/attic/woohaa/README b/attic/woohaa/README
new file mode 100644
index 0000000..406a3ba
--- /dev/null
+++ b/attic/woohaa/README
@@ -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
index 0000000..b1376df
--- /dev/null
+++ b/attic/woohaa/autogen.sh
@@ -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
index 0000000..963e010
--- /dev/null
+++ b/attic/woohaa/configure.ac
@@ -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
index 0000000..f41e49e
--- /dev/null
+++ b/attic/woohaa/data/Makefile.am
@@ -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
index 0000000..a65cfc2
--- /dev/null
+++ b/attic/woohaa/data/arrow-down.svg
@@ -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
index 0000000..1c18c0e
--- /dev/null
+++ b/attic/woohaa/data/arrow-next.svg
@@ -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
index 0000000..4e8869b
--- /dev/null
+++ b/attic/woohaa/data/arrow-prev.svg
@@ -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
index 0000000..c30f43f
--- /dev/null
+++ b/attic/woohaa/data/arrow-up.svg
@@ -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
index 0000000..5a5a55f
--- /dev/null
+++ b/attic/woohaa/data/bg.png
Binary files differ
diff --git a/attic/woohaa/data/busy.png b/attic/woohaa/data/busy.png
new file mode 100644
index 0000000..41765de
--- /dev/null
+++ b/attic/woohaa/data/busy.png
Binary files differ
diff --git a/attic/woohaa/data/default-thumb.png b/attic/woohaa/data/default-thumb.png
new file mode 100644
index 0000000..2e59381
--- /dev/null
+++ b/attic/woohaa/data/default-thumb.png
Binary files differ
diff --git a/attic/woohaa/data/header.svg b/attic/woohaa/data/header.svg
new file mode 100644
index 0000000..13c8133
--- /dev/null
+++ b/attic/woohaa/data/header.svg
@@ -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
index 0000000..9c86f4b
--- /dev/null
+++ b/attic/woohaa/data/play.svg
@@ -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
index 0000000..bfc3156
--- /dev/null
+++ b/attic/woohaa/data/selected.svg
@@ -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
index 0000000..57c5b96
--- /dev/null
+++ b/attic/woohaa/data/spinner.svg
@@ -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
index 0000000..979a512
--- /dev/null
+++ b/attic/woohaa/eggsequence.c
@@ -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
index 0000000..107db47
--- /dev/null
+++ b/attic/woohaa/eggsequence.h
@@ -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
index 0000000..4758fa6
--- /dev/null
+++ b/attic/woohaa/totem-resources.c
@@ -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
index 0000000..d1c0848
--- /dev/null
+++ b/attic/woohaa/totem-resources.h
@@ -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
index 0000000..dd7d098
--- /dev/null
+++ b/attic/woohaa/util.c
@@ -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
index 0000000..a363d55
--- /dev/null
+++ b/attic/woohaa/util.h
@@ -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
index 0000000..6a0df15
--- /dev/null
+++ b/attic/woohaa/wh-busy.c
@@ -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
index 0000000..d4ccabe
--- /dev/null
+++ b/attic/woohaa/wh-busy.h
@@ -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
index 0000000..945c12c
--- /dev/null
+++ b/attic/woohaa/wh-db.c
@@ -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
index 0000000..248ef4f
--- /dev/null
+++ b/attic/woohaa/wh-db.h
@@ -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
index 0000000..ef3de66
--- /dev/null
+++ b/attic/woohaa/wh-screen-video.c
@@ -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
index 0000000..84f3738
--- /dev/null
+++ b/attic/woohaa/wh-screen-video.h
@@ -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
index 0000000..8195405
--- /dev/null
+++ b/attic/woohaa/wh-slider-menu.c
@@ -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
index 0000000..eaa04e8
--- /dev/null
+++ b/attic/woohaa/wh-slider-menu.h
@@ -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
index 0000000..e611580
--- /dev/null
+++ b/attic/woohaa/wh-theme.c
@@ -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
index 0000000..afce57e
--- /dev/null
+++ b/attic/woohaa/wh-theme.h
@@ -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
index 0000000..778f559
--- /dev/null
+++ b/attic/woohaa/wh-video-model-row.c
@@ -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
index 0000000..fce0fdd
--- /dev/null
+++ b/attic/woohaa/wh-video-model-row.h
@@ -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
index 0000000..3d9e4f8
--- /dev/null
+++ b/attic/woohaa/wh-video-model.c
@@ -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
index 0000000..fd705e3
--- /dev/null
+++ b/attic/woohaa/wh-video-model.h
@@ -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
index 0000000..3120b0b
--- /dev/null
+++ b/attic/woohaa/wh-video-row-renderer.c
@@ -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
index 0000000..15e8591
--- /dev/null
+++ b/attic/woohaa/wh-video-row-renderer.h
@@ -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
index 0000000..3441358
--- /dev/null
+++ b/attic/woohaa/wh-video-thumbnailer.c
@@ -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
index 0000000..b99675e
--- /dev/null
+++ b/attic/woohaa/wh-video-view.c
@@ -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
index 0000000..6a99ae5
--- /dev/null
+++ b/attic/woohaa/wh-video-view.h
@@ -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
index 0000000..df463b2
--- /dev/null
+++ b/attic/woohaa/woohaa.c
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/youhaa/AUTHORS
diff --git a/attic/youhaa/ChangeLog b/attic/youhaa/ChangeLog
new file mode 100644
index 0000000..5cc17b1
--- /dev/null
+++ b/attic/youhaa/ChangeLog
@@ -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
index 0000000..ef2a989
--- /dev/null
+++ b/attic/youhaa/Makefile.am
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/attic/youhaa/NEWS
diff --git a/attic/youhaa/README b/attic/youhaa/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/attic/youhaa/README
diff --git a/attic/youhaa/autogen.sh b/attic/youhaa/autogen.sh
new file mode 100755
index 0000000..b1376df
--- /dev/null
+++ b/attic/youhaa/autogen.sh
@@ -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
index 0000000..053cd3f
--- /dev/null
+++ b/attic/youhaa/configure.ac
@@ -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
index 0000000..9976a4f
--- /dev/null
+++ b/attic/youhaa/data/Makefile.am
@@ -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
index 0000000..989bff5
--- /dev/null
+++ b/attic/youhaa/data/go-next.svg
@@ -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
index 0000000..f1eb977
--- /dev/null
+++ b/attic/youhaa/data/go-previous.svg
@@ -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
index 0000000..798427c
--- /dev/null
+++ b/attic/youhaa/libcurl.m4
@@ -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
index 0000000..4b2a969
--- /dev/null
+++ b/attic/youhaa/src/Makefile.am
@@ -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
index 0000000..8299d30
--- /dev/null
+++ b/attic/youhaa/src/glibcurl.c
@@ -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
index 0000000..fa167e3
--- /dev/null
+++ b/attic/youhaa/src/glibcurl.h
@@ -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
index 0000000..1be0fba
--- /dev/null
+++ b/attic/youhaa/src/yh-main.c
@@ -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
index 0000000..83ad9dc
--- /dev/null
+++ b/attic/youhaa/src/yh-theme.c
@@ -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
index 0000000..fdd904b
--- /dev/null
+++ b/attic/youhaa/src/yh-theme.h
@@ -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
index 0000000..5d4bc57
--- /dev/null
+++ b/attic/youhaa/src/yh-youtube-browser.c
@@ -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
index 0000000..87b88a3
--- /dev/null
+++ b/attic/youhaa/src/yh-youtube-browser.h
@@ -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
index 0000000..d68d870
--- /dev/null
+++ b/attic/youhaa/src/yh-youtube.c
@@ -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
index 0000000..2d55c98
--- /dev/null
+++ b/attic/youhaa/src/yh-youtube.h
@@ -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
index 0000000..a63d0f3
--- /dev/null
+++ b/circles/Makefile
@@ -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
index 0000000..eecd572
--- /dev/null
+++ b/circles/circles.c
@@ -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
index 0000000..233dc58
--- /dev/null
+++ b/courasel/Makefile
@@ -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
index 0000000..02361a9
--- /dev/null
+++ b/courasel/accessories-text-editor.png
Binary files differ
diff --git a/courasel/applications-games.png b/courasel/applications-games.png
new file mode 100644
index 0000000..67a1a4c
--- /dev/null
+++ b/courasel/applications-games.png
Binary files differ
diff --git a/courasel/courasel.c b/courasel/courasel.c
new file mode 100644
index 0000000..5f66707
--- /dev/null
+++ b/courasel/courasel.c
@@ -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
index 0000000..2824813
--- /dev/null
+++ b/courasel/dates.png
Binary files differ
diff --git a/courasel/im-client.png b/courasel/im-client.png
new file mode 100644
index 0000000..561519d
--- /dev/null
+++ b/courasel/im-client.png
Binary files differ
diff --git a/courasel/preferences-desktop-theme.png b/courasel/preferences-desktop-theme.png
new file mode 100644
index 0000000..8c93c14
--- /dev/null
+++ b/courasel/preferences-desktop-theme.png
Binary files differ
diff --git a/courasel/tasks.png b/courasel/tasks.png
new file mode 100644
index 0000000..e9ea953
--- /dev/null
+++ b/courasel/tasks.png
Binary files differ
diff --git a/courasel/utilities-terminal.png b/courasel/utilities-terminal.png
new file mode 100644
index 0000000..693c685
--- /dev/null
+++ b/courasel/utilities-terminal.png
Binary files differ
diff --git a/courasel/web-browser.png b/courasel/web-browser.png
new file mode 100644
index 0000000..1df505c
--- /dev/null
+++ b/courasel/web-browser.png
Binary files differ
diff --git a/foofone/Makefile b/foofone/Makefile
new file mode 100644
index 0000000..1a7d3d4
--- /dev/null
+++ b/foofone/Makefile
@@ -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
index 0000000..e643c30
--- /dev/null
+++ b/foofone/button.png
Binary files differ
diff --git a/foofone/call-background.png b/foofone/call-background.png
new file mode 100644
index 0000000..0131d8f
--- /dev/null
+++ b/foofone/call-background.png
Binary files differ
diff --git a/foofone/display.png b/foofone/display.png
new file mode 100644
index 0000000..7bf4dd6
--- /dev/null
+++ b/foofone/display.png
Binary files differ
diff --git a/foofone/foofone.c b/foofone/foofone.c
new file mode 100644
index 0000000..f732ea6
--- /dev/null
+++ b/foofone/foofone.c
@@ -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
index 0000000..f73f324
--- /dev/null
+++ b/gps-globe/.gitignore
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/gps-globe/AUTHORS
diff --git a/gps-globe/COPYING b/gps-globe/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/gps-globe/COPYING
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/gps-globe/ChangeLog
diff --git a/gps-globe/INSTALL b/gps-globe/INSTALL
new file mode 100644
index 0000000..8b82ade
--- /dev/null
+++ b/gps-globe/INSTALL
@@ -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
index 0000000..af437a6
--- /dev/null
+++ b/gps-globe/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/gps-globe/NEWS b/gps-globe/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gps-globe/NEWS
diff --git a/gps-globe/README b/gps-globe/README
new file mode 100644
index 0000000..a0aeabb
--- /dev/null
+++ b/gps-globe/README
@@ -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
index 0000000..7784749
--- /dev/null
+++ b/gps-globe/autogen.sh
@@ -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
index 0000000..8aff462
--- /dev/null
+++ b/gps-globe/configure.ac
@@ -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
index 0000000..f656b43
--- /dev/null
+++ b/gps-globe/data/visible-earth.jpg
Binary files differ
diff --git a/gps-globe/src/Makefile.am b/gps-globe/src/Makefile.am
new file mode 100644
index 0000000..5358c61
--- /dev/null
+++ b/gps-globe/src/Makefile.am
@@ -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
index 0000000..b8d63bd
--- /dev/null
+++ b/gps-globe/src/gpsg-enum-types.c.in
@@ -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
index 0000000..a8870d1
--- /dev/null
+++ b/gps-globe/src/gpsg-enum-types.h.in
@@ -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
index 0000000..61f8ccf
--- /dev/null
+++ b/gps-globe/src/gpsg-main.c
@@ -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
index 0000000..46d4f50
--- /dev/null
+++ b/gps-globe/src/gpsg-sphere-vertex-shader.glsl
@@ -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
index 0000000..4df21af
--- /dev/null
+++ b/gps-globe/src/gpsg-sphere-vertex-shader.h
@@ -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
index 0000000..bfb9181
--- /dev/null
+++ b/gps-globe/src/gpsg-sphere.c
@@ -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
index 0000000..0ff8b91
--- /dev/null
+++ b/gps-globe/src/gpsg-sphere.h
@@ -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
index 0000000..ac0e1ab
--- /dev/null
+++ b/nyancat/Makefile
@@ -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
index 0000000..f52eda8
--- /dev/null
+++ b/nyancat/nyan.json
@@ -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
index 0000000..8fde7b8
--- /dev/null
+++ b/nyancat/nyancat.c
@@ -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
index 0000000..c614e79
--- /dev/null
+++ b/nyancat/star.png
Binary files differ
diff --git a/object-store/Makefile b/object-store/Makefile
new file mode 100644
index 0000000..73f083b
--- /dev/null
+++ b/object-store/Makefile
@@ -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
index 0000000..45bb03f
--- /dev/null
+++ b/object-store/foo-object-store-test
Binary files differ
diff --git a/object-store/foo-object-store.c b/object-store/foo-object-store.c
new file mode 100644
index 0000000..c11c498
--- /dev/null
+++ b/object-store/foo-object-store.c
@@ -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
index 0000000..39f65b4
--- /dev/null
+++ b/object-store/foo-object-store.h
@@ -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
index 0000000..e3fd109
--- /dev/null
+++ b/object-store/foo-test-object.c
@@ -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
index 0000000..5c53e3d
--- /dev/null
+++ b/object-store/foo-test-object.h
@@ -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
index 0000000..b8d78a3
--- /dev/null
+++ b/object-store/object-store-example.c
@@ -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
index 0000000..8a9b050
--- /dev/null
+++ b/object-store/object-store-test.c
@@ -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
index 0000000..c46cffd
--- /dev/null
+++ b/odo/Makefile
@@ -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
index 0000000..487cebc
--- /dev/null
+++ b/odo/README
@@ -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
index 0000000..e72560a
--- /dev/null
+++ b/odo/grid.png
Binary files differ
diff --git a/odo/neghand.png b/odo/neghand.png
new file mode 100644
index 0000000..48e7d6a
--- /dev/null
+++ b/odo/neghand.png
Binary files differ
diff --git a/odo/odo-distort-funcs.c b/odo/odo-distort-funcs.c
new file mode 100644
index 0000000..3e66c73
--- /dev/null
+++ b/odo/odo-distort-funcs.c
@@ -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
index 0000000..ea8dcf6
--- /dev/null
+++ b/odo/odo-distort-funcs.h
@@ -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
index 0000000..aea5bea
--- /dev/null
+++ b/odo/odo-texture.c
@@ -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
index 0000000..5c2aae0
--- /dev/null
+++ b/odo/odo-texture.h
@@ -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
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
index 0000000..677aa52
--- /dev/null
+++ b/odo/oh-logo.png
Binary files differ
diff --git a/odo/redhand.png b/odo/redhand.png
new file mode 100644
index 0000000..c07d8ac
--- /dev/null
+++ b/odo/redhand.png
Binary files differ
diff --git a/opt/.gitignore b/opt/.gitignore
new file mode 100644
index 0000000..c58cb6f
--- /dev/null
+++ b/opt/.gitignore
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/opt/AUTHORS
diff --git a/opt/ChangeLog b/opt/ChangeLog
new file mode 100644
index 0000000..5a9d28f
--- /dev/null
+++ b/opt/ChangeLog
@@ -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
index 0000000..6ce7cbd
--- /dev/null
+++ b/opt/Makefile.am
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/opt/NEWS
diff --git a/opt/README b/opt/README
new file mode 100644
index 0000000..9ba9a4c
--- /dev/null
+++ b/opt/README
@@ -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
index 0000000..b1376df
--- /dev/null
+++ b/opt/autogen.sh
@@ -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
index 0000000..91a0d0e
--- /dev/null
+++ b/opt/bg.png
Binary files differ
diff --git a/opt/configure.ac b/opt/configure.ac
new file mode 100644
index 0000000..7cffba5
--- /dev/null
+++ b/opt/configure.ac
@@ -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
index 0000000..36a5840
--- /dev/null
+++ b/opt/demo.xml
@@ -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
index 0000000..1525386
--- /dev/null
+++ b/opt/hirez/oh-present.xcf
Binary files differ
diff --git a/opt/kitten.jpg b/opt/kitten.jpg
new file mode 100644
index 0000000..6232fb7
--- /dev/null
+++ b/opt/kitten.jpg
Binary files differ
diff --git a/opt/kitten2.jpg b/opt/kitten2.jpg
new file mode 100644
index 0000000..cfb4453
--- /dev/null
+++ b/opt/kitten2.jpg
Binary files differ
diff --git a/opt/opt-config.c b/opt/opt-config.c
new file mode 100644
index 0000000..963ce12
--- /dev/null
+++ b/opt/opt-config.c
@@ -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
index 0000000..5560dd2
--- /dev/null
+++ b/opt/opt-menu.c
@@ -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
index 0000000..91ae7ca
--- /dev/null
+++ b/opt/opt-menu.h
@@ -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
index 0000000..50fa126
--- /dev/null
+++ b/opt/opt-show.c
@@ -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
index 0000000..27cfdd6
--- /dev/null
+++ b/opt/opt-show.h
@@ -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
index 0000000..fd62491
--- /dev/null
+++ b/opt/opt-slide.c
@@ -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
index 0000000..dda8893
--- /dev/null
+++ b/opt/opt-slide.h
@@ -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
index 0000000..89b5d82
--- /dev/null
+++ b/opt/opt-transition.c
@@ -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
index 0000000..629fe16
--- /dev/null
+++ b/opt/opt-transition.h
@@ -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
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
index 0000000..ec82f85
--- /dev/null
+++ b/opt/opt.doap
@@ -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
index 0000000..f8a9329
--- /dev/null
+++ b/opt/opt.dtd
@@ -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
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
index 0000000..25c0423
--- /dev/null
+++ b/opt/powers.png
Binary files differ
diff --git a/opt/test.xml b/opt/test.xml
new file mode 100644
index 0000000..f47ff31
--- /dev/null
+++ b/opt/test.xml
@@ -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
index 0000000..b3f99cc
--- /dev/null
+++ b/packaging/clutter-toys.spec
@@ -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
index 0000000..59e6935
--- /dev/null
+++ b/patches/fix-colors.patch
@@ -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
index 0000000..a919175
--- /dev/null
+++ b/patches/fix-image-path.patch
@@ -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
index 0000000..e5a8ab7
--- /dev/null
+++ b/patches/map-escape-key-to-quit.patch
@@ -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
index 0000000..3555e3f
--- /dev/null
+++ b/pong/Makefile
@@ -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
index 0000000..d80af4c
--- /dev/null
+++ b/pong/pong-ball.png
Binary files differ
diff --git a/pong/pong-bat.png b/pong/pong-bat.png
new file mode 100644
index 0000000..1415dd3
--- /dev/null
+++ b/pong/pong-bat.png
Binary files differ
diff --git a/pong/pong2.c b/pong/pong2.c
new file mode 100644
index 0000000..3a57c34
--- /dev/null
+++ b/pong/pong2.c
@@ -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
index 0000000..b92ab06
--- /dev/null
+++ b/ripples/Makefile
@@ -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
index 0000000..bdd9a17
--- /dev/null
+++ b/ripples/ripples.c
@@ -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
index 0000000..514a634
--- /dev/null
+++ b/script-viewer/.gitignore
@@ -0,0 +1,2 @@
+script-viewer
+script-viewer.o
diff --git a/script-viewer/COPYING b/script-viewer/COPYING
new file mode 100644
index 0000000..b1e3f5a
--- /dev/null
+++ b/script-viewer/COPYING
@@ -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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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
+
+ 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
index 0000000..5d9b665
--- /dev/null
+++ b/script-viewer/ChangeLog
@@ -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
index 0000000..ac0e1ab
--- /dev/null
+++ b/script-viewer/Makefile
@@ -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
index 0000000..3b0fb6a
--- /dev/null
+++ b/script-viewer/README
@@ -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
index 0000000..7026a27
--- /dev/null
+++ b/script-viewer/alphas.json
@@ -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
index 0000000..816f919
--- /dev/null
+++ b/script-viewer/behaviours.json
@@ -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
index 0000000..c07d8ac
--- /dev/null
+++ b/script-viewer/redhand.png
Binary files differ
diff --git a/script-viewer/script-viewer.c b/script-viewer/script-viewer.c
new file mode 100644
index 0000000..afaa84e
--- /dev/null
+++ b/script-viewer/script-viewer.c
@@ -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
index 0000000..52c81f2
--- /dev/null
+++ b/script-viewer/test-script.json
@@ -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
index 0000000..c1b0514
--- /dev/null
+++ b/script-viewer/text.json
@@ -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" }
+ }
+ ]
+ },
+ ]
+ }
+]