├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── AUTHORS ├── LICENSE ├── NEWS ├── README.md ├── build-aux ├── meson │ └── postinstall.sh └── test │ ├── i18n-strings-check.sh │ └── vala-lint.conf ├── data ├── icons │ ├── hicolor │ │ ├── scalable │ │ │ └── apps │ │ │ │ ├── org.gnome.Usage.svg │ │ │ │ └── org.gnome.UsageDevel.svg │ │ └── symbolic │ │ │ └── apps │ │ │ └── org.gnome.Usage-symbolic.svg │ ├── org.gnome.Usage.Source.svg │ ├── scalable │ │ ├── actions │ │ │ ├── android-app-symbolic.svg │ │ │ ├── background-app-ghost-symbolic.svg │ │ │ └── memory-symbolic.svg │ │ └── status │ │ │ ├── info-symbolic.svg │ │ │ └── speedometer-symbolic.svg │ └── waydroid.source.svg ├── meson.build ├── org.gnome.Usage.desktop.in.in ├── org.gnome.Usage.gresource.xml ├── org.gnome.Usage.gschema.xml.in ├── org.gnome.Usage.metainfo.xml.in.in ├── style.css └── ui │ ├── app-dialog.ui │ ├── cpu-view.ui │ ├── memory-speedometer.ui │ ├── memory-view.ui │ ├── network-view.ui │ ├── no-results-found-view.ui │ ├── process-row.ui │ ├── quit-process-dialog.ui │ ├── speedometer.ui │ ├── storage-actionbar.ui │ ├── storage-view-row.ui │ ├── storage-view.ui │ ├── swap-speedometer.ui │ ├── switcher-row.ui │ └── window.ui ├── gnome-usage.doap ├── meson.build ├── meson_options.txt ├── org.gnome.Usage.json ├── po ├── LINGUAS ├── POTFILES.in ├── POTFILES.skip ├── be.po ├── ca.po ├── cs.po ├── da.po ├── de.po ├── el.po ├── en_GB.po ├── es.po ├── eu.po ├── fa.po ├── fi.po ├── fr.po ├── fur.po ├── gl.po ├── he.po ├── hi.po ├── hr.po ├── hu.po ├── id.po ├── it.po ├── ja.po ├── ka.po ├── ko.po ├── meson.build ├── nb.po ├── nl.po ├── oc.po ├── pl.po ├── pt.po ├── pt_BR.po ├── ro.po ├── ru.po ├── sk.po ├── sl.po ├── sr.po ├── sr@latin.po ├── sv.po ├── tr.po ├── uk.po ├── zh_CN.po └── zh_TW.po ├── screenshots ├── screenshot-performance-memory-view.png ├── screenshot-performance-view.png └── screenshot-storage-view.png ├── src ├── app-dialog.vala ├── app-item.vala ├── application.vala ├── background-monitor.vala ├── cpu-graph.vala ├── cpu-monitor.vala ├── cpu-view.vala ├── game-mode.vala ├── gnome-usage.vala ├── graph-box.vala ├── graph.vala ├── memory-graph.vala ├── memory-monitor.vala ├── memory-speedometer.vala ├── memory-view.vala ├── meson.build ├── monitor.vala ├── network │ ├── network-interface-graph.vala │ ├── network-view.vala │ └── vnstat.vala ├── no-results-found-view.vala ├── performance-graph-view.vala ├── process-list-box.vala ├── process-row-item.vala ├── process-user-tag.vala ├── process.vala ├── quit-process-dialog.vala ├── settings.vala ├── speedometer.vala ├── stack-list.vala ├── storage │ ├── query-builder.vala │ ├── sparql-controller.vala │ ├── sparql-worker.vala │ ├── storage-actionbar.vala │ ├── storage-graph.vala │ ├── storage-view-item.vala │ ├── storage-view-row.vala │ └── storage-view.vala ├── swap-speedometer.vala ├── system-monitor.vala ├── utils.vala ├── view.vala └── window.vala └── vapi ├── config.vapi ├── libgtop-2.0.vapi └── stopgap.vapi /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix style 5 | [*] 6 | end_of_line = lf 7 | trim_trailing_whitespace = true 8 | charset = utf-8 9 | 10 | [*.{vala,vapi}] 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [*.ui] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.css] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.xml.in] 23 | indent_style = space 24 | indent_size = 2 25 | 26 | [*.gschema.xml] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.gresource.xml] 31 | indent_style = space 32 | indent_size = 4 33 | 34 | [meson.build] 35 | indent_style = space 36 | indent_size = 2 37 | 38 | [.gitlab-ci.yml] 39 | indent_style = space 40 | indent_size = 2 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .bzrignore 3 | .hgignore 4 | .buildconfig 5 | install 6 | build 7 | .ccls-cache 8 | .gdb_history 9 | compile_commands.json 10 | *~ -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | MESON_BUILD_DIR: _build 3 | FLATPAK_MODULE: gnome-usage 4 | TARBALL_ARTIFACT_PATH: ".flatpak-builder/build/${FLATPAK_MODULE}/_flatpak_build/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz" 5 | 6 | include: 7 | - project: "GNOME/citemplates" 8 | file: "templates/default-rules.yml" 9 | - project: "GNOME/citemplates" 10 | file: "flatpak/flatpak_ci_initiative.yml" 11 | - component: "gitlab.gnome.org/GNOME/citemplates/release-service@master" 12 | inputs: 13 | job-stage: deploy 14 | dist-job-name: flatpak 15 | tarball-artifact-path: ${TARBALL_ARTIFACT_PATH} 16 | 17 | stages: 18 | - lint 19 | - build 20 | - deploy 21 | 22 | i18n: 23 | stage: lint 24 | script: 25 | - ./build-aux/test/i18n-strings-check.sh 26 | 27 | lint: 28 | stage: lint 29 | image: "valalang/lint:latest" 30 | script: 31 | - io.elementary.vala-lint src -c build-aux/test/vala-lint.conf 32 | 33 | alpine: 34 | stage: build 35 | allow_failure: true 36 | before_script: 37 | - apk upgrade -a 38 | - apk add alpine-sdk meson vala libgee-dev gtk4.0-dev libadwaita-dev 39 | libgtop-dev tinysparql-dev networkmanager-dev json-glib-dev 40 | image: alpine:latest 41 | script: 42 | - meson setup ${MESON_BUILD_DIR} 43 | - meson compile -C ${MESON_BUILD_DIR} 44 | 45 | flatpak: 46 | stage: build 47 | extends: '.flatpak' 48 | variables: 49 | MANIFEST_PATH: 'org.gnome.Usage.json' 50 | RUNTIME_REPO: 'https://nightly.gnome.org/gnome-nightly.flatpakrepo' 51 | FLATPAK_MODULE: 'gnome-usage' 52 | BUNDLE: "org.gnome.UsageDevel.flatpak" 53 | APP_ID: 'org.gnome.UsageDevel' 54 | 55 | nightly: 56 | stage: deploy 57 | extends: '.publish_nightly' 58 | dependencies: ['flatpak'] 59 | needs: ['flatpak'] 60 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GNOME/gnome-usage/c3ecf9775157c8144906f93ea97a05ed02fddbd6/.gitmodules -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Petr Štětka 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | A nice way to view information about use of system resources, like memory and disk space. 4 | 5 | ## TODO 6 | - [x] Processor Usage 7 | - [x] Memory usage 8 | - [x] Network usage 9 | - [x] Search in processes 10 | - [ ] UI for file operations errors (as duplicate file, not enough space, permission...) 11 | - [ ] UI for show progress about file operations 12 | - [ ] Notification for file operations with undo action 13 | - [ ] Storage support for more users (multiuser system) 14 | - [ ] Application in storage 15 | - [ ] Power view (Design?) 16 | - [ ] Disk usage (What library we can use?) 17 | - [ ] Data view - 0% 18 | 19 | ## Run 20 | In terminal run ```gnome-usage``` command or run Usage from app launcher. 21 | 22 | ## Dependencies 23 | - libgtop >= 2.34.2 24 | 25 | ## Compilation: 26 | ``` 27 | cd gnome-usage 28 | meson build && cd build 29 | ninja-build #or ninja 30 | sudo ninja-build install #or sudo ninja install 31 | ``` 32 | 33 | ## License 34 | Code is under GNU GPLv3 license. 35 | 36 | ## Screenshots 37 | Screenshots are placed in the screenshots subdirectory (however screenshots may be outdated). 38 | 39 | ![Screenshot](screenshots/screenshot-performance-view.png?raw=true ) 40 | 41 | ![Screenshot](screenshots/screenshot-performance-memory-view.png?raw=true ) 42 | 43 | ![Screenshot](screenshots/screenshot-storage-view.png?raw=true ) 44 | 45 | ## Design 46 | 47 | -------------------------------------------------------------------------------- /build-aux/meson/postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Package managers set this so we don't need to run 4 | if [ -z "$DESTDIR" ] && [ $# -gt 0 ]; then 5 | echo Compiling GSettings schemas... 6 | glib-compile-schemas $1/glib-2.0/schemas 7 | 8 | echo Updating desktop database... 9 | update-desktop-database -q $1/applications 10 | fi 11 | -------------------------------------------------------------------------------- /build-aux/test/i18n-strings-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | srcdirs="src" 4 | uidirs="data/ui" 5 | 6 | # find source files that contain gettext keywords 7 | vala_files="$(grep -lR --include='*.vala' '\(gettext\|[^I_)]_\)(' $srcdirs)" 8 | 9 | # find ui files that contain translatable string 10 | ui_files="$(grep -lRi --include='*.ui' 'translatable="[ty1]' $uidirs)" 11 | 12 | files="$vala_files $ui_files" 13 | 14 | # filter out excluded files 15 | if [ -f po/POTFILES.skip ]; then 16 | files="$(for f in $files; do ! grep -q "^$f$" po/POTFILES.skip && echo "$f"; done)" 17 | fi 18 | 19 | # Test 1: find all files that are missing from POTFILES.in 20 | missing="$(for f in $files; do ! grep -q "^$f$" po/POTFILES.in && echo "$f"; done)" 21 | if [ ${#missing} -ne 0 ]; then 22 | echo >&2 "The following files are missing from po/POTFILES.in:" 23 | for f in ${missing}; do 24 | echo " $f" >&2 25 | done 26 | echo >&2 27 | exit 1 28 | fi 29 | 30 | # Test 2: find all Vala files that miss a corresponding .c file in POTFILES.skip 31 | vala_c_files="$(for f in $vala_files; do echo "${f%.vala}.c"; done)" 32 | vala_c_files_missing="$(for f in ${vala_c_files}; do ! grep -q "^$f$" po/POTFILES.skip && echo "$f"; done)" 33 | if [ ${#vala_c_files_missing} -ne 0 ]; then 34 | echo >&2 "The following files are missing from po/POTFILES.skip:" 35 | for f in ${vala_c_files_missing}; do 36 | echo " $f" >&2 37 | done 38 | echo >&2 39 | exit 1 40 | fi 41 | -------------------------------------------------------------------------------- /build-aux/test/vala-lint.conf: -------------------------------------------------------------------------------- 1 | [Checks] 2 | # using lower-case namspaces 3 | naming-convention=warn 4 | 5 | # to be promoted to errors 6 | no-space=warn 7 | space-before-paren=warn 8 | double-spaces=warn 9 | trailing-newlines=warn 10 | block-opening-brace-space-before=warn 11 | trailing-whitespace=warn 12 | -------------------------------------------------------------------------------- /data/icons/hicolor/scalable/apps/org.gnome.Usage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /data/icons/hicolor/symbolic/apps/org.gnome.Usage-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/android-app-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/background-app-ghost-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/memory-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/status/info-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/status/speedometer-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | schema_conf = configuration_data() 2 | schema_conf.set('app-id', application_id) 3 | configure_file( 4 | input: '@0@.gschema.xml.in'.format(base_id), 5 | output: '@BASENAME@', 6 | configuration: schema_conf, 7 | install: true, 8 | install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas') 9 | ) 10 | 11 | desktop_conf = configuration_data() 12 | desktop_conf.set('icon', application_id) 13 | i18n.merge_file( 14 | type: 'desktop', 15 | input: configure_file( 16 | input: '@0@.desktop.in.in'.format(base_id), 17 | output: '@BASENAME@', 18 | configuration: desktop_conf 19 | ), 20 | output: '@0@.desktop'.format(application_id), 21 | po_dir: po_dir, 22 | install: true, 23 | install_dir: join_paths(get_option('datadir'), 'applications') 24 | ) 25 | 26 | metainfo_conf = configuration_data() 27 | metainfo_conf.set('app-id', application_id) 28 | metainfo = i18n.merge_file( 29 | input: configure_file( 30 | input: '@0@.metainfo.xml.in.in'.format(base_id), 31 | output: '@BASENAME@', 32 | configuration: metainfo_conf 33 | ), 34 | output: '@0@.metainfo.xml'.format(application_id), 35 | po_dir: po_dir, 36 | install: true, 37 | install_dir: join_paths(get_option('datadir'), 'metainfo') 38 | ) 39 | # install metainfo a second time to base_id location to work around 40 | # https://gitlab.gnome.org/GNOME/vala/-/issues/804 TODO: don't 41 | # see data/org.gnome.Usage.gresource.xml, src/application.vala 42 | if application_id != base_id 43 | metainfo = i18n.merge_file( 44 | input: configure_file( 45 | input: '@0@.metainfo.xml.in.in'.format(base_id), 46 | output: '@BASENAME@', 47 | configuration: metainfo_conf 48 | ), 49 | output: '@0@.metainfo.xml'.format(base_id), 50 | po_dir: po_dir, 51 | install: false 52 | ) 53 | endif 54 | 55 | resources_conf = configuration_data() 56 | resources_conf.set('app-id', application_id) 57 | resources_conf.set('base-id', base_id) 58 | resources = gnome.compile_resources( 59 | base_id, 60 | '@0@.gresource.xml'.format(base_id), 61 | c_name: 'resources', 62 | dependencies: [metainfo] 63 | ) 64 | 65 | install_data( 66 | 'icons/hicolor/scalable/apps/@0@.svg'.format(application_id), 67 | install_dir: join_paths(get_option('datadir'), 'icons', 'hicolor', 'scalable', 'apps'), 68 | rename: '@0@.svg'.format(application_id) 69 | ) 70 | -------------------------------------------------------------------------------- /data/org.gnome.Usage.desktop.in.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Usage 3 | Comment=A nice way to view information about use of system resources, like memory and disk space 4 | Categories=GNOME;GTK;System;Monitor; 5 | Exec=gnome-usage 6 | # Translators: Do NOT translate or transliterate this text (this is an icon file name)! 7 | Icon=@icon@ 8 | Terminal=false 9 | StartupNotify=true 10 | Type=Application 11 | # Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! 12 | Keywords=Monitor;System;Process;CPU;Memory;Network;History;Usage;Performance;Task;Manager; 13 | # Translators: Do NOT translate or transliterate this text (these are enum types)! 14 | X-Purism-FormFactor=Workstation;Mobile; 15 | -------------------------------------------------------------------------------- /data/org.gnome.Usage.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icons/scalable/actions/memory-symbolic.svg 5 | icons/scalable/status/speedometer-symbolic.svg 6 | icons/scalable/status/info-symbolic.svg 7 | icons/scalable/actions/background-app-ghost-symbolic.svg 8 | icons/scalable/actions/android-app-symbolic.svg 9 | style.css 10 | ui/app-dialog.ui 11 | ui/cpu-view.ui 12 | ui/memory-speedometer.ui 13 | ui/memory-view.ui 14 | ui/network-view.ui 15 | ui/no-results-found-view.ui 16 | ui/quit-process-dialog.ui 17 | ui/speedometer.ui 18 | ui/storage-actionbar.ui 19 | ui/storage-view.ui 20 | ui/storage-view-row.ui 21 | ui/switcher-row.ui 22 | ui/process-row.ui 23 | ui/swap-speedometer.ui 24 | ui/window.ui 25 | org.gnome.Usage.metainfo.xml 26 | 27 | 28 | -------------------------------------------------------------------------------- /data/org.gnome.Usage.gschema.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ['gnome-shell', 'gdm-x-session', 'gdm-wayland-session', 'gdm', 'systemd', 'gdm-session-worker', 'pulseaudio', 'pipewire-pulse', 'Xorg', 'system'] 5 | A list of processes which we don’t want killed 6 | This list is used for filtering which processes the user can’t stop. 7 | 8 | 9 | 45000 10 | time span (ms) of the graphs in the performance tab 11 | 12 | The time span for up to which the CPU and memory graphs in the 13 | performance tab and its sidebar go back in time in milliseconds. 14 | 15 | 16 | 17 | 2500 18 | interval (ms) for the performance data refresh 19 | 20 | The interval at which the data for the performance tab are updated 21 | and displayed periodically in milliseconds. 22 | 23 | 24 | 25 | 0 26 | minimum relative load of an app to be displayed in the performance tab 27 | 28 | The load an app has to have in total as the sum over all its 29 | processes, normalized to 1.00, to be listed in the performance 30 | tab. With 0.00, all apps are listed. With 1.00 an app is only 31 | listed if its processes fully utilise all CPU threads. 32 | 33 | 34 | 35 | 0 36 | minimum memory footprint of an app to be displayed in the performance tab 37 | 38 | The minimum amount of memory an app has to use in total as the sum 39 | over all its processes in bytes to be listed in the performance 40 | tab. 41 | 42 | 43 | 44 | true 45 | Force graphs to not continuously scrolling 46 | 47 | If enabled, the performance graphs will be forced to not scroll 48 | continuously, but instead will only jump when a new data point is 49 | added. 50 | If disabled, the graphs will decide, based on power-saving mode 51 | and GTK's global animations settings, how to behave. 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /data/org.gnome.Usage.metainfo.xml.in.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | CC0-1.0 4 | camelcasenick@bewares.it 5 | 6 | @app-id@ 7 | @app-id@.desktop 8 | GPL-3.0-or-later 9 | 10 | https://gitlab.gnome.org/GNOME/gnome-usage/issues 11 | https://gitlab.gnome.org/GNOME/gnome-usage 12 | https://liberapay.com/camelCaseNick/ 13 | 14 | https://l10n.gnome.org/module/gnome-usage/ 15 | gnome-usage 16 | 17 | Usage 18 | Usage developers 19 | 20 | Usage developers 21 | 22 | Analyse your system 23 | 24 |

25 | Usage helps with simple to understand ways to analyze how the system uses 26 | its resources. 27 |

28 |
    29 |
  • 30 | Easy access to which app uses what amount of processing power or memory, 31 | helps find performance issues. 32 |
  • 33 |
  • 34 | The storage view provides insight to simplify cleaning up unnecessary 35 | leftover files. 36 |
  • 37 |
