diff options
525 files changed, 79663 insertions, 0 deletions
@@ -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 Binary files differnew file mode 100644 index 0000000..fca6460 --- /dev/null +++ b/attic/astro-desktop/applets/cal.png 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 Binary files differnew file mode 100644 index 0000000..13bb265 --- /dev/null +++ b/attic/astro-desktop/applets/clock.png diff --git a/attic/astro-desktop/applets/clouds.png b/attic/astro-desktop/applets/clouds.png Binary files differnew file mode 100644 index 0000000..87e1db0 --- /dev/null +++ b/attic/astro-desktop/applets/clouds.png 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 Binary files differnew file mode 100644 index 0000000..5ad6e41 --- /dev/null +++ b/attic/astro-desktop/applets/mail.png 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 Binary files differnew file mode 100644 index 0000000..36e2745 --- /dev/null +++ b/attic/astro-desktop/data/albums/Amy_Winehouse_-_Back_To_Black.jpg diff --git a/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg b/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg Binary files differnew file mode 100644 index 0000000..7dab931 --- /dev/null +++ b/attic/astro-desktop/data/albums/Jay_Z_-_American_Gangster.jpg diff --git a/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg b/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg Binary files differnew file mode 100644 index 0000000..133687e --- /dev/null +++ b/attic/astro-desktop/data/albums/Kanye_West_-_Graduation.jpg 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 Binary files differnew file mode 100644 index 0000000..5ce60bd --- /dev/null +++ b/attic/astro-desktop/data/albums/Lupe_Fiasco_-_Food_and_Liquor.jpg 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 Binary files differnew file mode 100755 index 0000000..04de882 --- /dev/null +++ b/attic/astro-desktop/data/albums/Red_Hot_Chilli_Peppers_-_Greatest_Hits.jpg diff --git a/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg b/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg Binary files differnew file mode 100644 index 0000000..ad75622 --- /dev/null +++ b/attic/astro-desktop/data/albums/Santana_-_Ultimate_Santana.jpg diff --git a/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg b/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg Binary files differnew file mode 100755 index 0000000..216fbcc --- /dev/null +++ b/attic/astro-desktop/data/albums/Timbaland_-_Shock_Value.jpg diff --git a/attic/astro-desktop/data/applet_bg.png b/attic/astro-desktop/data/applet_bg.png Binary files differnew file mode 100644 index 0000000..9d25c90 --- /dev/null +++ b/attic/astro-desktop/data/applet_bg.png diff --git a/attic/astro-desktop/data/background.svg b/attic/astro-desktop/data/background.svg Binary files differnew file mode 100644 index 0000000..03d9b16 --- /dev/null +++ b/attic/astro-desktop/data/background.svg 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 Binary files differnew file mode 100644 index 0000000..9749d8b --- /dev/null +++ b/attic/astro-desktop/data/contact.png 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 Binary files differnew file mode 100644 index 0000000..5fca186 --- /dev/null +++ b/attic/astro-desktop/data/face.png 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 Binary files differnew file mode 100644 index 0000000..2b29dc5 --- /dev/null +++ b/attic/astro-desktop/data/icons/bt.png diff --git a/attic/astro-desktop/data/icons/close.png b/attic/astro-desktop/data/icons/close.png Binary files differnew file mode 100644 index 0000000..f17b36c --- /dev/null +++ b/attic/astro-desktop/data/icons/close.png diff --git a/attic/astro-desktop/data/icons/contacts.png b/attic/astro-desktop/data/icons/contacts.png Binary files differnew file mode 100644 index 0000000..d37e990 --- /dev/null +++ b/attic/astro-desktop/data/icons/contacts.png diff --git a/attic/astro-desktop/data/icons/exec.png b/attic/astro-desktop/data/icons/exec.png Binary files differnew file mode 100644 index 0000000..7c4abdb --- /dev/null +++ b/attic/astro-desktop/data/icons/exec.png diff --git a/attic/astro-desktop/data/icons/home.png b/attic/astro-desktop/data/icons/home.png Binary files differnew file mode 100644 index 0000000..f165f03 --- /dev/null +++ b/attic/astro-desktop/data/icons/home.png diff --git a/attic/astro-desktop/data/icons/images.png b/attic/astro-desktop/data/icons/images.png Binary files differnew file mode 100644 index 0000000..0432e78 --- /dev/null +++ b/attic/astro-desktop/data/icons/images.png diff --git a/attic/astro-desktop/data/icons/music.png b/attic/astro-desktop/data/icons/music.png Binary files differnew file mode 100644 index 0000000..637be83 --- /dev/null +++ b/attic/astro-desktop/data/icons/music.png diff --git a/attic/astro-desktop/data/icons/nm.png b/attic/astro-desktop/data/icons/nm.png Binary files differnew file mode 100644 index 0000000..a3d973e --- /dev/null +++ b/attic/astro-desktop/data/icons/nm.png diff --git a/attic/astro-desktop/data/info_bg.png b/attic/astro-desktop/data/info_bg.png Binary files differnew file mode 100644 index 0000000..b9f5fcc --- /dev/null +++ b/attic/astro-desktop/data/info_bg.png 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 Binary files differnew file mode 100755 index 0000000..a7617db --- /dev/null +++ b/attic/mallums-magic-browser/assets/back.png diff --git a/attic/mallums-magic-browser/assets/bground.png b/attic/mallums-magic-browser/assets/bground.png Binary files differnew file mode 100755 index 0000000..0d5b4c3 --- /dev/null +++ b/attic/mallums-magic-browser/assets/bground.png diff --git a/attic/mallums-magic-browser/assets/document-new.png b/attic/mallums-magic-browser/assets/document-new.png Binary files differnew file mode 100644 index 0000000..e6d64bb --- /dev/null +++ b/attic/mallums-magic-browser/assets/document-new.png diff --git a/attic/mallums-magic-browser/assets/forward.png b/attic/mallums-magic-browser/assets/forward.png Binary files differnew file mode 100755 index 0000000..266200d --- /dev/null +++ b/attic/mallums-magic-browser/assets/forward.png diff --git a/attic/mallums-magic-browser/assets/go-next.png b/attic/mallums-magic-browser/assets/go-next.png Binary files differnew file mode 100644 index 0000000..036e432 --- /dev/null +++ b/attic/mallums-magic-browser/assets/go-next.png diff --git a/attic/mallums-magic-browser/assets/go-previous.png b/attic/mallums-magic-browser/assets/go-previous.png Binary files differnew file mode 100644 index 0000000..895ce33 --- /dev/null +++ b/attic/mallums-magic-browser/assets/go-previous.png diff --git a/attic/mallums-magic-browser/assets/tabs.png b/attic/mallums-magic-browser/assets/tabs.png Binary files differnew file mode 100755 index 0000000..f872e21 --- /dev/null +++ b/attic/mallums-magic-browser/assets/tabs.png diff --git a/attic/mallums-magic-browser/assets/toolbar-bg.png b/attic/mallums-magic-browser/assets/toolbar-bg.png Binary files differnew file mode 100644 index 0000000..21fbd7d --- /dev/null +++ b/attic/mallums-magic-browser/assets/toolbar-bg.png 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 Binary files differnew file mode 100644 index 0000000..5b71eeb --- /dev/null +++ b/attic/table/hand0.png diff --git a/attic/table/hand1.png b/attic/table/hand1.png Binary files differnew file mode 100644 index 0000000..2cf1b78 --- /dev/null +++ b/attic/table/hand1.png diff --git a/attic/table/hand2.png b/attic/table/hand2.png Binary files differnew file mode 100644 index 0000000..ac5243a --- /dev/null +++ b/attic/table/hand2.png diff --git a/attic/table/hand3.png b/attic/table/hand3.png Binary files differnew file mode 100644 index 0000000..83c7c07 --- /dev/null +++ b/attic/table/hand3.png diff --git a/attic/table/hand4.png b/attic/table/hand4.png Binary files differnew file mode 100644 index 0000000..2d289ee --- /dev/null +++ b/attic/table/hand4.png diff --git a/attic/table/hand5.png b/attic/table/hand5.png Binary files differnew file mode 100644 index 0000000..f0fb783 --- /dev/null +++ b/attic/table/hand5.png diff --git a/attic/table/hand6.png b/attic/table/hand6.png Binary files differnew file mode 100644 index 0000000..7a50ab7 --- /dev/null +++ b/attic/table/hand6.png diff --git a/attic/table/hand7.png b/attic/table/hand7.png Binary files differnew file mode 100644 index 0000000..d0dfd4f --- /dev/null +++ b/attic/table/hand7.png diff --git a/attic/table/hand8.png b/attic/table/hand8.png Binary files differnew file mode 100644 index 0000000..21236ce --- /dev/null +++ b/attic/table/hand8.png 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 Binary files differnew file mode 100644 index 0000000..5a5a55f --- /dev/null +++ b/attic/woohaa/data/bg.png diff --git a/attic/woohaa/data/busy.png b/attic/woohaa/data/busy.png Binary files differnew file mode 100644 index 0000000..41765de --- /dev/null +++ b/attic/woohaa/data/busy.png diff --git a/attic/woohaa/data/default-thumb.png b/attic/woohaa/data/default-thumb.png Binary files differnew file mode 100644 index 0000000..2e59381 --- /dev/null +++ b/attic/woohaa/data/default-thumb.png 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>></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><</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 (®ex, YOUTUBE_REGEX, REG_EXTENDED) == 0) && + (regexec (®ex, 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 Binary files differnew file mode 100644 index 0000000..02361a9 --- /dev/null +++ b/courasel/accessories-text-editor.png diff --git a/courasel/applications-games.png b/courasel/applications-games.png Binary files differnew file mode 100644 index 0000000..67a1a4c --- /dev/null +++ b/courasel/applications-games.png 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 Binary files differnew file mode 100644 index 0000000..2824813 --- /dev/null +++ b/courasel/dates.png diff --git a/courasel/im-client.png b/courasel/im-client.png Binary files differnew file mode 100644 index 0000000..561519d --- /dev/null +++ b/courasel/im-client.png diff --git a/courasel/preferences-desktop-theme.png b/courasel/preferences-desktop-theme.png Binary files differnew file mode 100644 index 0000000..8c93c14 --- /dev/null +++ b/courasel/preferences-desktop-theme.png diff --git a/courasel/tasks.png b/courasel/tasks.png Binary files differnew file mode 100644 index 0000000..e9ea953 --- /dev/null +++ b/courasel/tasks.png diff --git a/courasel/utilities-terminal.png b/courasel/utilities-terminal.png Binary files differnew file mode 100644 index 0000000..693c685 --- /dev/null +++ b/courasel/utilities-terminal.png diff --git a/courasel/web-browser.png b/courasel/web-browser.png Binary files differnew file mode 100644 index 0000000..1df505c --- /dev/null +++ b/courasel/web-browser.png 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 Binary files differnew file mode 100644 index 0000000..e643c30 --- /dev/null +++ b/foofone/button.png diff --git a/foofone/call-background.png b/foofone/call-background.png Binary files differnew file mode 100644 index 0000000..0131d8f --- /dev/null +++ b/foofone/call-background.png diff --git a/foofone/display.png b/foofone/display.png Binary files differnew file mode 100644 index 0000000..7bf4dd6 --- /dev/null +++ b/foofone/display.png 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 Binary files differnew file mode 100644 index 0000000..f656b43 --- /dev/null +++ b/gps-globe/data/visible-earth.jpg 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", ¢er, + 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 Binary files differnew file mode 100644 index 0000000..c614e79 --- /dev/null +++ b/nyancat/star.png 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 Binary files differnew file mode 100644 index 0000000..45bb03f --- /dev/null +++ b/object-store/foo-object-store-test 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 Binary files differnew file mode 100644 index 0000000..e72560a --- /dev/null +++ b/odo/grid.png diff --git a/odo/neghand.png b/odo/neghand.png Binary files differnew file mode 100644 index 0000000..48e7d6a --- /dev/null +++ b/odo/neghand.png 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 Binary files differnew file mode 100644 index 0000000..677aa52 --- /dev/null +++ b/odo/oh-logo.png diff --git a/odo/redhand.png b/odo/redhand.png Binary files differnew file mode 100644 index 0000000..c07d8ac --- /dev/null +++ b/odo/redhand.png 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 Binary files differnew file mode 100644 index 0000000..91a0d0e --- /dev/null +++ b/opt/bg.png 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 Binary files differnew file mode 100644 index 0000000..1525386 --- /dev/null +++ b/opt/hirez/oh-present.xcf diff --git a/opt/kitten.jpg b/opt/kitten.jpg Binary files differnew file mode 100644 index 0000000..6232fb7 --- /dev/null +++ b/opt/kitten.jpg diff --git a/opt/kitten2.jpg b/opt/kitten2.jpg Binary files differnew file mode 100644 index 0000000..cfb4453 --- /dev/null +++ b/opt/kitten2.jpg 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 Binary files differnew file mode 100644 index 0000000..25c0423 --- /dev/null +++ b/opt/powers.png 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 Binary files differnew file mode 100644 index 0000000..d80af4c --- /dev/null +++ b/pong/pong-ball.png diff --git a/pong/pong-bat.png b/pong/pong-bat.png Binary files differnew file mode 100644 index 0000000..1415dd3 --- /dev/null +++ b/pong/pong-bat.png 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 Binary files differnew file mode 100644 index 0000000..c07d8ac --- /dev/null +++ b/script-viewer/redhand.png 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" } + } + ] + }, + ] + } +] |