Commit 3157ff05 authored by Jim Nelson's avatar Jim Nelson

#170: Auto-unmount on startup (when notified by nautilus). #171: Auto-unmount...

#170: Auto-unmount on startup (when notified by nautilus).  #171: Auto-unmount when running and notified by 
nautilus.  Added (sudo) make install and (sudo) make uninstall.  Added .desktop file (necessary for nautilus 
integration).
parent cbb211aa
......@@ -50,7 +50,7 @@ public class AppWindow : Gtk.Window {
}
public static GLib.File get_exec_file() {
return File.new_for_commandline_arg(args[0]);
return File.new_for_path(Environment.find_program_in_path(args[0]));
}
public static File get_exec_dir() {
......@@ -499,6 +499,10 @@ public class AppWindow : Gtk.Window {
return null;
}
private string get_port_uri(string port) {
return "gphoto2://[%s]/".printf(port);
}
//
// NOTE:
......@@ -508,12 +512,6 @@ public class AppWindow : Gtk.Window {
// first at usb:, then at usb:xxx,yyy. If the usb: device is removed, another usb:xxx,yyy
// device will lose its full-path name and be referred to as usb: only.
//
// For now, relying on the model name reported by libgphoto2 to find the duplicate. This is
// problematic, especially when you have cameras who do not report a model name and are referred
// to as "USB PTP Class Camera" by libgphoto2.
//
// A better strategy needs to be developed (probably involving HAL UID's).
//
private void update_camera_table() throws GPhotoError {
// need to do this because virtual ports come and go in the USB world (and probably others)
GPhoto.PortInfoList portInfoList;
......@@ -587,7 +585,7 @@ public class AppWindow : Gtk.Window {
sidebarStore.get_iter(out cameraIter, page.get_tree_row().get_path());
sidebarStore.remove(cameraIter);
cameraTable.remove(portInfo.path);
cameraTable.remove(get_port_uri(portInfo.path));
// switch away if necessary
if (currentPage == page)
......@@ -598,8 +596,9 @@ public class AppWindow : Gtk.Window {
bool first = true;
foreach (string port in detectedMap.get_keys()) {
string name = detectedMap.get(port);
string uri = get_port_uri(port);
if (cameraTable.contains(port)) {
if (cameraTable.contains(uri)) {
// already known about
debug("%s @ %s already registered, skipping", name, port);
......@@ -636,10 +635,10 @@ public class AppWindow : Gtk.Window {
sidebarStore.append(out child, camerasIter);
sidebarStore.set(child, 0, name);
ImportPage page = new ImportPage(camera);
ImportPage page = new ImportPage(camera, uri);
page.set_tree_row(sidebarStore, child);
cameraTable.set(port, page);
cameraTable.set(uri, page);
sidebar.expand_row(camerasRow.get_path(), true);
......@@ -671,8 +670,32 @@ public class AppWindow : Gtk.Window {
}
}
public static void mounted_camera_shell_notification(string mount) {
debug("mount point: %s", mount);
public static void mounted_camera_shell_notification(File uri) {
debug("mount point reported: %s", uri.get_uri());
if (uri.has_uri_scheme("gphoto2:")) {
debug("Only unmount URIs with gphoto2 scheme: %s (%s)", uri.get_uri(), uri.get_uri_scheme());
return;
}
Mount mount = null;
try {
mount = uri.find_enclosing_mount(null);
} catch (Error err) {
debug("%s", err.message);
return;
}
ImportPage page = get_instance().cameraTable.get(uri.get_uri());
if (page == null) {
debug("Unable to find camera for %s", uri.get_uri());
return;
}
mount.unmount(MountUnmountFlags.NONE, null, page.on_unmounted);
}
}
......@@ -95,6 +95,7 @@ public class ImportPage : CheckerboardPage {
private Gtk.ToolButton importAllButton;
private Gtk.ProgressBar progressBar = new Gtk.ProgressBar();
private GPhoto.Camera camera;
private string uri;
private ProgressBarContext initContext = null;
private ProgressBarContext loadingContext = null;
private bool busy = false;
......@@ -157,8 +158,9 @@ public class ImportPage : CheckerboardPage {
show_all();
}
public ImportPage(GPhoto.Camera camera) {
public ImportPage(GPhoto.Camera camera, string uri) {
this.camera = camera;
this.uri = uri;
GPhoto.CameraAbilities abilities;
GPhoto.Result res = camera.get_abilities(out abilities);
......@@ -173,6 +175,10 @@ public class ImportPage : CheckerboardPage {
return camera;
}
public string get_uri() {
return uri;
}
public override Gtk.Toolbar get_toolbar() {
return toolbar;
}
......@@ -190,7 +196,7 @@ public class ImportPage : CheckerboardPage {
} else {
switch (refreshResult) {
case GPhoto.Result.IO_LOCK: {
msg = "Please close any other applications which may be using the camera.";
msg = "Please close any other application which may be using the camera.";
} break;
default: {
......@@ -214,6 +220,21 @@ public class ImportPage : CheckerboardPage {
AppWindow.get_instance().switch_to_photo_page(this, preview);
}
public void on_unmounted(Object source, AsyncResult aresult) {
debug("on_unmounted");
Mount mount = (Mount) source;
try {
mount.unmount_finish(aresult);
debug("unmounted");
} catch (Error err) {
debug("%s", err.message);
}
// now with camera unmounted, refresh the view
refresh_camera();
}
public void refresh_camera() {
if (busy)
......@@ -342,7 +363,11 @@ public class ImportPage : CheckerboardPage {
// spin the event loop so the UI doesn't freeze
// TODO: Background thread
while (Gtk.events_pending()) {
Gtk.main_iteration();
if (Gtk.main_iteration()) {
debug("Gtk.main_quit called");
return false;
}
}
} catch (GPhotoError err) {
refreshError = err.message;
......
......@@ -32,7 +32,8 @@ RESOURCE_FILES = \
VAPI_DIRS = \
.
HEADER_DIRS =
HEADER_DIRS = \
.
PKGS = \
gtk+-2.0 \
......@@ -42,14 +43,26 @@ PKGS = \
fstream \
libgphoto2 \
hal \
dbus-glib-1 \
unique-1.0
unique-1.0 \
gnome-vfs-2.0
all: $(TARGET)
clean:
rm -f $(TARGET)
install: $(TARGET) shotwell.desktop
cp $(TARGET) /usr/local/bin
mkdir -p /usr/local/share/shotwell/icons
cp icons/* /usr/local/share/shotwell/icons
$(foreach res,$(RESOURCE_FILES),cp $(res) /usr/local/share/shotwell;)
cp shotwell.desktop /usr/share/applications
uninstall:
rm -f /usr/local/bin/$(TARGET)
rm -fr /usr/local/share/shotwell
rm -f /usr/share/applications/shotwell.desktop
$(TARGET): $(SRC_FILES) $(VAPI_FILES) Makefile
valac $(VALAC_OPTS) \
$(foreach pkg,$(PKGS),--pkg=$(pkg)) \
......
......@@ -11,6 +11,7 @@ public abstract class Page : Gtk.ScrolledWindow {
public static const Gdk.Color BG_COLOR = parse_color("#777");
private static Gtk.IconFactory factory = null;
private static File data_dir = null;
private static void addStockIcon(File file, string stockID) {
debug("Adding icon %s", file.get_path());
......@@ -32,10 +33,18 @@ public abstract class Page : Gtk.ScrolledWindow {
factory = new Gtk.IconFactory();
File icons = AppWindow.get_exec_dir().get_child("icons");
// TODO: Programatically determine where runtime data is stored from API calls ...
// for now, this uses the installed data if running from /usr, otherwise looks for
// them in the executable's folder
if (AppWindow.get_exec_dir().get_path().has_prefix("/usr")) {
data_dir = File.new_for_path("/usr/local/share/shotwell");
} else {
data_dir = AppWindow.get_exec_dir();
}
addStockIcon(icons.get_child("object-rotate-right.svg"), STOCK_CLOCKWISE);
addStockIcon(icons.get_child("object-rotate-left.svg"), STOCK_COUNTERCLOCKWISE);
File icons_dir = data_dir.get_child("icons");
addStockIcon(icons_dir.get_child("object-rotate-right.svg"), STOCK_CLOCKWISE);
addStockIcon(icons_dir.get_child("object-rotate-left.svg"), STOCK_COUNTERCLOCKWISE);
factory.add_default();
}
......@@ -93,7 +102,7 @@ public abstract class Page : Gtk.ScrolledWindow {
protected void init_ui(string uiFilename, string menuBarPath, string actionGroupName,
Gtk.ActionEntry[] entries) {
File uiFile = AppWindow.get_exec_dir().get_child(uiFilename);
File uiFile = data_dir.get_child(uiFilename);
try {
ui.add_ui_from_file(uiFile.get_path());
......
......@@ -9,7 +9,7 @@ Unique.Response on_shotwell_message(Unique.App shotwell, int command, Unique.Mes
switch (command) {
case ShotwellCommand.MOUNTED_CAMERA: {
AppWindow.get_instance().mounted_camera_shell_notification(data.get_text());
AppWindow.get_instance().mounted_camera_shell_notification(File.new_for_uri(data.get_text()));
} break;
case Unique.Command.ACTIVATE: {
......@@ -33,10 +33,10 @@ void main(string[] args) {
GLib.Environment.set_application_name(AppWindow.TITLE);
// examine command-line arguments for camera mounts
// (everything else is ignored for now, but don't try to process options)
// (everything else is ignored for now)
string[] mounts = new string[0];
for (int ctr = 1; ctr < args.length; ctr++) {
if (!args[ctr].has_prefix("-"))
if (args[ctr].has_prefix("gphoto2://"))
mounts += args[ctr];
}
......@@ -63,14 +63,13 @@ void main(string[] args) {
AppWindow.init(args);
DatabaseTable.init();
ThumbnailCache.init();
// create main application window
AppWindow appWindow = new AppWindow();
// report mount points
foreach (string mount in mounts) {
appWindow.mounted_camera_shell_notification(mount);
}
foreach (string mount in mounts)
appWindow.mounted_camera_shell_notification(File.new_for_uri(mount));
// throw it all on the display
appWindow.show_all();
......
[Desktop Entry]
Version=1.0
Name=Shotwell
GenericName=Photo Organizer
Comment=Import and organize your photos.
Exec=shotwell %U
Terminal=true
Type=Application
MimeType=x-content/image-dcf
Categories=Graphics;Photography;GNOME;GTK
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment