Merge 1.0.
authorCarl Hetherington <cth@carlh.net>
Thu, 24 Oct 2013 08:29:28 +0000 (09:29 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 24 Oct 2013 08:29:28 +0000 (09:29 +0100)
21 files changed:
ChangeLog
debian/changelog
platform/linux/control-13.10-32
platform/linux/control-13.10-64
src/lib/content.cc
src/lib/content.h
src/lib/content_factory.cc
src/lib/content_factory.h
src/lib/film.cc
src/lib/film.h
src/lib/player.cc
src/lib/playlist.cc
src/lib/playlist.h
src/tools/dcpomatic.cc
src/wx/content_menu.cc
src/wx/content_menu.h
src/wx/film_editor.cc
src/wx/film_viewer.cc
src/wx/wscript
src/wx/wx_util.h
wscript

index 8a0a7d1de77d5fcb9baaada6dc5dd0fb6337eafe..e251b1cabfd2956f446a2eb1d449e9ded6781ee2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2013-10-23  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.21 released.
+
+2013-10-23  Carl Hetherington  <cth@carlh.net>
+
+       * Use our own directory picker on Ubuntu 13.10 as well
+       as Ubuntu 13.04 as it seems similarly broken.
+
+2013-10-22  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.20 released.
+
+2013-10-22  Carl Hetherington  <cth@carlh.net>
+
+       * Allow films to be loaded when content is missing,
+       and then that content can be re-found.
+
 2013-10-21  Carl Hetherington  <cth@carlh.net>
 
        * Version 1.19 released.
index 7a9849e31993dada0cf1a0febfba30f2c709fcb9..832577378b9cce91aededb93ddd3466f6ea76db9 100644 (file)
@@ -1,4 +1,4 @@
-dcpomatic (1.19-1) UNRELEASED; urgency=low
+dcpomatic (1.21-1) UNRELEASED; urgency=low
 
   * New upstream release.
   * New upstream release.
@@ -23,8 +23,10 @@ dcpomatic (1.19-1) UNRELEASED; urgency=low
   * New upstream release.
   * New upstream release.
   * New upstream release.
+  * New upstream release.
+  * New upstream release.
 
- -- Carl Hetherington <carl@d1stkfactory>  Mon, 21 Oct 2013 22:42:54 +0100
+ -- Carl Hetherington <carl@d1stkfactory>  Wed, 23 Oct 2013 23:04:24 +0100
 
 dcpomatic (0.87-1) UNRELEASED; urgency=low
 
index f3b4edbdcdc48ed7ad186909762a119877aa5eec..420469c85cef81b116171b29ee7e759ccf63f851 100644 (file)
@@ -8,7 +8,7 @@ Homepage: http://dcpomatic.com/
 
 Package: dcpomatic
 Architecture: i386
-Depends: libc6 (>= 2.17-93), libssh-4 (>= 0.5.4), libboost-filesystem1.54.0 (>= 1.54.0), libboost-thread1.54.0 (>= 1.54.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.36.0), libgtk2.0-0 (>= 2.24.20), libxmlsec1 (>= 1.2.18-2), libboost-date-time1.54.0 (>= 1.54.0), libcurl3 (>= 7.32.0-1ubuntu1), libzip2 (>= 0.10.1-1.1)
+Depends: libc6 (>= 2.17-93), libssh-4 (>= 0.5.4), libboost-filesystem1.53.0 (>= 1.53.0), libboost-thread1.53.0 (>= 1.53.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.36.0), libgtk2.0-0 (>= 2.24.20), libxmlsec1 (>= 1.2.18-2), libboost-date-time1.53.0 (>= 1.53.0), libcurl3 (>= 7.32.0-1ubuntu1), libzip2 (>= 0.10.1-1.1)
 Description: Generator of Digital Cinema Packages (DCPs)
   DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio
   files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
index 55ca1622fa5f92e2b6c8c811d0cfabfd9b2f89d3..39b367241f6afb4828d3827c24dbac67586f1cb5 100644 (file)
@@ -8,7 +8,7 @@ Homepage: http://dcpomatic.com/
 
 Package: dcpomatic
 Architecture: amd64
-Depends: libc6 (>= 2.17-93), libssh-4 (>= 0.5.4), libboost-filesystem1.54.0 (>= 1.54.0), libboost-thread1.54.0 (>= 1.54.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.36.0), libgtk2.0-0 (>= 2.24.20), libxmlsec1 (>= 1.2.18-2), libboost-date-time1.54.0 (>= 1.54.0), libcurl3 (>= 7.32.0-1ubuntu1), libzip2 (>= 0.10.1-1.1)
+Depends: libc6 (>= 2.17-93), libssh-4 (>= 0.5.4), libboost-filesystem1.53.0 (>= 1.53.0), libboost-thread1.53.0 (>= 1.53.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.36.0), libgtk2.0-0 (>= 2.24.20), libxmlsec1 (>= 1.2.18-2), libboost-date-time1.53.0 (>= 1.53.0), libcurl3 (>= 7.32.0-1ubuntu1), libzip2 (>= 0.10.1-1.1)
 Description: Generator of Digital Cinema Packages (DCPs)
   DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio
   files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
index dbb84120034f441ed2028e2eb63a2836aed8ea48..e3ad42560edf82ef0e1870003f46eaa04c5cbfad 100644 (file)
@@ -31,10 +31,11 @@ using std::set;
 using boost::shared_ptr;
 using boost::lexical_cast;
 
-int const ContentProperty::POSITION = 400;
-int const ContentProperty::LENGTH = 401;
-int const ContentProperty::TRIM_START = 402;
-int const ContentProperty::TRIM_END = 403;
+int const ContentProperty::PATH = 400;
+int const ContentProperty::POSITION = 401;
+int const ContentProperty::LENGTH = 402;
+int const ContentProperty::TRIM_START = 403;
+int const ContentProperty::TRIM_END = 404;
 
 Content::Content (shared_ptr<const Film> f, Time p)
        : _film (f)
@@ -191,3 +192,18 @@ Content::identifier () const
 
        return s.str ();
 }
+
+bool
+Content::path_valid () const
+{
+       return boost::filesystem::exists (_path);
+}
+
+void
+Content::set_path (boost::filesystem::path path)
+{
+       _path = path;
+       signal_changed (ContentProperty::PATH);
+}
+
+       
index 9c7ad2fc2984df5ff021c2f623634ba96310f6a3..c066c61e036a047813ecde76a71c2a9d1c9552b6 100644 (file)
@@ -38,6 +38,7 @@ class Film;
 class ContentProperty
 {
 public:
+       static int const PATH;
        static int const POSITION;
        static int const LENGTH;
        static int const TRIM_START;
@@ -61,12 +62,16 @@ public:
        virtual std::string identifier () const;
 
        boost::shared_ptr<Content> clone () const;
+
+       void set_path (boost::filesystem::path);
        
        boost::filesystem::path path () const {
                boost::mutex::scoped_lock lm (_mutex);
                return _path;
        }
 
+       bool path_valid () const;
+
        /** @return MD5 digest of the content's file(s) */
        std::string digest () const {
                boost::mutex::scoped_lock lm (_mutex);
index 6ed01f174acb6e0068bdf9ca88d368a2de06455c..d42491f7f58c16f40b4542a11699edbf041bc107 100644 (file)
@@ -22,6 +22,7 @@
 #include "still_image_content.h"
 #include "moving_image_content.h"
 #include "sndfile_content.h"
+#include "util.h"
 
 using std::string;
 using boost::shared_ptr;
@@ -45,3 +46,19 @@ content_factory (shared_ptr<const Film> film, shared_ptr<cxml::Node> node)
 
        return content;
 }
+
+shared_ptr<Content>
+content_factory (shared_ptr<const Film> film, boost::filesystem::path path)
+{
+       shared_ptr<Content> content;
+               
+       if (valid_image_file (path)) {
+               content.reset (new StillImageContent (film, path));
+       } else if (SndfileContent::valid_file (path)) {
+               content.reset (new SndfileContent (film, path));
+       } else {
+               content.reset (new FFmpegContent (film, path));
+       }
+
+       return content;
+}
index 27cd36024c9046c6297b7c48c2f5434e12cf5222..93fd98d8346b3902c63e867eff1dfe5b50de0d39 100644 (file)
@@ -20,3 +20,4 @@
 class Film;
 
 extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, boost::shared_ptr<cxml::Node>);
+extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, boost::filesystem::path);
index f869289d5700fbab7fca1de7e5785d58a3775d29..650163efebe174b1e810f960869bfdb27ad46d6c 100644 (file)
@@ -844,6 +844,12 @@ Film::best_video_frame_rate () const
        return _playlist->best_dcp_frame_rate ();
 }
 
