diff options
Diffstat (limited to 'plugins')
17 files changed, 114 insertions, 110 deletions
| diff --git a/plugins/Makefile.plugin.mk b/plugins/Makefile.plugin.mk index 03df7b0..c26c672 100644 --- a/plugins/Makefile.plugin.mk +++ b/plugins/Makefile.plugin.mk @@ -28,9 +28,6 @@ PKGS := $(shell sed ':a;N;$$!ba;s/\n/ /g' ../shotwell-plugin-dev-1.0.deps) $(PKG  EXT_PKGS := $(PKGS)  PKGS := shotwell-plugin-dev-1.0 $(PKGS) $(PLUGIN_PKGS) -# automatically include the Resources.vala common file -SRC_FILES := ../common/Resources.vala $(SRC_FILES) -  CFILES := $(notdir $(SRC_FILES:.vala=.c))  OFILES := $(notdir $(SRC_FILES:.vala=.o)) @@ -41,10 +38,14 @@ DEFINES := -D_VERSION='"$(PLUGINS_VERSION)"' -DGETTEXT_PACKAGE='"shotwell"'  all: $(PLUGIN).so +PLUGIN_EXTRAFLAGS ?= --vapidir=../common --pkg shotwell-plugin-common +PLUGIN_EXTRALINKFLAGS ?= -L../common/ -lshotwell-plugin-common +  .stamp: $(SRC_FILES) $(MAKE_FILES) $(HEADER_FILES)  	$(VALAC) --target-glib=$(MIN_GLIB_VERSION) -g --enable-checking --fatal-warnings --ccode --enable-deprecated \  		--vapidir=../ $(foreach pkg,$(PKGS),--pkg=$(pkg)) $(foreach pkg,$(CUSTOM_VAPI_PKGS),--pkg=$(pkg)) \  		$(USER_VALAFLAGS) \ +		$(PLUGIN_EXTRAFLAGS) \  		--vapidir=../../vapi \  		$(SRC_FILES)  	@touch .stamp @@ -53,10 +54,10 @@ $(CFILES): .stamp  	@  .c.o: -	$(CC) -c $(CFLAGS) $(DEFINES) -I../.. $< +	$(CC) -c $(CFLAGS) $(DEFINES) -I../.. -I ../common $<  $(PLUGIN).so: $(OFILES) -	$(CC) $(LDFLAGS) -shared $(OFILES) $(LIBS) -o $@ +	$(CC) $(LDFLAGS) -shared $(OFILES) $(LIBS) $(PLUGIN_EXTRALINKFLAGS) -o $@  .PHONY: cleantemps  cleantemps: @@ -70,8 +71,10 @@ clean: cleantemps  .PHONY: distclean  distclean: clean +PLUGIN_DIR ?= $(PLUGIN) +  .PHONY: listfiles  listfiles: -	@printf "plugins/$(PLUGIN)/Makefile $(foreach file,$(SRC_FILES),plugins/$(PLUGIN)/$(file)) " -	@printf "$(foreach rc,$(RC_FILES),plugins/$(PLUGIN)/$(rc)) " +	@printf "plugins/$(PLUGIN_DIR)/Makefile $(foreach file,$(SRC_FILES),plugins/$(PLUGIN_DIR)/$(file)) " +	@printf "$(foreach rc,$(RC_FILES),plugins/$(PLUGIN_DIR)/$(rc)) " diff --git a/plugins/common/Makefile b/plugins/common/Makefile new file mode 100644 index 0000000..90714a0 --- /dev/null +++ b/plugins/common/Makefile @@ -0,0 +1,20 @@ + +PLUGIN := libshotwell-plugin-common +PLUGIN_DIR := common + +PLUGIN_PKGS := \ +	gee-0.8 \ +	libxml-2.0 \ +	libsoup-2.4 \ +	json-glib-1.0 \ +	webkit2gtk-4.0 + +SRC_FILES := Resources.vala RESTSupport.vala + +PLUGIN_EXTRAFLAGS := --vapi=shotwell-plugin-common.vapi \ +	--header=shotwell-plugin-common.h + +PLUGIN_EXTRALINKFLAGS := + +include ../Makefile.plugin.mk + diff --git a/plugins/common/RESTSupport.vala b/plugins/common/RESTSupport.vala index b512fe7..d9bf2ce 100644 --- a/plugins/common/RESTSupport.vala +++ b/plugins/common/RESTSupport.vala @@ -4,10 +4,24 @@   * (version 2.1 or later).  See the COPYING file in this distribution.   */ -extern Soup.Message soup_form_request_new_from_multipart(string uri, Soup.Multipart multipart); -  namespace Publishing.RESTSupport { +// Ported from librest +// https://git.gnome.org/browse/librest/tree/rest/sha1.c?id=e412da58080eec2e771482e7e4c509b9e71477ff#n38 + +internal const int SHA1_HMAC_LENGTH = 20; + +public string hmac_sha1(string key, string message) { +    uint8 buffer[SHA1_HMAC_LENGTH]; +    size_t len = SHA1_HMAC_LENGTH; + +    var mac = new Hmac (ChecksumType.SHA1, key.data); +    mac.update (message.data); +    mac.get_digest (buffer, ref len); + +    return Base64.encode (buffer[0:len]); +} +  public abstract class Session {      private string? endpoint_url = null;      private Soup.Session soup_session = null; @@ -109,13 +123,17 @@ public class Argument {      }      public static Argument[] sort(Argument[] inputArray) { -        FixedTreeSet<Argument> sorted_args = new FixedTreeSet<Argument>(Argument.compare); +        Gee.TreeSet<Argument> sorted_args = new Gee.TreeSet<Argument>(Argument.compare);          foreach (Argument arg in inputArray)              sorted_args.add(arg);          return sorted_args.to_array();      } + +    public string to_string () { +        return "%s=%s".printf (this.key, this.value); +    }  }  public class Transaction { @@ -298,7 +316,7 @@ public class Transaction {          // concatenate the REST arguments array into an HTTP formdata string          string formdata_string = "";          for (int i = 0; i < arguments.length; i++) { -            formdata_string += ("%s=%s".printf(arguments[i].key, arguments[i].value)); +            formdata_string += arguments[i].to_string ();              if (i < arguments.length - 1)                  formdata_string += "&";          } @@ -338,6 +356,11 @@ public class Transaction {          assert(get_is_executed());          return message.response_headers;      } + +    public Soup.Message get_message() { +        assert(get_is_executed()); +        return message; +    }      public void add_argument(string name, string value) {          arguments += new Argument(name, value); @@ -437,7 +460,7 @@ public class UploadTransaction : Transaction {          image_part_header.set_content_disposition("form-data", binary_disposition_table);          Soup.Message outbound_message = -            soup_form_request_new_from_multipart(get_endpoint_url(), message_parts); +            Soup.Form.request_new_from_multipart(get_endpoint_url(), message_parts);          // TODO: there must be a better way to iterate over a map          Gee.MapIterator<string, string> i = message_headers.map_iterator();          bool cont = i.next(); @@ -562,7 +585,7 @@ public string decimal_entity_encode(string source) {      return encoded_str_builder.str;  } -internal abstract class BatchUploader { +public abstract class BatchUploader {      private int current_file = 0;      private Spit.Publishing.Publishable[] publishables = null;      private Session session = null; @@ -659,20 +682,6 @@ public string asciify_string(string s) {      return b.str;  } -/** @brief Work-around for a problem in libgee where a TreeSet can leak references when it - * goes out of scope; please see https://bugzilla.gnome.org/show_bug.cgi?id=695045 for more - * details. This class merely wraps it and adds a call to clear() to the destructor. - */ -public class FixedTreeSet<G> : Gee.TreeSet<G> { -    public FixedTreeSet(owned CompareDataFunc<G>? comp_func = null) { -        base((owned) comp_func); -    } -     -    ~FixedTreeSet() { -        clear(); -    } -} -  public abstract class GoogleSession : Session {      public abstract string get_user_name();      public abstract string get_access_token(); diff --git a/plugins/plugins.mk b/plugins/plugins.mk index 2f28608..687ceeb 100644 --- a/plugins/plugins.mk +++ b/plugins/plugins.mk @@ -1,5 +1,6 @@  PLUGINS := \ +	common \  	shotwell-transitions \  	shotwell-publishing \  	shotwell-data-imports diff --git a/plugins/shotwell-data-imports/Makefile b/plugins/shotwell-data-imports/Makefile index 52329e7..203aeed 100644 --- a/plugins/shotwell-data-imports/Makefile +++ b/plugins/shotwell-data-imports/Makefile @@ -5,12 +5,14 @@ PLUGIN_PKGS := \  	gtk+-3.0 \  	gexiv2 \  	gee-0.8 \ -	sqlite3 +	sqlite3 \ +	libxml-2.0 \ +	libsoup-2.4  SRC_FILES := \  	shotwell-data-imports.vala \ -	../common/VersionNumber.vala \ -	../common/SqliteSupport.vala \ +	VersionNumber.vala \ +	SqliteSupport.vala \  	FSpotImporter.vala \  	FSpotDatabaseBehavior.vala \  	FSpotDatabase.vala \ diff --git a/plugins/common/SqliteSupport.vala b/plugins/shotwell-data-imports/SqliteSupport.vala index 0dcc99c..859dc84 100644 --- a/plugins/common/SqliteSupport.vala +++ b/plugins/shotwell-data-imports/SqliteSupport.vala @@ -14,26 +14,26 @@ public errordomain DatabaseError {  }  public abstract class ImportableDatabaseTable { -     +      protected static Sqlite.Database db; -     +      public string table_name = null; -     +      protected void set_table_name(string table_name) {          this.table_name = table_name;      } -     +      // This method will throw an error on an SQLite return code unless it's OK, DONE, or ROW, which      // are considered normal results.      protected static void throw_error(string method, int res) throws DatabaseError {          string msg = "(%s) [%d] - %s".printf(method, res, db.errmsg()); -         +          switch (res) {              case Sqlite.OK:              case Sqlite.DONE:              case Sqlite.ROW:                  return; -             +              case Sqlite.PERM:              case Sqlite.BUSY:              case Sqlite.READONLY: @@ -45,26 +45,26 @@ public abstract class ImportableDatabaseTable {              case Sqlite.FORMAT:              case Sqlite.NOTADB:                  throw new DatabaseError.BACKING(msg); -             +              case Sqlite.NOMEM:                  throw new DatabaseError.MEMORY(msg); -             +              case Sqlite.ABORT:              case Sqlite.LOCKED:              case Sqlite.INTERRUPT:                  throw new DatabaseError.ABORT(msg); -             +              case Sqlite.FULL:              case Sqlite.EMPTY:              case Sqlite.TOOBIG:              case Sqlite.CONSTRAINT:              case Sqlite.RANGE:                  throw new DatabaseError.LIMITS(msg); -             +              case Sqlite.SCHEMA:              case Sqlite.MISMATCH:                  throw new DatabaseError.TYPESPEC(msg); -             +              case Sqlite.ERROR:              case Sqlite.INTERNAL:              case Sqlite.MISUSE: @@ -73,4 +73,3 @@ public abstract class ImportableDatabaseTable {          }      }  } - diff --git a/plugins/common/VersionNumber.vala b/plugins/shotwell-data-imports/VersionNumber.vala index 503cd65..7077597 100644 --- a/plugins/common/VersionNumber.vala +++ b/plugins/shotwell-data-imports/VersionNumber.vala @@ -12,25 +12,25 @@ namespace Utils {   */  public class VersionNumber : Object, Gee.Comparable<VersionNumber> {      private int[] version; -     +      public VersionNumber(int[] version) {          this.version = version;      } -     +      public VersionNumber.from_string(string str_version, string separator = ".") {          string[] version_items = str_version.split(separator);          this.version = new int[version_items.length];          for (int i = 0; i < version_items.length; i++)              this.version[i] = int.parse(version_items[i]);      } -     +      public string to_string() {          string[] version_items = new string[this.version.length];          for (int i = 0; i < this.version.length; i++)              version_items[i] = this.version[i].to_string();          return string.joinv(".", version_items);      } -     +      public int compare_to(VersionNumber other) {          int max_len = ((this.version.length > other.version.length) ?                         this.version.length : other.version.length); @@ -47,4 +47,3 @@ public class VersionNumber : Object, Gee.Comparable<VersionNumber> {  }  } - diff --git a/plugins/shotwell-publishing-extras/Makefile b/plugins/shotwell-publishing-extras/Makefile index 91452cf..83a42c2 100644 --- a/plugins/shotwell-publishing-extras/Makefile +++ b/plugins/shotwell-publishing-extras/Makefile @@ -16,8 +16,6 @@ SRC_FILES := \  	YandexPublishing.vala \  	TumblrPublishing.vala \  	RajcePublishing.vala \ -	../../src/util/string.vala \ -	../common/RESTSupport.vala  # RC_FILES must also be added to ../plugins.mk to ensure they're installed properly  RC_FILES := \ diff --git a/plugins/shotwell-publishing-extras/RajcePublishing.vala b/plugins/shotwell-publishing-extras/RajcePublishing.vala index 8ae05c6..d282ed5 100644 --- a/plugins/shotwell-publishing-extras/RajcePublishing.vala +++ b/plugins/shotwell-publishing-extras/RajcePublishing.vala @@ -932,10 +932,8 @@ internal class AuthenticationPane : Spit.Publishing.DialogPane, Object      private void update_login_button_sensitivity()  	{ -        login_button.set_sensitive( -            !is_string_empty(username_entry.get_text()) && -            !is_string_empty(password_entry.get_text()) -        ); +        login_button.set_sensitive(username_entry.text_length > 0 && +                                   password_entry.text_length > 0);      }      public Gtk.Widget get_widget() diff --git a/plugins/shotwell-publishing-extras/TumblrPublishing.vala b/plugins/shotwell-publishing-extras/TumblrPublishing.vala index 6bafb21..9e17b4e 100644 --- a/plugins/shotwell-publishing-extras/TumblrPublishing.vala +++ b/plugins/shotwell-publishing-extras/TumblrPublishing.vala @@ -6,7 +6,6 @@   */ -extern string hmac_sha1(string key, string message);  public class TumblrService : Object, Spit.Pluggable, Spit.Publishing.Service {     private const string ICON_FILENAME = "tumblr.png"; @@ -656,10 +655,8 @@ internal class AuthenticationPane : Spit.Publishing.DialogPane, Object {      }      private void update_login_button_sensitivity() { -        login_button.set_sensitive( -            !is_string_empty(username_entry.get_text()) && -            !is_string_empty(password_entry.get_text()) -        ); +        login_button.set_sensitive(username_entry.text_length > 0 && +                                   password_entry.text_length > 0);      }      public Gtk.Widget get_widget() { @@ -954,12 +951,7 @@ internal class UploadTransaction : Publishing.RESTSupport.UploadTransaction {  			string[] keywords = base.publishable.get_publishing_keywords();  			string tags = "";  			if (keywords != null) { -				foreach (string tag in keywords) { -				if (!is_string_empty(tags)) { -					tags += ","; -				} -				tags += tag; -				} +                tags = string.joinv (",", keywords);  			}  			add_argument("tags", Soup.URI.encode(tags, ENCODE_RFC_3986_EXTRA)); @@ -1105,7 +1097,7 @@ internal class Session : Publishing.RESTSupport.Session {          debug("signing key = '%s'", signing_key);          // compute the signature -        string signature = hmac_sha1(signing_key, signature_base_string); +        string signature = Publishing.RESTSupport.hmac_sha1(signing_key, signature_base_string);          debug("signature = '%s'", signature);          signature = Soup.URI.encode(signature, ENCODE_RFC_3986_EXTRA); diff --git a/plugins/shotwell-publishing-extras/YandexPublishing.vala b/plugins/shotwell-publishing-extras/YandexPublishing.vala index ec99c2b..6504572 100644 --- a/plugins/shotwell-publishing-extras/YandexPublishing.vala +++ b/plugins/shotwell-publishing-extras/YandexPublishing.vala @@ -338,7 +338,7 @@ private class UploadTransaction: Transaction {          image_part_header.set_content_disposition("form-data", result); -        Soup.Message outbound_message = soup_form_request_new_from_multipart(get_endpoint_url(), message_parts); +        Soup.Message outbound_message = Soup.Form.request_new_from_multipart(get_endpoint_url(), message_parts);          outbound_message.request_headers.append("Authorization", ("OAuth %s").printf(session.get_auth_token()));          outbound_message.request_headers.append("Connection", "close");          set_message(outbound_message); diff --git a/plugins/shotwell-publishing/FacebookPublishing.vala b/plugins/shotwell-publishing/FacebookPublishing.vala index 04dc51f..f6cccb6 100644 --- a/plugins/shotwell-publishing/FacebookPublishing.vala +++ b/plugins/shotwell-publishing/FacebookPublishing.vala @@ -940,8 +940,7 @@ internal class WebAuthenticationPane : Spit.Publishing.DialogPane, Object {      private string get_login_url() {          string facebook_locale = get_system_locale_as_facebook_locale(); - -        return "https://%s.facebook.com/dialog/oauth?client_id=%s&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=publish_actions,user_photos,user_videos&response_type=token".printf(facebook_locale, APPLICATION_ID); +        return "https://%s.facebook.com/dialog/oauth?client_id=%s&redirect_uri=https://www.facebook.com/connect/login_success.html&display=popup&scope=publish_actions,user_photos,user_videos&response_type=token".printf(facebook_locale, APPLICATION_ID);      }      private void on_page_load() { diff --git a/plugins/shotwell-publishing/Makefile b/plugins/shotwell-publishing/Makefile index 6b3945b..607bc6b 100644 --- a/plugins/shotwell-publishing/Makefile +++ b/plugins/shotwell-publishing/Makefile @@ -17,9 +17,7 @@ SRC_FILES := \  	PicasaPublishing.vala \  	FlickrPublishing.vala \  	YouTubePublishing.vala \ -	PiwigoPublishing.vala \ -	../../src/util/string.vala \ -	../common/RESTSupport.vala +	PiwigoPublishing.vala  RC_FILES := \  	facebook.png \ diff --git a/plugins/shotwell-publishing/PicasaPublishing.vala b/plugins/shotwell-publishing/PicasaPublishing.vala index d1af942..cb6352c 100644 --- a/plugins/shotwell-publishing/PicasaPublishing.vala +++ b/plugins/shotwell-publishing/PicasaPublishing.vala @@ -588,7 +588,7 @@ internal class UploadTransaction :          // create a message that can be sent over the wire whose payload is the multipart container          // that we've been building up          Soup.Message outbound_message = -            soup_form_request_new_from_multipart(get_endpoint_url(), message_parts); +            Soup.Form.request_new_from_multipart(get_endpoint_url(), message_parts);          outbound_message.request_headers.append("Authorization", "Bearer " +              session.get_access_token());          set_message(outbound_message); diff --git a/plugins/shotwell-publishing/PiwigoPublishing.vala b/plugins/shotwell-publishing/PiwigoPublishing.vala index d7b972b..7dd9090 100644 --- a/plugins/shotwell-publishing/PiwigoPublishing.vala +++ b/plugins/shotwell-publishing/PiwigoPublishing.vala @@ -937,29 +937,18 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {       * @param txn the received transaction       * @return the value of pwg_id if present or null if not found       */ -    private new string? get_pwg_id_from_transaction(Publishing.RESTSupport.Transaction txn) { -        string cookie = txn.get_response_headers().get_list("Set-Cookie"); -        string pwg_id = null; -        debug("Full cookie string: %s".printf(cookie)); -        if (!is_string_empty(cookie)) { -            string[] cookie_segments = cookie.split(";"); -            debug("Split full string into %d individual segments".printf(cookie_segments.length)); -            foreach(string cookie_segment in cookie_segments) { -                debug("Individual cookie segment: %s".printf(cookie_segment)); -                string[] cookie_sub_segments = cookie_segment.split(","); -                debug("Split segment into %d individual sub-segments".printf(cookie_sub_segments.length)); -                foreach(string cookie_sub_segment in cookie_sub_segments) { -                    debug("Individual cookie sub-segment: %s".printf(cookie_sub_segment)); -                    string[] cookie_kv = cookie_sub_segment.split("="); -                    debug("Split sub-segment into %d chunks".printf(cookie_kv.length)); -                    if (cookie_kv.length > 1 && cookie_kv[0].strip() == "pwg_id") { -                        debug("Found pwg_id: %s".printf(cookie_kv[1].strip())); -                        pwg_id = cookie_kv[1].strip(); -                    } -                } +    private string? get_pwg_id_from_transaction(Publishing.RESTSupport.Transaction txn) { +        string? pwg_id = null; + +        foreach (var cookie in Soup.cookies_from_response(txn.get_message())) { +            if (cookie.get_name() == "pwg_id") { +                // Collect all ids, last one is the one to use. First one is +                // for Guest apparently +                pwg_id = cookie.get_value(); +                debug ("Found pwg_id %s", pwg_id);              }          } -         +          return pwg_id;      }  } @@ -1093,11 +1082,9 @@ internal class AuthenticationPane : Spit.Publishing.DialogPane, Object {      }      private void update_login_button_sensitivity() { -        login_button.set_sensitive( -            !is_string_empty(url_entry.get_text()) && -            !is_string_empty(username_entry.get_text()) && -            !is_string_empty(password_entry.get_text()) -        ); +        login_button.set_sensitive(url_entry.text_length != 0 && +                                   username_entry.text_length != 0 && +                                   password_entry.text_length != 0);      }      public Gtk.Widget get_widget() { @@ -1325,7 +1312,7 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, Object {              !(                  create_new_radio.get_active() &&                  ( -                    is_string_empty(category_name) || +                    category_name != "" ||                      category_already_exists(search_name)                  )              ) @@ -1669,12 +1656,7 @@ private class ImagesAddTransaction : Publishing.RESTSupport.UploadTransaction {          string[] keywords = publishable.get_publishing_keywords();          string tags = "";          if (keywords != null) { -            foreach (string tag in keywords) { -                if (!is_string_empty(tags)) { -                    tags += ","; -                } -                tags += tag; -            } +            tags = string.joinv (",", keywords);          }          debug("PiwigoConnector: Uploading photo %s to category id %d with perm level %d", @@ -1683,16 +1665,16 @@ private class ImagesAddTransaction : Publishing.RESTSupport.UploadTransaction {          string name = publishable.get_publishing_name();          string comment = publishable.get_param_string(              Spit.Publishing.Publishable.PARAM_STRING_COMMENT); -        if (is_string_empty(name)) { +        if (name != "") {              name = publishable.get_param_string(                  Spit.Publishing.Publishable.PARAM_STRING_BASENAME);              add_argument("name", name); -            if (!is_string_empty(comment)) { +            if (comment != null && comment != "") {                  add_argument("comment", comment);              }          } else {              // name is set -            if (!is_string_empty(comment)) { +            if (comment != null && comment != "") {                  add_argument("name", name);                  add_argument("comment", comment);              } else { @@ -1710,7 +1692,7 @@ private class ImagesAddTransaction : Publishing.RESTSupport.UploadTransaction {          add_argument("category", parameters.category.id.to_string());          add_argument("level", parameters.perm_level.id.to_string());          if (!parameters.no_upload_tags) -            if (!is_string_empty(tags)) +            if (tags != "")                  add_argument("tags", tags);          // TODO: update the Publishable interface so that it gives access to          // the image's meta-data where the author (artist) is kept diff --git a/plugins/shotwell-publishing/YouTubePublishing.vala b/plugins/shotwell-publishing/YouTubePublishing.vala index ccb835f..15f283f 100644 --- a/plugins/shotwell-publishing/YouTubePublishing.vala +++ b/plugins/shotwell-publishing/YouTubePublishing.vala @@ -592,7 +592,7 @@ internal class UploadTransaction : Publishing.RESTSupport.GooglePublisher.Authen          // create a message that can be sent over the wire whose payload is the multipart container          // that we've been building up          Soup.Message outbound_message = -            soup_form_request_new_from_multipart(get_endpoint_url(), message_parts); +            Soup.Form.request_new_from_multipart(get_endpoint_url(), message_parts);          outbound_message.request_headers.append("X-GData-Key", "key=%s".printf(DEVELOPER_KEY));          outbound_message.request_headers.append("Slug",              publishable.get_param_string(Spit.Publishing.Publishable.PARAM_STRING_BASENAME)); diff --git a/plugins/shotwell-transitions/Makefile b/plugins/shotwell-transitions/Makefile index 043891c..9044011 100644 --- a/plugins/shotwell-transitions/Makefile +++ b/plugins/shotwell-transitions/Makefile @@ -1,6 +1,10 @@  PLUGIN := shotwell-transitions +PLUGIN_PKGS := \ +	libxml-2.0 \ +	libsoup-2.4 +  SRC_FILES := \  	shotwell-transitions.vala \  	FadeEffect.vala \ | 
