diff options
| author | Jörg Frings-Fürst <debian@jff.email> | 2023-11-20 18:26:07 +0100 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff.email> | 2023-11-20 18:26:07 +0100 | 
| commit | 445dc18bf3e37044e17083fe76f76c17ceb6a0d7 (patch) | |
| tree | 315f7cf2a7934b0ecf45ac2caa3c87949a90dfc4 /src | |
| parent | 918f560d56129ed03f19d843ea2efd7cb4b23821 (diff) | |
| parent | 394326a81d1248bbc5b1a35a8ae623c65ef6a9ea (diff) | |
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'src')
| -rw-r--r-- | src/AppWindow.vala | 52 | ||||
| -rw-r--r-- | src/BatchImport.vala | 6 | ||||
| -rw-r--r-- | src/MediaDataRepresentation.vala | 2 | ||||
| -rw-r--r-- | src/Photo.vala | 3 | ||||
| -rw-r--r-- | src/PhotoPage.vala | 13 | ||||
| -rw-r--r-- | src/Properties.vala | 10 | ||||
| -rw-r--r-- | src/Thumbnail.vala | 7 | ||||
| -rw-r--r-- | src/ThumbnailCache.vala | 17 | ||||
| -rw-r--r-- | src/camera/GPhoto.vala | 14 | ||||
| -rw-r--r-- | src/camera/ImportPage.vala | 5 | ||||
| -rw-r--r-- | src/db/TagTable.vala | 2 | ||||
| -rw-r--r-- | src/direct/DirectPhotoPage.vala | 11 | ||||
| -rw-r--r-- | src/direct/DirectWindow.vala | 3 | ||||
| -rw-r--r-- | src/folders/FoldersBranch.vala | 10 | ||||
| -rw-r--r-- | src/util/string.vala | 6 | 
15 files changed, 98 insertions, 63 deletions
| diff --git a/src/AppWindow.vala b/src/AppWindow.vala index 438806c..1fb0515 100644 --- a/src/AppWindow.vala +++ b/src/AppWindow.vala @@ -23,7 +23,17 @@ public class FullscreenWindow : PageWindow {          { "LeaveFullscreen", on_close }      }; -    public FullscreenWindow(Page page) { +    public struct Monitor { +        Gdk.Screen screen; +        Gdk.Monitor? monitor; +        int monitor_nr; + +        public Gdk.Rectangle get_geometry() { +            return monitor.get_geometry(); +        } +    } + +    public FullscreenWindow(Page page, Monitor monitor) {          base ();          set_current_page(page); @@ -32,12 +42,7 @@ public class FullscreenWindow : PageWindow {          const string[] accels = { "F11", null };          Application.set_accels_for_action ("win.LeaveFullscreen", accels); -        set_screen(AppWindow.get_instance().get_screen()); -         -        // Needed so fullscreen will occur on correct monitor in multi-monitor setups -        Gdk.Rectangle monitor = get_monitor_geometry(); -        move(monitor.x, monitor.y); -         +        set_screen(monitor.screen);          set_border_width(0);          // restore pin state @@ -80,10 +85,11 @@ public class FullscreenWindow : PageWindow {          // call to set_default_size() saves one repaint caused by changing          // size from default to full screen. In slideshow mode, this change          // also causes pixbuf cache updates, so it really saves some work. -        set_default_size(monitor.width, monitor.height); +        Gdk.Rectangle monitor_geometry = monitor.get_geometry(); +        set_default_size(monitor_geometry.width, monitor_geometry.height);          // need to create a Gdk.Window to set masks -        fullscreen(); +        fullscreen_on_monitor(monitor.screen, monitor.monitor_nr);          show_all();          // capture motion events to show the toolbar @@ -113,11 +119,6 @@ public class FullscreenWindow : PageWindow {      public void update_toolbar_dismissal() {          is_toolbar_dismissal_enabled = !pin_button.get_active();      } - -    private Gdk.Rectangle get_monitor_geometry() { -        var monitor = get_display().get_monitor_at_window(AppWindow.get_instance().get_window()); -        return monitor.get_geometry(); -    }      public override bool configure_event(Gdk.EventConfigure event) {          bool result = base.configure_event(event); @@ -200,6 +201,11 @@ public class FullscreenWindow : PageWindow {          int py;          seat.get_pointer().get_position(null, null, out py); + +        // If we are on a completely different screen, ignore it +        if (seat.get_display() != toolbar.get_display()) { +            return false; +        }          int wy;          toolbar.get_window().get_geometry(null, out wy, null, null); @@ -402,8 +408,6 @@ public abstract class AppWindow : PageWindow {      // added to is the one that claims its accelerators      protected bool maximized = false;      protected Dimensions dimensions; -    protected int pos_x = 0; -    protected int pos_y = 0;      protected AppWindow() {          base(); @@ -659,10 +663,20 @@ public abstract class AppWindow : PageWindow {              return;          } -        get_position(out pos_x, out pos_y); +        // Need to call this before hide() otherwise we will always get  +        // the left-most monitor +        FullscreenWindow.Monitor monitor= {get_screen(), null, 0}; +        var display = get_display(); +        for (var i = 0; i < display.get_n_monitors(); i++) { +            if  (display.get_monitor(i) == display.get_monitor_at_window(get_window())) { +                monitor.monitor = display.get_monitor(i); +                monitor.monitor_nr = i; +                break; +            } +        }          hide(); -        FullscreenWindow fsw = new FullscreenWindow(page); +        FullscreenWindow fsw = new FullscreenWindow(page, monitor);          if (get_current_page() != null)              get_current_page().switching_to_fullscreen(fsw); @@ -675,8 +689,6 @@ public abstract class AppWindow : PageWindow {          if (fullscreen_window == null)              return; -        move(pos_x, pos_y); -          show_all();          if (get_current_page() != null) diff --git a/src/BatchImport.vala b/src/BatchImport.vala index 90ccba8..ae4f573 100644 --- a/src/BatchImport.vala +++ b/src/BatchImport.vala @@ -1508,7 +1508,13 @@ private class WorkSniffer : BackgroundImportJob {              FileToPrepare file_a = (FileToPrepare) a;              FileToPrepare file_b = (FileToPrepare) b;              string sa = file_a.get_path(); +            if (!sa.validate()) { +                sa = Uri.escape_string(sa, Uri.RESERVED_CHARS_ALLOWED_IN_PATH, true); +            }                          string sb = file_b.get_path(); +            if (!sb.validate()) { +                sb = Uri.escape_string(sa, Uri.RESERVED_CHARS_ALLOWED_IN_PATH, true); +            }              return utf8_cs_compare(sa, sb);          }); diff --git a/src/MediaDataRepresentation.vala b/src/MediaDataRepresentation.vala index 3400577..e0e6b7f 100644 --- a/src/MediaDataRepresentation.vala +++ b/src/MediaDataRepresentation.vala @@ -596,7 +596,7 @@ public abstract class MediaSourceCollection : DatabaseSourceCollection {          string[] components = source_id.split("-");          assert(components.length == 2); -        return fetch_by_numeric_id(parse_int64(components[1], 16)); +        return fetch_by_numeric_id(int64.parse(components[1], 16));      }      public abstract Gee.Collection<string> get_event_source_ids(EventID event_id); diff --git a/src/Photo.vala b/src/Photo.vala index 34cfedf..f636a32 100644 --- a/src/Photo.vala +++ b/src/Photo.vala @@ -3808,6 +3808,7 @@ public abstract class Photo : PhotoSource, Dateable, Positionable {          if (ext == null || !file_format.get_properties().is_recognized_extension(ext))              ext = file_format.get_properties().get_default_extension(); +        // TRANSLATORS: "modified" here is part of a file name that was changed with another image tool outside of Shotwell. Note that there are potential issues with UTF-8 characters          string editable_basename = "%s_%s.%s".printf(name, _("modified"), ext);          bool collision; @@ -4837,7 +4838,7 @@ public class LibraryPhotoSourceCollection : MediaSourceCollection {          assert(source_id.has_prefix(Photo.TYPENAME));          string numeric_only = source_id.substring(Photo.TYPENAME.length, -1); -        return fetch_by_numeric_id(parse_int64(numeric_only, 16)); +        return fetch_by_numeric_id(int64.parse(numeric_only, 16));      }      public override Gee.Collection<string> get_event_source_ids(EventID event_id){ diff --git a/src/PhotoPage.vala b/src/PhotoPage.vala index 10ebb10..a279d89 100644 --- a/src/PhotoPage.vala +++ b/src/PhotoPage.vala @@ -78,17 +78,24 @@ public class ZoomBuffer : Object {      private TransformationJob? demand_transform_job = null; // only 1 demand transform job can be                                                              // active at a time      private Workers workers = null; -    private SinglePhotoPage parent_page; +    private unowned SinglePhotoPage parent_page;      private bool is_interactive_redraw_in_progress = false;      public ZoomBuffer(SinglePhotoPage parent_page, Photo backing_photo,          Gdk.Pixbuf preview_image) {          this.parent_page = parent_page; +        this.parent_page.add_weak_pointer(&this.parent_page);          this.preview_image = preview_image;          this.backing_photo = backing_photo;          this.workers = new Workers(2, false);      } +    ~ZoomBuffer() { +        if (this.parent_page != null) { +            this.parent_page.remove_weak_pointer(&this.parent_page); +        } +    } +      private void on_iso_source_fetch_complete(BackgroundJob job) {          IsoSourceFetchJob fetch_job = (IsoSourceFetchJob) job;          if (fetch_job.fetched == null) { @@ -103,7 +110,7 @@ public class ZoomBuffer : Object {          }          object_state = ObjectState.SOURCE_NOT_TRANSFORMED; -        if (!is_interactive_redraw_in_progress) +        if (!is_interactive_redraw_in_progress && parent_page != null)              parent_page.repaint();          BackgroundJob transformation_job = new TransformationJob(this, iso_source_image, @@ -140,7 +147,7 @@ public class ZoomBuffer : Object {          demand_transform_cached_pixbuf = transform_job.transformed;          demand_transform_job = null; -        parent_page.repaint(); +        if (parent_page != null) parent_page.repaint();      }      // passing a 'reduced_pixbuf' that has one-quarter the number of pixels as the 'iso_pixbuf' is diff --git a/src/Properties.vala b/src/Properties.vala index c0cf2fd..b8c3e0d 100644 --- a/src/Properties.vala +++ b/src/Properties.vala @@ -46,13 +46,13 @@ private abstract class Properties : Gtk.Box {          } else {              Gtk.Label info_label = new Gtk.Label("");              if (!is_string_empty(info_text)) { -                info_label.set_tooltip_markup(info_text); +                info_label.set_tooltip_text(info_text);              }              if (href == null) { -                info_label.set_markup(is_string_empty(info_text) ? "" : info_text); +                info_label.set_text(is_string_empty(info_text) ? "" : info_text);              } else { -                info_label.set_markup("<a href=\"%s\">%s</a>".printf(href, info_text)); +                info_label.set_markup("<a href=\"%s\">%s</a>".printf(href, Markup.escape_text(info_text)));              }              info_label.set_ellipsize(Pango.EllipsizeMode.END);              info_label.halign = Gtk.Align.START; @@ -534,8 +534,8 @@ private class ExtendedProperties : Properties {          if (source is MediaSource) {              MediaSource media = (MediaSource) source; -            file_path = media.get_master_file().get_path(); -            development_path = media.get_file().get_path(); +            file_path = Filename.display_name(media.get_master_file().get_path()); +            development_path = Filename.display_name(media.get_file().get_path());              filesize = media.get_master_filesize();              // as of right now, all extended properties other than filesize, filepath & comment aren't diff --git a/src/Thumbnail.vala b/src/Thumbnail.vala index 51d2612..54fe361 100644 --- a/src/Thumbnail.vala +++ b/src/Thumbnail.vala @@ -194,6 +194,13 @@ public class Thumbnail : MediaSourceItem {      public static int64 filename_ascending_comparator(void *a, void *b) {          string path_a = ((Thumbnail *) a)->media.get_file().get_basename().down();          string path_b = ((Thumbnail *) b)->media.get_file().get_basename().down(); +        if (!path_a.validate()) { +            path_a = Uri.escape_string(path_a, Uri.RESERVED_CHARS_ALLOWED_IN_PATH, true); +        } + +        if (!path_b.validate()) { +            path_b = Uri.escape_string(path_b, Uri.RESERVED_CHARS_ALLOWED_IN_PATH, true); +        }          int64 result = strcmp(path_a.collate_key_for_filename(), path_b.collate_key_for_filename());          return (result != 0) ? result : photo_id_ascending_comparator(a, b); diff --git a/src/ThumbnailCache.vala b/src/ThumbnailCache.vala index 5585708..2664cf3 100644 --- a/src/ThumbnailCache.vala +++ b/src/ThumbnailCache.vala @@ -509,13 +509,26 @@ public class ThumbnailCache : Object {          File src_file = get_source_cached_file(src_source);          File dest_file = get_cached_file(dest_source.get_representative_id(),              src_source.get_preferred_thumbnail_format()); +        bool success = false;          try {              src_file.copy(dest_file, FileCopyFlags.ALL_METADATA | FileCopyFlags.OVERWRITE, null, null); +            success = true;          } catch (Error err) { -            AppWindow.panic("%s".printf(err.message)); +            debug("Failed to duplicate thumbnail: %s", err.message);          } -         + +        if (success) { +            return; +        } + +        try {             +            _import_from_source(dest_source, true); +            _import_from_source(src_source, false); +        } catch (Error err) { +            debug("Failed to duplicate thumbnail: %s", err.message); +        } +          // Do NOT store in memory cache, for similar reasons as stated in _import().      } diff --git a/src/camera/GPhoto.vala b/src/camera/GPhoto.vala index 702f307..5c0b9a8 100644 --- a/src/camera/GPhoto.vala +++ b/src/camera/GPhoto.vala @@ -92,21 +92,9 @@ namespace GPhoto {          }      } -    // For CameraFileInfoFile, CameraFileInfoPreview, and CameraStorageInformation.  See: -    // https://bugzilla.gnome.org/show_bug.cgi?id=716252 -    // https://bugzilla.redhat.com/show_bug.cgi?id=585676 -    // https://sourceforge.net/tracker/?func=detail&aid=3000198&group_id=8874&atid=108874 -    public const int MAX_FILENAME_LENGTH = 63; -    public const int MAX_BASEDIR_LENGTH = 255; -          public bool get_info(Context context, Camera camera, string folder, string filename,          out CameraFileInfo info) throws Error { -        if (folder.length > MAX_BASEDIR_LENGTH || filename.length > MAX_FILENAME_LENGTH) { -            info = {}; -             -            return false; -        } -         +          Result res = camera.get_file_info(folder, filename, out info, context);          if (res != Result.OK)              throw new GPhotoError.LIBRARY("[%d] Error retrieving file information for %s/%s: %s", diff --git a/src/camera/ImportPage.vala b/src/camera/ImportPage.vala index a5d3b4e..463317b 100644 --- a/src/camera/ImportPage.vala +++ b/src/camera/ImportPage.vala @@ -1346,10 +1346,7 @@ public class ImportPage : CheckerboardPage {          }      } -    public static string? get_fulldir(GPhoto.Camera camera, string camera_name, int fsid, string folder) { -        if (folder.length > GPhoto.MAX_BASEDIR_LENGTH) -            return null; -         +    public static string? get_fulldir(GPhoto.Camera camera, string camera_name, int fsid, string folder) {                  string basedir = get_fs_basedir(camera, fsid);          if (basedir == null) {              debug("Unable to find base directory for %s fsid %d", camera_name, fsid); diff --git a/src/db/TagTable.vala b/src/db/TagTable.vala index ce191c1..e8bb701 100644 --- a/src/db/TagTable.vala +++ b/src/db/TagTable.vala @@ -235,7 +235,7 @@ public class TagTable : DatabaseTable {              // a typename followed by an identifying number (e.g., "video-022354").              if (token[0].isdigit()) {                  // this is a legacy entry -                result.add(PhotoID.upgrade_photo_id_to_source_id(PhotoID(parse_int64(token, 10)))); +                result.add(PhotoID.upgrade_photo_id_to_source_id(PhotoID(int64.parse(token, 10))));              } else if (token[0].isalpha()) {                  // this is a modern entry                  result.add(token); diff --git a/src/direct/DirectPhotoPage.vala b/src/direct/DirectPhotoPage.vala index cc7186c..50321e9 100644 --- a/src/direct/DirectPhotoPage.vala +++ b/src/direct/DirectPhotoPage.vala @@ -9,6 +9,7 @@ public class DirectPhotoPage : EditingHostPage {      private DirectViewCollection? view_controller = null;      private File current_save_dir;      private bool drop_if_dirty = false; +    private bool in_shutdown = false;      public DirectPhotoPage(File file) {          base (DirectPhoto.global, file.get_basename()); @@ -319,7 +320,10 @@ public class DirectPhotoPage : EditingHostPage {              return true;          } +        // Check if we can write the target format          bool is_writeable = get_photo().get_file_format().can_write(); +         +        // TODO: Check if we can actually write to the file          string save_option = is_writeable ? _("_Save") : _("_Save a Copy");          Gtk.ResponseType response = AppWindow.negate_affirm_cancel_question( @@ -336,6 +340,7 @@ public class DirectPhotoPage : EditingHostPage {                  on_save_as();          } else if ((response == Gtk.ResponseType.CANCEL) || (response == Gtk.ResponseType.DELETE_EVENT) ||              (response == Gtk.ResponseType.CLOSE)) { +            in_shutdown = false;              return false;          } @@ -343,6 +348,7 @@ public class DirectPhotoPage : EditingHostPage {      }      public bool check_quit() { +        in_shutdown = true;          return check_ok_to_close_photo(get_photo(), false);      } @@ -352,8 +358,9 @@ public class DirectPhotoPage : EditingHostPage {      private void save(File dest, int scale, ScaleConstraint constraint, Jpeg.Quality quality,          PhotoFileFormat format, bool copy_unmodified = false, bool save_metadata = true) { +          Scaling scaling = Scaling.for_constraint(constraint, scale, false); -         +              try {              get_photo().export(dest, scaling, quality, format, copy_unmodified, save_metadata);          } catch (Error err) { @@ -363,6 +370,8 @@ public class DirectPhotoPage : EditingHostPage {              return;          } +        if (in_shutdown) return; +          // Fetch the DirectPhoto and reimport.          DirectPhoto photo;          DirectPhoto.global.fetch(dest, out photo, true); diff --git a/src/direct/DirectWindow.vala b/src/direct/DirectWindow.vala index 9eec5b1..baf6124 100644 --- a/src/direct/DirectWindow.vala +++ b/src/direct/DirectWindow.vala @@ -66,9 +66,6 @@ public class DirectWindow : AppWindow {      }      protected override void on_quit() { -        if (!get_direct_page().check_quit()) -            return; -          Config.Facade.get_instance().set_direct_window_state(maximized, dimensions);          base.on_quit(); diff --git a/src/folders/FoldersBranch.vala b/src/folders/FoldersBranch.vala index 5de7082..49b2d97 100644 --- a/src/folders/FoldersBranch.vala +++ b/src/folders/FoldersBranch.vala @@ -168,11 +168,15 @@ public class Folders.SidebarEntry : Sidebar.SimplePageEntry, Sidebar.ExpandableE      public SidebarEntry(File dir) {          this.dir = dir; -        collation = dir.get_path().collate_key_for_filename(); +        collation = to_string().collate_key_for_filename();      }      public override string get_sidebar_name() { -        return dir.get_basename(); +        try { +            return dir.query_info(FileAttribute.STANDARD_DISPLAY_NAME, FileQueryInfoFlags.NONE, null).get_display_name(); +        } catch (Error err) { +            return this.to_string(); +        }      }      public override string? get_sidebar_icon() { @@ -180,7 +184,7 @@ public class Folders.SidebarEntry : Sidebar.SimplePageEntry, Sidebar.ExpandableE      }      public override string to_string() { -        return dir.get_path(); +        return Filename.display_name(dir.get_path());      }      public bool expand_on_select() { diff --git a/src/util/string.vala b/src/util/string.vala index 89424d0..976f8ee 100644 --- a/src/util/string.vala +++ b/src/util/string.vala @@ -4,8 +4,6 @@   * (version 2.1 or later).  See the COPYING file in this distribution.   */ -extern int64 g_ascii_strtoll(string str, out char *endptr, uint num_base); -  public const int DEFAULT_USER_TEXT_INPUT_LENGTH = 1024;  public inline bool is_string_empty(string? s) { @@ -173,10 +171,6 @@ public string? prepare_input_text(string? text, PrepareInputTextOptions options,      return prepped;  } -public int64 parse_int64(string str, int num_base) { -    return g_ascii_strtoll(str, null, num_base); -} -  namespace String {  public inline bool contains_char(string haystack, unichar needle) { | 
