summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff.email>2023-11-20 18:26:07 +0100
committerJörg Frings-Fürst <debian@jff.email>2023-11-20 18:26:07 +0100
commit445dc18bf3e37044e17083fe76f76c17ceb6a0d7 (patch)
tree315f7cf2a7934b0ecf45ac2caa3c87949a90dfc4 /src
parent918f560d56129ed03f19d843ea2efd7cb4b23821 (diff)
parent394326a81d1248bbc5b1a35a8ae623c65ef6a9ea (diff)
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'src')
-rw-r--r--src/AppWindow.vala52
-rw-r--r--src/BatchImport.vala6
-rw-r--r--src/MediaDataRepresentation.vala2
-rw-r--r--src/Photo.vala3
-rw-r--r--src/PhotoPage.vala13
-rw-r--r--src/Properties.vala10
-rw-r--r--src/Thumbnail.vala7
-rw-r--r--src/ThumbnailCache.vala17
-rw-r--r--src/camera/GPhoto.vala14
-rw-r--r--src/camera/ImportPage.vala5
-rw-r--r--src/db/TagTable.vala2
-rw-r--r--src/direct/DirectPhotoPage.vala11
-rw-r--r--src/direct/DirectWindow.vala3
-rw-r--r--src/folders/FoldersBranch.vala10
-rw-r--r--src/util/string.vala6
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) {