[gnome-usage] Added Storage Analyzer. Added ListBox in storage. Enhancements of HeaderBar.
- From: Petr Štětka <pstetka src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-usage] Added Storage Analyzer. Added ListBox in storage. Enhancements of HeaderBar.
- Date: Wed, 22 Feb 2017 14:01:03 +0000 (UTC)
commit 76009d8059de9b7ba7c0d64d8dd1251fb9e16e23
Author: Petr Štětka <pstetka redhat com>
Date: Wed Feb 22 15:00:45 2017 +0100
Added Storage Analyzer.
Added ListBox in storage.
Enhancements of HeaderBar.
README.md | 2 +-
data/interface/adwaita-dark.css | 38 +---
data/interface/adwaita.css | 36 +---
gnome-usage.avprj | 10 +
po/POTFILES.in | 7 +-
src/application.vala | 7 +
src/color-rectangle.vala | 17 ++-
src/graph-block-row.vala | 2 +-
src/graph-stack-switcher.vala | 8 +-
src/header-bar.vala | 97 ++++++++-
src/storage-analyzer.vala | 470 +++++++++++++++++++++++++++++++++++++++
src/storage-item.vala | 128 +++++++++++
src/storage-list-box.vala | 140 ++++++++++++
src/storage-row.vala | 129 +++++++++++
src/storage-view.vala | 38 +++
src/storage-worker.vala | 87 +++++++
src/utils.vala | 30 +++
src/vapis/glibtop.vapi | 36 +++-
src/window.vala | 38 +++-
19 files changed, 1243 insertions(+), 77 deletions(-)
---
diff --git a/README.md b/README.md
index 3e0beb9..bb15993 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ New GNOME Usage!
- [x] Support other architectures than x86_64 (netinfo precompiled library)
- [ ] Fix bug with refreshing ProcessListBox 50% (focus, and click when refresh)
- [ ] Search in processes
-- [ ] Storage view - 1%
+- [ ] Storage view - 75%
- [ ] Power view (Design?)
- [ ] Disk usage (What library we can use?)
- [ ] Data view - 0%
diff --git a/data/interface/adwaita-dark.css b/data/interface/adwaita-dark.css
index 01ebe34..b197f61 100644
--- a/data/interface/adwaita-dark.css
+++ b/data/interface/adwaita-dark.css
@@ -112,45 +112,17 @@ PieChart.available, ColorRectangle.available {
}
ColorRectangle.system {
- color: #2e3436;
+ color: #3c4447;
}
ColorRectangle.applications {
color: #4e9a06;
}
-ColorRectangle.documents {
- color: #99b9dc;
-}
-
-ColorRectangle.downloads {
- color: #9bb8db;
-}
-
-ColorRectangle.music {
- color: #457fd3;
-}
-
-ColorRectangle.pictures {
- color: #3466a5;
-}
-
-ColorRectangle.videos {
- color: #204a87;
-}
-
-ColorRectangle.others-storage {
- color: #16325c;
-}
-
ColorRectangle.trash {
color: #ef2929;
}
-ColorRectangle.cache {
- color: #fce94f;
-}
-
ColorRectangle.user {
color: #ad7fa8;
}
@@ -158,3 +130,11 @@ ColorRectangle.user {
ColorRectangle.available-storage {
color: #d3d7cf;
}
+
+row.folders {
+ color: #457fd3;
+}
+
+list.folders {
+ color: #457fd3;
+}
\ No newline at end of file
diff --git a/data/interface/adwaita.css b/data/interface/adwaita.css
index 35527cd..9a22685 100644
--- a/data/interface/adwaita.css
+++ b/data/interface/adwaita.css
@@ -125,38 +125,10 @@ ColorRectangle.applications {
color: #4e9a06;
}
-ColorRectangle.documents {
- color: #99b9dc;
-}
-
-ColorRectangle.downloads {
- color: #9bb8db;
-}
-
-ColorRectangle.music {
- color: #457fd3;
-}
-
-ColorRectangle.pictures {
- color: #3466a5;
-}
-
-ColorRectangle.videos {
- color: #204a87;
-}
-
-ColorRectangle.others_storage {
- color: #16325c;
-}
-
ColorRectangle.trash {
color: #ef2929;
}
-ColorRectangle.cache {
- color: #fce94f;
-}
-
ColorRectangle.user {
color: #ad7fa8;
}
@@ -164,3 +136,11 @@ ColorRectangle.user {
ColorRectangle.available_storage {
color: #d3d7cf;
}
+
+row.folders {
+ color: #457fd3;
+}
+
+list.folders {
+ color: #457fd3;
+}
diff --git a/gnome-usage.avprj b/gnome-usage.avprj
index 31686fb..cde0b5d 100644
--- a/gnome-usage.avprj
+++ b/gnome-usage.avprj
@@ -58,8 +58,13 @@ c_library: rg egg gmodule-2.0 m rt gtop-2.0 pthread dl netinfo
*vala_source: process-row.vala
*vala_source: process.vala
*vala_source: settings.vala
+*vala_source: storage-analyzer.vala
*vala_source: storage-graph.vala
+*vala_source: storage-item.vala
+*vala_source: storage-list-box.vala
+*vala_source: storage-row.vala
*vala_source: storage-view.vala
+*vala_source: storage-worker.vala
*vala_source: sub-process-list-box.vala
*vala_source: sub-process-sub-row.vala
*vala_source: system-monitor.vala
@@ -108,8 +113,13 @@ h_folder: /usr/include/libgtop-2.0
*translate: vala src/process-row.vala
*translate: vala src/process.vala
*translate: vala src/settings.vala
+*translate: vala src/storage-analyzer.vala
*translate: vala src/storage-graph.vala
+*translate: vala src/storage-item.vala
+*translate: vala src/storage-list-box.vala
+*translate: vala src/storage-row.vala
*translate: vala src/storage-view.vala
+*translate: vala src/storage-worker.vala
*translate: vala src/sub-process-list-box.vala
*translate: vala src/sub-process-sub-row.vala
*translate: vala src/system-monitor.vala
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5083f41..bdb26a0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,17 +2,18 @@
# Please keep this file sorted alphabetically.
data/org.gnome.Usage.desktop
data/org.gnome.Usage.gschema.xml
-external/egg/egg-date-time.c
-external/egg/egg-file-chooser-entry.c
-external/egg/egg-search-bar.c
src/application.vala
src/cpu-sub-view.vala
src/data-view.vala
src/graph-block.vala
+src/graph-stack-switcher.vala
src/memory-sub-view.vala
src/network-sub-view.vala
src/performance-view.vala
src/power-view.vala
src/process-dialog.vala
+src/storage-analyzer.vala
+src/storage-item.vala
src/storage-view.vala
+src/utils.vala
src/window.vala
diff --git a/src/application.vala b/src/application.vala
index 5289b4c..fdc120f 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -7,6 +7,7 @@ namespace Usage
public Settings settings;
private Window window;
private SystemMonitor monitor;
+ private StorageAnalyzer storage_analyzer;
private const GLib.ActionEntry app_entries[] =
{
@@ -19,6 +20,7 @@ namespace Usage
application_id = "org.gnome.Usage";
settings = new Settings();
monitor = new SystemMonitor();
+ storage_analyzer = new StorageAnalyzer();
}
public SystemMonitor get_system_monitor()
@@ -26,6 +28,11 @@ namespace Usage
return monitor;
}
+ public StorageAnalyzer get_storage_analyzer()
+ {
+ return storage_analyzer;
+ }
+
public Window? get_window()
{
return window;
diff --git a/src/color-rectangle.vala b/src/color-rectangle.vala
index 8a90578..a5a4542 100644
--- a/src/color-rectangle.vala
+++ b/src/color-rectangle.vala
@@ -10,11 +10,26 @@ namespace Usage {
set_css_name("ColorRectangle");
}
- public ColorRectangle(string css_class)
+ public Gdk.RGBA get_color()
+ {
+ return color;
+ }
+
+ public ColorRectangle.new_from_rgba(Gdk.RGBA color)
+ {
+ this.color = color;
+ init();
+ }
+
+ public ColorRectangle.new_from_css(string css_class)
{
get_style_context().add_class(css_class);
color = get_style_context().get_color(get_style_context().get_state());
+ init();
+ }
+ private void init()
+ {
this.height_request = 17;
this.width_request = 17;
this.valign = Gtk.Align.CENTER;
diff --git a/src/graph-block-row.vala b/src/graph-block-row.vala
index 4d2f7f3..fde5bf1 100644
--- a/src/graph-block-row.vala
+++ b/src/graph-block-row.vala
@@ -10,7 +10,7 @@ namespace Usage {
public GraphBlockRow(GraphBlockType type, string label_text, string css_class)
{
Object(orientation: Gtk.Orientation.HORIZONTAL);
- var color_rectangle = new ColorRectangle(css_class);
+ var color_rectangle = new ColorRectangle.new_from_css(css_class);
var label = new Gtk.Label(label_text);
label.margin = 5;
label.ellipsize = Pango.EllipsizeMode.END;
diff --git a/src/graph-stack-switcher.vala b/src/graph-stack-switcher.vala
index 89e1ff7..f35d3e4 100644
--- a/src/graph-stack-switcher.vala
+++ b/src/graph-stack-switcher.vala
@@ -22,10 +22,10 @@ namespace Usage
this.sub_views = sub_views;
buttons = {
- new GraphSwitcherButton.processor("Processor"),
- new GraphSwitcherButton.memory("Memory"),
- new GraphSwitcherButton.disk("Disk I/O"),
- new GraphSwitcherButton.network("Network"),
+ new GraphSwitcherButton.processor(_("Processor")),
+ new GraphSwitcherButton.memory(_("Memory")),
+ new GraphSwitcherButton.disk(_("Disk I/O")),
+ new GraphSwitcherButton.network(_("Network")),
};
foreach(Gtk.ToggleButton button in buttons)
diff --git a/src/header-bar.vala b/src/header-bar.vala
index 5274257..f68a40a 100644
--- a/src/header-bar.vala
+++ b/src/header-bar.vala
@@ -1,20 +1,109 @@
namespace Usage
{
+ public enum HeaderBarMode
+ {
+ PERFORMANCE,
+ DATA,
+ STORAGE,
+ POWER
+ }
+
public class HeaderBar : Gtk.HeaderBar
{
private Gtk.StackSwitcher stack_switcher;
- private Gtk.MenuButton menu_button;
+ private Gtk.Button? storage_back_button;
+ private bool show_storage_back_btn = false;
+ private Gtk.Button? storage_rescan_button;
+ private HeaderBarMode mode;
public HeaderBar(Gtk.Stack stack)
{
+ mode = HeaderBarMode.PERFORMANCE;
show_close_button = true;
stack_switcher = new Gtk.StackSwitcher();
stack_switcher.halign = Gtk.Align.CENTER;
stack_switcher.set_stack(stack);
- set_custom_title(stack_switcher);
- menu_button = new Gtk.MenuButton();
- menu_button.add(new Gtk.Image.from_icon_name("open-menu-symbolic", Gtk.IconSize.BUTTON));
+
+ set_mode(HeaderBarMode.PERFORMANCE);
show_all();
}
+
+ public void set_mode(HeaderBarMode mode)
+ {
+ switch(this.mode)
+ {
+ case HeaderBarMode.PERFORMANCE:
+ break;
+ case HeaderBarMode.DATA:
+ break;
+ case HeaderBarMode.STORAGE:
+ remove(storage_back_button);
+ remove(storage_rescan_button);
+ storage_rescan_button = null;
+ storage_back_button = null;
+ break;
+ case HeaderBarMode.POWER:
+ break;
+ }
+
+ switch(mode)
+ {
+ case HeaderBarMode.PERFORMANCE:
+ show_stack_switcher();
+ break;
+ case HeaderBarMode.DATA:
+ show_stack_switcher();
+ break;
+ case HeaderBarMode.STORAGE:
+ show_stack_switcher();
+ storage_back_button = new Gtk.Button.from_icon_name("go-previous-symbolic");
+ storage_back_button.clicked.connect(() => {
+ ((StorageView) (GLib.Application.get_default() as
Application).get_window().get_views()[2]).get_storage_list_box().on_back_button_clicked();
+ });
+ show_storage_back_button(show_storage_back_btn);
+ storage_rescan_button = new Gtk.Button.from_icon_name("view-refresh-symbolic");
+ storage_rescan_button.clicked.connect(() => {
+ (GLib.Application.get_default() as
Application).get_storage_analyzer().create_cache.begin(true);
+ ((StorageView) (GLib.Application.get_default() as
Application).get_window().get_views()[2]).get_storage_list_box().reload();
+ });
+ storage_rescan_button.show();
+ pack_start(storage_back_button);
+ pack_end(storage_rescan_button);
+ break;
+ case HeaderBarMode.POWER:
+ show_stack_switcher();
+ break;
+ }
+ this.mode = mode;
+ }
+
+ public void show_title_text(string title)
+ {
+ set_custom_title(null);
+ set_title(title);
+ }
+
+ public void show_stack_switcher()
+ {
+ set_custom_title(stack_switcher);
+ }
+
+ public void show_storage_back_button(bool show)
+ {
+ if(storage_back_button != null)
+ {
+ if(show)
+ {
+ storage_back_button.show();
+ show_storage_back_btn = true;
+ }
+ else
+ {
+ storage_back_button.hide();
+ show_storage_back_btn = false;
+ }
+ }
+
+ }
}
}
\ No newline at end of file
diff --git a/src/storage-analyzer.vala b/src/storage-analyzer.vala
new file mode 100644
index 0000000..ff31fb8
--- /dev/null
+++ b/src/storage-analyzer.vala
@@ -0,0 +1,470 @@
+using GTop;
+
+namespace Usage
+{
+ public class StorageAnalyzer : Object
+ {
+ public signal void cache_complete();
+ public bool cache { private set; get; }
+ public bool separate_home = false;
+
+ private Cancellable cancellable;
+ private HashTable<string, Directory?> directory_table;
+ private HashTable<string, Storage?> storages;
+ private AsyncQueue<StorageResult> results_queue;
+ private string[] exclude_from_home;
+ private static bool path_null;
+
+ private struct Directory
+ {
+ public uint64 size;
+ public float percentage;
+ }
+
+ private struct Storage
+ {
+ public uint64 used;
+ public uint64 free;
+ public uint64 total;
+ public string name;
+ public string mount_path;
+ }
+
+ private Storage? get_storage(string mount_path)
+ {
+ return storages[mount_path];
+ }
+
+ private Directory? get_directory(string path)
+ {
+ return directory_table[path];
+ }
+
+ public void stop_scanning()
+ {
+ cancellable.cancel();
+ }
+
+ public async List<StorageItem> prepare_items(string? path, Gdk.RGBA color)
+ {
+ if(path == null)
+ {
+ path_null = true;
+ List<StorageItem> items = new List<StorageItem>();
+
+ if(separate_home)
+ {
+ Storage? home = get_storage("/home");
+ items.insert_sorted(new StorageItem.storage(_("Storage 1"), home.mount_path, home.total,
0), (CompareFunc) sort);
+ add_home_items(ref items, 0);
+ items.insert_sorted(new StorageItem.available(home.free, ((float) home.free /
home.total) * 100, 0), (CompareFunc) sort);
+ Storage? root = get_storage("/");
+ items.insert_sorted(new StorageItem.storage(_("Storage 2"), root.mount_path, root.total,
1), (CompareFunc) sort);
+ add_root_items(ref items, root, 1);
+ items.insert_sorted(new StorageItem.available(root.free, ((float) root.free /
root.total) * 100, 1), (CompareFunc) sort);
+ }
+ else
+ {
+ Storage? root = get_storage("/");
+ items.insert_sorted(new StorageItem.storage(_("Storage 1"), root.mount_path, root.total,
0), (CompareFunc) sort);
+ add_root_items(ref items, root, 0);
+ add_home_items(ref items, 0);
+ items.insert_sorted(new StorageItem.available(root.free, ((float) root.free /
root.total) * 100), (CompareFunc) sort);
+ }
+
+ set_colors(ref items, color);
+ return items;
+ } else
+ {
+ path_null = false;
+ return get_items_for_path(path, color, exclude_from_home);
+ }
+ }
+
+ private static int sort(StorageItem a, StorageItem b)
+ {
+ if(a.get_section() > b.get_section())
+ return 1;
+ else if (a.get_section() < b.get_section())
+ return -1;
+ else
+ {
+ switch(a.get_prefered_position())
+ {
+ case StorageItemPosition.FIRST:
+ return -1;
+ case StorageItemPosition.SECOND:
+ if(b.get_prefered_position() != StorageItemPosition.FIRST)
+ return -1;
+ else
+ return 1;
+ case StorageItemPosition.ANYWHERE:
+ switch(b.get_prefered_position())
+ {
+ case StorageItemPosition.FIRST:
+ return 1;
+ case StorageItemPosition.SECOND:
+ return 1;
+ case StorageItemPosition.ANYWHERE:
+ if(path_null == true)
+ return sort_alphabetically(a.get_name(), b.get_name());
+ else
+ return (int) ((uint64) (a.get_size() < b.get_size()) - (uint64)
(a.get_size() > b.get_size()));
+ case StorageItemPosition.PENULTIMATE:
+ return -1;
+ case StorageItemPosition.LAST:
+ return -1;
+ }
+ break;
+ case StorageItemPosition.PENULTIMATE:
+ if(b.get_prefered_position() != StorageItemPosition.LAST)
+ return 1;
+ else
+ return -1;
+ case StorageItemPosition.LAST:
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ private static int sort_alphabetically(string first, string second)
+ {
+ int length = first.length < second.length ? first.length : second.length;
+ for(int i = 0; i < length; i++)
+ {
+ if(first[i] < second[i])
+ return -1;
+ else if(first[i] > second[i])
+ return 1;
+ }
+ return first.length < second.length ? -1 : 1;
+ }
+
+ private void set_colors(ref List<StorageItem> items, Gdk.RGBA default_color)
+ {
+ for(int i = 0; i < items.length(); i++)
+ {
+ unowned StorageItem item = items.nth_data(i);
+ switch(item.get_item_type())
+ {
+ case StorageItemType.DOCUMENTS:
+ case StorageItemType.DOWNLOADS:
+ case StorageItemType.DESKTOP:
+ case StorageItemType.MUSIC:
+ case StorageItemType.PICTURES:
+ case StorageItemType.VIDEOS:
+ item.set_color(generate_color(default_color, i-2, 6, false)); //6 because DOCUMENTS,
DOWNLOADS, DESKTOP, MUSIC, PICTURES, VIDEOS, 2 because header and Home
+ break;
+ case StorageItemType.DIRECTORY:
+ case StorageItemType.FILE:
+ item.set_color(generate_color(default_color, i, items.length(), true));
+ break;
+ }
+ }
+ }
+
+ private Gdk.RGBA generate_color(Gdk.RGBA default_color, int order, uint all_color, bool reverse =
false)
+ {
+ order += 1;
+
+ double step = 100 / all_color;
+ if(all_color % 2 == 1)
+ {
+ if((all_color / 2) + 1 == order)
+ return default_color;
+ else
+ step = 100 / (all_color - 1);
+ }
+
+ if(order > (all_color / 2))
+ {
+ if(all_color % 2 == 1)
+ order -= 1;
+ double percentage = step * (order - (all_color/2));
+ if(reverse)
+ return Utils.color_lighter(default_color, percentage);
+ else
+ return Utils.color_darker(default_color, percentage);
+ }
+ else
+ {
+ double percentage = step * ((all_color/2) - (order-1));
+ if(reverse)
+ return Utils.color_darker(default_color, percentage);
+ else
+ return Utils.color_lighter(default_color, percentage);
+ }
+ }
+
+ public async void create_cache(bool force_override = false)
+ {
+ if(force_override == true)
+ cache = false;
+
+ if(cache == false)
+ {
+ cache = true;
+ analyze_storages();
+ stop_scanning();
+ cancellable.reset();
+ directory_table.remove_all();
+ SourceFunc callback = create_cache.callback;
+
+ ThreadFunc<void*> run = () => {
+ scan_cache();
+ Idle.add((owned) callback);
+ return null;
+ };
+
+ var thread = new Thread<void*>("storage_analyzer", run);
+ yield;
+ thread.join();
+ cache_complete();
+ }
+ }
+
+ private void scan_cache()
+ {
+ uint64 total_size;
+ if(separate_home)
+ {
+ Storage? home = get_storage("/home");
+ total_size = home.total;
+ }
+ else
+ {
+ Storage? root = get_storage("/");
+ total_size = root.total;
+ }
+
+ var desktop = new
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DESKTOP)), total_size, ref
cancellable, ref results_queue);
+ var documents = new
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DOCUMENTS)), total_size, ref
cancellable, ref results_queue);
+ var downloads = new
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DOWNLOAD)), total_size, ref
cancellable, ref results_queue);
+ var music = new
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.MUSIC)), total_size, ref
cancellable, ref results_queue);
+ var pictures = new
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.PICTURES)), total_size, ref
cancellable, ref results_queue);
+ var videos = new
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.VIDEOS)), total_size, ref
cancellable, ref results_queue);
+ var trash = new StorageWorker(File.new_for_path(Environment.get_home_dir() +
"/.local/share/Trash/files"), total_size, ref cancellable, ref results_queue, _("Trash"));
+ var home = new StorageWorker(File.new_for_path(Environment.get_home_dir()), total_size, ref
cancellable, ref results_queue, Environment.get_real_name(), exclude_from_home);
+
+ try {
+ ThreadPool<StorageWorker> threads = new ThreadPool<StorageWorker>.with_owned_data((worker)
=> {
+ worker.run();
+ }, (int) get_num_processors(), false);
+
+ threads.add(home);
+ threads.add(desktop);
+ threads.add(documents);
+ threads.add(downloads);
+ threads.add(music);
+ threads.add(pictures);
+ threads.add(videos);
+ threads.add(trash);
+ }
+ catch (ThreadError e)
+ {
+ stderr.printf("%s", e.message);
+ }
+
+ StorageResult result;
+ while ((result = results_queue.try_pop()) != null)
+ {
+ var directory = Directory();
+ directory.size = result.size;
+ directory.percentage = result.percentage;
+ directory_table.insert (result.path, directory);
+ }
+ }
+
+ private void add_root_items(ref List<StorageItem> items, Storage storage, int section)
+ {
+ items.insert_sorted(new StorageItem.system(_("Operation System"), storage.used, ((float)
storage.free / storage.total) * 100, section), (CompareFunc) sort);
+ }
+
+ private void add_home_items(ref List<StorageItem> items, int section)
+ {
+ Directory? user = get_directory(Environment.get_home_dir());
+ if(user != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.USER,
+ _("Home"),
+ Environment.get_home_dir(),
+ user.size,
+ user.percentage,
+ section,
+ StorageItemPosition.SECOND), (CompareFunc) sort);
+ }
+ Directory? desktop = get_directory(Environment.get_user_special_dir(UserDirectory.DESKTOP));
+ if(desktop != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.DESKTOP,
+ Path.get_basename(Environment.get_user_special_dir(UserDirectory.DESKTOP)),
+ Environment.get_user_special_dir(UserDirectory.DESKTOP),
+ desktop.size,
+ desktop.percentage,
+ section), (CompareFunc) sort);
+ }
+ Directory? documents = get_directory(Environment.get_user_special_dir(UserDirectory.DOCUMENTS));
+ if(documents != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.DOCUMENTS,
+ Path.get_basename(Environment.get_user_special_dir(UserDirectory.DOCUMENTS)),
+ Environment.get_user_special_dir(UserDirectory.DOCUMENTS),
+ documents.size,
+ documents.percentage,
+ section), (CompareFunc) sort);
+ }
+ Directory? downloads = get_directory(Environment.get_user_special_dir(UserDirectory.DOWNLOAD));
+ if(downloads != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.DOWNLOADS,
+ Path.get_basename(Environment.get_user_special_dir(UserDirectory.DOWNLOAD)),
+ Environment.get_user_special_dir(UserDirectory.DOWNLOAD),
+ downloads.size,
+ downloads.percentage,
+ section), (CompareFunc) sort);
+ }
+ Directory? music = get_directory(Environment.get_user_special_dir(UserDirectory.MUSIC));
+ if(music != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.MUSIC,
+ Path.get_basename(Environment.get_user_special_dir(UserDirectory.MUSIC)),
+ Environment.get_user_special_dir(UserDirectory.MUSIC),
+ music.size,
+ music.percentage,
+ section), (CompareFunc) sort);
+ }
+ Directory? pictures = get_directory(Environment.get_user_special_dir(UserDirectory.PICTURES));
+ if(pictures != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.PICTURES,
+ Path.get_basename(Environment.get_user_special_dir(UserDirectory.PICTURES)),
+ Environment.get_user_special_dir(UserDirectory.PICTURES),
+ pictures.size,
+ pictures.percentage,
+ section), (CompareFunc) sort);
+ }
+ Directory? videos = get_directory(Environment.get_user_special_dir(UserDirectory.VIDEOS));
+ if(videos != null)
+ {
+ items.insert_sorted(new StorageItem.item(StorageItemType.VIDEOS,
+ Path.get_basename(Environment.get_user_special_dir(UserDirectory.VIDEOS)),
+ Environment.get_user_special_dir(UserDirectory.VIDEOS),
+ videos.size,
+ videos.percentage,
+ section), (CompareFunc) sort);
+ }
+ var trash_path = Environment.get_home_dir() + "/.local/share/Trash/files";
+ Directory? trash = get_directory(trash_path);
+ if(trash != null)
+ {
+ items.insert_sorted(new StorageItem.trash(
+ trash_path,
+ trash.size,
+ trash.percentage,
+ section), (CompareFunc) sort);
+ }
+ }
+
+ private List<StorageItem> get_items_for_path(string path, Gdk.RGBA color, string[]? exclude_paths =
null)
+ {
+ List<StorageItem> items = new List<StorageItem>();
+
+ File file = File.new_for_path(path);
+ FileEnumerator enumerator;
+
+ try {
+ enumerator = file.enumerate_children(FileAttribute.STANDARD_SIZE,
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+ FileInfo info;
+
+ while((info = enumerator.next_file(null)) != null && cancellable.is_cancelled() == false)
+ {
+ if(info.get_file_type() == FileType.DIRECTORY)
+ {
+ if(exclude_paths == null || !(file.resolve_relative_path(info.get_name()).get_path()
in exclude_paths))
+ {
+ string folder_path = file.get_child(info.get_name()).get_parse_name();
+ Directory? folder = get_directory(folder_path);
+ uint64 folder_size = 0;
+ double folder_percentage = 0;
+
+ if(folder != null)
+ {
+ folder_size = folder.size;
+ folder_percentage = folder.percentage;
+ }
+
+ items.insert_sorted(new StorageItem.directory(info.get_name(), folder_path,
folder_size,
+ folder_percentage), (CompareFunc) sort);
+ }
+ }
+ else if(info.get_file_type() == FileType.REGULAR)
+ {
+ Directory? parent = get_directory(path);
+ float percentage = ((float) info.get_size() / parent.size) * 100;
+
+ items.insert_sorted(new StorageItem.file(info.get_name(),
+ file.get_child(info.get_name()).get_parse_name(), info.get_size(), percentage),
+ (CompareFunc) sort);
+ }
+ }
+ }
+ catch (Error e) {
+ stderr.printf ("Error: %s\n", e.message);
+ }
+
+ set_colors(ref items, color);
+
+ return items;
+ }
+
+ private void analyze_storages()
+ {
+ separate_home = false;
+ storages.remove_all();
+
+ MountList mount_list;
+ MountEntry[] entries = GTop.get_mountlist(out mount_list, false);
+
+ for (int i = 0; i < mount_list.number; i++)
+ {
+ string mountdir = (string) entries[i].mountdir;
+ if(mountdir == "/" || mountdir == "/home")
+ {
+ if(mountdir == "/home")
+ separate_home = true;
+
+ FsUsage root;
+ GTop.get_fsusage(out root, mountdir);
+
+ Storage storage = Storage();
+ storage.free = root.bfree * root.block_size;
+ storage.total = root.blocks * root.block_size;
+ storage.used = storage.total - storage.free;
+ storage.name = (string) entries[i].devname;
+ storage.mount_path = mountdir;
+ storages.insert (mountdir, storage);
+ }
+ }
+ }
+
+ public StorageAnalyzer()
+ {
+ cache = false;
+ cancellable = new Cancellable();
+ directory_table = new HashTable<string, Directory?>(str_hash, str_equal);
+ storages = new HashTable<string, Storage?>(str_hash, str_equal);
+ results_queue = new AsyncQueue<StorageResult>();
+ exclude_from_home = {
+ Environment.get_user_special_dir(UserDirectory.DESKTOP),
+ Environment.get_user_special_dir(UserDirectory.DOCUMENTS),
+ Environment.get_user_special_dir(UserDirectory.DOWNLOAD),
+ Environment.get_user_special_dir(UserDirectory.MUSIC),
+ Environment.get_user_special_dir(UserDirectory.PICTURES),
+ Environment.get_user_special_dir(UserDirectory.VIDEOS),
+ Environment.get_home_dir() + "/.local/share/Trash/files"
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/storage-item.vala b/src/storage-item.vala
new file mode 100644
index 0000000..76e6a71
--- /dev/null
+++ b/src/storage-item.vala
@@ -0,0 +1,128 @@
+using Gee;
+
+namespace Usage
+{
+ public enum StorageItemPosition
+ {
+ FIRST,
+ SECOND,
+ ANYWHERE,
+ PENULTIMATE,
+ LAST
+ }
+
+ public enum StorageItemType
+ {
+ STORAGE,
+ SYSTEM,
+ DOCUMENTS,
+ DOWNLOADS,
+ DESKTOP,
+ MUSIC,
+ PICTURES,
+ VIDEOS,
+ TRASH,
+ USER,
+ AVAILABLE,
+ FILE,
+ DIRECTORY
+ }
+
+ public class StorageItem : Object
+ {
+ private string name;
+ private string path;
+ private StorageItemType type;
+ private uint64 size;
+ private double percentage;
+ private StorageItemPosition prefered_position = StorageItemPosition.ANYWHERE;
+ private int section;
+ private Gdk.RGBA color;
+
+ public StorageItem.item(StorageItemType type, string name, string path, uint64 size, double
percentage, int section = 0, StorageItemPosition prefered_position = StorageItemPosition.ANYWHERE)
+ {
+ this.type = type;
+ this.name = name;
+ this.path = path;
+ this.size = size;
+ this.percentage = percentage;
+ this.section = section;
+ this.prefered_position = prefered_position;
+ }
+
+ public StorageItem.directory(string name, string path, uint64 size, double percentage)
+ {
+ StorageItem.item(StorageItemType.DIRECTORY, name, path, size, percentage);
+ }
+
+ public StorageItem.file(string name, string path, uint64 size, double percentage)
+ {
+ StorageItem.item(StorageItemType.FILE, name, path, size, percentage);
+ }
+
+ public StorageItem.trash(string path, uint64 size, double percentage, int section = 0)
+ {
+ StorageItem.item(StorageItemType.TRASH, _("Trash"), path, size, percentage, section,
StorageItemPosition.PENULTIMATE);
+ }
+
+ public StorageItem.storage(string name, string path, uint64 size, int section = 0)
+ {
+ StorageItem.item(StorageItemType.STORAGE, name, path, size, 0, section,
StorageItemPosition.FIRST);
+ }
+
+ public StorageItem.system(string name, uint64 size, double percentage, int section = 0)
+ {
+ StorageItem.item(StorageItemType.SYSTEM, name, "", size, percentage, section);
+ }
+
+ public StorageItem.available(uint64 size, double percentage, int section = 0)
+ {
+ StorageItem.item(StorageItemType.AVAILABLE, _("Available"), "", size, percentage, section,
StorageItemPosition.LAST);
+ }
+
+ public StorageItemPosition get_prefered_position()
+ {
+ return prefered_position;
+ }
+
+ public void set_color(Gdk.RGBA color)
+ {
+ this.color = color;
+ }
+
+ public Gdk.RGBA get_color()
+ {
+ return color;
+ }
+
+ public int get_section()
+ {
+ return section;
+ }
+
+ public uint64 get_size()
+ {
+ return size;
+ }
+
+ public double get_percentage()
+ {
+ return percentage;
+ }
+
+ public string get_name()
+ {
+ return name;
+ }
+
+ public StorageItemType get_item_type()
+ {
+ return type;
+ }
+
+ public string get_path()
+ {
+ return path;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/storage-list-box.vala b/src/storage-list-box.vala
new file mode 100644
index 0000000..bcedbae
--- /dev/null
+++ b/src/storage-list-box.vala
@@ -0,0 +1,140 @@
+namespace Usage
+{
+ public class StorageListBox : Gtk.ListBox
+ {
+ public signal void loading();
+ public signal void loaded();
+
+ private List<string?> path_history;
+ private List<string?> name_history;
+ private string? actual_path;
+ private string? actual_name;
+ private ListStore model;
+ private bool root = true;
+ private StorageAnalyzer storage_analyzer;
+ private Gdk.RGBA color;
+
+ public StorageListBox()
+ {
+ set_selection_mode (Gtk.SelectionMode.NONE);
+ set_header_func (update_header);
+
+ model = new ListStore(typeof(StorageItem));
+ bind_model(model, on_row_created);
+
+ row_activated.connect(on_row_activated);
+
+ path_history = new List<string>();
+ name_history = new List<string>();
+ actual_path = null;
+ actual_name = null;
+ storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
+ reload();
+ }
+
+ public void on_back_button_clicked()
+ {
+ unowned List<string>? path = path_history.last();
+ unowned List<string>? name = name_history.last();
+ actual_path = path.data;
+ actual_name = name.data;
+ load(path.data);
+ path_history.delete_link(path);
+ name_history.delete_link(name);
+ if(root)
+ {
+ (GLib.Application.get_default() as
Application).get_window().get_header_bar().show_storage_back_button(false);
+ (GLib.Application.get_default() as
Application).get_window().get_header_bar().show_stack_switcher();
+ }
+ else
+ (GLib.Application.get_default() as
Application).get_window().get_header_bar().show_title_text(actual_name);
+ }
+
+ public void reload()
+ {
+ get_style_context().add_class("folders");
+ color = get_style_context().get_color(get_style_context().get_state());
+ get_style_context().remove_class("folders");
+ this.hide();
+ loading();
+ root = true;
+ storage_analyzer.cache_complete.connect(() => {
+ storage_analyzer.prepare_items.begin(actual_path, color, (obj, res) => {
+ loaded();
+ this.show();
+ model.remove_all();
+
+ foreach(unowned StorageItem item in storage_analyzer.prepare_items.end(res))
+ model.append(item);
+ });
+ });
+ }
+
+ private void load(string? path)
+ {
+ if(path == null)
+ {
+ root = true;
+ get_style_context().add_class("folders");
+ color = get_style_context().get_color(get_style_context().get_state());
+ get_style_context().remove_class("folders");
+ }
+ else
+ root = false;
+
+ this.hide();
+ loading();
+ storage_analyzer.prepare_items.begin(path, color, (obj, res) => {
+ loaded();
+ this.show();
+ model.remove_all();
+
+ foreach(unowned StorageItem item in storage_analyzer.prepare_items.end(res))
+ model.append(item);
+ });
+ }
+
+ private void on_row_activated (Gtk.ListBoxRow row)
+ {
+ StorageRow storage_row = (StorageRow) row;
+ if(storage_row.get_item_type() == StorageItemType.FILE)
+ ;//TODO: action on click
+ else if(storage_row.get_item_type() != StorageItemType.STORAGE && storage_row.get_item_type() !=
StorageItemType.SYSTEM
+ && storage_row.get_item_type() != StorageItemType.AVAILABLE)
+ {
+ path_history.append(actual_path);
+ name_history.append(actual_name);
+ actual_path = storage_row.get_item_path();
+ actual_name = storage_row.get_item_name();
+
+ (GLib.Application.get_default() as
Application).get_window().get_header_bar().show_storage_back_button(true);
+ (GLib.Application.get_default() as
Application).get_window().get_header_bar().show_title_text(actual_name);
+
+ if(root)
+ color = storage_row.get_color();
+
+ load(actual_path);
+ }
+ }
+
+ private Gtk.Widget on_row_created (Object item)
+ {
+ unowned StorageItem storage_item = (StorageItem) item;
+ var row = new StorageRow(storage_item);
+ return row;
+ }
+
+ private void update_header(Gtk.ListBoxRow row, Gtk.ListBoxRow? before_row)
+ {
+ if(before_row == null)
+ row.set_header(null);
+ else
+ {
+ var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
+ separator.get_style_context().add_class("list");
+ separator.show();
+ row.set_header(separator);
+ }
+ }
+ }
+}
diff --git a/src/storage-row.vala b/src/storage-row.vala
new file mode 100644
index 0000000..d083ffd
--- /dev/null
+++ b/src/storage-row.vala
@@ -0,0 +1,129 @@
+using Posix;
+using Gee;
+
+namespace Usage
+{
+ public class StorageRow : Gtk.ListBoxRow
+ {
+ private StorageItemType type;
+ private string item_path;
+ private string item_name;
+ private Gdk.RGBA color;
+
+ public StorageRow(StorageItem storage_item)
+ {
+ var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
+ box.margin = 10;
+ box.margin_top = 12;
+ box.margin_bottom = 12;
+ var size_label = new Gtk.Label(Utils.format_size_values(storage_item.get_size()));
+ item_path = storage_item.get_path();
+ item_name = storage_item.get_name();
+ type = storage_item.get_item_type();
+
+ string? color_css_class = null;
+ bool is_header = false;
+
+ ColorRectangle color_rectangle;
+
+ switch(storage_item.get_item_type())
+ {
+ case StorageItemType.SYSTEM:
+ color_css_class = "system";
+ color_rectangle = new ColorRectangle.new_from_css(color_css_class);
+ color = color_rectangle.get_color();
+ box.pack_start(color_rectangle, false, false, 5);
+ break;
+ case StorageItemType.TRASH:
+ color_css_class = "trash";
+ color_rectangle = new ColorRectangle.new_from_css(color_css_class);
+ color = color_rectangle.get_color();
+ box.pack_start(color_rectangle, false, false, 5);
+ break;
+ case StorageItemType.USER:
+ color_css_class = "user";
+ color_rectangle = new ColorRectangle.new_from_css(color_css_class);
+ color = color_rectangle.get_color();
+ box.pack_start(color_rectangle, false, false, 5);
+ break;
+ case StorageItemType.AVAILABLE:
+ color_css_class = "available-storage";
+ color_rectangle = new ColorRectangle.new_from_css(color_css_class);
+ color = color_rectangle.get_color();
+ box.pack_start(color_rectangle, false, false, 5);
+ break;
+ case StorageItemType.STORAGE:
+ is_header = true;
+ box.margin_top = 9;
+ box.margin_bottom = 9;
+ break;
+ case StorageItemType.DOCUMENTS:
+ case StorageItemType.DOWNLOADS:
+ case StorageItemType.DESKTOP:
+ case StorageItemType.MUSIC:
+ case StorageItemType.PICTURES:
+ case StorageItemType.VIDEOS:
+ get_style_context().add_class("folders");
+ color = get_style_context().get_color(get_style_context().get_state());
+ get_style_context().remove_class("folders");
+ color_rectangle = new ColorRectangle.new_from_rgba(storage_item.get_color());
+ box.pack_start(color_rectangle, false, false, 5);
+ break;
+ case StorageItemType.DIRECTORY:
+ color = storage_item.get_color();
+ var info = Gtk.IconTheme.get_default().lookup_icon("folder-symbolic", 15, 0);
+
+ try {
+ var pixbuf = info.load_symbolic (storage_item.get_color());
+ var icon = new Gtk.Image.from_pixbuf (pixbuf);
+ box.pack_start(icon, false, false, 5);
+ }
+ catch(Error e) {
+ GLib.stderr.printf ("Could not load folder-symbolic icon: %s\n", e.message);
+ }
+ break;
+ case StorageItemType.FILE:
+ color = storage_item.get_color();
+ var info = Gtk.IconTheme.get_default().lookup_icon("folder-documents-symbolic", 15, 0);
+
+ try {
+ var pixbuf = info.load_symbolic (storage_item.get_color());
+ var icon = new Gtk.Image.from_pixbuf (pixbuf);
+ box.pack_start(icon, false, false, 5);
+ }
+ catch(Error e) {
+ GLib.stderr.printf ("Could not load folder-documents-symbolic icon: %s\n",
e.message);
+ }
+ break;
+ }
+
+ var title_label = new Gtk.Label(storage_item.get_name());
+ title_label.set_ellipsize(Pango.EllipsizeMode.MIDDLE);
+ box.pack_start(title_label, false, true, 5);
+ box.pack_end(size_label, false, true, 10);
+ add(box);
+
+ show_all();
+ }
+
+ public Gdk.RGBA get_color()
+ {
+ return color;
+ }
+
+ public string get_item_name()
+ {
+ return item_name;
+ }
+
+ public string get_item_path()
+ {
+ return item_path;
+ }
+
+ public StorageItemType get_item_type()
+ {
+ return type;
+ }
+ }
+}
diff --git a/src/storage-view.vala b/src/storage-view.vala
index d036784..f531c67 100644
--- a/src/storage-view.vala
+++ b/src/storage-view.vala
@@ -2,10 +2,48 @@ namespace Usage
{
public class StorageView : View
{
+ private StorageListBox storage_list_box;
+
public StorageView ()
{
name = "STORAGE";
title = _("Storage");
+
+ var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
+ storage_list_box = new StorageListBox();
+ var scrolled_window = new Gtk.ScrolledWindow(null, null);
+ scrolled_window.add(box);
+
+ var spinner = new Gtk.Spinner();
+ spinner.active = true;
+ spinner.margin_top = 30;
+ spinner.margin_bottom = 20;
+
+ box.pack_start(spinner, true, true, 0);
+ box.pack_start(storage_list_box, false, false, 0);
+
+ storage_list_box.loading.connect(() =>
+ {
+ spinner.show();
+ });
+
+ storage_list_box.loaded.connect(() =>
+ {
+ spinner.hide();
+ });
+
+ var graph = new StorageGraph();
+
+ var paned = new Gtk.Paned(Gtk.Orientation.HORIZONTAL);
+ paned.position = 300;
+ paned.add1(scrolled_window);
+ paned.add(graph);
+ add(paned);
+ }
+
+ public StorageListBox get_storage_list_box()
+ {
+ return storage_list_box;
}
}
}
diff --git a/src/storage-worker.vala b/src/storage-worker.vala
new file mode 100644
index 0000000..f51e15f
--- /dev/null
+++ b/src/storage-worker.vala
@@ -0,0 +1,87 @@
+namespace Usage
+{
+ [Compact]
+ public class StorageResult {
+ internal string path;
+ internal uint64 size;
+ internal float percentage;
+ }
+
+ public class StorageWorker
+ {
+ private AsyncQueue<StorageResult> results_queue;
+ private File path;
+ private string[] exclude_paths;
+ private Cancellable cancellable;
+ private string? name;
+ private uint64 total_size;
+
+ public StorageWorker(File path, uint64 total_size, ref Cancellable cancellable, ref
AsyncQueue<StorageResult> results_queue, string? name = null, string[]? exclude_paths = null)
+ {
+ this.path = path;
+ this.cancellable = cancellable;
+ this.name = name;
+ this.exclude_paths = exclude_paths;
+ this.results_queue = results_queue;
+ this.total_size = total_size;
+ }
+
+ private StorageResult get_directory(File file, out uint64 size)
+ {
+ string path = file.get_parse_name();
+ FileEnumerator enumerator;
+ List<StorageResult> childs = new List<StorageResult>();
+ size = 0;
+
+ try {
+ enumerator = file.enumerate_children(FileAttribute.STANDARD_SIZE,
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+ FileInfo info;
+
+ while((info = enumerator.next_file(null)) != null && cancellable.is_cancelled() == false)
+ {
+ if(info.get_file_type() == FileType.DIRECTORY)
+ {
+ if(exclude_paths == null || !(file.resolve_relative_path(info.get_name()).get_path()
in exclude_paths))
+ {
+ var child = file.get_child(info.get_name());
+ uint64 child_size = 0;
+ childs.append(get_directory(child, out child_size));
+ size += child_size;
+ }
+ }
+ else if(info.get_file_type() == FileType.REGULAR)
+ {
+ size += info.get_size();
+ }
+ }
+ }
+ catch (Error e) {
+ stderr.printf ("Error: %s\n", e.message);
+ }
+
+ StorageResult result = new StorageResult();
+ result.path = path;
+ result.size = size;
+
+ foreach (unowned StorageResult child in childs)
+ {
+ child.percentage = ((float) child.size / size) * 100;
+ var child_copy = new StorageResult();
+ child_copy.path = child.path;
+ child_copy.size = child.size;
+ child_copy.percentage = child.percentage;
+ results_queue.push ((owned) child_copy);
+ }
+
+ return result;
+ }
+
+ public void run ()
+ {
+ uint64 size = 0;
+ var child = get_directory(path, out size);
+ child.percentage = ((float) size / total_size) * 100;
+ results_queue.push ((owned) child);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/utils.vala b/src/utils.vala
index 37f7138..f4cdb61 100644
--- a/src/utils.vala
+++ b/src/utils.vala
@@ -31,5 +31,35 @@ namespace Usage
else
return value.to_string() + " B/s";
}
+
+ public static Gdk.RGBA color_darker(Gdk.RGBA color, double percentage)
+ {
+ color.red = color_field_darker(color.red, percentage);
+ color.green = color_field_darker(color.green, percentage);
+ color.blue = color_field_darker(color.blue, percentage);
+
+ return color;
+ }
+
+ public static Gdk.RGBA color_lighter(Gdk.RGBA color, double percentage)
+ {
+ color.red = color_field_lighter(color.red, percentage);
+ color.green = color_field_lighter(color.green, percentage);
+ color.blue = color_field_lighter(color.blue, percentage);
+
+ return color;
+ }
+
+ private static double color_field_darker(double field, double percentage)
+ {
+ field = field * 255;
+ return (field - ((field / 100) * percentage)) / 255;
+ }
+
+ private static double color_field_lighter(double field, double percentage)
+ {
+ field = field * 255;
+ return (field + (((255 - field) / 100) * percentage)) / 255;
+ }
}
}
diff --git a/src/vapis/glibtop.vapi b/src/vapis/glibtop.vapi
index 41d9feb..b55250e 100644
--- a/src/vapis/glibtop.vapi
+++ b/src/vapis/glibtop.vapi
@@ -134,7 +134,7 @@ namespace GTop {
uint32 number;
}
- [CCode(array_length = false, array_null_terminated = false)]
+ [CCode(array_null_terminated = "true")]
public string[] get_netlist(out Netlist netlist);
[CCode(cname = "glibtop_proc_uid", cheader_filename = "glibtop/procuid.h")]
@@ -168,4 +168,38 @@ namespace GTop {
}
[CCode(array_null_terminated = "true")]
public string[] get_proc_argv(out ProcArgs proc_args, Posix.pid_t pid);
+
+ [CCode(cname = "glibtop_fsusage", cheader_filename = "glibtop/fsusage.h")]
+ public struct FsUsage {
+ uint64 flags;
+ uint64 blocks;
+ uint64 bfree;
+ uint64 bavail;
+ uint64 files;
+ uint64 ffree;
+ uint32 block_size;
+ uint64 read;
+ uint64 write;
+ }
+ public void get_fsusage(out FsUsage fs_usage, string mount_dir);
+
+ [CCode(cname = "glibtop_mountentry", cheader_filename = "glibtop/mountlist.h",
destroy_function="g_free")]
+ public struct MountEntry
+ {
+ uint64 dev;
+ char devname[80];
+ char mountdir[80];
+ char type[80];
+ }
+
+ [CCode(cname = "glibtop_mountlist", cheader_filename = "glibtop/mountlist.h")]
+ public struct MountList
+ {
+ uint64 flags;
+ uint64 number;
+ uint64 total;
+ uint64 size;
+ }
+ [CCode(array_length = false)]
+ public MountEntry[] get_mountlist(out MountList mount_list, bool all_fs);
}
diff --git a/src/window.vala b/src/window.vala
index 5a1c125..238e5db 100644
--- a/src/window.vala
+++ b/src/window.vala
@@ -2,8 +2,8 @@ namespace Usage
{
public class Window : Gtk.ApplicationWindow
{
- private Gtk.Stack stack;
private Usage.HeaderBar header_bar;
+ private View[] views;
public Window(Gtk.Application application)
{
@@ -20,13 +20,11 @@ namespace Usage
load_css();
});
- stack = new Gtk.Stack();
+ var stack = new Gtk.Stack();
header_bar = new Usage.HeaderBar(stack);
set_titlebar(header_bar);
- header_bar.show_close_button = true;
-
- var views = new View[]
+ views = new View[]
{
new PerformanceView(),
new DataView(),
@@ -37,9 +35,39 @@ namespace Usage
foreach(var view in views)
stack.add_titled(view, view.name, view.title);
+ stack.notify.connect(() => {
+ if(stack.visible_child_name == views[0].name)
+ {
+ header_bar.set_mode(HeaderBarMode.PERFORMANCE);
+ }
+ else if(stack.visible_child_name == views[1].name)
+ {
+ header_bar.set_mode(HeaderBarMode.DATA);
+ }
+ else if(stack.visible_child_name == views[2].name)
+ {
+ header_bar.set_mode(HeaderBarMode.STORAGE);
+ (GLib.Application.get_default() as
Application).get_storage_analyzer().create_cache.begin();
+ }
+ else if(stack.visible_child_name == views[3].name)
+ {
+ header_bar.set_mode(HeaderBarMode.POWER);
+ }
+ });
+
this.add(stack);
}
+ public Usage.HeaderBar get_header_bar()
+ {
+ return header_bar;
+ }
+
+ public View[] get_views()
+ {
+ return views;
+ }
+
private void load_css()
{
string name_css = "adwaita.css";
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]