38 |
39 | 40 | 41 | https://gitlab.gnome.org/GNOME/gnome-usage/raw/main/screenshots/screenshot-performance-view.png 42 | See where the processing power is going 43 | 44 | 45 | https://gitlab.gnome.org/GNOME/gnome-usage/raw/main/screenshots/screenshot-performance-memory-view.png 46 | Understand which application is using up the memory 47 | 48 | 49 | https://gitlab.gnome.org/GNOME/gnome-usage/raw/main/screenshots/screenshot-storage-view.png 50 | Find what fills the storage 51 | 52 | 53 | 54 | 55 | keyboard 56 | pointing 57 | touch 58 | 59 | 60 | 360 61 | 360 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |

A few have been identified and fixed, for example

70 |
    71 |
  • some applications were not correctly identified if they provide background services,
  • 72 |
  • some users experienced a missing app icon for Usage, and
  • 73 |
  • stopping an app used to regularly result in Usage crashing.
  • 74 |
75 |
76 |
77 | 78 | 79 |

The new release alongside GNOME 46 is out and now Usage

80 |
    81 |
  • is displaying individual Waydroid applications,
  • 82 |
  • is highlighting applications running in background,
  • 83 |
  • has split the CPU and memory views for a new look and feel, and
  • 84 |
  • has an improved performance of the CPU and memory views.
  • 85 |
86 |
87 |
88 | 89 | 90 |

Usage 45.1 contains a few bug fixes.

91 |
    92 |
  • It avoids glitches in graphs on systems with no swap,
  • 93 |
  • has better keyboard navigation in the storage view, and
  • 94 |
  • more often correctly classifies applications.
  • 95 |
96 |
97 |
98 | 99 | 100 |

Usage 45 is out with

101 |
    102 |
  • the new look and feel of modern Adwaita on GNOME
  • 103 |
  • improved graphs that now just update every two seconds with a measurement for performance
  • 104 |
  • more reliable application classifications due to fixed bugs
  • 105 |
  • scaling the CPU usage with its amount of threads, so that 100 % now means all cores are in use
  • 106 |
107 |
108 |
109 | 110 | 111 |

3.32.0 is the latest stable release of GNOME Usage.

112 |
113 |
114 |
115 |
116 | -------------------------------------------------------------------------------- /data/style.css: -------------------------------------------------------------------------------- 1 | graph-box:not(.card) { 2 | border: 1px solid @borders; 3 | border-radius: 6px; 4 | } 5 | 6 | listview row { 7 | font-feature-settings: "tnum"; 8 | } 9 | 10 | listview.switcher-sidebar > row { 11 | padding: 8px; 12 | } 13 | 14 | /* ListView is not supported by .boxed-list, this is needed for using .card */ 15 | listview.card > row:first-child { 16 | border-top-left-radius: 12px; 17 | border-top-right-radius: 12px; 18 | } 19 | 20 | listview.card > row:last-child { 21 | border-bottom-left-radius: 12px; 22 | border-bottom-right-radius: 12px; 23 | } 24 | 25 | rg-graph.big { 26 | background-size: 57px 57px; 27 | background-image: repeating-linear-gradient(0deg, @borders, @borders 1px, transparent 1px, transparent 57px); 28 | } 29 | 30 | StorageGraph { 31 | color: @view_bg_color; 32 | } 33 | 34 | /* Speedometer */ 35 | Speedometer { 36 | font-feature-settings: "tnum"; 37 | } 38 | 39 | .speedometer-outter, .speedometer-inner, .speedometer-content-area { 40 | border-radius: 50%; 41 | } 42 | 43 | .speedometer-outter { 44 | background-color: @accent_bg_color; 45 | } 46 | 47 | .speedometer-inner { 48 | margin: -1px; 49 | background: linear-gradient(90deg, transparent 50%, @view_bg_color 50%), 50 | linear-gradient(90deg, @view_bg_color 50%, transparent 50%); 51 | transition: background 200ms ease-in-out; 52 | } 53 | 54 | .speedometer-content-area { 55 | background-color: @window_bg_color; 56 | margin: 5px; 57 | } 58 | 59 | .tag { 60 | border-style: none; 61 | border-radius: 3px; 62 | padding: 3px 6px; 63 | color: @view_bg_color; 64 | } 65 | 66 | .tag.tag-root { 67 | background-color: red; 68 | } 69 | 70 | .tag.tag-system { 71 | background-color: orange; 72 | } 73 | 74 | .tag.tag-user { 75 | background: alpha(@window_fg_color, 0.4); 76 | } 77 | 78 | /* Storage */ 79 | .row-tag { 80 | border-radius: 100%; 81 | background-color: var(--storage-row-colour); 82 | } 83 | 84 | .used-tag { 85 | background-image: 86 | linear-gradient(90deg, 87 | #737373 33%, 88 | #ffe451 33%, 89 | #ffe451 66%, 90 | #ff002c 66%); 91 | } 92 | 93 | .available-tag { background: white; border: 1px solid @borders; } 94 | .os-tag { background: black; } 95 | 96 | .storage-row { 97 | padding: 0 5px; 98 | font-feature-settings: "tnum"; 99 | --storage-row-colour: var(--accent-color); 100 | } 101 | -------------------------------------------------------------------------------- /data/ui/cpu-view.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 32 | -------------------------------------------------------------------------------- /data/ui/memory-speedometer.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 86 | 87 | 88 | horizontal 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /data/ui/memory-view.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 32 | -------------------------------------------------------------------------------- /data/ui/network-view.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 59 | 60 | -------------------------------------------------------------------------------- /data/ui/no-results-found-view.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 49 | 50 | -------------------------------------------------------------------------------- /data/ui/process-row.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 116 | 117 | -------------------------------------------------------------------------------- /data/ui/quit-process-dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /data/ui/speedometer.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 36 | 37 | -------------------------------------------------------------------------------- /data/ui/storage-actionbar.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | -------------------------------------------------------------------------------- /data/ui/storage-view-row.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 58 | 59 | -------------------------------------------------------------------------------- /data/ui/storage-view.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 114 | 115 | -------------------------------------------------------------------------------- /data/ui/swap-speedometer.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 84 | 85 | 86 | horizontal 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /data/ui/switcher-row.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 37 | 38 | -------------------------------------------------------------------------------- /gnome-usage.doap: -------------------------------------------------------------------------------- 1 | 2 | 7 | Usage 8 | View system usage information 9 | A nice way to view information about use of system resources, like memory and disk space. 10 | Vala 11 | 12 | 13 | 14 | 15 | Markus Göllnitz 16 | 17 | mgoellnitz 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'gnome-usage', ['vala', 'c'], 3 | version: '48.rc', 4 | license: 'GPL3', 5 | meson_version: '>= 0.50.0' 6 | ) 7 | 8 | cc = meson.get_compiler('c') 9 | valac = meson.get_compiler('vala') 10 | 11 | # Development versions of Usage might use features from pre-release 12 | # versions of its dependencies if their release schedules align, 13 | # esp. when following GNOME's. 14 | if get_option('profile') == 'development' 15 | add_project_arguments( 16 | '--disable-since-check', 17 | language: 'vala' 18 | ) 19 | endif 20 | 21 | gee_dep = dependency('gee-0.8') 22 | glib_dep = dependency('glib-2.0', version : '>=2.38') 23 | gobject_dep = dependency('gobject-2.0') 24 | gio_dep = dependency('gio-2.0', version : '>=2.74') 25 | gio_unix_dep = dependency('gio-unix-2.0') 26 | gtk_dep = dependency('gtk4', version : '>=4.11.3') 27 | json_dep = dependency('json-glib-1.0') 28 | libgtop_dep = dependency('libgtop-2.0', version : '>= 2.34.0') 29 | libnm_dep = dependency('libnm', version : '>= 1.44.0') 30 | libadwaita_dep = dependency('libadwaita-1', version : '>=1.6') 31 | tinysparql_dep = dependency('tinysparql-3.0') 32 | 33 | gnome = import('gnome') 34 | i18n = import('i18n') 35 | 36 | po_dir = join_paths(meson.source_root(), 'po') 37 | vapi_dir = join_paths (meson.source_root (), 'vapi') 38 | 39 | vapi_dirs = [ '--vapidir=@0@'.format(vapi_dir) ] 40 | 41 | base_id = 'org.gnome.Usage' 42 | resource_path = '/org/gnome/Usage/' 43 | 44 | if get_option('profile') == 'development' 45 | profile = 'Devel' 46 | version_suffix = '-devel' 47 | vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD', check: false).stdout().strip() 48 | if vcs_tag != '' 49 | version_suffix = '-@0@'.format(vcs_tag) 50 | endif 51 | else 52 | profile = '' 53 | version_suffix = '' 54 | endif 55 | 56 | if profile != '' 57 | application_id = '@0@@1@'.format(base_id, profile) 58 | else 59 | application_id = base_id 60 | endif 61 | 62 | subdir('data') 63 | subdir('po') 64 | subdir('src') 65 | 66 | meson.add_install_script( 67 | join_paths('build-aux', 'meson', 'postinstall.sh'), 68 | join_paths(get_option('prefix'), get_option('datadir')) 69 | ) 70 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'profile', 3 | type: 'combo', 4 | choices: [ 5 | 'default', 6 | 'development' 7 | ], 8 | value: 'default', 9 | description: 'The build profile for Usage. One of "default" or "development".' 10 | ) 11 | 12 | -------------------------------------------------------------------------------- /org.gnome.Usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id": "org.gnome.UsageDevel", 3 | "runtime": "org.gnome.Sdk", 4 | "runtime-version": "master", 5 | "sdk": "org.gnome.Sdk", 6 | "sdk-extensions": [ 7 | "org.freedesktop.Sdk.Extension.vala-nightly" 8 | ], 9 | "command": "gnome-usage", 10 | "tags": ["devel"], 11 | "finish-args": [ 12 | "--share=ipc", "--device=dri", "--socket=fallback-x11", 13 | "--socket=wayland", 14 | "--share=network", 15 | "--system-talk-name=org.freedesktop.NetworkManager.*", 16 | "--add-policy=Tracker3.dbus:org.freedesktop.LocalSearch3=tracker:FileSystem", 17 | "--filesystem=xdg-documents", "--filesystem=xdg-download", "--filesystem=xdg-music", "--filesystem=xdg-pictures", "--filesystem=xdg-videos", 18 | "--filesystem=/var/lib/vnstat/vnstat.db", 19 | "--filesystem=xdg-run/dconf", "--filesystem=~/.config/dconf:ro", 20 | "--talk-name=ca.desrt.dconf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf", 21 | "--talk-name=org.freedesktop.background.Monitor", 22 | "--env=G_MESSAGES_DEBUG=gnome-usage" 23 | ], 24 | "cleanup": ["/include", "/lib/pkgconfig", 25 | "/share/pkgconfig", "/share/aclocal", 26 | "/man", "/share/man", "/share/gtk-doc", 27 | "/share/vala", 28 | "*.la", "*.a"], 29 | "modules": [ 30 | { 31 | "name": "libgtop-2.0", 32 | "sources": [ 33 | { 34 | "type": "git", 35 | "url": "https://gitlab.gnome.org/gnome/libgtop" 36 | } 37 | ] 38 | }, 39 | { 40 | "name": "vnstat", 41 | "buildsystem": "autotools", 42 | "sources": [ 43 | { 44 | "type": "git", 45 | "url": "https://github.com/vergoh/vnstat" 46 | } 47 | ] 48 | }, 49 | { 50 | "name" : "NetworkManager", 51 | "buildsystem" : "meson", 52 | "build-options" : { 53 | "cflags" : "-ltinfo", 54 | "cxxflags" : "-ltinfo", 55 | "append-path": "/usr/lib/sdk/vala-nightly/bin", 56 | "append-ld-library-path": "/usr/lib/sdk/vala-nightly/lib", 57 | "env": { 58 | "ACLOCAL_PATH": "/usr/lib/sdk/vala-nightly/share/aclocal" 59 | } 60 | }, 61 | "config-opts" : [ 62 | "-Dlibaudit=no", 63 | "-Ddbus_conf_dir=/app/etc/dbus-1/system.d", 64 | "-Ddnsmasq=/usr/bin/true", 65 | "-Ddocs=false", 66 | "-Dintrospection=true", 67 | "-Diptables=/usr/bin/true", 68 | "-Dlibpsl=false", 69 | "-Dmodem_manager=false", 70 | "-Dnmtui=false", 71 | "-Dnm_cloud_setup=false", 72 | "-Dovs=false", 73 | "-Dppp=false", 74 | "-Dqt=false", 75 | "-Dselinux=false", 76 | "-Dsession_tracking=no", 77 | "-Dsystemdsystemunitdir=/app/lib/systemd/system", 78 | "-Dudev_dir=/app/lib/udev", 79 | "-Dsystemd_journal=false", 80 | "-Dtests=no", 81 | "-Dvapi=true" 82 | ], 83 | "sources" : [ 84 | { 85 | "type" : "git", 86 | "branch": "main", 87 | "url" : "https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git" 88 | } 89 | ], 90 | "modules": [ 91 | { 92 | "name" : "libndp", 93 | "buildsystem" : "autotools", 94 | "sources" : [ 95 | { 96 | "type" : "archive", 97 | "url" : "http://libndp.org/files/libndp-1.6.tar.gz", 98 | "sha256" : "0c7dfa84e013bd5e569ef2c6292a6f72cfaf14f4ff77a77425e52edc33ffac0e" 99 | } 100 | ] 101 | } 102 | ] 103 | }, 104 | { 105 | "name": "gee-0.8", 106 | "buildsystem": "autotools", 107 | "build-options" : { 108 | "append-path": "/usr/lib/sdk/vala-nightly/bin", 109 | "append-ld-library-path": "/usr/lib/sdk/vala-nightly/lib", 110 | "env": { 111 | "ACLOCAL_PATH": "/usr/lib/sdk/vala-nightly/share/aclocal" 112 | } 113 | }, 114 | "sources": [ 115 | { 116 | "type": "git", 117 | "url": "https://gitlab.gnome.org/GNOME/libgee", 118 | "branch": "main" 119 | } 120 | ] 121 | }, 122 | { 123 | "name": "json-glib", 124 | "buildsystem": "meson", 125 | "sources": [ 126 | { 127 | "type": "git", 128 | "url": "https://gitlab.gnome.org/GNOME/json-glib", 129 | "branch": "master" 130 | } 131 | ] 132 | }, 133 | { 134 | "buildsystem": "meson", 135 | "config-opts": [ 136 | "-Dprofile=development" 137 | ], 138 | "build-options" : { 139 | "append-path": "/usr/lib/sdk/vala-nightly/bin", 140 | "append-ld-library-path": "/usr/lib/sdk/vala-nightly/lib" 141 | }, 142 | "name": "gnome-usage", 143 | "sources": [ 144 | { 145 | "type": "git", 146 | "url": "https://gitlab.gnome.org/gnome/gnome-usage" 147 | } 148 | ] 149 | } 150 | ] 151 | } 152 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | # Please keep this list sorted alphabetically 2 | be 3 | ca 4 | cs 5 | da 6 | de 7 | el 8 | en_GB 9 | es 10 | eu 11 | fa 12 | fi 13 | fr 14 | fur 15 | gl 16 | he 17 | hi 18 | hr 19 | hu 20 | id 21 | it 22 | ja 23 | ka 24 | ko 25 | nb 26 | nl 27 | oc 28 | pl 29 | pt 30 | pt_BR 31 | ro 32 | ru 33 | sk 34 | sl 35 | sr 36 | sr@latin 37 | sv 38 | tr 39 | uk 40 | zh_CN 41 | zh_TW 42 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | # List of source files containing translatable strings. 2 | # Please keep this file sorted alphabetically. 3 | data/org.gnome.Usage.desktop.in.in 4 | data/org.gnome.Usage.metainfo.xml.in.in 5 | data/org.gnome.Usage.gschema.xml.in 6 | data/ui/app-dialog.ui 7 | data/ui/memory-speedometer.ui 8 | data/ui/network-view.ui 9 | data/ui/no-results-found-view.ui 10 | data/ui/process-row.ui 11 | data/ui/quit-process-dialog.ui 12 | data/ui/storage-actionbar.ui 13 | data/ui/storage-view.ui 14 | data/ui/swap-speedometer.ui 15 | data/ui/window.ui 16 | src/app-dialog.vala 17 | src/app-item.vala 18 | src/application.vala 19 | src/cpu-view.vala 20 | src/memory-view.vala 21 | src/network/network-interface-graph.vala 22 | src/network/network-view.vala 23 | src/storage/storage-actionbar.vala 24 | src/storage/storage-view.vala 25 | src/utils.vala 26 | src/window.vala 27 | -------------------------------------------------------------------------------- /po/POTFILES.skip: -------------------------------------------------------------------------------- 1 | # List of source files that should *not* be translated. 2 | # Please keep this file sorted alphabetically. 3 | src/app-dialog.c 4 | src/app-item.c 5 | src/application.c 6 | src/cpu-view.c 7 | src/memory-view.c 8 | src/network/network-interface-graph.c 9 | src/network/network-view.c 10 | src/performance-view.c 11 | src/storage/storage-actionbar.c 12 | src/storage/storage-view.c 13 | src/utils.c 14 | src/window.c 15 | subprojects/libhandy 16 | -------------------------------------------------------------------------------- /po/it.po: -------------------------------------------------------------------------------- 1 | # Italian translation for gnome-usage. 2 | # Copyright (C) 2018-2019 gnome-usage's COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the gnome-usage package. 4 | # Gianvito Cavasoli , 2018-2019. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: gnome-usage master\n" 9 | "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-usage/issues\n" 10 | "POT-Creation-Date: 2019-09-09 06:48+0000\n" 11 | "PO-Revision-Date: 2019-09-09 12:36+0200\n" 12 | "Last-Translator: Gianvito Cavasoli \n" 13 | "Language-Team: Italiano \n" 14 | "Language: it\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | "X-Generator: Gtranslator 3.32.1\n" 20 | 21 | #: data/org.gnome.Usage.appdata.xml.in:5 22 | msgid "GNOME Usage" 23 | msgstr "GNOME Usage" 24 | 25 | #: data/org.gnome.Usage.appdata.xml.in:6 26 | msgid "A nice way to view information about use of system resources" 27 | msgstr "" 28 | "Un buon modo per visualizzare informazioni sull'uso delle risorse di sistema" 29 | 30 | #: data/org.gnome.Usage.appdata.xml.in:8 31 | msgid "" 32 | "A simple GNOME 3 application to monitor and analyze system resources such as " 33 | "processing, memory, and storage." 34 | msgstr "" 35 | "Una semplice applicazione di GNOME 3 per monitorare e analizzare le risorse " 36 | "di sistema come l'elaborazione, la memoria e l'archiviazione." 37 | 38 | #: data/org.gnome.Usage.desktop.in:3 src/application.vala:79 src/window.vala:41 39 | msgid "Usage" 40 | msgstr "Utilizzo" 41 | 42 | #: data/org.gnome.Usage.desktop.in:4 43 | msgid "" 44 | "A nice way to view information about use of system resources, like memory " 45 | "and disk space" 46 | msgstr "" 47 | "Un buon modo per visualizzare informazioni sull'uso delle risorse di " 48 | "sistema, come la memoria e lo spazio su disco" 49 | 50 | #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! 51 | #: data/org.gnome.Usage.desktop.in:13 52 | msgid "" 53 | "Monitor;System;Process;CPU;Memory;Network;History;Usage;Performance;Task;" 54 | "Manager;" 55 | msgstr "" 56 | "Monitor;Sistema;Processo;CPU;Processore;Memoria;Rete;Cronologia;Utilizzo;Uso;" 57 | "Performance;Prestazione;Attività;Gestione;" 58 | 59 | #: data/org.gnome.Usage.gschema.xml:5 60 | msgid "A list of processes which we don’t want killed" 61 | msgstr "Un elenco di processi che non devono essere uccisi" 62 | 63 | #: data/org.gnome.Usage.gschema.xml:6 64 | msgid "This list is used for filtering which processes the user can’t stop." 65 | msgstr "" 66 | "Questo elenco è usato per filtrare quali processi l'utente non può terminare." 67 | 68 | #: data/ui/memory-speedometer.ui:38 69 | msgid "RAM" 70 | msgstr "RAM" 71 | 72 | #: data/ui/memory-speedometer.ui:53 data/ui/storage-view.ui:46 73 | #: data/ui/swap-speedometer.ui:51 74 | msgid "Used" 75 | msgstr "Usata" 76 | 77 | #: data/ui/memory-speedometer.ui:77 data/ui/storage-view.ui:53 78 | #: data/ui/swap-speedometer.ui:75 79 | msgid "Available" 80 | msgstr "Disponibile" 81 | 82 | #: data/ui/no-results-found-view.ui:23 83 | msgid "No results found" 84 | msgstr "Nessun risultato trovato" 85 | 86 | #: data/ui/no-results-found-view.ui:32 87 | msgid "Try a different search" 88 | msgstr "Provare una differente ricerca" 89 | 90 | #: data/ui/primary-menu.ui:14 91 | msgid "_About Usage" 92 | msgstr "I_nformazioni su Utilizzo" 93 | 94 | #: data/ui/primary-menu.ui:29 95 | msgid "Group system processes" 96 | msgstr "Processi di sistema di gruppo" 97 | 98 | #: data/ui/primary-menu.ui:37 99 | msgid "Show all processes" 100 | msgstr "Mostra tutti i processi" 101 | 102 | #. Translators: This sentence is later suffixed with an application name. Example: “Force Quit Videos?” 103 | #: data/ui/quit-process-dialog.ui:9 104 | msgid "Force Quit %s?" 105 | msgstr "Uscita forzata di %s?" 106 | 107 | #: data/ui/quit-process-dialog.ui:10 108 | msgid "Unsaved work might be lost." 109 | msgstr "Il lavoro non salvato potrebbe essere perso." 110 | 111 | #: data/ui/quit-process-dialog.ui:16 112 | msgid "Cancel" 113 | msgstr "Annulla" 114 | 115 | #: data/ui/quit-process-dialog.ui:24 116 | msgid "Force Quit" 117 | msgstr "Uscita forzata" 118 | 119 | #: data/ui/storage-actionbar.ui:17 120 | #| msgid "Delete" 121 | msgid "Delete…" 122 | msgstr "Elimina…" 123 | 124 | #: data/ui/storage-view.ui:37 125 | msgid "Home Partition" 126 | msgstr "Partizione home" 127 | 128 | #: data/ui/swap-speedometer.ui:36 129 | msgid "Swap" 130 | msgstr "Swap" 131 | 132 | #: src/app-item.vala:71 133 | msgid "System" 134 | msgstr "Sistema" 135 | 136 | #: src/application.vala:80 137 | msgid "" 138 | "A nice way to view information about use of system resources, like memory " 139 | "and disk space." 140 | msgstr "" 141 | "Un buon modo per visualizzare informazioni sull'uso delle risorse di " 142 | "sistema, come la memoria e lo spazio su disco." 143 | 144 | #: src/application.vala:83 145 | msgid "translator-credits" 146 | msgstr "Gianvito Cavasoli " 147 | 148 | #: src/application.vala:85 149 | msgid "Websites" 150 | msgstr "Siti web" 151 | 152 | #: src/cpu-sub-view.vala:32 src/graph-stack-switcher.vala:45 153 | msgid "Processor" 154 | msgstr "Processore" 155 | 156 | #: src/graph-stack-switcher.vala:46 src/memory-sub-view.vala:32 157 | msgid "Memory" 158 | msgstr "Memoria" 159 | 160 | #: src/performance-view.vala:48 161 | msgid "Performance" 162 | msgstr "Prestazione" 163 | 164 | #: src/storage/storage-actionbar.vala:40 165 | #, c-format 166 | #| msgid "%u selected" 167 | #| msgid_plural "%u selected" 168 | msgid "%s selected" 169 | msgstr "%s selezionato" 170 | 171 | #: src/storage/storage-actionbar.vala:45 172 | #| msgid "Are you sure you want to permanently delete the %d selected item?" 173 | #| msgid_plural "" 174 | #| "Are you sure you want to permanently delete the %d selected items?" 175 | msgid "Are you sure you want to permanently delete selected items?" 176 | msgstr "Eliminare definitivamente gli oggetti selezionati?" 177 | 178 | #: src/storage/storage-actionbar.vala:49 179 | msgid "If you delete these items, they will be permanently lost." 180 | msgstr "Se si eliminano questi oggetti, saranno persi definitivamente?" 181 | 182 | #: src/storage/storage-row-popover.vala:32 183 | msgid "" 184 | "Operating system files are an essential part of your system and cannot be " 185 | "removed." 186 | msgstr "" 187 | "I file del sistema operativo sono una parte essenziale del sistema e non " 188 | "possono essere rimossi." 189 | 190 | #: src/storage/storage-view.vala:78 191 | msgid "Storage" 192 | msgstr "Archiviazione" 193 | 194 | #: src/storage/storage-view.vala:245 195 | msgid "Operating System" 196 | msgstr "Sistema operativo" 197 | 198 | #: src/storage/storage-view.vala:271 199 | msgid "Scanning directories" 200 | msgstr "Scansione directory" 201 | -------------------------------------------------------------------------------- /po/ja.po: -------------------------------------------------------------------------------- 1 | # Japanese translation for gnome-usage. 2 | # Copyright (C) 2020, 2022 gnome-usage's COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the gnome-usage package. 4 | # Ryo Nakano , 2020. 5 | # sicklylife , 2020, 2022. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: gnome-usage master\n" 10 | "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-usage/issues\n" 11 | "POT-Creation-Date: 2021-12-08 11:25+0000\n" 12 | "PO-Revision-Date: 2022-01-16 19:00+0900\n" 13 | "Last-Translator: sicklylife \n" 14 | "Language-Team: Japanese \n" 15 | "Language: ja\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: data/org.gnome.Usage.appdata.xml.in.in:5 22 | msgid "GNOME Usage" 23 | msgstr "GNOME Usage" 24 | 25 | #: data/org.gnome.Usage.appdata.xml.in.in:6 26 | msgid "A nice way to view information about use of system resources" 27 | msgstr "システムリソースの使用情報を表示します" 28 | 29 | #: data/org.gnome.Usage.appdata.xml.in.in:8 30 | msgid "" 31 | "A simple GNOME 3 application to monitor and analyze system resources such as " 32 | "processing, memory, and storage." 33 | msgstr "" 34 | "プロセス、メモリ、ストレージなどのシステムリソースを監視したり分析したりする" 35 | "ための、シンプルな GNOME 3 アプリケーションです。" 36 | 37 | #: data/org.gnome.Usage.desktop.in.in:3 data/ui/window.ui:8 38 | #: data/ui/window.ui:23 src/application.vala:73 39 | msgid "Usage" 40 | msgstr "Usage" 41 | 42 | #: data/org.gnome.Usage.desktop.in.in:4 43 | msgid "" 44 | "A nice way to view information about use of system resources, like memory " 45 | "and disk space" 46 | msgstr "メモリやディスク領域などのシステムリソースの使用情報を表示します" 47 | 48 | #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! 49 | #: data/org.gnome.Usage.desktop.in.in:13 50 | msgid "" 51 | "Monitor;System;Process;CPU;Memory;Network;History;Usage;Performance;Task;" 52 | "Manager;" 53 | msgstr "" 54 | "Monitor;System;Process;CPU;Memory;Network;History;Usage;Performance;Task;" 55 | "Manager;モニター;監視;システム;プロセス;メモリ;RAM;ネットワーク;履歴;使用量;" 56 | "パフォーマンス;タスク;マネージャー;" 57 | 58 | #: data/org.gnome.Usage.gschema.xml.in:5 59 | msgid "A list of processes which we don’t want killed" 60 | msgstr "強制終了しないプロセス一覧" 61 | 62 | #: data/org.gnome.Usage.gschema.xml.in:6 63 | msgid "This list is used for filtering which processes the user can’t stop." 64 | msgstr "" 65 | "この一覧はユーザーが停止できないプロセスをフィルタリングするのに使用します。" 66 | 67 | #: data/ui/memory-speedometer.ui:38 68 | msgid "RAM" 69 | msgstr "RAM" 70 | 71 | #: data/ui/memory-speedometer.ui:53 data/ui/storage-view.ui:51 72 | #: data/ui/swap-speedometer.ui:51 73 | msgid "Used" 74 | msgstr "使用済み" 75 | 76 | #: data/ui/memory-speedometer.ui:77 data/ui/storage-view.ui:58 77 | #: data/ui/swap-speedometer.ui:75 78 | msgid "Available" 79 | msgstr "利用可能" 80 | 81 | #: data/ui/no-results-found-view.ui:23 82 | msgid "No results found" 83 | msgstr "何も見つかりませんでした" 84 | 85 | #: data/ui/no-results-found-view.ui:32 86 | msgid "Try a different search" 87 | msgstr "他のキーワードを試してください" 88 | 89 | #: data/ui/primary-menu.ui:14 90 | msgid "_About Usage" 91 | msgstr "Usage について(_A)" 92 | 93 | #: data/ui/primary-menu.ui:29 94 | msgid "Group system processes" 95 | msgstr "システムプロセスをグループ化" 96 | 97 | #: data/ui/primary-menu.ui:37 98 | msgid "Show all processes" 99 | msgstr "すべてのプロセスを表示" 100 | 101 | #. Translators: This sentence is later suffixed with an application name. Example: “Force Quit Videos?” 102 | #: data/ui/quit-process-dialog.ui:9 103 | msgid "Force Quit %s?" 104 | msgstr "%s を強制終了しますか?" 105 | 106 | #: data/ui/quit-process-dialog.ui:10 107 | msgid "Unsaved work might be lost." 108 | msgstr "未保存の作業は失われます。" 109 | 110 | #: data/ui/quit-process-dialog.ui:16 111 | msgid "Cancel" 112 | msgstr "キャンセル" 113 | 114 | #: data/ui/quit-process-dialog.ui:24 115 | msgid "Force Quit" 116 | msgstr "強制終了" 117 | 118 | #: data/ui/storage-actionbar.ui:17 119 | msgid "Delete…" 120 | msgstr "削除…" 121 | 122 | #: data/ui/storage-view.ui:42 123 | msgid "Home Partition" 124 | msgstr "ホームパーティション" 125 | 126 | #: data/ui/swap-speedometer.ui:36 127 | msgid "Swap" 128 | msgstr "スワップ" 129 | 130 | #: src/app-item.vala:148 131 | msgid "System" 132 | msgstr "システム" 133 | 134 | #: src/application.vala:74 135 | msgid "" 136 | "A nice way to view information about use of system resources, like memory " 137 | "and disk space." 138 | msgstr "メモリやディスク領域などのシステムリソースの使用情報を表示します。" 139 | 140 | #: src/application.vala:77 141 | msgid "translator-credits" 142 | msgstr "" 143 | "Ryo Nakano \n" 144 | "sicklylife " 145 | 146 | #: src/application.vala:79 147 | msgid "Websites" 148 | msgstr "ウェブサイト" 149 | 150 | #: src/cpu-sub-view.vala:29 src/graph-stack-switcher.vala:41 151 | msgid "Processor" 152 | msgstr "プロセッサー" 153 | 154 | #: src/graph-stack-switcher.vala:42 src/memory-sub-view.vala:29 155 | msgid "Memory" 156 | msgstr "メモリ" 157 | 158 | #: src/performance-view.vala:45 159 | msgid "Performance" 160 | msgstr "パフォーマンス" 161 | 162 | #: src/storage/storage-actionbar.vala:38 163 | #, c-format 164 | msgid "%s selected" 165 | msgstr "%s 件選択" 166 | 167 | #: src/storage/storage-actionbar.vala:44 168 | msgid "Are you sure you want to permanently delete selected items?" 169 | msgstr "本当に選択したものを完全に削除しますか?" 170 | 171 | #: src/storage/storage-actionbar.vala:51 172 | msgid "If you delete these items, they will be permanently lost." 173 | msgstr "削除すると元に戻すことはできません。" 174 | 175 | #: src/storage/storage-row-popover.vala:32 176 | msgid "" 177 | "Operating system files are an essential part of your system and cannot be " 178 | "removed." 179 | msgstr "" 180 | "オペレーティングシステムのファイルはシステムに必要なため削除できません。" 181 | 182 | #: src/storage/storage-view.vala:78 183 | msgid "Storage" 184 | msgstr "ストレージ" 185 | 186 | #: src/storage/storage-view.vala:246 187 | msgid "Operating System" 188 | msgstr "オペレーティングシステム" 189 | 190 | #: src/storage/storage-view.vala:272 191 | msgid "Scanning directories" 192 | msgstr "ディレクトリをスキャン中" 193 | 194 | #: src/utils.vala:27 195 | #, c-format 196 | msgid "%llu B" 197 | msgstr "%llu B" 198 | 199 | #: src/utils.vala:32 200 | #, c-format 201 | msgid "%s/s" 202 | msgstr "%s/s" 203 | 204 | #: src/utils.vala:34 205 | #, c-format 206 | msgid "%llu B/s" 207 | msgstr "%llu B/s" 208 | -------------------------------------------------------------------------------- /po/ko.po: -------------------------------------------------------------------------------- 1 | # Korean translation for gnome-usage. 2 | # Copyright (C) 2021 gnome-usage's COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the gnome-usage package. 4 | # Seong-ho Cho , 2021. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: gnome-usage master\n" 9 | "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-usage/issues\n" 10 | "POT-Creation-Date: 2021-09-15 06:17+0000\n" 11 | "PO-Revision-Date: 2021-10-09 23:57+0900\n" 12 | "Language-Team: Korean \n" 13 | "Language: ko\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=1; plural=0;\n" 18 | "Last-Translator: Seong-ho Cho \n" 19 | "X-Generator: Poedit 2.3.1\n" 20 | 21 | #: data/org.gnome.Usage.appdata.xml.in.in:5 22 | msgid "GNOME Usage" 23 | msgstr "그놈 사용 정보" 24 | 25 | #: data/org.gnome.Usage.appdata.xml.in.in:6 26 | msgid "A nice way to view information about use of system resources" 27 | msgstr "시스템 자원 사용 정보를 보는 멋진 수단입니다" 28 | 29 | #: data/org.gnome.Usage.appdata.xml.in.in:8 30 | msgid "" 31 | "A simple GNOME 3 application to monitor and analyze system resources such as " 32 | "processing, memory, and storage." 33 | msgstr "" 34 | "프로세스, 메모리, 저장소 등의 시스템 자원을 감시하고 분석하는 간단한 그놈 3 " 35 | "프로그램입니다." 36 | 37 | #: data/org.gnome.Usage.desktop.in.in:3 data/ui/window.ui:8 38 | #: data/ui/window.ui:23 src/application.vala:85 39 | msgid "Usage" 40 | msgstr "사용 정보" 41 | 42 | #: data/org.gnome.Usage.desktop.in.in:4 43 | msgid "" 44 | "A nice way to view information about use of system resources, like memory " 45 | "and disk space" 46 | msgstr "" 47 | "메모리 및 디스크 공간 같은 시스템 자원의 사용 정보를 보는 멋진 수단입니다" 48 | 49 | #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! 50 | #: data/org.gnome.Usage.desktop.in.in:13 51 | msgid "" 52 | "Monitor;System;Process;CPU;Memory;Network;History;Usage;Performance;Task;" 53 | "Manager;" 54 | msgstr "" 55 | "Monitor;감시;System;시스템;Process;프로세스;CPU;씨피유;시피유;Memory;메모리;" 56 | "RAM;Network;네트워크;History;기록;이력;Usage;사용량;사용;정보;Performance;성" 57 | "능;Task;작업;Manager;관리자;" 58 | 59 | #: data/org.gnome.Usage.gschema.xml.in:5 60 | msgid "A list of processes which we don’t want killed" 61 | msgstr "강제로 끝내고 싶지 않은 프로세스의 목록" 62 | 63 | #: data/org.gnome.Usage.gschema.xml.in:6 64 | msgid "This list is used for filtering which processes the user can’t stop." 65 | msgstr "이 목록은 사용자가 멈출 수 없는 프로세스를 선별해볼 때 활용합니다." 66 | 67 | #: data/ui/memory-speedometer.ui:38 68 | msgid "RAM" 69 | msgstr "RAM" 70 | 71 | #: data/ui/memory-speedometer.ui:53 data/ui/storage-view.ui:51 72 | #: data/ui/swap-speedometer.ui:51 73 | msgid "Used" 74 | msgstr "사용 중" 75 | 76 | #: data/ui/memory-speedometer.ui:77 data/ui/storage-view.ui:58 77 | #: data/ui/swap-speedometer.ui:75 78 | msgid "Available" 79 | msgstr "사용 가능" 80 | 81 | #: data/ui/no-results-found-view.ui:23 82 | msgid "No results found" 83 | msgstr "결과 없음" 84 | 85 | #: data/ui/no-results-found-view.ui:32 86 | msgid "Try a different search" 87 | msgstr "다른 단어로 검색해보십시오" 88 | 89 | #: data/ui/primary-menu.ui:14 90 | msgid "_About Usage" 91 | msgstr "\"사용 정보\" 정보(_A)" 92 | 93 | #: data/ui/primary-menu.ui:29 94 | msgid "Group system processes" 95 | msgstr "시스템 프로세스 모아보기" 96 | 97 | #: data/ui/primary-menu.ui:37 98 | msgid "Show all processes" 99 | msgstr "모든 프로세스 표시" 100 | 101 | #. Translators: This sentence is later suffixed with an application name. Example: “Force Quit Videos?” 102 | #: data/ui/quit-process-dialog.ui:9 103 | msgid "Force Quit %s?" 104 | msgstr "%s 프로그램을 강제로 끝냅니까?" 105 | 106 | #: data/ui/quit-process-dialog.ui:10 107 | msgid "Unsaved work might be lost." 108 | msgstr "저장하지 않은 자료는 잃을 수 있습니다." 109 | 110 | #: data/ui/quit-process-dialog.ui:16 111 | msgid "Cancel" 112 | msgstr "취소" 113 | 114 | #: data/ui/quit-process-dialog.ui:24 115 | msgid "Force Quit" 116 | msgstr "강제로 끝내기" 117 | 118 | #: data/ui/storage-actionbar.ui:17 119 | msgid "Delete…" 120 | msgstr "삭제…" 121 | 122 | #: data/ui/storage-view.ui:42 123 | msgid "Home Partition" 124 | msgstr "기본 분할 영역" 125 | 126 | #: data/ui/swap-speedometer.ui:36 127 | msgid "Swap" 128 | msgstr "스왑" 129 | 130 | #: src/app-item.vala:155 131 | msgid "System" 132 | msgstr "시스템" 133 | 134 | #: src/application.vala:86 135 | msgid "" 136 | "A nice way to view information about use of system resources, like memory " 137 | "and disk space." 138 | msgstr "" 139 | "메모리 및 디스크 공간 같은 시스템 자원의 사용 정보를 보는 멋진 수단입니다." 140 | 141 | #: src/application.vala:89 142 | msgid "translator-credits" 143 | msgstr "조성호 , 2021" 144 | 145 | #: src/application.vala:91 146 | msgid "Websites" 147 | msgstr "웹사이트" 148 | 149 | #: src/cpu-sub-view.vala:32 src/graph-stack-switcher.vala:45 150 | msgid "Processor" 151 | msgstr "프로세서" 152 | 153 | #: src/graph-stack-switcher.vala:46 src/memory-sub-view.vala:32 154 | msgid "Memory" 155 | msgstr "메모리" 156 | 157 | #: src/performance-view.vala:48 158 | msgid "Performance" 159 | msgstr "성능" 160 | 161 | #: src/storage/storage-actionbar.vala:40 162 | #, c-format 163 | msgid "%s selected" 164 | msgstr "%s 선택함" 165 | 166 | #: src/storage/storage-actionbar.vala:45 167 | msgid "Are you sure you want to permanently delete selected items?" 168 | msgstr "선택한 항목을 정말로 완전히 삭제하시겠습니까?" 169 | 170 | #: src/storage/storage-actionbar.vala:49 171 | msgid "If you delete these items, they will be permanently lost." 172 | msgstr "이 항목을 삭제하면 완전히 잃게 됩니다." 173 | 174 | #: src/storage/storage-row-popover.vala:32 175 | msgid "" 176 | "Operating system files are an essential part of your system and cannot be " 177 | "removed." 178 | msgstr "운영체제 파일은 시스템의 중요한 부분이며 제거할 수 없습니다." 179 | 180 | #: src/storage/storage-view.vala:78 181 | msgid "Storage" 182 | msgstr "저장장치" 183 | 184 | #: src/storage/storage-view.vala:246 185 | msgid "Operating System" 186 | msgstr "운영체제" 187 | 188 | #: src/storage/storage-view.vala:272 189 | msgid "Scanning directories" 190 | msgstr "디렉터리 탐색 중" 191 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext(meson.project_name(), preset: 'glib') 2 | -------------------------------------------------------------------------------- /screenshots/screenshot-performance-memory-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GNOME/gnome-usage/c3ecf9775157c8144906f93ea97a05ed02fddbd6/screenshots/screenshot-performance-memory-view.png -------------------------------------------------------------------------------- /screenshots/screenshot-performance-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GNOME/gnome-usage/c3ecf9775157c8144906f93ea97a05ed02fddbd6/screenshots/screenshot-performance-view.png -------------------------------------------------------------------------------- /screenshots/screenshot-storage-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GNOME/gnome-usage/c3ecf9775157c8144906f93ea97a05ed02fddbd6/screenshots/screenshot-storage-view.png -------------------------------------------------------------------------------- /src/app-dialog.vala: -------------------------------------------------------------------------------- 1 | /* app-dialog.vala 2 | * 3 | * Copyright (C) 2024 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | public class Usage.AppDialogProperty : Object { 22 | public string name { get; set; } 23 | public string @value { get; set; } 24 | } 25 | 26 | public class Usage.AppDialogProperties : Object, ListModel { 27 | private ListStore model = new ListStore (typeof (AppDialogProperty)); 28 | 29 | public AppDialogProperties (AppDialogProperty[]? properties = null) { 30 | foreach (AppDialogProperty property in properties) { 31 | this.model.append ((Object) property); 32 | } 33 | this.model.items_changed.connect (this.items_changed); 34 | } 35 | 36 | public void append (AppDialogProperty property) { 37 | this.model.append (property); 38 | } 39 | 40 | public Object? get_item (uint position) { 41 | return model.get_item (position); 42 | } 43 | 44 | public Type get_item_type () { 45 | return model.get_item_type (); 46 | } 47 | 48 | public uint get_n_items () { 49 | return model.get_n_items (); 50 | } 51 | } 52 | 53 | [GtkTemplate (ui = "/org/gnome/Usage/ui/app-dialog.ui")] 54 | public class Usage.AppDialog : Adw.Dialog { 55 | private AppItem app; 56 | 57 | [GtkChild] 58 | private unowned Gtk.Image icon; 59 | 60 | [GtkChild] 61 | private unowned Gtk.Label app_title; 62 | 63 | [GtkChild] 64 | private unowned Gtk.Label app_user; 65 | 66 | [GtkChild] 67 | private unowned Gtk.Box in_background_info; 68 | 69 | [GtkChild] 70 | private unowned Gtk.ListView simple_properties; 71 | 72 | [GtkChild] 73 | private unowned Gtk.Button quit_button; 74 | 75 | [GtkChild] 76 | private unowned Gtk.Button force_quit_button; 77 | 78 | static construct { 79 | add_binding_action (Gdk.Key.Escape, 0, "window.close", null); 80 | } 81 | 82 | public AppDialog (AppItem app) { 83 | this.app = app; 84 | 85 | this.app.bind_property ("display_name", this, "title", BindingFlags.SYNC_CREATE); 86 | this.app.bind_property ("display_name", this.app_title, "label", BindingFlags.SYNC_CREATE); 87 | this.app_user.label = this.app.user?.RealName ?? ""; 88 | this.app.bind_property ("is_background", this.in_background_info, "visible", BindingFlags.SYNC_CREATE); 89 | this.app.bind_property ("icon", this.icon, "gicon", BindingFlags.SYNC_CREATE); 90 | this.quit_button.sensitive = this.app.is_killable (); 91 | 92 | AppDialogProperty cpu_property = new AppDialogProperty () { 93 | name = _("CPU"), 94 | @value = "%.1f %%".printf (this.app.cpu_load * 100), 95 | }; 96 | this.app.notify["cpu-load"].connect (() => { 97 | cpu_property.@value = "%.1f %%".printf (this.app.cpu_load * 100); 98 | cpu_property.notify_property ("value"); 99 | }); 100 | AppDialogProperty memory_property = new AppDialogProperty () { 101 | name = _("Memory"), 102 | @value = Utils.format_size_values (this.app.mem_usage), 103 | }; 104 | this.app.notify["mem-usage"].connect (() => { 105 | memory_property.@value = Utils.format_size_values (this.app.mem_usage); 106 | memory_property.notify_property ("value"); 107 | }); 108 | 109 | this.simple_properties.model = new Gtk.NoSelection (new AppDialogProperties ({ 110 | cpu_property, 111 | memory_property, 112 | })); 113 | } 114 | 115 | [GtkCallback] 116 | public void quit_clicked (Gtk.Button quit_button) { 117 | if (this.app.is_killable ()) { 118 | QuitProcessDialog dialog = new QuitProcessDialog (app); 119 | dialog.present ((Gtk.Window) this.get_root ()); 120 | 121 | dialog.response.connect ((dialog, response_type) => { 122 | if (response_type == "quit") { 123 | this.quit_button.sensitive = false; 124 | this.quit_button.set_child (new Adw.Spinner ()); 125 | 126 | this.app.notify["running"].connect (() => { 127 | if (!this.app.is_running ()) { 128 | this.close (); 129 | } 130 | }); 131 | Timeout.add (2 * Settings.get_default ().data_update_interval, () => { 132 | this.quit_button.visible = false; 133 | this.force_quit_button.visible = true; 134 | return false; 135 | }); 136 | } 137 | }); 138 | } 139 | } 140 | 141 | [GtkCallback] 142 | public void force_quit_clicked (Gtk.Button quit_button) { 143 | if (this.app.is_running () && this.app.is_killable ()) { 144 | this.app.kill (Posix.Signal.KILL); 145 | } 146 | this.close (); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/application.vala: -------------------------------------------------------------------------------- 1 | /* application.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Petr Štětka 19 | */ 20 | 21 | using Gtk; 22 | 23 | public class Usage.Application : Adw.Application { 24 | private Window window; 25 | 26 | private const GLib.ActionEntry app_entries[] = { 27 | { "about", on_about }, 28 | { "search", on_search }, 29 | { "quit", on_quit }, 30 | { "filter-processes", on_activate_radio, "s", "'group-system'", change_filter_processes_state } 31 | }; 32 | 33 | public Application () { 34 | Object (application_id: Config.APPLICATION_ID, flags: ApplicationFlags.DEFAULT_FLAGS, resource_base_path: Config.APPLICATION_RESOURCE_PATH); 35 | } 36 | 37 | public Window? get_window () { 38 | return window; 39 | } 40 | 41 | public override void activate () { 42 | if (window == null) 43 | window = new Window (this); 44 | 45 | window.present (); 46 | } 47 | 48 | protected override void startup () { 49 | base.startup (); 50 | 51 | add_action_entries (app_entries, this); 52 | set_accels_for_action ("app.search", {"f"}); 53 | set_accels_for_action ("app.quit", {"q"}); 54 | Gtk.Window.set_default_icon_name ("org.gnome.Usage"); 55 | } 56 | 57 | private void on_about (GLib.SimpleAction action, GLib.Variant? parameter) { 58 | string[] authors = { 59 | "Petr Štětka ", 60 | "Markus Göllnitz " 61 | }; 62 | string[] artists = { 63 | "Allan Day ", 64 | "Jon McCann ", 65 | "Jakub Steiner " 66 | }; 67 | 68 | // TODO: should use Config.APPLICATION_ID, see data/meson.build 69 | new Adw.AboutDialog.from_appdata (Config.APPLICATION_RESOURCE_PATH + "org.gnome.Usage" + ".metainfo.xml", 70 | Config.VERSION.split ("-")[0]) { 71 | comments = _("A nice way to view information about use of system resources, like memory and disk space."), 72 | developers = authors, 73 | designers = artists, 74 | translator_credits = _("translator-credits"), 75 | }.present (window); 76 | } 77 | 78 | private void on_quit (GLib.SimpleAction action, GLib.Variant? parameter) { 79 | window.destroy (); 80 | } 81 | 82 | private void on_search (GLib.SimpleAction action, GLib.Variant? parameter) { 83 | window.action_on_search (); 84 | } 85 | 86 | private void on_activate_radio (GLib.SimpleAction action, GLib.Variant? state) { 87 | action.change_state (state); 88 | } 89 | 90 | private void change_filter_processes_state (GLib.SimpleAction action, GLib.Variant? state) { 91 | action.set_state (state); 92 | SystemMonitor.get_default ().group_system_apps = state.get_string () == "group-system" ? true : false; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/background-monitor.vala: -------------------------------------------------------------------------------- 1 | /* background-monitor.vala 2 | * 3 | * Copyright (C) 2024 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | [DBus (name = "org.freedesktop.background.Monitor", timeout = 120000)] 22 | public interface org.freedesktop.background.Monitor : Object { 23 | [DBus (name = "BackgroundApps")] 24 | public abstract HashTable[] background_apps { owned get; } 25 | 26 | [DBus (name = "version")] 27 | public abstract uint version { get; } 28 | } 29 | 30 | public struct org.freedesktop.background.BackgroundApp { 31 | public string app_id; 32 | public string instance; 33 | public string? message; 34 | } 35 | 36 | public class Usage.BackgroundMonitor : Object { 37 | org.freedesktop.background.Monitor? monitor; 38 | 39 | public BackgroundMonitor () { 40 | try { 41 | monitor = Bus.get_proxy_sync (BusType.SESSION, 42 | "org.freedesktop.background.Monitor", 43 | "/org/freedesktop/background/monitor"); 44 | 45 | if (monitor?.version > 1) { 46 | warning ("Usage.BackgroundMonitor only makes use of org.freedesktop.background.Monitor version 1"); 47 | } 48 | } catch (IOError e) { 49 | warning ("BackgroundMonitor proxy creation failed: %s", e.message); 50 | } 51 | } 52 | 53 | public org.freedesktop.background.BackgroundApp[] get_background_apps () { 54 | org.freedesktop.background.BackgroundApp[] background_apps = {}; 55 | foreach (HashTable app_as_table in monitor?.background_apps) { 56 | background_apps += org.freedesktop.background.BackgroundApp () { 57 | app_id = ((!) app_as_table["app_id"]).get_string (), 58 | instance = ((!) app_as_table["instance"]).get_string (), 59 | message = app_as_table["message"]?.get_string (), 60 | }; 61 | } 62 | return background_apps; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/cpu-graph.vala: -------------------------------------------------------------------------------- 1 | /* cpu-graph.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * Copyright (C) 2023 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | /** 24 | * Graph showing most used core 25 | **/ 26 | public class Usage.CpuGraphMostUsedCore : PerformanceGraphView { 27 | Graph max_load_graph = new Graph (); 28 | 29 | public CpuGraphMostUsedCore () { 30 | this.add_graph (this.max_load_graph); 31 | } 32 | 33 | protected override void update_graphs () { 34 | SystemMonitor monitor = SystemMonitor.get_default (); 35 | int64 timestamp = get_monotonic_time (); 36 | double most_used_core = monitor.x_cpu_load[0]; 37 | 38 | for (int i = 1; i < get_num_processors (); i++) { 39 | if (monitor.x_cpu_load[i] > most_used_core) 40 | most_used_core = monitor.x_cpu_load[i]; 41 | } 42 | 43 | GraphPoint point = GraphPoint (timestamp, most_used_core); 44 | max_load_graph.push_point (point); 45 | } 46 | } 47 | 48 | /** 49 | * Graph showing all processor cores. 50 | **/ 51 | public class Usage.CpuGraph : PerformanceGraphView { 52 | public CpuGraph () { 53 | for (int i = 0; i < get_num_processors (); i++) { 54 | Graph graph = new Graph (); 55 | this.add_graph (graph); 56 | } 57 | 58 | this.add_css_class ("big"); 59 | } 60 | 61 | protected override void update_graphs () { 62 | SystemMonitor monitor = SystemMonitor.get_default (); 63 | int64 timestamp = get_monotonic_time (); 64 | 65 | for (int i = 0; i < get_num_processors (); i++) { 66 | GraphPoint point = GraphPoint (timestamp, monitor.x_cpu_load[i]); 67 | this.get_graph(i).push_point (point); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/cpu-monitor.vala: -------------------------------------------------------------------------------- 1 | /* cpu-monitor.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Petr Štětka 19 | */ 20 | 21 | public class Usage.CpuMonitor : Monitor { 22 | private double cpu_load; 23 | private double[] x_cpu_load; 24 | private uint64 cpu_last_used = 0; 25 | private uint64 cpu_last_total = 0; 26 | private uint64 cpu_last_total_step = 0; 27 | private uint64[] x_cpu_last_used; 28 | private uint64[] x_cpu_last_total; 29 | 30 | public CpuMonitor () { 31 | x_cpu_load = new double[get_num_processors ()]; 32 | x_cpu_last_used = new uint64[get_num_processors ()]; 33 | x_cpu_last_total = new uint64[get_num_processors ()]; 34 | } 35 | 36 | public void update () { 37 | GTop.Cpu cpu_data; 38 | GTop.get_cpu (out cpu_data); 39 | var used = cpu_data.user + cpu_data.nice + cpu_data.sys; 40 | cpu_load = ((double) (used - cpu_last_used)) / (cpu_data.total - cpu_last_total); 41 | cpu_last_total_step = cpu_data.total - cpu_last_total; 42 | 43 | var x_cpu_used = new uint64[get_num_processors ()]; 44 | for (int i = 0; i < x_cpu_load.length; i++) { 45 | x_cpu_used[i] = cpu_data.xcpu_user[i] + cpu_data.xcpu_nice[i] + cpu_data.xcpu_sys[i]; 46 | x_cpu_load[i] = ((double) (x_cpu_used[i] - x_cpu_last_used[i])) / (cpu_data.xcpu_total[i] - x_cpu_last_total[i]); 47 | } 48 | 49 | cpu_last_used = used; 50 | cpu_last_total = cpu_data.total; 51 | x_cpu_last_used = x_cpu_used; 52 | x_cpu_last_total = cpu_data.xcpu_total; 53 | } 54 | 55 | public double get_cpu_load () { 56 | return cpu_load; 57 | } 58 | 59 | public double[] get_x_cpu_load () { 60 | return x_cpu_load; 61 | } 62 | 63 | public void update_process (ref Process process) { 64 | GTop.ProcTime proc_time; 65 | GTop.ProcState proc_state; 66 | 67 | GTop.get_proc_time (out proc_time, process.pid); 68 | GTop.get_proc_state (out proc_state, process.pid); 69 | 70 | process.last_processor = proc_state.last_processor; 71 | double cpu_load = ((double) (proc_time.rtime - process.cpu_last_used)) / cpu_last_total_step; 72 | process.cpu_load = double.min (1, cpu_load); 73 | process.cpu_last_used = proc_time.rtime; 74 | process.x_cpu_last_used = proc_time.xcpu_utime[process.last_processor] + proc_time.xcpu_stime[process.last_processor]; 75 | process.start_time = proc_time.start_time; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/cpu-view.vala: -------------------------------------------------------------------------------- 1 | /* cpu-view.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2024 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | [GtkTemplate (ui = "/org/gnome/Usage/ui/cpu-view.ui")] 24 | public class Usage.CpuView : View { 25 | private ProcessListBox process_list_box; 26 | private NoResultsFoundView no_process_view; 27 | 28 | [GtkChild] 29 | private unowned Gtk.Box cpu_box; 30 | 31 | public CpuView () { 32 | name = "PROCESSOR"; 33 | title = _("Processor"); 34 | icon_name = "speedometer-symbolic"; 35 | search_available = true; 36 | switcher_widget = new GraphBox (new CpuGraphMostUsedCore ()); 37 | switcher_widget.height_request = 80; 38 | 39 | var cpu_graph = new CpuGraph (); 40 | var cpu_graph_box = new GraphBox (cpu_graph); 41 | cpu_graph_box.height_request = 225; 42 | cpu_graph_box.valign = Gtk.Align.START; 43 | cpu_graph_box.add_css_class ("card"); 44 | 45 | process_list_box = new ProcessListBox (ProcessListBoxType () { 46 | comparator = (a, b) => { 47 | return (int) ((uint64) (a.cpu_load < b.cpu_load) - (uint64) (a.cpu_load > b.cpu_load)); 48 | }, 49 | filter = (item) => { 50 | return item.cpu_load > Settings.get_default ().app_minimum_load; 51 | }, 52 | load_widget_factory = (item) => { 53 | Gtk.Label load_label = new Gtk.Label ("%.1f %%".printf (item.cpu_load * 100)); 54 | 55 | load_label.ellipsize = Pango.EllipsizeMode.END; 56 | load_label.max_width_chars = 30; 57 | 58 | return load_label; 59 | }, 60 | }); 61 | 62 | var spinner = new Adw.Spinner () { 63 | margin_top = 30, 64 | height_request = 250, 65 | }; 66 | 67 | no_process_view = new NoResultsFoundView (); 68 | 69 | cpu_box.append (cpu_graph_box); 70 | cpu_box.append (spinner); 71 | cpu_box.append (no_process_view); 72 | 73 | var system_monitor = SystemMonitor.get_default (); 74 | system_monitor.notify["process-list-ready"].connect ((sender, property) => { 75 | if (system_monitor.process_list_ready) { 76 | cpu_box.append (process_list_box); 77 | cpu_box.remove (spinner); 78 | } else { 79 | cpu_box.append (spinner); 80 | cpu_box.remove (process_list_box); 81 | } 82 | }); 83 | 84 | process_list_box.bind_property ("empty", no_process_view, "visible", BindingFlags.BIDIRECTIONAL); 85 | } 86 | 87 | public override void set_search_text (string query) { 88 | process_list_box.search_text = query; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/game-mode.vala: -------------------------------------------------------------------------------- 1 | /* Generated by vala-dbus-binding-tool 1.0-aa2fb. Do not modify! Haha, but I did. Beat me! */ 2 | /* Generated with: vala-dbus-binding-tool --no-synced --api-path=com.feralinteractive.GameMode.xml */ 3 | using GLib; 4 | 5 | [DBus (name = "com.feralinteractive.GameMode.Game", timeout = 120000)] 6 | public interface GameMode.Game : GLib.Object { 7 | 8 | [DBus (name = "ProcessId")] 9 | public abstract int process_id { get; } 10 | 11 | [DBus (name = "Executable")] 12 | public abstract string executable { owned get; } 13 | } 14 | 15 | [DBus (name = "com.feralinteractive.GameMode", timeout = 120000)] 16 | public interface GameMode.Client : GLib.Object { 17 | 18 | [DBus (name = "ClientCount")] 19 | public abstract int client_count { get; } 20 | 21 | [DBus (name = "RegisterGame")] 22 | public abstract int register_game (int pid) throws DBusError, IOError; 23 | 24 | [DBus (name = "UnregisterGame")] 25 | public abstract int unregister_game (int pid) throws DBusError, IOError; 26 | 27 | [DBus (name = "QueryStatus")] 28 | public abstract int query_status (int pid) throws DBusError, IOError; 29 | 30 | [DBus (name = "RegisterGameByPID")] 31 | public abstract int register_game_by_pid (int pid, int requestor) throws DBusError, IOError; 32 | 33 | [DBus (name = "UnregisterGameByPID")] 34 | public abstract int unregister_game_by_pid (int pid, int requestor) throws DBusError, IOError; 35 | 36 | [DBus (name = "QueryStatusByPID")] 37 | public abstract int query_status_by_pid (int pid, int requestor) throws DBusError, IOError; 38 | 39 | [DBus (name = "RefreshConfig")] 40 | public abstract int refresh_config () throws DBusError, IOError; 41 | 42 | [DBus (name = "ListGames")] 43 | public abstract GameInfo[] list_games () throws DBusError, IOError; 44 | 45 | [DBus (name = "GameRegistered")] 46 | public signal void game_registered (int pid, GLib.ObjectPath path); 47 | 48 | [DBus (name = "GameUnregistered")] 49 | public signal void game_unregistered (int pid, GLib.ObjectPath path); 50 | } 51 | 52 | public struct GameMode.GameInfo { 53 | public int pid; 54 | public GLib.ObjectPath path; 55 | } 56 | 57 | public class GameMode.PidList : GLib.Object { 58 | private Client? client; 59 | private HashTable pids; 60 | 61 | /* singleton */ 62 | private static PidList? singleton; 63 | 64 | public static PidList get_default () ensures (singleton != null) { 65 | if (singleton == null) 66 | singleton = new PidList (); 67 | 68 | return (!) singleton; 69 | } 70 | 71 | /* construction */ 72 | construct { 73 | pids = new HashTable (direct_hash, direct_equal); 74 | } 75 | 76 | public PidList () { 77 | try { 78 | client = Bus.get_proxy_sync (BusType.SESSION, 79 | "com.feralinteractive.GameMode", 80 | "/com/feralinteractive/GameMode"); 81 | 82 | client.game_registered.connect (this.on_game_registered); 83 | client.game_unregistered.connect (this.on_game_unregistered); 84 | 85 | GameInfo[] games = client?.list_games (); 86 | foreach (GameMode.GameInfo info in games) { 87 | pids.insert (info.pid, info.path); 88 | } 89 | } catch (IOError e) { 90 | warning ("GameMode Proxy creation failed: %s", e.message); 91 | } catch (GLib.DBusError e) { 92 | info ("GameMode D-Bus error: %s", e.message); 93 | } 94 | } 95 | 96 | public bool contains (int pid) { 97 | return pid in pids; 98 | } 99 | 100 | [Signal (detailed = true)] 101 | public signal void changed (int pid, bool added); 102 | 103 | /* Signals */ 104 | private void on_game_registered (int pid, GLib.ObjectPath path) { 105 | pids.insert (pid, path); 106 | changed["added"](pid, true); 107 | } 108 | 109 | private void on_game_unregistered (int pid, GLib.ObjectPath path) { 110 | pids.remove (pid); 111 | changed["removed"](pid, false); 112 | } 113 | } -------------------------------------------------------------------------------- /src/gnome-usage.vala: -------------------------------------------------------------------------------- 1 | /* gnome-usage.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Petr Štětka 19 | */ 20 | 21 | public static int main (string[] args) { 22 | Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR); 23 | Intl.setlocale (LocaleCategory.ALL, ""); 24 | Intl.textdomain (Config.GETTEXT_PACKAGE); 25 | Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "utf-8"); 26 | 27 | var application = new Usage.Application (); 28 | return application.run (args); 29 | } 30 | -------------------------------------------------------------------------------- /src/graph-box.vala: -------------------------------------------------------------------------------- 1 | /* graph-box.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2024 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | using Gtk; 24 | 25 | public class Usage.GraphBox : Adw.Bin { 26 | 27 | class construct { 28 | set_css_name ("graph-box"); 29 | } 30 | 31 | public GraphBox (GraphView graph) { 32 | this.add_css_class ("view"); 33 | this.overflow = Gtk.Overflow.HIDDEN; 34 | graph.hexpand = true; 35 | graph.vexpand = true; 36 | this.child = graph; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/graph.vala: -------------------------------------------------------------------------------- 1 | /* graph.vala 2 | * 3 | * Copyright (C) 2023 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | public class Usage.GraphView : Gtk.Widget { 22 | private Gee.ArrayList graphs = new Gee.ArrayList (); 23 | 24 | public int64 _offset_x = 0; 25 | public int64 _range_x = 1; 26 | public int64 _offset_y = 0; 27 | public int64 _range_y = 1; 28 | 29 | public virtual int64 offset_x { 30 | get { return _offset_x; } 31 | set { 32 | _offset_x = value; 33 | this.queue_draw (); 34 | } 35 | } 36 | public int64 range_x { 37 | get { return _range_x; } 38 | set { 39 | _range_x = value; 40 | this.queue_draw (); 41 | } 42 | } 43 | public int64 offset_y { 44 | get { return _offset_y; } 45 | set { 46 | _offset_y = value; 47 | this.queue_draw (); 48 | } 49 | } 50 | public int64 range_y { 51 | get { return _range_y; } 52 | set { 53 | _range_y = value; 54 | this.queue_draw (); 55 | } 56 | } 57 | 58 | class construct { 59 | set_css_name ("rg-graph"); 60 | } 61 | 62 | construct { 63 | this.overflow = Gtk.Overflow.HIDDEN; 64 | } 65 | 66 | public void add_graph (Graph graph) { 67 | this.graphs.add (graph); 68 | graph.updated.connect (this.queue_draw); 69 | this.queue_draw (); 70 | } 71 | 72 | public void remove_graph (Graph graph) { 73 | this.graphs.remove (graph); 74 | graph.updated.disconnect (this.queue_draw); 75 | this.queue_draw (); 76 | } 77 | 78 | public Graph get_graph (int i) { 79 | return this.graphs.@get (i); 80 | } 81 | 82 | public override void snapshot (Gtk.Snapshot snapshot) { 83 | float thickness = 2.5f; 84 | 85 | int view_width = this.get_width (); 86 | int view_height = (int) Math.llrintf (this.get_height () - thickness); 87 | 88 | foreach (Graph graph in graphs) { 89 | Gdk.RGBA color; 90 | if (graph.color != null) { 91 | color = (!) graph.color; 92 | } else { 93 | color = Adw.StyleManager.get_default ().get_accent_color ().to_rgba (); 94 | } 95 | Gdk.RGBA color_transparent = color.copy (); 96 | color_transparent.alpha = 0; 97 | 98 | Gsk.ColorStop[] stops = { 99 | Gsk.ColorStop () { offset = 0, color = color_transparent }, 100 | Gsk.ColorStop () { offset = 0.3f, color = color }, 101 | Gsk.ColorStop () { offset = 0.7f, color = color }, 102 | Gsk.ColorStop () { offset = 1, color = color_transparent }, 103 | }; 104 | 105 | for (uint n = 1; n < graph.values.get_length (); n++) { 106 | GraphPoint graph_point = graph.values.peek_nth (n); 107 | GraphPoint graph_point_next = graph.values.peek_nth (n - 1); 108 | 109 | double delta_x = (double) (graph_point_next.timestamp - graph_point.timestamp) * view_width / range_x; 110 | double delta_y = (graph_point_next.level - graph_point.level) * view_height / range_y; 111 | 112 | float x = (float) (graph_point.timestamp - offset_x) * view_width / range_x; 113 | float y = (offset_y + range_y - (float) graph_point.level) * view_height / range_y + thickness/2; 114 | 115 | double angle = Math.atan2(delta_y, delta_x); 116 | double sin_angle; 117 | double cos_angle; 118 | Math.sincos(angle, out sin_angle, out cos_angle); 119 | 120 | Graphene.Rect bounds = Graphene.Rect (); 121 | bounds.init (x, Math.fminf(y, y - (float) delta_y) - thickness/2, (float) delta_x, Math.fabsf((float) delta_y) + thickness); 122 | 123 | Graphene.Point start = Graphene.Point (); 124 | Graphene.Point end = Graphene.Point (); 125 | start.init (x - thickness/2 * (float) sin_angle, y - thickness/2 * (float) cos_angle); 126 | end.init (x + thickness/2 * (float) sin_angle, y + thickness/2 * (float) cos_angle); 127 | 128 | snapshot.append_linear_gradient (bounds, start, end, stops); 129 | } 130 | } 131 | } 132 | } 133 | 134 | public class Usage.Graph { 135 | public Gsk.RenderNode render_node; 136 | public Queue values = new Queue (); 137 | public uint maximal_queue_length = 0; 138 | public Gdk.RGBA? color = null; 139 | 140 | public void push_point (GraphPoint point) { 141 | this.values.push_head (point); 142 | if (maximal_queue_length > 0) { 143 | while (this.values.get_length () > maximal_queue_length) { 144 | this.values.pop_tail (); 145 | } 146 | } 147 | this.updated (); 148 | } 149 | 150 | public signal void updated (); 151 | } 152 | 153 | public struct Usage.GraphPoint { 154 | int64 timestamp; 155 | double level; 156 | 157 | public GraphPoint (int64 timestamp, double level) { 158 | this.timestamp = timestamp; 159 | this.level = level; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/memory-graph.vala: -------------------------------------------------------------------------------- 1 | /* memory-graph.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * Copyright (C) 2023 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | public class Usage.MemoryGraph : PerformanceGraphView { 24 | Graph mem_graph = new Graph (); 25 | Graph swap_graph = new Graph (); 26 | 27 | public MemoryGraph () { 28 | this.add_graph (this.mem_graph); 29 | this.add_graph (this.swap_graph); 30 | } 31 | 32 | protected override void update_graphs () { 33 | SystemMonitor monitor = SystemMonitor.get_default (); 34 | int64 timestamp = get_monotonic_time (); 35 | 36 | double ram_usage = 0; 37 | if (monitor.ram_total != 0) 38 | ram_usage = (double) monitor.ram_usage / monitor.ram_total; 39 | 40 | GraphPoint mem_point = GraphPoint (timestamp, ram_usage); 41 | mem_graph.push_point (mem_point); 42 | 43 | if (monitor.swap_total != 0) { 44 | double swap_usage = (double) monitor.swap_usage / monitor.swap_total; 45 | 46 | GraphPoint swap_point = GraphPoint (timestamp, swap_usage); 47 | swap_graph.push_point (swap_point); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/memory-monitor.vala: -------------------------------------------------------------------------------- 1 | /* memory-monitor.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Petr Štětka 19 | */ 20 | 21 | public class Usage.MemoryMonitor : Monitor { 22 | private uint64 ram_usage; 23 | private uint64 ram_total; 24 | private uint64 swap_usage; 25 | private uint64 swap_total; 26 | 27 | public void update () { 28 | /* Memory */ 29 | GTop.Mem mem; 30 | GTop.get_mem (out mem); 31 | ram_usage = mem.user; 32 | ram_total = mem.total; 33 | 34 | /* Swap */ 35 | GTop.Swap swap; 36 | GTop.get_swap (out swap); 37 | swap_usage = swap.used; 38 | swap_total = swap.total; 39 | } 40 | 41 | public uint64 get_ram_usage () { 42 | return ram_usage; 43 | } 44 | public uint64 get_swap_usage () { 45 | return swap_usage; 46 | } 47 | public uint64 get_ram_total () { 48 | return ram_total; 49 | } 50 | public uint64 get_swap_total () { 51 | return swap_total; 52 | } 53 | 54 | public void update_process (ref Process process) { 55 | GTop.Mem mem; 56 | GTop.ProcMem proc_mem; 57 | 58 | GTop.get_mem (out mem); 59 | GTop.get_proc_mem (out proc_mem, process.pid); 60 | 61 | process.mem_usage = proc_mem.resident - proc_mem.share; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/memory-speedometer.vala: -------------------------------------------------------------------------------- 1 | /* memory-speedometer.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | using Gtk; 22 | 23 | [GtkTemplate (ui = "/org/gnome/Usage/ui/memory-speedometer.ui")] 24 | public class Usage.MemorySpeedometer : Adw.Bin { 25 | [GtkChild] 26 | private unowned Usage.Speedometer speedometer; 27 | 28 | [GtkChild] 29 | private unowned Gtk.Label label; 30 | 31 | [GtkChild] 32 | private unowned Gtk.Label ram_used; 33 | 34 | [GtkChild] 35 | private unowned Gtk.Label ram_available; 36 | 37 | private double ram_usage { get; set; } 38 | 39 | construct { 40 | var monitor = SystemMonitor.get_default (); 41 | Timeout.add_seconds (1, () => { 42 | var percentage = (((double) monitor.ram_usage / monitor.ram_total) * 100); 43 | 44 | this.speedometer.percentage = (int)percentage; 45 | label.label = "%d".printf ((int)percentage) + "%"; 46 | 47 | var available = (monitor.ram_total - monitor.ram_usage); 48 | 49 | ram_used.label = Utils.format_size_values (monitor.ram_usage); 50 | ram_available.label = Utils.format_size_values (available); 51 | 52 | return true; 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/memory-view.vala: -------------------------------------------------------------------------------- 1 | /* memory-view.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2024 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | [GtkTemplate (ui = "/org/gnome/Usage/ui/memory-view.ui")] 24 | public class Usage.MemoryView : View { 25 | private ProcessListBox process_list_box; 26 | private NoResultsFoundView no_process_view; 27 | 28 | [GtkChild] 29 | private unowned Gtk.Box memory_box; 30 | 31 | public MemoryView () { 32 | name = "MEMORY"; 33 | title = _("Memory"); 34 | icon_name = "memory-symbolic"; 35 | search_available = true; 36 | switcher_widget = new GraphBox (new MemoryGraph ()); 37 | switcher_widget.height_request = 80; 38 | 39 | process_list_box = new ProcessListBox (ProcessListBoxType () { 40 | comparator = (a, b) => { 41 | return (int) ((uint64) (a.mem_usage < b.mem_usage) - (uint64) (a.mem_usage > b.mem_usage)); 42 | }, 43 | filter = (item) => { 44 | return item.mem_usage > Settings.get_default ().app_minimum_memory; 45 | }, 46 | load_widget_factory = (item) => { 47 | Gtk.Label load_label = new Gtk.Label (Utils.format_size_values (item.mem_usage)); 48 | 49 | load_label.ellipsize = Pango.EllipsizeMode.END; 50 | load_label.max_width_chars = 30; 51 | 52 | return load_label; 53 | }, 54 | }); 55 | 56 | var spinner = new Adw.Spinner () { 57 | margin_top = 30, 58 | height_request = 250, 59 | }; 60 | 61 | no_process_view = new NoResultsFoundView (); 62 | 63 | var memory_graph = new MemorySpeedometer (); 64 | var swap_graph = new SwapSpeedometer (); 65 | swap_graph.valign = Gtk.Align.END; 66 | 67 | var speedometers = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { 68 | margin_top = 12, 69 | margin_bottom = 6, 70 | }; 71 | speedometers.append (memory_graph); 72 | speedometers.append (swap_graph); 73 | 74 | memory_box.append (speedometers); 75 | memory_box.append (spinner); 76 | memory_box.append (no_process_view); 77 | 78 | var system_monitor = SystemMonitor.get_default (); 79 | system_monitor.notify["process-list-ready"].connect ((sender, property) => { 80 | if (system_monitor.process_list_ready) { 81 | memory_box.append (process_list_box); 82 | memory_box.remove (spinner); 83 | } else { 84 | memory_box.append (spinner); 85 | memory_box.remove (process_list_box); 86 | } 87 | }); 88 | 89 | process_list_box.bind_property ("empty", no_process_view, "visible", BindingFlags.BIDIRECTIONAL); 90 | } 91 | 92 | public override void set_search_text (string query) { 93 | process_list_box.search_text = query; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | vala_sources = [ 2 | 'app-dialog.vala', 3 | 'app-item.vala', 4 | 'application.vala', 5 | 'background-monitor.vala', 6 | 'cpu-graph.vala', 7 | 'cpu-monitor.vala', 8 | 'cpu-view.vala', 9 | 'gnome-usage.vala', 10 | 'game-mode.vala', 11 | 'graph.vala', 12 | 'graph-box.vala', 13 | 'memory-graph.vala', 14 | 'memory-monitor.vala', 15 | 'memory-speedometer.vala', 16 | 'memory-view.vala', 17 | 'monitor.vala', 18 | 'network/network-interface-graph.vala', 19 | 'network/network-view.vala', 20 | 'network/vnstat.vala', 21 | 'no-results-found-view.vala', 22 | 'performance-graph-view.vala', 23 | 'process-list-box.vala', 24 | 'process-row-item.vala', 25 | 'process-user-tag.vala', 26 | 'process.vala', 27 | 'quit-process-dialog.vala', 28 | 'settings.vala', 29 | 'speedometer.vala', 30 | 'stack-list.vala', 31 | 'storage/storage-actionbar.vala', 32 | 'storage/storage-graph.vala', 33 | 'storage/query-builder.vala', 34 | 'storage/storage-view-item.vala', 35 | 'storage/storage-view.vala', 36 | 'storage/storage-view-row.vala', 37 | 'storage/sparql-controller.vala', 38 | 'storage/sparql-worker.vala', 39 | 'swap-speedometer.vala', 40 | 'system-monitor.vala', 41 | 'utils.vala', 42 | 'view.vala', 43 | 'window.vala' 44 | ] 45 | 46 | deps = [ 47 | gee_dep, 48 | gio_dep, 49 | gio_unix_dep, 50 | glib_dep, 51 | gobject_dep, 52 | gtk_dep, 53 | json_dep, 54 | libgtop_dep, 55 | libnm_dep, 56 | tinysparql_dep, 57 | libadwaita_dep, 58 | cc.find_library('m'), 59 | valac.find_library('config', dirs: vapi_dir), 60 | valac.find_library('stopgap', dirs: vapi_dir), 61 | valac.find_library('posix') 62 | ] 63 | 64 | c_args = [ 65 | '-DVERSION="@0@@1@"'.format(meson.project_version(), version_suffix), 66 | '-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()), 67 | '-DGNOMELOCALEDIR="@0@"'.format(join_paths(get_option('prefix'), get_option('localedir'))), 68 | '-DPROFILE="@0@"'.format(profile), 69 | '-DAPPLICATION_ID="@0@"'.format(application_id), 70 | '-DAPPLICATION_RESOURCE_PATH="@0@"'.format(resource_path), 71 | '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()), 72 | ] 73 | 74 | executable( 75 | meson.project_name(), 76 | vala_sources + resources, 77 | dependencies: deps, 78 | c_args: c_args, 79 | vala_args: vapi_dirs, 80 | install: true 81 | ) 82 | -------------------------------------------------------------------------------- /src/monitor.vala: -------------------------------------------------------------------------------- 1 | /* monitor.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Petr Štětka 19 | */ 20 | 21 | public interface Usage.Monitor { 22 | public abstract void update (); 23 | public abstract void update_process (ref Usage.Process process); 24 | } 25 | -------------------------------------------------------------------------------- /src/network/network-interface-graph.vala: -------------------------------------------------------------------------------- 1 | /* network-interface-graph.vala 2 | * 3 | * Copyright (C) 2023–2025 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | public class Usage.NetworkInterfaceGraph : Adw.Bin { 22 | public Graph download_graph { 23 | get; private set; default = new Graph () { 24 | color = Gdk.RGBA () { red = 46f / 255f, green = 194f / 255f, blue = 126f / 255f, alpha = 1f }, 25 | }; 26 | } 27 | public Graph upload_graph { 28 | get; private set; default = new Graph () { 29 | color = Gdk.RGBA () { red = 192f / 255f, green = 97f / 255f, blue = 203f / 255f, alpha = 1f }, 30 | }; 31 | } 32 | public GraphView graph_view { get; private set; default = new GraphView (); } 33 | 34 | public static Gtk.SizeGroup y_labels_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); 35 | 36 | private Gtk.Label y_label_max; 37 | private Gtk.Label t_label_min; 38 | private Gtk.Label t_label_max; 39 | 40 | public NetworkInterfaceGraph () { 41 | graph_view.add_css_class ("big"); 42 | graph_view.add_graph (download_graph); 43 | graph_view.add_graph (upload_graph); 44 | 45 | var network_graph_box = new GraphBox (graph_view); 46 | network_graph_box.height_request = 225; 47 | network_graph_box.valign = Gtk.Align.START; 48 | network_graph_box.add_css_class ("card"); 49 | 50 | Gtk.Label y_label_min = new Gtk.Label (Utils.format_size_values (0)); 51 | y_label_max = new Gtk.Label ("…"); 52 | Gtk.Box y_labels = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); 53 | y_labels_group.add_widget (y_labels); 54 | y_labels.append (y_label_max); 55 | y_labels.append (y_label_min); 56 | y_label_min.xalign = 1; 57 | y_label_max.xalign = 1; 58 | y_label_max.vexpand = true; 59 | y_label_max.valign = Gtk.Align.START; 60 | 61 | Gtk.Box timestamp_labels = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6); 62 | t_label_min = new Gtk.Label ("…"); 63 | t_label_min.hexpand = true; 64 | t_label_min.halign = Gtk.Align.START; 65 | t_label_max = new Gtk.Label ("…"); 66 | t_label_max.hexpand = true; 67 | t_label_max.halign = Gtk.Align.END; 68 | timestamp_labels.append (t_label_min); 69 | timestamp_labels.append (t_label_max); 70 | 71 | Gtk.Grid network_box = new Gtk.Grid (); 72 | network_box.column_spacing = 6; 73 | network_box.row_spacing = 6; 74 | network_box.valign = Gtk.Align.START; 75 | network_box.attach (y_labels, 0, 0, 1, 1); 76 | network_box.attach (network_graph_box, 1, 0, 1, 1); 77 | network_box.attach (timestamp_labels, 1, 1, 1, 1); 78 | 79 | this.child = network_box; 80 | } 81 | 82 | public void set_ranges (int64 min_timestamp, int64 max_timestamp, int64 max_val) { 83 | DateTime start_date = new DateTime.from_unix_local (min_timestamp); 84 | DateTime end_date = new DateTime.from_unix_local (max_timestamp); 85 | 86 | this.graph_view.offset_x = min_timestamp; 87 | this.graph_view.offset_y = 0; 88 | this.graph_view.range_x = max_timestamp - min_timestamp; 89 | this.graph_view.range_y = (int64) max_val; 90 | 91 | y_label_max.label = Utils.format_size_values (graph_view.range_y); 92 | t_label_min.label = start_date.format (_("%b %e, %Y")); 93 | t_label_max.label = end_date.format (_("%b %e, %Y")); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/network/network-view.vala: -------------------------------------------------------------------------------- 1 | /* network-view.vala 2 | * 3 | * Copyright (C) 2023–2025 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | [GtkTemplate (ui = "/org/gnome/Usage/ui/network-view.ui")] 22 | public class Usage.NetworkView : Usage.View { 23 | private const int64 DAY = 24 * 60 * 60; 24 | 25 | [GtkChild] 26 | private unowned Adw.ViewStack interface_graphs; 27 | 28 | construct { 29 | name = "NETWORK"; 30 | title = _("Network"); 31 | icon_name = "network-transmit-receive-symbolic"; 32 | search_available = false; 33 | switcher_widget = null; 34 | } 35 | 36 | public NetworkView () { 37 | HashTable devices = new HashTable (GLib.str_hash, GLib.str_equal); 38 | uint ethernet_count = 0, wifi_count = 0, p2p_count = 0, modem_count = 0, bt_count = 0; 39 | 40 | try { 41 | NM.Client nm_client = new NM.Client (); 42 | 43 | foreach (NM.Device device in nm_client.devices) { 44 | if (device.@interface != null && (!devices.contains (device.@interface) || device.managed)) { 45 | devices.insert (device.@interface, device); 46 | } 47 | if (device.ip_interface != null && (!devices.contains (device.ip_interface) || device.managed)) { 48 | devices.insert (device.ip_interface, device); 49 | } 50 | } 51 | } catch (Error error) { 52 | info ("Error with NetworkManager: %s\n", error.message); 53 | } 54 | 55 | foreach (Vnstat.Interface iface in Vnstat.list_interfaces ()) { 56 | List interface_daily_data = iface.get_traffic (Vnstat.Mode.DAILY); 57 | 58 | /* interfaces with no data available are often temporary */ 59 | if (!iface.recently_used) { 60 | continue; 61 | } 62 | 63 | string interface_name = iface.name; 64 | NM.Device? device = devices[interface_name]; 65 | NetworkInterfaceGraph interface_view = new NetworkInterfaceGraph (); 66 | 67 | string title = interface_name; 68 | if (device == null) { 69 | warning ("skipping unknown interface “%s”", interface_name); 70 | continue; 71 | } else { 72 | /* possibly use device.udi, device.vendor, device.product if too simple */ 73 | switch (((!) device).device_type) { 74 | case NM.DeviceType.ETHERNET: 75 | ethernet_count++; 76 | title = _("Wired"); 77 | if (ethernet_count > 1) { 78 | title += @" $ethernet_count"; 79 | } 80 | break; 81 | case NM.DeviceType.WIFI: 82 | wifi_count++; 83 | title = _("WiFi"); 84 | if (wifi_count > 1) { 85 | title += @" $wifi_count"; 86 | } 87 | break; 88 | case NM.DeviceType.WIFI_P2P: 89 | p2p_count++; 90 | title = _("WiFi (Peer to Peer)"); 91 | if (p2p_count > 1) { 92 | title += @" $p2p_count"; 93 | } 94 | break; 95 | case NM.DeviceType.MODEM: 96 | modem_count++; 97 | title = _("Mobile Connection"); 98 | if (modem_count > 1) { 99 | title += @" $modem_count"; 100 | } 101 | break; 102 | case NM.DeviceType.BT: 103 | bt_count++; 104 | title = _("Bluetooth Hotspot"); 105 | if (bt_count > 1) { 106 | title += @" $bt_count"; 107 | } 108 | break; 109 | default: 110 | info ("including interface “%s” of unknown type %i", interface_name, ((!) device).device_type); 111 | break; 112 | } 113 | } 114 | 115 | int64 start_timestamp = DAY * ((int64) ((get_real_time () / 1000000) / DAY) - 30); 116 | double max_val = 1; 117 | foreach (Vnstat.TrafficDataPoint? nullable_data_point in interface_daily_data) { 118 | if (nullable_data_point == null) { 119 | continue; 120 | } 121 | Vnstat.TrafficDataPoint data_point = (!) nullable_data_point; 122 | 123 | GraphPoint download_point = GraphPoint (data_point.timestamp, data_point.download); 124 | GraphPoint upload_point = GraphPoint (data_point.timestamp, data_point.upload); 125 | 126 | interface_view.download_graph.push_point (download_point); 127 | interface_view.upload_graph.push_point (upload_point); 128 | 129 | if (data_point.timestamp >= start_timestamp) { 130 | max_val = Math.fmax (Math.fmax (data_point.download, data_point.upload), max_val); 131 | } 132 | } 133 | 134 | interface_graphs.add_titled_with_icon (interface_view, 135 | interface_name, 136 | title, 137 | "network-transmit-receive-symbolic"); 138 | 139 | interface_view.set_ranges (start_timestamp, start_timestamp + (30 * DAY), (int64) max_val); 140 | } 141 | } 142 | 143 | public override bool prerequisite_fulfilled () { 144 | return Vnstat.test_exists (); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/no-results-found-view.vala: -------------------------------------------------------------------------------- 1 | /* no-results-found-box.vala 2 | * 3 | * Copyright (C) 2017 Radhika Dua 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | [GtkTemplate (ui = "/org/gnome/Usage/ui/no-results-found-view.ui")] 20 | public class Usage.NoResultsFoundView : Adw.Bin { } 21 | -------------------------------------------------------------------------------- /src/performance-graph-view.vala: -------------------------------------------------------------------------------- 1 | /* performance-graph-view.vala 2 | * 3 | * Copyright (C) 2023 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | public abstract class Usage.PerformanceGraphView : GraphView { 22 | private Settings settings = Settings.get_default (); 23 | private bool constant_redraw; 24 | 25 | construct { 26 | this.range_y = 1; 27 | this.offset_y = 0; 28 | this.range_x = 1000 * settings.graph_timespan; 29 | this.update_x_offset (); 30 | 31 | this.reevaluate_constant_redraw (); 32 | 33 | Timeout.add (settings.graph_update_interval, () => { 34 | this.update_graphs (); 35 | 36 | this.reevaluate_constant_redraw (); 37 | if (!constant_redraw) { 38 | this.update_x_offset (); 39 | } 40 | 41 | return true; 42 | }); 43 | } 44 | 45 | private void reevaluate_constant_redraw () { 46 | constant_redraw = settings.enable_scrolling_graph; 47 | 48 | if (constant_redraw) { 49 | this.add_tick_callback (() => { 50 | this.update_x_offset (); 51 | return constant_redraw; 52 | }); 53 | } 54 | } 55 | 56 | public new void add_graph (Graph graph) { 57 | graph.maximal_queue_length = (int) Math.ceilf((float) settings.graph_timespan/settings.graph_update_interval) + 2; 58 | base.add_graph (graph); 59 | } 60 | 61 | public void update_x_offset () { 62 | int64 timestamp = get_monotonic_time (); 63 | int64 offset = timestamp - 1000 * settings.graph_timespan; 64 | if (constant_redraw) { 65 | offset -= 1000 * settings.graph_update_interval; 66 | } 67 | this.offset_x = offset; 68 | } 69 | 70 | protected abstract void update_graphs (); 71 | } 72 | -------------------------------------------------------------------------------- /src/process-list-box.vala: -------------------------------------------------------------------------------- 1 | /* process-list-box.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2023-2024 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | public delegate bool Usage.FilterFunc (T object); 24 | public delegate Gtk.Widget Usage.WidgetFactoryFunc (T object); 25 | public struct Usage.ProcessListBoxType { 26 | public unowned CompareDataFunc comparator; 27 | public unowned Usage.FilterFunc filter; 28 | public unowned Usage.WidgetFactoryFunc load_widget_factory; 29 | } 30 | 31 | public class Usage.ProcessListBox : Adw.Bin { 32 | public Gtk.ListView list_view { get; private set; } 33 | 34 | public bool empty { get; set; default = true; } 35 | public string search_text { get; set; default = ""; } 36 | 37 | private ListStore model; 38 | private Gtk.Filter filter; 39 | private Gtk.Sorter sorter; 40 | private ProcessListBoxType type; 41 | private HashTable item_for_app; 42 | 43 | public ProcessListBox (ProcessListBoxType type) { 44 | this.type = type; 45 | this.item_for_app = new HashTable (GLib.direct_hash, GLib.direct_equal); 46 | this.model = new ListStore (typeof (ProcessRowItem)); 47 | this.filter = new Gtk.CustomFilter ((item) => { 48 | AppItem app = ((ProcessRowItem) item).app; 49 | 50 | if (search_text != "") { 51 | return app.display_name.down ().contains (search_text.down ()) 52 | || app.representative_cmdline.down ().contains (search_text.down ()) 53 | || (app.container?.down ()?.contains (search_text.down ()) ?? false); 54 | } 55 | 56 | return this.type.filter (app); 57 | }); 58 | this.sorter = new Gtk.CustomSorter((a, b) => { 59 | return this.type.comparator (((ProcessRowItem) a).app, ((ProcessRowItem) b).app); 60 | }); 61 | 62 | Gtk.FilterListModel filter_model = new Gtk.FilterListModel (this.model, filter); 63 | Gtk.SortListModel sort_model = new Gtk.SortListModel (filter_model, sorter); 64 | Gtk.SelectionModel selection_model = new Gtk.NoSelection (sort_model); 65 | 66 | typeof (Usage.ProcessUserTag).ensure (); 67 | Gtk.BuilderListItemFactory factory = new Gtk.BuilderListItemFactory.from_resource (null, "/org/gnome/Usage/ui/process-row.ui"); 68 | this.list_view = new Gtk.ListView (selection_model, factory); 69 | 70 | this.list_view.add_css_class ("card"); 71 | this.list_view.show_separators = true; 72 | this.list_view.single_click_activate = true; 73 | 74 | this.list_view.activate.connect ((list_view, position) => { 75 | AppItem app = ((ProcessRowItem) list_view.get_model ().get_item (position)).app; 76 | 77 | if (app.representative_cmdline != "system") { 78 | AppDialog dialog = new AppDialog (app); 79 | dialog.present ((Gtk.Window) this.get_root ()); 80 | } 81 | }); 82 | 83 | this.set_child (list_view); 84 | 85 | this.notify["search-text"].connect ((sender, property) => { 86 | update (); 87 | }); 88 | 89 | var system_monitor = SystemMonitor.get_default (); 90 | system_monitor.notify["process-list-ready"].connect (() => { 91 | if (system_monitor.process_list_ready) 92 | update (); 93 | }); 94 | 95 | var settings = Settings.get_default (); 96 | Timeout.add (settings.list_update_interval_UI, update); 97 | 98 | this.bind_property ("empty", this, "visible", BindingFlags.INVERT_BOOLEAN | BindingFlags.SYNC_CREATE); 99 | } 100 | 101 | private bool update () { 102 | var system_monitor = SystemMonitor.get_default (); 103 | List apps = system_monitor.get_apps (); 104 | 105 | uint inserted = 0; 106 | uint removed = 0; 107 | 108 | for (uint position = 0; position < model.n_items; position++) { 109 | AppItem app = ((ProcessRowItem) model.get_item (position)).app; 110 | if (apps.index (app) < 0 || !app.is_running ()) { 111 | model.remove (position); 112 | item_for_app.remove (app); 113 | removed++; 114 | } 115 | } 116 | foreach (unowned AppItem app in system_monitor.get_apps ()) { 117 | uint index; 118 | if (!model.find (item_for_app.@get (app), out index) && app.is_running ()) { 119 | ProcessRowItem item = new ProcessRowItem (app, type); 120 | model.append (item); 121 | item_for_app.insert (app, item); 122 | inserted++; 123 | } 124 | } 125 | 126 | debug (@"$inserted started; $removed stopped"); 127 | 128 | for (uint position = 0; position < model.n_items; position++) { 129 | ProcessRowItem item = (ProcessRowItem) model.get_item (position); 130 | item.notify_property ("load_widget"); 131 | } 132 | filter.changed (Gtk.FilterChange.DIFFERENT); 133 | sorter.changed (Gtk.SorterChange.DIFFERENT); 134 | 135 | empty = (this.list_view.model.get_n_items () == 0); 136 | return true; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/process-row-item.vala: -------------------------------------------------------------------------------- 1 | /* process-row.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2023-2024 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | public class Usage.ProcessRowItem : Object { 24 | private const string CSS_TAG_USER = "tag-user"; 25 | private const string CSS_TAG_ROOT = "tag-root"; 26 | private const string CSS_TAG_SYSTEM = "tag-system"; 27 | 28 | private ProcessListBoxType type; 29 | 30 | public AppItem app { get; private set; } 31 | 32 | public virtual Gtk.Widget load_widget { 33 | owned get { 34 | return this.type.load_widget_factory (app); 35 | } 36 | } 37 | 38 | public virtual string user { 39 | owned get { 40 | if (app.user != null) { 41 | return app.user.UserName; 42 | } 43 | return ""; 44 | } 45 | } 46 | public virtual bool not_current_user { 47 | get { 48 | return app.user == null || app.user.UserName != GLib.Environment.get_user_name (); 49 | } 50 | } 51 | public virtual string? user_type { 52 | get { 53 | if (app.user == null) { 54 | return null; 55 | } 56 | 57 | if (app.user.LocalAccount) { 58 | return CSS_TAG_USER; 59 | } else if (app.user.AccountType == UserAccountType.ADMINISTRATOR) { 60 | return CSS_TAG_ROOT; 61 | } else if (app.user.SystemAccount) { 62 | return CSS_TAG_SYSTEM; 63 | } 64 | 65 | return null; 66 | } 67 | } 68 | public virtual Icon? container_icon { 69 | owned get { 70 | string? container = this.app.container; 71 | if (container == null) { 72 | return null; 73 | } 74 | switch ((!) container) { 75 | case "Waydroid": 76 | return new GLib.ThemedIcon ("android-app-symbolic"); 77 | default: 78 | return null; 79 | } 80 | } 81 | } 82 | 83 | public ProcessRowItem (AppItem app, ProcessListBoxType type) { 84 | this.app = app; 85 | this.type = type; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/process-user-tag.vala: -------------------------------------------------------------------------------- 1 | /* process-user-tag.vala 2 | * 3 | * Copyright (C) 2024 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | public class Usage.ProcessUserTag : Adw.Bin { 22 | private string _user_type = "default"; 23 | public string user_type { 24 | get { 25 | return _user_type; 26 | } 27 | set { 28 | if (_user_type != null) { 29 | this.remove_css_class (_user_type); 30 | } 31 | _user_type = value; 32 | if (_user_type != null) { 33 | this.add_css_class (_user_type); 34 | } 35 | } 36 | } 37 | public virtual string label { 38 | get { 39 | return inner_label.label; 40 | } 41 | set { 42 | inner_label.label = value; 43 | } 44 | } 45 | 46 | private Gtk.Label inner_label; 47 | 48 | construct { 49 | this.inner_label = new Gtk.Label (""); 50 | this.child = inner_label; 51 | 52 | this.add_css_class ("tag"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/quit-process-dialog.vala: -------------------------------------------------------------------------------- 1 | /* quit-process-dialog.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2023 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Felipe Borges 20 | * Petr Štětka 21 | * Markus Göllnitz 22 | */ 23 | 24 | using Gtk; 25 | 26 | [GtkTemplate (ui = "/org/gnome/Usage/ui/quit-process-dialog.ui")] 27 | public class Usage.QuitProcessDialog : Adw.AlertDialog { 28 | private AppItem app; 29 | 30 | public QuitProcessDialog (AppItem app) { 31 | this.app = app; 32 | this.heading = this.heading.printf (app.display_name); 33 | } 34 | 35 | [GtkCallback] 36 | public void responded (Adw.AlertDialog dialog, string response_type) { 37 | switch (response_type) { 38 | case "quit": 39 | app.kill (); 40 | break; 41 | default: 42 | break; 43 | } 44 | this.destroy (); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/settings.vala: -------------------------------------------------------------------------------- 1 | /* settings.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2023 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | using Gtk; 24 | 25 | public class Usage.Settings : GLib.Settings { 26 | private Gtk.Settings gtk_settings = Gtk.Settings.get_default (); 27 | private GLib.PowerProfileMonitor power_profile_monitor = GLib.PowerProfileMonitor.dup_default (); 28 | 29 | public uint graph_timespan { get { return settings.get_uint ("performance-graphs-timespan"); } } 30 | public uint graph_update_interval { get { return settings.get_uint ("performance-update-interval"); } } 31 | public uint list_update_interval_UI { 32 | get { 33 | uint performance_interval = settings.get_uint ("performance-update-interval"); 34 | if (performance_interval >= 5000) return performance_interval; 35 | return (int) Math.ceil(5000.0/performance_interval) * performance_interval; 36 | } 37 | } 38 | public uint list_update_pie_charts_UI { get { return settings.get_uint ("performance-update-interval"); } } 39 | public uint data_update_interval { get { return settings.get_uint ("performance-update-interval"); } } 40 | public double app_minimum_load { get { return settings.get_double ("app-minimum-load"); } } 41 | public double app_minimum_memory { get { return settings.get_double ("app-minimum-memory"); } } 42 | public bool enable_scrolling_graph { 43 | get { 44 | return gtk_settings.gtk_enable_animations 45 | && !power_profile_monitor.power_saver_enabled 46 | && !settings.get_boolean ("disable-scrolling-graphs"); 47 | } 48 | } 49 | 50 | private static Settings settings; 51 | 52 | public static Settings get_default () { 53 | if (settings == null) 54 | settings = new Settings (); 55 | 56 | return settings; 57 | } 58 | 59 | public Settings () { 60 | Object (schema_id: Config.APPLICATION_ID); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/speedometer.vala: -------------------------------------------------------------------------------- 1 | /* speedometer.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | using Gtk; 22 | 23 | [GtkTemplate (ui = "/org/gnome/Usage/ui/speedometer.ui")] 24 | public class Usage.Speedometer : Buildable, Adw.Bin { 25 | [GtkChild] 26 | private unowned Gtk.Box inner; 27 | 28 | [GtkChild] 29 | private unowned Gtk.Box content_area; 30 | 31 | private Gtk.CssProvider css_provider; 32 | 33 | private int _percentage = 0; 34 | public int percentage { 35 | get { 36 | return _percentage; 37 | } 38 | set { 39 | on_percentage_changed (value); 40 | 41 | _percentage = value; 42 | } 43 | } 44 | 45 | class construct { 46 | set_css_name ("Speedometer"); 47 | } 48 | 49 | construct { 50 | css_provider = new Gtk.CssProvider (); 51 | inner.get_style_context ().add_provider (css_provider, 52 | Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); 53 | 54 | bind_property ("width-request", content_area, "width-request", BindingFlags.BIDIRECTIONAL); 55 | bind_property ("height-request", content_area, "height-request", BindingFlags.BIDIRECTIONAL); 56 | } 57 | 58 | private void on_percentage_changed (int new_value) { 59 | if (new_value <= 0 && new_value >= 100) 60 | return; 61 | 62 | double new_angle = 90 + (360 * (new_value/100.0)); 63 | var filling_color = "@view_bg_color"; 64 | 65 | if (new_value > 50) { 66 | new_angle -= 180; 67 | filling_color = "@accent_bg_color"; 68 | } 69 | 70 | var css = 71 | @".speedometer-inner { 72 | background: linear-gradient($(new_angle)deg, transparent 50%, $filling_color 50%), 73 | linear-gradient(90deg, @view_bg_color 50%, transparent 50%); 74 | }"; 75 | 76 | css_provider.load_from_string (css); 77 | } 78 | 79 | public void add_child (Builder builder, Object child, string? type) { 80 | /* This is a Vala bug. It will cause a "warning". 81 | (content_area as Buildable).add_child (builder, child, type);*/ 82 | if (child is Gtk.Label) { 83 | content_area.append (child as Gtk.Widget); 84 | 85 | return; 86 | } 87 | 88 | base.add_child (builder, child, type); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/stack-list.vala: -------------------------------------------------------------------------------- 1 | /* stack-list.vala 2 | * 3 | * Copyright (C) 2023 Markus Göllnitz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Markus Göllnitz 19 | */ 20 | 21 | public class Usage.StackList : Gtk.Box { 22 | private Gtk.ListBox list_box = new Gtk.ListBox (); 23 | private Queue models = new Queue(); 24 | private int depth = 0; 25 | public Gtk.SelectionMode selection_mode { 26 | get { return list_box.selection_mode; } 27 | set { list_box.selection_mode = value; } 28 | } 29 | 30 | public void init (Gtk.ListBoxCreateWidgetFunc row_function) { 31 | Gtk.ScrolledWindow scrolled_window = new Gtk.ScrolledWindow (); 32 | 33 | scrolled_window.vexpand = true; 34 | scrolled_window.hexpand = true; 35 | scrolled_window.child = list_box; 36 | 37 | list_box.margin_top = 12; 38 | list_box.margin_bottom = 12; 39 | list_box.margin_start = 12; 40 | list_box.margin_end = 12; 41 | list_box.valign = Gtk.Align.START; 42 | list_box.add_css_class ("boxed-list"); 43 | 44 | this.append (scrolled_window); 45 | 46 | list_box.row_activated.connect ((box, row) => { 47 | this.row_activated (row); 48 | }); 49 | this.model_changed.connect ((model) => { 50 | list_box.bind_model (model, (item) => { 51 | return row_function (item); 52 | }); 53 | }); 54 | } 55 | 56 | public ListStore get_model () { 57 | return models.peek_head (); 58 | } 59 | 60 | public int get_depth () { 61 | return depth; 62 | } 63 | 64 | public void push_layer (ListStore model) { 65 | models.push_head (model); 66 | this.model_changed (model); 67 | depth += 1; 68 | } 69 | 70 | public bool layer_up () { 71 | ListStore previous_head = models.pop_head (); 72 | if (models.peek_head () != null) { 73 | this.model_changed (models.peek_head ()); 74 | } 75 | depth -= 1; 76 | return previous_head != null; 77 | } 78 | 79 | public signal void model_changed (ListStore model); 80 | public signal void row_activated (Gtk.ListBoxRow row); 81 | } 82 | -------------------------------------------------------------------------------- /src/storage/query-builder.vala: -------------------------------------------------------------------------------- 1 | /* query-builder.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | public class Usage.StorageQueryBuilder { 22 | public string enumerate_children (string uri, bool recursive = false) { 23 | string filter; 24 | if (recursive) { 25 | filter = @"tracker:uri-is-descendant ('$uri', ?uri)"; 26 | } else { 27 | filter = @"tracker:uri-is-parent ('$uri', ?uri)"; 28 | } 29 | 30 | return @"SELECT ?uri rdf:type(?u) FROM tracker:FileSystem { ?u nie:url ?uri . FILTER($filter) }"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/storage/sparql-controller.vala: -------------------------------------------------------------------------------- 1 | /* sparql-controller.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | public class Usage.SparqlController : GLib.Object { 22 | private Tsparql.SparqlConnection connection; 23 | private StorageQueryBuilder query_builder; 24 | private GLib.ListStore model; 25 | 26 | construct { 27 | this.query_builder = new StorageQueryBuilder (); 28 | } 29 | 30 | public SparqlController (Tsparql.SparqlConnection connection) { 31 | this.connection = connection; 32 | } 33 | 34 | public void set_model (GLib.ListStore model) { 35 | this.model = model; 36 | } 37 | 38 | public async uint64 enumerate_children (string uri, UserDirectory? dir, Cancellable cancellable) { 39 | string query = this.query_builder.enumerate_children (uri); 40 | 41 | uint64 uri_size = 0; 42 | try { 43 | 44 | SparqlWorker worker = yield new SparqlWorker (connection, query); 45 | string n_uri = null; 46 | string file_type = null; 47 | 48 | File parent = File.new_for_uri (uri); 49 | uint64 parent_size = 1; 50 | if (parent != null) 51 | parent_size = yield this.get_file_size (uri); 52 | 53 | while (yield worker.fetch_next (out n_uri, out file_type)) { 54 | if (!cancellable.is_cancelled ()) { 55 | File file = File.new_for_uri (n_uri); 56 | StorageViewItem item = StorageViewItem.from_file (file); 57 | 58 | if (item == null) 59 | continue; 60 | 61 | item.ontology = file_type; 62 | item.dir = dir; 63 | 64 | if (item.type == FileType.DIRECTORY) { 65 | item.size = yield this.get_file_size (n_uri); 66 | } 67 | 68 | item.percentage = item.size * 100 / (double) parent_size; 69 | uri_size += item.size; 70 | 71 | model.insert_sorted (item, (a, b) => { 72 | StorageViewItem item_a = a as StorageViewItem; 73 | StorageViewItem item_b = b as StorageViewItem; 74 | 75 | if (item_a.custom_type == StorageViewType.UP_FOLDER || item_a.size > item_b.size) { 76 | return -1; 77 | } 78 | 79 | if (item_b.custom_type == StorageViewType.UP_FOLDER || item_b.size > item_a.size) { 80 | return 1; 81 | } 82 | 83 | return 0; 84 | }); 85 | } else 86 | return uri_size; 87 | } 88 | } catch (GLib.Error error) { 89 | warning (error.message); 90 | } 91 | 92 | return uri_size; 93 | } 94 | 95 | private uint64 get_g_file_size (string uri) { 96 | try { 97 | File file = File.new_for_uri (uri); 98 | FileInfo info = file.query_info (FileAttribute.STANDARD_SIZE, FileQueryInfoFlags.NOFOLLOW_SYMLINKS); 99 | 100 | return info.get_size (); 101 | } catch (GLib.Error error) { 102 | return 0; 103 | } 104 | } 105 | 106 | public async uint64 get_file_size (string uri) throws GLib.Error { 107 | uint64 total = 0; 108 | 109 | string query = this.query_builder.enumerate_children (uri, true); 110 | 111 | SparqlWorker worker = yield new SparqlWorker (connection, query); 112 | 113 | string n_uri = null; 114 | while (yield worker.fetch_next (out n_uri, null)) 115 | total += this.get_g_file_size (n_uri); 116 | 117 | return total; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/storage/sparql-worker.vala: -------------------------------------------------------------------------------- 1 | /* sparql-worker.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | public class Usage.SparqlWorker { 22 | private Tsparql.SparqlCursor cursor; 23 | 24 | public async SparqlWorker (Tsparql.SparqlConnection connection, string query) throws GLib.Error { 25 | this.cursor = yield connection.query_async (query); 26 | } 27 | 28 | public async bool fetch_next (out string uri, out string file_type) throws GLib.Error { 29 | uri = file_type = null; 30 | 31 | if (!(yield this.cursor.next_async ())) 32 | return false; 33 | 34 | uri = this.cursor.get_string (0); 35 | string type = this.cursor.get_string (1); 36 | file_type = type.substring (type.last_index_of_char ('/') + 1, -1); 37 | if (uri == null) 38 | return yield this.fetch_next (out uri, out file_type); 39 | 40 | return true; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/storage/storage-actionbar.vala: -------------------------------------------------------------------------------- 1 | /* storage-actionbar.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * Copyright (C) 2023 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | [GtkTemplate (ui = "/org/gnome/Usage/ui/storage-actionbar.ui")] 24 | public class Usage.StorageActionBar : Adw.Bin { 25 | private unowned List selected_items; 26 | 27 | [GtkChild] 28 | private unowned Gtk.Label size_label; 29 | 30 | public signal void refresh_listbox (); 31 | 32 | public void update_selected_items (List selected_items) { 33 | this.selected_items = selected_items; 34 | 35 | uint64 size = 0; 36 | foreach (var item in selected_items) { 37 | size += item.size; 38 | } 39 | 40 | ulong most_significant; 41 | string size_formatted = Utils.format_size_values (size, out most_significant); 42 | size_label.label = GLib.ngettext("%s selected", "%s selected", most_significant).printf (size_formatted); 43 | } 44 | 45 | [GtkCallback] 46 | private void delete_clicked () { 47 | string display_message = _("Are you sure you want to permanently delete selected items?"); 48 | string display_explanation = _("If you delete these items, they will be permanently lost."); 49 | 50 | Adw.AlertDialog dialog = new Adw.AlertDialog (display_message, display_explanation); 51 | 52 | dialog.add_response ("cancel", _("Cancel")); 53 | dialog.add_response ("delete", _("Delete")); 54 | 55 | dialog.set_response_appearance ("delete", Adw.ResponseAppearance.DESTRUCTIVE); 56 | 57 | dialog.set_default_response ("cancel"); 58 | dialog.set_close_response ("cancel"); 59 | 60 | dialog.response.connect ((dialog, response_type) => { 61 | switch (response_type) { 62 | case "replace": 63 | foreach (var item in selected_items) { 64 | if (item.type == FileType.DIRECTORY && item.custom_type == StorageViewType.ROOT_ITEM) 65 | delete_file (item.uri, false); 66 | else 67 | delete_file (item.uri, true); 68 | } 69 | refresh_listbox (); 70 | break; 71 | case "cancel": 72 | default: 73 | break; 74 | } 75 | dialog.destroy (); 76 | }); 77 | dialog.present ((Gtk.Window) this.get_root ()); 78 | } 79 | 80 | private void delete_file (string uri, bool delete_basefile) { 81 | var file = File.new_for_uri (uri); 82 | var type = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS); 83 | 84 | try { 85 | if (type == FileType.DIRECTORY) { 86 | FileInfo info; 87 | FileEnumerator enumerator = file.enumerate_children ("standard::*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null); 88 | 89 | while ((info = enumerator.next_file (null)) != null) { 90 | var child = file.get_child (info.get_name ()); 91 | delete_file (child.get_uri (), true); 92 | } 93 | } 94 | 95 | if (delete_basefile) 96 | file.@delete (); 97 | } 98 | catch (Error e) { 99 | stderr.printf ("Error: %s\n", e.message); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/storage/storage-graph.vala: -------------------------------------------------------------------------------- 1 | /* storage-graph.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Petr Štětka 19 | */ 20 | 21 | using Gtk; 22 | 23 | public class Usage.StorageGraph : Gtk.DrawingArea { 24 | private unowned List selected_items; 25 | private unowned GLib.ListStore _model; 26 | private uint64 selected_size = 0; 27 | 28 | public virtual GLib.ListStore model { 29 | get { return _model; } 30 | set { 31 | _model = value; 32 | value.items_changed.connect (this.queue_draw); 33 | this.queue_draw (); 34 | } 35 | } 36 | 37 | public uint min_percentage_shown_files { get; set; } 38 | 39 | class construct { 40 | set_css_name ("StorageGraph"); 41 | } 42 | 43 | construct { 44 | this.set_draw_func (draw_storage_graph); 45 | } 46 | 47 | public enum Circle { 48 | HOME, 49 | ROOT, 50 | BASE 51 | } 52 | 53 | public void update_selected_items (List selected_items) { 54 | this.selected_items = selected_items; 55 | 56 | uint64 size = 0; 57 | foreach (var item in selected_items) 58 | size += item.size; 59 | 60 | selected_size = size; 61 | this.queue_draw (); 62 | } 63 | 64 | private void draw_circle (Cairo.Context context, double x, double y, double radius, int section, Circle circle) { 65 | double start_angle = 0; 66 | double final_angle = - Math.PI / 2.0; 67 | double ratio = 0; 68 | Gdk.RGBA background_color; 69 | this.get_style_context ().lookup_color ("window_bg_color", out background_color); 70 | Gdk.RGBA foreground_color = this.get_color (); 71 | 72 | for (int i = 0; i < this.model.get_n_items (); i++) { 73 | StorageViewItem item = (StorageViewItem) this.model.get_item (i); 74 | 75 | if (item.custom_type == StorageViewType.UP_FOLDER || item.size == 0) 76 | continue; 77 | 78 | double item_radius = radius; 79 | Gdk.RGBA fill_color = item.color; 80 | 81 | if (this.selected_items.find (item) != null) 82 | item_radius += radius / 6; 83 | 84 | context.set_line_width (2.0); 85 | start_angle = final_angle; 86 | 87 | if (item.percentage < 0.3) 88 | ratio = ratio + ((double) 0.3 / 100); 89 | else 90 | ratio = ratio + ((double) item.percentage / 100); 91 | 92 | final_angle = ratio * 2 * Math.PI - Math.PI / 2.0; 93 | if (final_angle >= (2 * Math.PI - Math.PI / 2.0)) 94 | final_angle = 2 * Math.PI - Math.PI / 2.0; 95 | 96 | context.move_to (x, y); 97 | Gdk.cairo_set_source_rgba (context, fill_color); 98 | context.arc (x, y, item_radius, start_angle, final_angle); 99 | context.line_to (x, y); 100 | context.fill_preserve (); 101 | Gdk.cairo_set_source_rgba (context, foreground_color); 102 | context.stroke (); 103 | 104 | if (start_angle >= (2 * Math.PI - Math.PI / 2.0)) 105 | break; 106 | } 107 | 108 | context.move_to (x, y); 109 | context.line_to (x, y - radius); 110 | context.stroke (); 111 | 112 | context.arc (x, y, radius / 1.8, 0, 2 * Math.PI); 113 | Gdk.cairo_set_source_rgba (context, background_color); 114 | context.fill_preserve (); 115 | Gdk.cairo_set_source_rgba (context, foreground_color); 116 | context.stroke (); 117 | } 118 | 119 | private void draw_storage_graph (Gtk.DrawingArea drawing_area, Cairo.Context context, int width, int height) { 120 | double x = 0; 121 | double y = 0; 122 | double radius = 0; 123 | 124 | radius = int.min (width, height) / 2.0; 125 | radius -= radius / 4; 126 | x = width / 2.0; 127 | y = height / 2.0; 128 | 129 | draw_circle (context, x, y, radius, 0, Circle.BASE); 130 | draw_selected_size_text (context); 131 | } 132 | 133 | private void draw_selected_size_text (Cairo.Context context) { 134 | if (selected_size == 0) 135 | return; 136 | 137 | var layout = create_pango_layout (null); 138 | var text = Utils.format_size_values (selected_size); 139 | 140 | int height = this.get_height (); 141 | int width = this.get_width (); 142 | double radius = int.min (width, height) / 22; 143 | 144 | var text_color = this.get_root ().get_color (); 145 | var text_color_string = "#%02x%02x%02x".printf ( 146 | (uint) (Math.round (text_color.red * 255)), 147 | (uint) (Math.round (text_color.green * 255)), 148 | (uint) (Math.round (text_color.blue * 255))).up (); 149 | 150 | var markup = @"$text"; 151 | layout.set_markup (markup, -1); 152 | 153 | Pango.Rectangle layout_rect; 154 | layout.get_pixel_extents (null, out layout_rect); 155 | layout.set_alignment (Pango.Alignment.CENTER); 156 | 157 | var x = (width - layout_rect.width) / 2; 158 | var y = (height - layout_rect.height) / 2; 159 | get_style_context ().render_layout (context, x, y, layout); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/storage/storage-view-row.vala: -------------------------------------------------------------------------------- 1 | /* storage-view-row.vala 2 | * 3 | * Copyright (C) 2018 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | [GtkTemplate (ui = "/org/gnome/Usage/ui/storage-view-row.ui")] 22 | public class Usage.StorageViewRow : Gtk.ListBoxRow { 23 | public string label { 24 | get { 25 | return title.label; 26 | } 27 | set { 28 | title.label = value; 29 | } 30 | } 31 | 32 | [GtkChild] 33 | private unowned Gtk.Label title; 34 | 35 | [GtkChild] 36 | public unowned Gtk.CheckButton check_button; 37 | 38 | [GtkChild] 39 | public unowned Gtk.Label size_label; 40 | 41 | [GtkChild] 42 | public unowned Adw.Spinner spinner; 43 | 44 | [GtkChild] 45 | public unowned Gtk.Box tag; 46 | 47 | public enum TagSize { 48 | SMALL, 49 | BIG, 50 | } 51 | public TagSize tag_size { 52 | get { 53 | return (tag.width_request == 20 ? TagSize.BIG : TagSize.SMALL); 54 | } 55 | set { 56 | if (value == TagSize.BIG) { 57 | tag.width_request = tag.height_request = 20; 58 | } 59 | } 60 | } 61 | 62 | public bool selected { 63 | get { return check_button.active; } 64 | } 65 | 66 | public signal void check_button_toggled (); 67 | 68 | public StorageViewItem item; 69 | 70 | public StorageViewRow.from_item (StorageViewItem item) { 71 | this.item = item; 72 | 73 | this.name = "row-" + direct_hash (this).to_string (); 74 | 75 | tag.add_css_class (item.style_class); 76 | item.color = item.get_base_color (); 77 | 78 | check_button.visible = item.show_check_button; 79 | check_button.toggled.connect (() => { 80 | check_button_toggled (); 81 | }); 82 | 83 | item.notify.connect (() => { 84 | set_up (); 85 | }); 86 | set_up (); 87 | 88 | if (item.type == FileType.DIRECTORY || item.custom_type != StorageViewType.NONE) 89 | tag.width_request = tag.height_request = 20; 90 | 91 | if (item.custom_type == StorageViewType.UP_FOLDER) { 92 | this.add_css_class ("up-folder"); 93 | 94 | if (!item.loaded) { 95 | spinner.visible = true; 96 | size_label.visible = false; 97 | } 98 | 99 | item.notify["loaded"].connect (() => { 100 | if (item.loaded) { 101 | spinner.visible = false; 102 | size_label.visible = true; 103 | } 104 | }); 105 | } 106 | } 107 | 108 | private void set_up () { 109 | title.label = item.name; 110 | size_label.label = Utils.format_size_values (item.size); 111 | change_color (item.color); 112 | } 113 | 114 | private void change_color (Gdk.RGBA color) { 115 | Gtk.CssProvider css_provider = new Gtk.CssProvider (); 116 | string css = @"#$name { --storage-row-colour: $color; }"; 117 | 118 | css_provider.load_from_string (css); 119 | Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), css_provider, 120 | Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/swap-speedometer.vala: -------------------------------------------------------------------------------- 1 | /* swap-speedometer.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: Felipe Borges 19 | */ 20 | 21 | using Gtk; 22 | 23 | [GtkTemplate (ui = "/org/gnome/Usage/ui/swap-speedometer.ui")] 24 | public class Usage.SwapSpeedometer : Adw.Bin { 25 | [GtkChild] 26 | private unowned Usage.Speedometer speedometer; 27 | 28 | [GtkChild] 29 | private unowned Gtk.Label label; 30 | 31 | [GtkChild] 32 | private unowned Gtk.Label swap_used; 33 | 34 | [GtkChild] 35 | private unowned Gtk.Label swap_available; 36 | 37 | private double swap_usage { get; set; } 38 | 39 | construct { 40 | var monitor = SystemMonitor.get_default (); 41 | Timeout.add_seconds (1, () => { 42 | var available = (monitor.swap_total - monitor.swap_usage); 43 | var percentage = 0.0; 44 | if (monitor.swap_total > 0) 45 | percentage = (((double) monitor.swap_usage / monitor.swap_total) * 100); 46 | 47 | this.speedometer.percentage = (int) percentage; 48 | label.label = "%d".printf ((int) percentage) + "%"; 49 | 50 | swap_used.label = Utils.format_size_values (monitor.swap_usage); 51 | swap_available.label = Utils.format_size_values (available); 52 | 53 | return true; 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/utils.vala: -------------------------------------------------------------------------------- 1 | /* utils.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2023 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | public class Usage.Utils { 24 | public static string unescape (string escaped) { 25 | string unescaped = escaped; 26 | unichar c = 0; 27 | int index = 0; 28 | while (unescaped.get_next_char (ref index, out c)) { 29 | if (c != '\\') { 30 | continue; 31 | } 32 | unescaped.get_next_char (ref index, out c); 33 | if (c == 'x') { 34 | string char_point = unescaped.slice (index, index + 2); 35 | char unescaped_char = 0; 36 | for (int i = 0; i < char_point.length; i++) { 37 | char offset = '0'; 38 | if (char_point.data[i] >= 'A') offset = 'A' - 10; 39 | if (char_point.data[i] >= 'a') offset = 'a' - 10; 40 | unescaped_char = unescaped_char * 16 + char_point.data[i] - offset; 41 | } 42 | unescaped = unescaped.splice (index - 2, index + 2, unescaped_char.to_string ()); 43 | } 44 | } 45 | return unescaped.compress (); 46 | } 47 | 48 | public static string format_size_values (uint64 @value, out ulong? most_significant = null) { 49 | uint64 significant = @value; 50 | while (significant > 1000) { 51 | significant /= 1000; 52 | } 53 | most_significant = (ulong) significant; 54 | 55 | if (@value >= 1000) 56 | return GLib.format_size (@value); 57 | else 58 | return _("%llu B").printf (@value); 59 | } 60 | 61 | public static string format_size_speed_values (uint64 @value) { 62 | if (@value >= 1000) 63 | return _("%s/s").printf (GLib.format_size (@value)); 64 | else 65 | return _("%llu B/s").printf (@value); 66 | } 67 | 68 | public static Gdk.RGBA generate_color (Gdk.RGBA default_color, uint order, uint all_count, bool reverse = false) { 69 | float step = 100 / (float) all_count; 70 | uint half_count = all_count / 2; 71 | 72 | if (order >= all_count) 73 | order = all_count - 1; 74 | 75 | if (order > (all_count / 2)) { 76 | float percentage = step * (order - half_count); 77 | if (reverse) 78 | return Utils.color_lighter (default_color, percentage); 79 | else 80 | return Utils.color_darker (default_color, percentage); 81 | } else { 82 | float percentage = step * (half_count - (order-1)); 83 | if (reverse) 84 | return Utils.color_darker (default_color, percentage); 85 | else 86 | return Utils.color_lighter (default_color, percentage); 87 | } 88 | } 89 | 90 | public static Gdk.RGBA color_darker (Gdk.RGBA color, float percentage) { 91 | color.red = color_field_darker (color.red, percentage); 92 | color.green = color_field_darker (color.green, percentage); 93 | color.blue = color_field_darker (color.blue, percentage); 94 | 95 | return color; 96 | } 97 | 98 | public static Gdk.RGBA color_lighter (Gdk.RGBA color, float percentage) { 99 | color.red = color_field_lighter (color.red, percentage); 100 | color.green = color_field_lighter (color.green, percentage); 101 | color.blue = color_field_lighter (color.blue, percentage); 102 | 103 | return color; 104 | } 105 | 106 | private static float color_field_darker (float field, float percentage) { 107 | field = field * 255; 108 | return (field - ((field / 100) * percentage)) / 255; 109 | } 110 | 111 | private static float color_field_lighter (float field, float percentage) { 112 | field = field * 255; 113 | return (field + (((255 - field) / 100) * percentage)) / 255; 114 | } 115 | } 116 | 117 | public enum Usage.UserAccountType { 118 | STANDARD, 119 | ADMINISTRATOR; 120 | } 121 | 122 | [DBus (name = "org.freedesktop.Accounts")] 123 | public interface Usage.Fdo.Accounts : Object { 124 | public abstract async string FindUserById (int64 id) throws GLib.Error; 125 | } 126 | 127 | [DBus (name = "org.freedesktop.Accounts.User")] 128 | public interface Usage.Fdo.AccountsUser : Object { 129 | public abstract bool SystemAccount { get; } 130 | public abstract bool LocalAccount { get; } 131 | public abstract int32 AccountType { get; } 132 | public abstract string RealName { owned get; } 133 | public abstract string UserName { owned get; } 134 | public abstract uint64 Uid { get; } 135 | } 136 | -------------------------------------------------------------------------------- /src/view.vala: -------------------------------------------------------------------------------- 1 | /* view.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2023–2024 Markus Göllnitz 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: Petr Štětka 20 | * Markus Göllnitz 21 | */ 22 | 23 | public abstract class Usage.View : Adw.BreakpointBin { 24 | public string title; 25 | public string icon_name; 26 | public Gtk.Widget? switcher_widget; 27 | public bool search_available = false; 28 | 29 | construct { 30 | this.width_request = 360; 31 | this.height_request = 210; 32 | } 33 | 34 | protected View () { 35 | } 36 | 37 | public virtual void set_search_text (string query) { 38 | if (search_available) { 39 | critical ("Search Feature Not Yet Implemented"); 40 | } 41 | } 42 | 43 | public virtual bool prerequisite_fulfilled () { 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/window.vala: -------------------------------------------------------------------------------- 1 | /* window.vala 2 | * 3 | * Copyright (C) 2017 Red Hat, Inc. 4 | * Copyright (C) 2020 Adrien Plazas 5 | * Copyright (C) 2024 Markus Göllnitz 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | * 20 | * Authors: Petr Štětka 21 | * Markus Göllnitz 22 | */ 23 | 24 | [GtkTemplate (ui = "/org/gnome/Usage/ui/window.ui")] 25 | public class Usage.Window : Adw.ApplicationWindow { 26 | [GtkChild] 27 | private unowned Adw.ViewStack stack; 28 | 29 | [GtkChild] 30 | private unowned Gtk.Revealer performance_search_revealer; 31 | 32 | [GtkChild] 33 | private unowned Gtk.ToggleButton performance_search_button; 34 | 35 | [GtkChild] 36 | private unowned Gtk.SearchEntry search_entry; 37 | 38 | [GtkChild] 39 | private unowned Adw.ToolbarView content_area; 40 | 41 | private View[] views; 42 | 43 | public Window (Gtk.Application application) { 44 | GLib.Object (application : application); 45 | 46 | if (Config.PROFILE == "Devel") { 47 | this.add_css_class ("devel"); 48 | } 49 | 50 | views = new View[] { 51 | new CpuView (), 52 | new MemoryView (), 53 | new NetworkView (), 54 | new StorageView (), 55 | }; 56 | 57 | foreach (var view in views) { 58 | if (view.prerequisite_fulfilled ()) { 59 | stack.add_titled_with_icon (view, view.name, view.title, view.icon_name); 60 | } 61 | } 62 | 63 | this.search_entry.set_key_capture_widget (content_area); 64 | } 65 | 66 | public void action_on_search () { 67 | if (((View) this.stack.visible_child).search_available) { 68 | performance_search_button.set_active (!performance_search_button.get_active ()); 69 | } 70 | } 71 | 72 | [GtkCallback] 73 | private void on_performance_search_button_toggled () { 74 | if (!this.performance_search_button.active) { 75 | this.search_entry.text = ""; 76 | } else { 77 | search_entry.grab_focus (); 78 | } 79 | } 80 | 81 | [GtkCallback] 82 | private void on_search_entry_changed () { 83 | foreach (View view in views) { 84 | view.set_search_text (search_entry.get_text ()); 85 | } 86 | } 87 | 88 | [GtkCallback] 89 | private bool on_search_entry_key_pressed (uint keyvalue, uint keycode, Gdk.ModifierType state) { 90 | if (keyvalue == Gdk.Key.Down || keyvalue == Gdk.Key.KP_Down) { 91 | return this.child_focus (Gtk.DirectionType.TAB_FORWARD); 92 | } 93 | 94 | if (keyvalue == Gdk.Key.Escape) { 95 | this.performance_search_button.active = false; 96 | } 97 | 98 | return false; 99 | } 100 | 101 | [GtkCallback] 102 | private void on_visible_child_changed () { 103 | bool search_available = ((View) this.stack.visible_child).search_available; 104 | 105 | this.performance_search_button.active &= search_available; 106 | this.performance_search_revealer.reveal_child = search_available; 107 | 108 | SimpleAction performance_action = this.get_application ().lookup_action ("filter-processes") as SimpleAction; 109 | if (performance_action != null) { 110 | performance_action.set_enabled (search_available); 111 | } 112 | } 113 | 114 | [GtkCallback] 115 | string get_title_for_usage_view (Usage.View? view) { 116 | if (view != null) { 117 | return view.title; 118 | } 119 | return ""; 120 | } 121 | 122 | /* TODO: use GtkCallback attribute, see https://gitlab.gnome.org/GNOME/vala/-/issues/1523 */ 123 | static construct { 124 | bind_template_callback_full ("get_switcher_widget_for_usage_view", (Callback) get_switcher_widget_for_usage_view); 125 | } 126 | 127 | Gtk.Widget get_switcher_widget_for_usage_view (Usage.View? view) { 128 | Gtk.Widget? switcher_widget = null; 129 | string fallback_icon_name = "speedometer-symbolic"; 130 | 131 | if (view != null) { 132 | switcher_widget = view.switcher_widget; 133 | fallback_icon_name = view.icon_name; 134 | } 135 | 136 | if (switcher_widget == null) { 137 | Gtk.Image fallback_icon = new Gtk.Image.from_icon_name (fallback_icon_name); 138 | fallback_icon.icon_size = Gtk.IconSize.LARGE; 139 | switcher_widget = fallback_icon; 140 | } 141 | 142 | return switcher_widget; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /vapi/config.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cprefix = "", lower_case_cprefix = "")] 2 | namespace Config { 3 | public const string VERSION; 4 | public const string GETTEXT_PACKAGE; 5 | public const string GNOMELOCALEDIR; 6 | public const string APPLICATION_ID; 7 | public const string APPLICATION_RESOURCE_PATH; 8 | public const string PROFILE; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /vapi/stopgap.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cprefix = "", lower_case_cprefix = "")] 2 | namespace StopGap { 3 | 4 | [CCode (cheader_filename = "fcntl.h")] 5 | public const int O_DIRECTORY; 6 | [CCode (cheader_filename = "fcntl.h")] 7 | public const int O_CLOEXEC; 8 | [CCode (cheader_filename = "fcntl.h")] 9 | public const int AT_FDCWD; 10 | [CCode (cheader_filename = "fcntl.h", feature_test_macro = "_GNU_SOURCE")] 11 | public int openat (int dirfd, string path, int oflag, Posix.mode_t mode=0); 12 | 13 | } --------------------------------------------------------------------------------