+bool
+Film::content_paths_valid () const
+{
+       return _playlist->content_paths_valid ();
+}
+
 void
 Film::playlist_content_changed (boost::weak_ptr<Content> c, int p)
 {
index 8cfc490886629ea99c3cc5e0cddd07b7932ceb7a..6bd04572b4f771979dfee6cf568652a4d22da2fd 100644 (file)
@@ -111,10 +111,10 @@ public:
        /* Proxies for some Playlist methods */
 
        ContentList content () const;
-
        Time length () const;
        bool has_subtitles () const;
        OutputVideoFrame best_video_frame_rate () const;
+       bool content_paths_valid () const;
 
        libdcp::KDM
        make_kdm (
index 73c873c59f1a00944879e56f28bd0b0ca3034c00..02d3903654649f33ba7ce582221768a3f34447fe 100644 (file)
@@ -536,6 +536,10 @@ Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
                property == VideoContentProperty::VIDEO_RATIO
                ) {
                
+               Changed (frequent);
+
+       } else if (property == ContentProperty::PATH) {
+
                Changed (frequent);
        }
 }
index 1712dc8ff54dee392f5e865830aa91cea76c2cf1..621b99dd742ed6aa914beabb8f60d6042c622ebf 100644 (file)
@@ -390,3 +390,15 @@ Playlist::move_later (shared_ptr<Content> c)
        
        Changed ();
 }
+
+bool
+Playlist::content_paths_valid () const
+{
+       for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) {
+               if (!(*i)->path_valid ()) {
+                       return false;
+               }
+       }
+
+       return true;
+}
index 05928ee57c13e48aa6755a6b04e06acbc8299708..a1ae9b151bfad4647fc6b9e4cd67158bbe0f8f53 100644 (file)
@@ -80,6 +80,8 @@ public:
 
        void repeat (ContentList, int);
 
+       bool content_paths_valid () const;
+
        mutable boost::signals2::signal<void ()> Changed;
        /** Third parameter is true if signals are currently being emitted frequently */
        mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int, bool)> ContentChanged;
index 8d1ebf5d3930410672a3788d383143258bffccb5..4972654b27aabd28ed39674c0f672f2575f7c914 100644 (file)
@@ -501,21 +501,12 @@ private:
        }       
 };
 
-#if wxMINOR_VERSION == 9
 static const wxCmdLineEntryDesc command_line_description[] = {
        { wxCMD_LINE_OPTION, "l", "log", "set log level (silent, verbose or timing)", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_SWITCH, "n", "new", "create new film", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 }
 };
-#else
-static const wxCmdLineEntryDesc command_line_description[] = {
-       { wxCMD_LINE_OPTION, wxT("l"), wxT("log"), wxT("set log level (silent, verbose or timing)"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
-       { wxCMD_LINE_SWITCH, wxT("n"), wxT("new"), wxT("create new film"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
-       { wxCMD_LINE_PARAM, 0, 0, wxT("film to load or create"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
-       { wxCMD_LINE_NONE, wxT(""), wxT(""), wxT(""), wxCmdLineParamType (0), 0 }
-};
-#endif
 
 class App : public wxApp
 {
index 60a95a9f26ed8c5166849f114ee7cb3c87220ba1..6183e344470fc496871746c80a8aa83d84891808 100644 (file)
 */
 
 #include <wx/wx.h>
+#include <wx/dirdlg.h>
 #include "lib/playlist.h"
 #include "lib/film.h"
+#include "lib/moving_image_content.h"
+#include "lib/content_factory.h"
+#include "lib/examine_content_job.h"
+#include "lib/job_manager.h"
 #include "content_menu.h"
 #include "repeat_dialog.h"
+#include "wx_util.h"
 
 using std::cout;
 using boost::shared_ptr;
+using boost::weak_ptr;
+using boost::dynamic_pointer_cast;
 
 enum {
        ID_repeat = 1,
+       ID_find_missing,
        ID_remove
 };
 
@@ -36,12 +45,14 @@ ContentMenu::ContentMenu (shared_ptr<Film> f, wxWindow* p)
        , _film (f)
        , _parent (p)
 {
-       _menu->Append (ID_repeat, _("Repeat..."));
+       _repeat = _menu->Append (ID_repeat, _("Repeat..."));
+       _find_missing = _menu->Append (ID_find_missing, _("Find missing..."));
        _menu->AppendSeparator ();
-       _menu->Append (ID_remove, _("Remove"));
+       _remove = _menu->Append (ID_remove, _("Remove"));
 
-       _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, &ContentMenu::repeat, this, ID_repeat);
-       _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, &ContentMenu::remove, this, ID_remove);
+       _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&ContentMenu::repeat, this), ID_repeat);
+       _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&ContentMenu::find_missing, this), ID_find_missing);
+       _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&ContentMenu::remove, this), ID_remove);
 }
 
 ContentMenu::~ContentMenu ()
@@ -53,32 +64,38 @@ void
 ContentMenu::popup (ContentList c, wxPoint p)
 {
        _content = c;
+       _repeat->Enable (!_content.empty ());
+       _find_missing->Enable (_content.size() == 1 && !_content.front()->path_valid ());
+       _remove->Enable (!_content.empty ());
        _parent->PopupMenu (_menu, p);
 }
 
 void
-ContentMenu::repeat (wxCommandEvent &)
+ContentMenu::repeat ()
 {
        if (_content.empty ()) {
                return;
        }
                
-       RepeatDialog d (_parent);
-       d.ShowModal ();
+       RepeatDialog* d = new RepeatDialog (_parent);
+       if (d->ShowModal() != wxID_OK) {
+               d->Destroy ();
+               return;
+       }
 
        shared_ptr<const Film> film = _film.lock ();
        if (!film) {
                return;
        }
 
-       film->playlist()->repeat (_content, d.number ());
-       d.Destroy ();
+       film->playlist()->repeat (_content, d->number ());
+       d->Destroy ();
 
        _content.clear ();
 }
 
 void
-ContentMenu::remove (wxCommandEvent &)
+ContentMenu::remove ()
 {
        if (_content.empty ()) {
                return;
@@ -94,3 +111,73 @@ ContentMenu::remove (wxCommandEvent &)
        _content.clear ();
 }
 
+void
+ContentMenu::find_missing ()
+{
+       if (_content.size() != 1) {
+               return;
+       }
+
+       shared_ptr<const Film> film = _film.lock ();
+       if (!film) {
+               return;
+       }
+       
+       shared_ptr<Content> content;
+
+       /* XXX: a bit nasty */
+       if (dynamic_pointer_cast<MovingImageContent> (_content.front ())) {
+               wxDirDialog* d = new wxDirDialog (0, _("Choose a folder"), wxT (""), wxDD_DIR_MUST_EXIST);
+               int const r = d->ShowModal ();
+               if (r == wxID_OK) {
+                       content.reset (new MovingImageContent (film, boost::filesystem::path (wx_to_std (d->GetPath ()))));
+               }
+               d->Destroy ();
+       } else {
+               wxFileDialog* d = new wxFileDialog (0, _("Choose a file"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE);
+               int const r = d->ShowModal ();
+               if (r == wxID_OK) {
+                       content = content_factory (film, wx_to_std (d->GetPath ()));
+               }
+               d->Destroy ();
+       }
+
+       if (!content) {
+               return;
+       }
+
+       shared_ptr<Job> j (new ExamineContentJob (film, content));
+       
+       j->Finished.connect (
+               bind (
+                       &ContentMenu::maybe_found_missing,
+                       this,
+                       boost::weak_ptr<Job> (j),
+                       boost::weak_ptr<Content> (_content.front ()),
+                       boost::weak_ptr<Content> (content)
+                       )
+               );
+       
+       JobManager::instance()->add (j);
+}
+
+void
+ContentMenu::maybe_found_missing (weak_ptr<Job> j, weak_ptr<Content> oc, weak_ptr<Content> nc)
+{
+       shared_ptr<Job> job = j.lock ();
+       if (!job || !job->finished_ok ()) {
+               return;
+       }
+
+       shared_ptr<Content> old_content = oc.lock ();
+       shared_ptr<Content> new_content = nc.lock ();
+       assert (old_content);
+       assert (new_content);
+
+       if (new_content->digest() != old_content->digest()) {
+               error_dialog (0, _("The content file(s) you specified are not the same as those that are missing.  Either try again with the correct content file or remove the missing content."));
+               return;
+       }
+
+       old_content->set_path (new_content->path ());
+}
index 127fbea1a2ee05b4e9508772d5425d48f1ab3ccf..2a672532001ca0ddaebcec1f41c04d4d03a599b8 100644 (file)
@@ -36,13 +36,18 @@ public:
        void popup (ContentList, wxPoint);
 
 private:
-       void repeat (wxCommandEvent &);
-       void remove (wxCommandEvent &);
+       void repeat ();
+       void find_missing ();
+       void remove ();
+       void maybe_found_missing (boost::weak_ptr<Job>, boost::weak_ptr<Content>, boost::weak_ptr<Content>);
        
        wxMenu* _menu;
        boost::weak_ptr<Film> _film;
        wxWindow* _parent;
        ContentList _content;
+       wxMenuItem* _repeat;
+       wxMenuItem* _find_missing;
+       wxMenuItem* _remove;
 };
 
 #endif
index f2514da510358bab694432a43fb5e35ba8128ac2..1472c8b89571b1c4f9bb35361919c9c3e2f6ed99 100644 (file)
@@ -44,6 +44,8 @@
 #include "lib/sound_processor.h"
 #include "lib/scaler.h"
 #include "lib/playlist.h"
+#include "lib/content.h"
+#include "lib/content_factory.h"
 #include "timecode.h"
 #include "wx_util.h"
 #include "film_editor.h"
@@ -490,6 +492,8 @@ FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property)
 
        if (property == FFmpegContentProperty::AUDIO_STREAM) {
                setup_dcp_name ();
+       } else if (property == ContentProperty::PATH) {
+               setup_content ();
        }
 }
 
@@ -705,10 +709,22 @@ FilmEditor::setup_content ()
        ContentList content = _film->content ();
        for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
                int const t = _content->GetItemCount ();
-               _content->InsertItem (t, std_to_wx ((*i)->summary ()));
+               bool const valid = (*i)->path_valid ();
+
+               string s = (*i)->summary ();
+               if (!valid) {
+                       s = _("MISSING: ") + s;
+               }
+                       
+               _content->InsertItem (t, std_to_wx (s));
+
                if ((*i)->summary() == selected_summary) {
                        _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
                }
+
+               if (!valid) {
+                       _content->SetItemTextColour (t, *wxRED);
+               }
        }
 
        if (selected_summary.empty () && !content.empty ()) {
@@ -734,19 +750,7 @@ FilmEditor::content_add_file_clicked ()
        /* XXX: check for lots of files here and do something */
 
        for (unsigned int i = 0; i < paths.GetCount(); ++i) {
-               boost::filesystem::path p (wx_to_std (paths[i]));
-
-               shared_ptr<Content> c;
-
-               if (valid_image_file (p)) {
-                       c.reset (new StillImageContent (_film, p));
-               } else if (SndfileContent::valid_file (p)) {
-                       c.reset (new SndfileContent (_film, p));
-               } else {
-                       c.reset (new FFmpegContent (_film, p));
-               }
-
-               _film->examine_and_add_content (c);
+               _film->examine_and_add_content (content_factory (_film, wx_to_std (paths[i])));
        }
 }
 
@@ -916,7 +920,9 @@ void
 FilmEditor::content_right_click (wxListEvent& ev)
 {
        ContentList cl;
-       cl.push_back (selected_content ());
+       if (selected_content ()) {
+               cl.push_back (selected_content ());
+       }
        _menu.popup (cl, ev.GetPoint ());
 }
 
index a1a47a943a3685811a4b3b6070b4c8aafc281774..03e8419a091f16b5fa95c7085af4f376824ff5a9 100644 (file)
@@ -334,6 +334,10 @@ FilmViewer::fetch_next_frame ()
                _play_button->SetValue (false);
                check_play_state ();
                error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data()));
+       } catch (OpenFileError& e) {
+               /* There was a problem opening a content file; we'll let this slide as it
+                  probably means a missing content file, which we're already taking care of.
+               */
        }
 
        _panel->Refresh ();
index 8f35e2facea49aa784b761ef4dbb3cc341f3b537..09e78316158d5b2fc464918dd4a89d49c6ad6133 100644 (file)
@@ -69,7 +69,6 @@ def build(bld):
         obj = bld(features = 'cxx cxxshlib')
 
     obj.name   = 'libdcpomatic-wx'
-#    obj.includes = [ '..' ]
     obj.export_includes = ['..']
     obj.uselib = 'WXWIDGETS'
     if bld.env.TARGET_LINUX:
index aefa75fca57749ef679371bb16ed04f223c8063a..48683492c3599428b1b8f947d0ea77885394a652 100644 (file)
@@ -85,9 +85,10 @@ extern void checked_set (wxRadioButton* widget, bool value);
 extern void checked_set (wxStaticText* widget, std::string value);
 
 /* GTK 2.24.17 has a buggy GtkFileChooserButton and it was put in Ubuntu 13.04.
+   This also seems to apply to 2.24.20 in Ubuntu 13.10
    Use our own dir picker as this is the least bad option I can think of.
 */
-#if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && GTK_MICRO_VERSION == 17)
+#if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && (GTK_MICRO_VERSION == 17 || GTK_MICRO_VERSION == 20))
 #define DCPOMATIC_USE_OWN_DIR_PICKER
 #endif
 
diff --git a/wscript b/wscript
index c05e0e051a31ea6600486007906a79e00463191f..c3033f60c1d576e5814da75fe8967ce4eb2e537b 100644 (file)
--- a/wscript
+++ b/wscript
@@ -3,7 +3,7 @@ import os
 import sys
 
 APPNAME = 'dcpomatic'
-VERSION = '1.20pre'
+VERSION = '1.22pre'
 
 def options(opt):
     opt.load('compiler_cxx')