diff --git a/config.h.meson b/config.h.meson index 09ab069f20..651360abd2 100644 --- a/config.h.meson +++ b/config.h.meson @@ -15,6 +15,9 @@ /* Define to 1 if you have the `bind_textdomain_codeset' function. */ #mesondefine HAVE_BIND_TEXTDOMAIN_CODESET +/* Have the cloudproviders library */ +#mesondefine HAVE_CLOUDPROVIDERS + /* define if we have colord */ #mesondefine HAVE_COLORD diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c index 037fed9b1f..ff11d65b5a 100644 --- a/gtk/gtkplacessidebar.c +++ b/gtk/gtkplacessidebar.c @@ -24,6 +24,10 @@ #include "config.h" #include +#ifdef HAVE_CLOUDPROVIDERS +#include +#include +#endif #include "gtkplacessidebarprivate.h" #include "gtksidebarrowprivate.h" @@ -121,6 +125,9 @@ struct _GtkPlacesSidebar { GtkWidget *new_bookmark_row; GtkBookmarksManager *bookmarks_manager; +#ifdef HAVE_CLOUDPROVIDERS + CloudProviders *cloud_manager; +#endif GVolumeMonitor *volume_monitor; GtkTrashMonitor *trash_monitor; GtkSettings *gtk_settings; @@ -150,6 +157,8 @@ struct _GtkPlacesSidebar { DropState drop_state; GtkGesture *long_press_gesture; + GList *cloud_rows; + /* volume mounting - delayed open process */ GtkPlacesOpenFlags go_to_after_mount_open_flags; GCancellable *cancellable; @@ -164,6 +173,8 @@ struct _GtkPlacesSidebar { GtkPlacesOpenFlags open_flags; + GActionGroup *action_group; + guint mounting : 1; guint drag_data_received : 1; guint drop_occurred : 1; @@ -425,11 +436,17 @@ add_place (GtkPlacesSidebar *sidebar, GtkPlacesSidebarPlaceType place_type, GtkPlacesSidebarSectionType section_type, const gchar *name, - GIcon *icon, + GIcon *start_icon, + GIcon *end_icon, const gchar *uri, GDrive *drive, GVolume *volume, GMount *mount, +#ifdef HAVE_CLOUDPROVIDERS + CloudProviderAccount *cloud_provider_account, +#else + gpointer *cloud_provider_account, +#endif const gint index, const gchar *tooltip) { @@ -448,7 +465,8 @@ add_place (GtkPlacesSidebar *sidebar, row = g_object_new (GTK_TYPE_SIDEBAR_ROW, "sidebar", sidebar, - "icon", icon, + "start-icon", start_icon, + "end-icon", end_icon, "label", name, "tooltip", tooltip, "ejectable", show_eject_button, @@ -459,6 +477,9 @@ add_place (GtkPlacesSidebar *sidebar, "drive", drive, "volume", volume, "mount", mount, +#ifdef HAVE_CLOUDPROVIDERS + "cloud-provider", cloud_provider_account, +#endif NULL); eject_button = gtk_sidebar_row_get_eject_button (GTK_SIDEBAR_ROW (row)); @@ -582,7 +603,7 @@ add_special_dirs (GtkPlacesSidebar *sidebar) { const gchar *path; GFile *root; - GIcon *icon; + GIcon *start_icon; gchar *name; gchar *mount_uri; gchar *tooltip; @@ -607,18 +628,18 @@ add_special_dirs (GtkPlacesSidebar *sidebar) if (!name) name = g_file_get_basename (root); - icon = special_directory_get_gicon (index); + start_icon = special_directory_get_gicon (index); mount_uri = g_file_get_uri (root); tooltip = g_file_get_parse_name (root); add_place (sidebar, PLACES_XDG_DIR, SECTION_COMPUTER, - name, icon, mount_uri, - NULL, NULL, NULL, 0, + name, start_icon, NULL, mount_uri, + NULL, NULL, NULL, NULL, 0, tooltip); g_free (name); g_object_unref (root); - g_object_unref (icon); + g_object_unref (start_icon); g_free (mount_uri); g_free (tooltip); @@ -721,11 +742,11 @@ on_app_shortcuts_query_complete (GObject *source, gchar *uri; gchar *tooltip; const gchar *name; - GIcon *icon; + GIcon *start_icon; int pos = 0; name = g_file_info_get_display_name (info); - icon = g_file_info_get_symbolic_icon (info); + start_icon = g_file_info_get_symbolic_icon (info); uri = g_file_get_uri (file); tooltip = g_file_get_parse_name (file); @@ -738,8 +759,8 @@ on_app_shortcuts_query_complete (GObject *source, add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, - name, icon, uri, - NULL, NULL, NULL, + name, start_icon, NULL, uri, + NULL, NULL, NULL, NULL, pos, tooltip); @@ -794,7 +815,7 @@ on_bookmark_query_info_complete (GObject *source, gchar *bookmark_name; gchar *mount_uri; gchar *tooltip; - GIcon *icon; + GIcon *start_icon; info = g_file_query_info_finish (root, result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) @@ -815,23 +836,23 @@ on_bookmark_query_info_complete (GObject *source, } if (info) - icon = g_object_ref (g_file_info_get_symbolic_icon (info)); + start_icon = g_object_ref (g_file_info_get_symbolic_icon (info)); else - icon = g_themed_icon_new_with_default_fallbacks (clos->is_native ? ICON_NAME_FOLDER : ICON_NAME_FOLDER_NETWORK); + start_icon = g_themed_icon_new_with_default_fallbacks (clos->is_native ? ICON_NAME_FOLDER : ICON_NAME_FOLDER_NETWORK); mount_uri = g_file_get_uri (root); tooltip = g_file_get_parse_name (root); add_place (sidebar, PLACES_BOOKMARK, SECTION_BOOKMARKS, - bookmark_name, icon, mount_uri, - NULL, NULL, NULL, clos->index, + bookmark_name, start_icon, NULL, mount_uri, + NULL, NULL, NULL, NULL, clos->index, tooltip); g_free (mount_uri); g_free (tooltip); g_free (bookmark_name); - g_object_unref (icon); + g_object_unref (start_icon); out: g_clear_object (&info); @@ -871,11 +892,69 @@ update_trash_icon (GtkPlacesSidebar *sidebar) GIcon *icon; icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor); - gtk_sidebar_row_set_icon (GTK_SIDEBAR_ROW (sidebar->trash_row), icon); + gtk_sidebar_row_set_start_icon (GTK_SIDEBAR_ROW (sidebar->trash_row), icon); g_object_unref (icon); } } +#ifdef HAVE_CLOUDPROVIDERS +static void +cloud_row_update (CloudProviderAccount *cloud_provider_account, + GtkWidget *cloud_row) +{ + GIcon *end_icon; + gint provider_status; + provider_status = cloud_provider_account_get_status (cloud_provider_account); + switch (provider_status) + { + case CLOUD_PROVIDER_STATUS_IDLE: + end_icon = NULL; + break; + + case CLOUD_PROVIDER_STATUS_SYNCING: + end_icon = g_themed_icon_new ("emblem-synchronizing-symbolic"); + break; + + case CLOUD_PROVIDER_STATUS_ERROR: + end_icon = g_themed_icon_new ("dialog-warning-symbolic"); + break; + + default: + return; + } + + gtk_sidebar_row_set_end_icon (GTK_SIDEBAR_ROW (cloud_row), end_icon); + if (end_icon != NULL) + g_object_unref (end_icon); + + g_object_set (cloud_row, + "label", cloud_provider_account_get_name (cloud_provider_account), + NULL); + g_object_set (cloud_row, + "tooltip", cloud_provider_account_get_status_details (cloud_provider_account), + NULL); + +} + +void +cloud_row_destroy (GtkWidget *object, + gpointer user_data) +{ + GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data); + CloudProviderAccount *cloud_provider_account = NULL; + g_object_get (GTK_SIDEBAR_ROW (object), "cloud-provider", &cloud_provider_account, NULL); + if (cloud_provider_account != NULL) + { + g_signal_handlers_disconnect_matched (cloud_provider_account, + G_SIGNAL_MATCH_DATA, + 0, 0, 0, cloud_row_update, object); + g_object_unref (object); + g_object_unref (cloud_provider_account); + } + sidebar->cloud_rows = g_list_remove (sidebar->cloud_rows, object); +} +#endif + static void update_places (GtkPlacesSidebar *sidebar) { @@ -890,11 +969,17 @@ update_places (GtkPlacesSidebar *sidebar) gchar *original_uri, *name, *identifier; GtkListBoxRow *selected; gchar *home_uri; - GIcon *icon; + GIcon *start_icon; GFile *root; gchar *tooltip; GList *network_mounts, *network_volumes; GIcon *new_bookmark_icon; +#ifdef HAVE_CLOUDPROVIDERS + GIcon *end_icon; + GList *cloud_provider_proxies; + guint provider_status; + gchar *cloudprovider_path; +#endif GtkStyleContext *context; /* save original selection */ @@ -921,24 +1006,24 @@ update_places (GtkPlacesSidebar *sidebar) /* add built-in places */ if (should_show_recent (sidebar)) { - icon = g_themed_icon_new_with_default_fallbacks ("document-open-recent-symbolic"); + start_icon = g_themed_icon_new_with_default_fallbacks ("document-open-recent-symbolic"); add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, - _("Recent"), icon, "recent:///", - NULL, NULL, NULL, 0, + _("Recent"), start_icon, NULL, "recent:///", + NULL, NULL, NULL, NULL, 0, _("Recent files")); - g_object_unref (icon); + g_object_unref (start_icon); } /* home folder */ home_uri = get_home_directory_uri (); - icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_HOME); + start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_HOME); add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, - _("Home"), icon, home_uri, - NULL, NULL, NULL, 0, + _("Home"), start_icon, NULL, home_uri, + NULL, NULL, NULL, NULL, 0, _("Open your personal folder")); - g_object_unref (icon); + g_object_unref (start_icon); g_free (home_uri); /* desktop */ @@ -947,13 +1032,13 @@ update_places (GtkPlacesSidebar *sidebar) char *mount_uri = get_desktop_directory_uri (); if (mount_uri) { - icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_DESKTOP); + start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_DESKTOP); add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, - _("Desktop"), icon, mount_uri, - NULL, NULL, NULL, 0, + _("Desktop"), start_icon, NULL, mount_uri, + NULL, NULL, NULL, NULL, 0, _("Open the contents of your desktop in a folder")); - g_object_unref (icon); + g_object_unref (start_icon); g_free (mount_uri); } } @@ -963,32 +1048,83 @@ update_places (GtkPlacesSidebar *sidebar) if (sidebar->show_enter_location) { - icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER); + start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER); add_place (sidebar, PLACES_ENTER_LOCATION, SECTION_COMPUTER, - _("Enter Location"), icon, NULL, - NULL, NULL, NULL, 0, + _("Enter Location"), start_icon, NULL, NULL, + NULL, NULL, NULL, NULL, 0, _("Manually enter a location")); - g_object_unref (icon); + g_object_unref (start_icon); } /* Trash */ if (!sidebar->local_only && sidebar->show_trash) { - icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor); + start_icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor); sidebar->trash_row = add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, - _("Trash"), icon, "trash:///", - NULL, NULL, NULL, 0, + _("Trash"), start_icon, NULL, "trash:///", + NULL, NULL, NULL, NULL, 0, _("Open the trash")); g_object_add_weak_pointer (G_OBJECT (sidebar->trash_row), (gpointer *) &sidebar->trash_row); - g_object_unref (icon); + g_object_unref (start_icon); } /* Application-side shortcuts */ add_application_shortcuts (sidebar); + /* Cloud providers */ +#ifdef HAVE_CLOUDPROVIDERS + cloud_provider_proxies = cloud_providers_get_providers (sidebar->cloud_manager); + for (l = cloud_provider_proxies; l != NULL; l = l->next) + { + start_icon = cloud_provider_account_get_icon (l->data); + name = cloud_provider_account_get_name (l->data); + provider_status = cloud_provider_account_get_status (l->data); + cloudprovider_path = cloud_provider_account_get_path (l->data); + if (start_icon == NULL + || name == NULL + || provider_status == CLOUD_PROVIDER_STATUS_INVALID + || cloudprovider_path == NULL) + continue; + cloudprovider_path = g_strconcat ("file://", cloud_provider_account_get_path (l->data), NULL); + switch (provider_status) + { + case CLOUD_PROVIDER_STATUS_IDLE: + end_icon = NULL; + break; + + case CLOUD_PROVIDER_STATUS_SYNCING: + end_icon = g_themed_icon_new ("emblem-synchronizing-symbolic"); + break; + + case CLOUD_PROVIDER_STATUS_ERROR: + end_icon = g_themed_icon_new ("dialog-warning-symbolic"); + break; + + default: + continue; + } + + /* translators: %s is the name of a cloud provider for files */ + tooltip = g_strdup_printf (_("Open %s"), name); + + GtkWidget *cloud_row = NULL; + cloud_row = add_place (sidebar, PLACES_BUILT_IN, + SECTION_CLOUD, + name, start_icon, end_icon, cloudprovider_path, + NULL, NULL, NULL, l->data, 0, + tooltip); + + g_signal_connect (l->data, "changed", G_CALLBACK (cloud_row_update), cloud_row); + g_signal_connect (cloud_row, "destroy", G_CALLBACK (cloud_row_destroy), sidebar); + g_object_ref (cloud_row); + g_object_ref (l->data); + sidebar->cloud_rows = g_list_append (sidebar->cloud_rows, cloud_row); + } +#endif + /* go through all connected drives */ drives = g_volume_monitor_get_connected_drives (sidebar->volume_monitor); @@ -1024,7 +1160,7 @@ update_places (GtkPlacesSidebar *sidebar) char *mount_uri; /* Show mounted volume in the sidebar */ - icon = g_mount_get_symbolic_icon (mount); + start_icon = g_mount_get_symbolic_icon (mount); root = g_mount_get_default_location (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); @@ -1032,11 +1168,11 @@ update_places (GtkPlacesSidebar *sidebar) add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_MOUNTS, - name, icon, mount_uri, - drive, volume, mount, 0, tooltip); + name, start_icon, NULL, mount_uri, + drive, volume, mount, NULL, 0, tooltip); g_object_unref (root); g_object_unref (mount); - g_object_unref (icon); + g_object_unref (start_icon); g_free (tooltip); g_free (name); g_free (mount_uri); @@ -1051,15 +1187,15 @@ update_places (GtkPlacesSidebar *sidebar) * cue that the user should remember to yank out the media if * he just unmounted it. */ - icon = g_volume_get_symbolic_icon (volume); + start_icon = g_volume_get_symbolic_icon (volume); name = g_volume_get_name (volume); tooltip = g_strdup_printf (_("Mount and open “%s”"), name); add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_MOUNTS, - name, icon, NULL, - drive, volume, NULL, 0, tooltip); - g_object_unref (icon); + name, start_icon, NULL, NULL, + drive, volume, NULL, NULL, 0, tooltip); + g_object_unref (start_icon); g_free (name); g_free (tooltip); } @@ -1079,15 +1215,15 @@ update_places (GtkPlacesSidebar *sidebar) * work.. but it's also for human beings who like to turn off media detection * in the OS to save battery juice. */ - icon = g_drive_get_symbolic_icon (drive); + start_icon = g_drive_get_symbolic_icon (drive); name = g_drive_get_name (drive); tooltip = g_strdup_printf (_("Mount and open “%s”"), name); add_place (sidebar, PLACES_BUILT_IN, SECTION_MOUNTS, - name, icon, NULL, - drive, NULL, NULL, 0, tooltip); - g_object_unref (icon); + name, start_icon, NULL, NULL, + drive, NULL, NULL, NULL, 0, tooltip); + g_object_unref (start_icon); g_free (tooltip); g_free (name); } @@ -1129,18 +1265,18 @@ update_places (GtkPlacesSidebar *sidebar) { char *mount_uri; - icon = g_mount_get_symbolic_icon (mount); + start_icon = g_mount_get_symbolic_icon (mount); root = g_mount_get_default_location (mount); mount_uri = g_file_get_uri (root); tooltip = g_file_get_parse_name (root); name = g_mount_get_name (mount); add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_MOUNTS, - name, icon, mount_uri, - NULL, volume, mount, 0, tooltip); + name, start_icon, NULL, mount_uri, + NULL, volume, mount, NULL, 0, tooltip); g_object_unref (mount); g_object_unref (root); - g_object_unref (icon); + g_object_unref (start_icon); g_free (name); g_free (tooltip); g_free (mount_uri); @@ -1148,13 +1284,13 @@ update_places (GtkPlacesSidebar *sidebar) else { /* see comment above in why we add an icon for an unmounted mountable volume */ - icon = g_volume_get_symbolic_icon (volume); + start_icon = g_volume_get_symbolic_icon (volume); name = g_volume_get_name (volume); add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_MOUNTS, - name, icon, NULL, - NULL, volume, NULL, 0, name); - g_object_unref (icon); + name, start_icon, NULL, NULL, + NULL, volume, NULL, NULL, 0, name); + g_object_unref (start_icon); g_free (name); } g_object_unref (volume); @@ -1164,13 +1300,13 @@ update_places (GtkPlacesSidebar *sidebar) /* file system root */ if (!sidebar->show_other_locations) { - icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_FILESYSTEM); + start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_FILESYSTEM); add_place (sidebar, PLACES_BUILT_IN, SECTION_MOUNTS, - sidebar->hostname, icon, "file:///", - NULL, NULL, NULL, 0, + sidebar->hostname, start_icon, NULL, "file:///", + NULL, NULL, NULL, NULL, 0, _("Open the contents of the file system")); - g_object_unref (icon); + g_object_unref (start_icon); } /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */ @@ -1202,17 +1338,17 @@ update_places (GtkPlacesSidebar *sidebar) continue; } - icon = g_mount_get_symbolic_icon (mount); + start_icon = g_mount_get_symbolic_icon (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); tooltip = g_file_get_parse_name (root); add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_COMPUTER, - name, icon, mount_uri, - NULL, NULL, mount, 0, tooltip); + name, start_icon, NULL, mount_uri, + NULL, NULL, mount, NULL, 0, tooltip); g_object_unref (root); g_object_unref (mount); - g_object_unref (icon); + g_object_unref (start_icon); g_free (name); g_free (mount_uri); g_free (tooltip); @@ -1255,8 +1391,8 @@ update_places (GtkPlacesSidebar *sidebar) new_bookmark_icon = g_themed_icon_new ("bookmark-new-symbolic"); sidebar->new_bookmark_row = add_place (sidebar, PLACES_DROP_FEEDBACK, SECTION_BOOKMARKS, - _("New bookmark"), new_bookmark_icon, NULL, - NULL, NULL, NULL, 0, + _("New bookmark"), new_bookmark_icon, NULL, NULL, + NULL, NULL, NULL, NULL, 0, _("Add a new bookmark")); context = gtk_widget_get_style_context (sidebar->new_bookmark_row); gtk_style_context_add_class (context, "sidebar-new-bookmark-row"); @@ -1278,15 +1414,15 @@ update_places (GtkPlacesSidebar *sidebar) } else { - icon = g_volume_get_symbolic_icon (volume); + start_icon = g_volume_get_symbolic_icon (volume); name = g_volume_get_name (volume); tooltip = g_strdup_printf (_("Mount and open “%s”"), name); add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_MOUNTS, - name, icon, NULL, - NULL, volume, NULL, 0, tooltip); - g_object_unref (icon); + name, start_icon, NULL, NULL, + NULL, volume, NULL, NULL, 0, tooltip); + g_object_unref (start_icon); g_free (name); g_free (tooltip); } @@ -1299,16 +1435,16 @@ update_places (GtkPlacesSidebar *sidebar) mount = l->data; root = g_mount_get_default_location (mount); - icon = g_mount_get_symbolic_icon (mount); + start_icon = g_mount_get_symbolic_icon (mount); mount_uri = g_file_get_uri (root); name = g_mount_get_name (mount); tooltip = g_file_get_parse_name (root); add_place (sidebar, PLACES_MOUNTED_VOLUME, SECTION_MOUNTS, - name, icon, mount_uri, - NULL, NULL, mount, 0, tooltip); + name, start_icon, NULL, mount_uri, + NULL, NULL, mount, NULL, 0, tooltip); g_object_unref (root); - g_object_unref (icon); + g_object_unref (start_icon); g_free (name); g_free (mount_uri); g_free (tooltip); @@ -1321,14 +1457,14 @@ update_places (GtkPlacesSidebar *sidebar) /* Other locations */ if (sidebar->show_other_locations) { - icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_OTHER_LOCATIONS); + start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_OTHER_LOCATIONS); add_place (sidebar, PLACES_OTHER_LOCATIONS, SECTION_OTHER_LOCATIONS, - _("Other Locations"), icon, "other-locations:///", - NULL, NULL, NULL, 0, _("Show other locations")); + _("Other Locations"), start_icon, NULL, "other-locations:///", + NULL, NULL, NULL, NULL, 0, _("Show other locations")); - g_object_unref (icon); + g_object_unref (start_icon); } gtk_widget_show (GTK_WIDGET (sidebar)); @@ -3357,6 +3493,56 @@ on_row_popover_destroy (GtkWidget *row_popover, sidebar->popover = NULL; } +#ifdef HAVE_CLOUDPROVIDERS +static void +build_popup_menu_using_gmenu (GtkSidebarRow *row) +{ + CloudProviderAccount *cloud_provider_account; + GtkPlacesSidebar *sidebar; + GMenuModel *cloud_provider_menu; + GActionGroup *cloud_provider_action_group; + + g_object_get (row, + "sidebar", &sidebar, + "cloud-provider", &cloud_provider_account, + NULL); + + /* Cloud provider */ + if (cloud_provider_account) + { + GMenu *menu = g_menu_new (); + GMenuItem *item; + item = g_menu_item_new (_("_Open"), "row.open"); + g_menu_item_set_action_and_target_value (item, "row.open", + g_variant_new_int32 (GTK_PLACES_OPEN_NORMAL)); + g_menu_append_item (menu, item); + item = g_menu_item_new (_("Open in New _Tab"), "row.open-other"); + g_menu_item_set_action_and_target_value (item, "row.open-other", + g_variant_new_int32 (GTK_PLACES_OPEN_NEW_TAB)); + g_menu_append_item (menu, item); + item = g_menu_item_new (_("Open in New _Window"), "row.open-other"); + g_menu_item_set_action_and_target_value (item, "row.open-other", + g_variant_new_int32 (GTK_PLACES_OPEN_NEW_WINDOW)); + g_menu_append_item (menu, item); + cloud_provider_menu = cloud_provider_account_get_menu_model (cloud_provider_account); + g_menu_append_section (menu, NULL, cloud_provider_menu); + cloud_provider_action_group = cloud_provider_account_get_action_group (cloud_provider_account); + gtk_widget_insert_action_group (GTK_WIDGET (sidebar), + "cloudprovider", + G_ACTION_GROUP (cloud_provider_action_group)); + add_actions (sidebar); + if (sidebar->popover) + gtk_widget_destroy (sidebar->popover); + + sidebar->popover = gtk_popover_new_from_model (GTK_WIDGET (sidebar), + G_MENU_MODEL (menu)); + g_signal_connect (sidebar->popover, "destroy", G_CALLBACK (on_row_popover_destroy), sidebar); + g_object_unref (sidebar); + g_object_unref (cloud_provider_account); + } +} +#endif + /* Constructs the popover for the sidebar row if needed */ static void create_row_popover (GtkPlacesSidebar *sidebar, @@ -3365,6 +3551,18 @@ create_row_popover (GtkPlacesSidebar *sidebar, PopoverData data; GtkWidget *box; +#ifdef HAVE_CLOUDPROVIDERS + CloudProviderAccount *cloud_provider_account; + + g_object_get (row, "cloud-provider", &cloud_provider_account, NULL); + + if (cloud_provider_account) + { + build_popup_menu_using_gmenu (row); + return; + } +#endif + sidebar->popover = gtk_popover_new (GTK_WIDGET (sidebar)); /* Clean sidebar pointer when its destroyed, most of the times due to its * relative_to associated row being destroyed */ @@ -3860,6 +4058,17 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar) g_object_get (sidebar->gtk_settings, "gtk-shell-shows-desktop", &show_desktop, NULL); sidebar->show_desktop = show_desktop; + /* Cloud providers */ +#ifdef HAVE_CLOUDPROVIDERS + sidebar->cloud_rows = NULL; + sidebar->cloud_manager = cloud_providers_dup_singleton (); + g_signal_connect_swapped (sidebar->cloud_manager, + "owners-changed", + G_CALLBACK (update_places), + sidebar); + cloud_providers_update (sidebar->cloud_manager); +#endif + /* populate the sidebar */ update_places (sidebar); diff --git a/gtk/gtkplacessidebarprivate.h b/gtk/gtkplacessidebarprivate.h index 73a636cdb3..aee1e18365 100644 --- a/gtk/gtkplacessidebarprivate.h +++ b/gtk/gtkplacessidebarprivate.h @@ -31,6 +31,7 @@ typedef enum { SECTION_INVALID, SECTION_COMPUTER, SECTION_MOUNTS, + SECTION_CLOUD, SECTION_BOOKMARKS, SECTION_OTHER_LOCATIONS, N_SECTIONS diff --git a/gtk/gtksidebarrow.c b/gtk/gtksidebarrow.c index 78a837f3c0..6939bf5a72 100644 --- a/gtk/gtksidebarrow.c +++ b/gtk/gtksidebarrow.c @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include "config.h" + #include "gtksidebarrowprivate.h" /* For section and place type enums */ #include "gtkplacessidebarprivate.h" @@ -27,11 +29,17 @@ #include "gtkrevealer.h" #include "gtkselection.h" +#ifdef HAVE_CLOUDPROVIDERS +#include +#endif + struct _GtkSidebarRow { GtkListBoxRow parent_instance; - GIcon *icon; - GtkWidget *icon_widget; + GIcon *start_icon; + GIcon *end_icon; + GtkWidget *start_icon_widget; + GtkWidget *end_icon_widget; gchar *label; gchar *tooltip; GtkWidget *label_widget; @@ -44,6 +52,7 @@ struct _GtkSidebarRow GDrive *drive; GVolume *volume; GMount *mount; + GObject *cloud_provider; gboolean placeholder; GtkPlacesSidebar *sidebar; GtkWidget *revealer; @@ -54,7 +63,8 @@ G_DEFINE_TYPE (GtkSidebarRow, gtk_sidebar_row, GTK_TYPE_LIST_BOX_ROW) enum { PROP_0, - PROP_ICON, + PROP_START_ICON, + PROP_END_ICON, PROP_LABEL, PROP_TOOLTIP, PROP_EJECTABLE, @@ -66,6 +76,7 @@ enum PROP_DRIVE, PROP_VOLUME, PROP_MOUNT, + PROP_CLOUD_PROVIDER, PROP_PLACEHOLDER, LAST_PROP }; @@ -86,8 +97,12 @@ gtk_sidebar_row_get_property (GObject *object, g_value_set_object (value, self->sidebar); break; - case PROP_ICON: - g_value_set_object (value, self->icon); + case PROP_START_ICON: + g_value_set_object (value, self->start_icon); + break; + + case PROP_END_ICON: + g_value_set_object (value, self->end_icon); break; case PROP_LABEL: @@ -130,6 +145,10 @@ gtk_sidebar_row_get_property (GObject *object, g_value_set_object (value, self->mount); break; + case PROP_CLOUD_PROVIDER: + g_value_set_object (value, self->cloud_provider); + break; + case PROP_PLACEHOLDER: g_value_set_boolean (value, self->placeholder); break; @@ -154,9 +173,43 @@ gtk_sidebar_row_set_property (GObject *object, self->sidebar = g_value_get_object (value); break; - case PROP_ICON: - gtk_sidebar_row_set_icon (self, g_value_get_object (value)); - break; + case PROP_START_ICON: + { + g_clear_object (&self->start_icon); + object = g_value_get_object (value); + if (object != NULL) + { + self->start_icon = g_object_ref (object); + gtk_image_set_from_gicon (GTK_IMAGE (self->start_icon_widget), + self->start_icon, + GTK_ICON_SIZE_MENU); + } + else + { + gtk_image_clear (GTK_IMAGE (self->start_icon_widget)); + } + break; + } + + case PROP_END_ICON: + { + g_clear_object (&self->end_icon); + object = g_value_get_object (value); + if (object != NULL) + { + self->end_icon = g_object_ref (object); + gtk_image_set_from_gicon (GTK_IMAGE (self->end_icon_widget), + self->end_icon, + GTK_ICON_SIZE_MENU); + gtk_widget_show (self->end_icon_widget); + } + else + { + gtk_image_clear (GTK_IMAGE (self->end_icon_widget)); + gtk_widget_hide (self->end_icon_widget); + } + break; + } case PROP_LABEL: g_free (self->label); @@ -212,33 +265,48 @@ gtk_sidebar_row_set_property (GObject *object, g_set_object (&self->mount, g_value_get_object (value)); break; + case PROP_CLOUD_PROVIDER: + { +#ifdef HAVE_CLOUDPROVIDERS + gpointer *object; + object = g_value_get_object (value); + if (IS_CLOUD_PROVIDER_ACCOUNT(object)) + self->cloud_provider = g_object_ref (object); +#endif + break; + } + case PROP_PLACEHOLDER: - self->placeholder = g_value_get_boolean (value); - if (self->placeholder) - { - g_clear_object (&self->icon); - g_free (self->label); - self->label = NULL; - g_free (self->tooltip); - self->tooltip = NULL; - gtk_widget_set_tooltip_text (GTK_WIDGET (self), NULL); - self->ejectable = FALSE; - self->section_type = SECTION_BOOKMARKS; - self->place_type = PLACES_BOOKMARK_PLACEHOLDER; - g_free (self->uri); - self->uri = NULL; - g_clear_object (&self->drive); - g_clear_object (&self->volume); - g_clear_object (&self->mount); + { + self->placeholder = g_value_get_boolean (value); + if (self->placeholder) + { + g_clear_object (&self->start_icon); + g_clear_object (&self->end_icon); + g_free (self->label); + self->label = NULL; + g_free (self->tooltip); + self->tooltip = NULL; + gtk_widget_set_tooltip_text (GTK_WIDGET (self), NULL); + self->ejectable = FALSE; + self->section_type = SECTION_BOOKMARKS; + self->place_type = PLACES_BOOKMARK_PLACEHOLDER; + g_free (self->uri); + self->uri = NULL; + g_clear_object (&self->drive); + g_clear_object (&self->volume); + g_clear_object (&self->mount); - gtk_container_foreach (GTK_CONTAINER (self), - (GtkCallback) gtk_widget_destroy, - NULL); + gtk_container_foreach (GTK_CONTAINER (self), + (GtkCallback) gtk_widget_destroy, + NULL); - context = gtk_widget_get_style_context (GTK_WIDGET (self)); - gtk_style_context_add_class (context, "sidebar-placeholder-row"); - } - break; + context = gtk_widget_get_style_context (GTK_WIDGET (self)); + gtk_style_context_add_class (context, "sidebar-placeholder-row"); + } + + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -280,21 +348,41 @@ gtk_sidebar_row_hide (GtkSidebarRow *self, } void -gtk_sidebar_row_set_icon (GtkSidebarRow *self, - GIcon *icon) +gtk_sidebar_row_set_start_icon (GtkSidebarRow *self, + GIcon *icon) { g_return_if_fail (GTK_IS_SIDEBAR_ROW (self)); - if (self->icon != icon) + if (self->start_icon != icon) { - g_set_object (&self->icon, icon); - if (self->icon != NULL) - gtk_image_set_from_gicon (GTK_IMAGE (self->icon_widget), self->icon, + g_set_object (&self->start_icon, icon); + if (self->start_icon != NULL) + gtk_image_set_from_gicon (GTK_IMAGE (self->start_icon_widget), self->start_icon, GTK_ICON_SIZE_MENU); else - gtk_image_clear (GTK_IMAGE (self->icon_widget)); + gtk_image_clear (GTK_IMAGE (self->start_icon_widget)); - g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_START_ICON]); + } +} + +void +gtk_sidebar_row_set_end_icon (GtkSidebarRow *self, + GIcon *icon) +{ + g_return_if_fail (GTK_IS_SIDEBAR_ROW (self)); + + if (self->end_icon != icon) + { + g_set_object (&self->end_icon, icon); + if (self->end_icon != NULL) + gtk_image_set_from_gicon (GTK_IMAGE (self->end_icon_widget), self->end_icon, + GTK_ICON_SIZE_MENU); + else + if (self->end_icon_widget != NULL) + gtk_image_clear (GTK_IMAGE (self->end_icon_widget)); + + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_END_ICON]); } } @@ -303,7 +391,8 @@ gtk_sidebar_row_finalize (GObject *object) { GtkSidebarRow *self = GTK_SIDEBAR_ROW (object); - g_clear_object (&self->icon); + g_clear_object (&self->start_icon); + g_clear_object (&self->end_icon); g_free (self->label); self->label = NULL; g_free (self->tooltip); @@ -342,10 +431,18 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - properties [PROP_ICON] = - g_param_spec_object ("icon", - "icon", - "The place icon.", + properties [PROP_START_ICON] = + g_param_spec_object ("start-icon", + "start-icon", + "The start icon.", + G_TYPE_ICON, + (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + properties [PROP_END_ICON] = + g_param_spec_object ("end-icon", + "end-icon", + "The end icon.", G_TYPE_ICON, (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -436,6 +533,14 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + properties [PROP_CLOUD_PROVIDER] = + g_param_spec_object ("cloud-provider", + "CloudProviderAccount", + "CloudProviderAccount", + G_TYPE_OBJECT, + (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + properties [PROP_PLACEHOLDER] = g_param_spec_boolean ("placeholder", "Placeholder", @@ -450,7 +555,8 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtksidebarrow.ui"); - gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, icon_widget); + gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, start_icon_widget); + gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, end_icon_widget); gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, label_widget); gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, eject_button); gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, revealer); @@ -459,13 +565,13 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass) gtk_widget_class_set_css_name (widget_class, "row"); } - GtkSidebarRow* gtk_sidebar_row_clone (GtkSidebarRow *self) { return g_object_new (GTK_TYPE_SIDEBAR_ROW, "sidebar", self->sidebar, - "icon", self->icon, + "start-icon", self->start_icon, + "end-icon", self->end_icon, "label", self->label, "tooltip", self->tooltip, "ejectable", self->ejectable, @@ -476,10 +582,11 @@ gtk_sidebar_row_clone (GtkSidebarRow *self) "drive", self->drive, "volume", self->volume, "mount", self->mount, + "cloud-provider", self->cloud_provider, NULL); } -GtkWidget * +GtkWidget* gtk_sidebar_row_get_eject_button (GtkSidebarRow *self) { return self->eject_button; diff --git a/gtk/gtksidebarrowprivate.h b/gtk/gtksidebarrowprivate.h index ee0fe28812..f9337572e6 100644 --- a/gtk/gtksidebarrowprivate.h +++ b/gtk/gtksidebarrowprivate.h @@ -49,7 +49,9 @@ void gtk_sidebar_row_hide (GtkSidebarRow *self, void gtk_sidebar_row_reveal (GtkSidebarRow *self); GtkWidget *gtk_sidebar_row_get_eject_button (GtkSidebarRow *self); -void gtk_sidebar_row_set_icon (GtkSidebarRow *self, +void gtk_sidebar_row_set_start_icon (GtkSidebarRow *self, + GIcon *icon); +void gtk_sidebar_row_set_end_icon (GtkSidebarRow *self, GIcon *icon); G_END_DECLS diff --git a/gtk/meson.build b/gtk/meson.build index 931d6c4e5e..121839d3a9 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -845,6 +845,10 @@ if x11_enabled or wayland_enabled gtk_deps += pangoft_dep endif +if cloudproviders_enabled + gtk_deps += cloudproviders_dep +endif + gtk_settings_schemas = [ 'org.gtk.Settings.FileChooser.gschema.xml', 'org.gtk.Settings.ColorChooser.gschema.xml', diff --git a/gtk/ui/gtksidebarrow.ui b/gtk/ui/gtksidebarrow.ui index 9b590e2ad7..3f433da56e 100644 --- a/gtk/ui/gtksidebarrow.ui +++ b/gtk/ui/gtksidebarrow.ui @@ -16,7 +16,7 @@ - + @@ -31,6 +31,17 @@ + + + False + True + end + center + + + center diff --git a/meson.build b/meson.build index 52a080713a..31f7071f62 100644 --- a/meson.build +++ b/meson.build @@ -24,19 +24,20 @@ else glib_max_allowed = 'GLIB_VERSION_@0@_@1@'.format(glib_major_req, glib_minor_req) endif -glib_req = '>= @0@.@1@.@2@'.format(glib_major_req, glib_minor_req, glib_micro_req) -pango_req = '>= 1.37.3' -atk_req = '>= 2.15.1' -cairo_req = '>= 1.14.0' -gdk_pixbuf_req = '>= 2.30.0' -introspection_req = '>= 1.39.0' -wayland_proto_req = '>= 1.7' -wayland_req = '>= 1.9.91' -mirclient_req = '>= 0.22.0' -mircookie_req = '>= 0.17.0' -graphene_req = '>= 1.5.1' -epoxy_req = '>= 1.0' -xkbcommon_req = '>= 0.2.0' +glib_req = '>= @0@.@1@.@2@'.format(glib_major_req, glib_minor_req, glib_micro_req) +pango_req = '>= 1.37.3' +atk_req = '>= 2.15.1' +cairo_req = '>= 1.14.0' +gdk_pixbuf_req = '>= 2.30.0' +introspection_req = '>= 1.39.0' +wayland_proto_req = '>= 1.7' +wayland_req = '>= 1.9.91' +mirclient_req = '>= 0.22.0' +mircookie_req = '>= 0.17.0' +graphene_req = '>= 1.5.1' +epoxy_req = '>= 1.0' +cloudproviders_req = '>= 0.2.0' +xkbcommon_req = '>= 0.2.0' gnome = import('gnome') @@ -86,12 +87,13 @@ gtk_soversion = '0.@0@.@1@'.format(gtk_binary_age - gtk_interface_age, gtk_inter gtk_api_version = '4.0' -x11_enabled = get_option('enable-x11-backend') -wayland_enabled = get_option('enable-wayland-backend') -broadway_enabled = get_option('enable-broadway-backend') -mir_enabled = get_option('enable-mir-backend') -quartz_enabled = get_option('enable-quartz-backend') -win32_enabled = get_option('enable-win32-backend') +x11_enabled = get_option('enable-x11-backend') +wayland_enabled = get_option('enable-wayland-backend') +broadway_enabled = get_option('enable-broadway-backend') +mir_enabled = get_option('enable-mir-backend') +quartz_enabled = get_option('enable-quartz-backend') +win32_enabled = get_option('enable-win32-backend') +cloudproviders_enabled = get_option('enable-cloudproviders') os_unix = false os_linux = false @@ -505,6 +507,15 @@ else message('Vulkan support explicitly disabled') endif +if cloudproviders_enabled + cloudproviders_dep = dependency('cloudproviders', required: true) + if cloudproviders_dep.found() + cdata.set('HAVE_CLOUDPROVIDERS', cloudproviders_dep.found()) + else + error('Cloudproviders support not found, but was explicitly requested.') + endif +endif + subdir('modules/input') subdir('gdk') subdir('gsk') diff --git a/meson_options.txt b/meson_options.txt index bcd4967e52..586ad3e884 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -22,6 +22,8 @@ option('enable-papi-print-backend', type: 'combo', choices : ['yes', 'no', 'auto description : 'Enable the papi print backend') option('enable-cloudprint-print-backend', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto', description : 'Enable the cloudprint print backend') +option('enable-cloudproviders', type: 'boolean', value: false, + description : 'Enable the cloudproviders support') option('enable-xinerama', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto', description : 'Enable support for the Xinerama extension') option('disable-modules', type: 'boolean', value : 'false',