├── .editorconfig
├── .github
└── workflows
│ ├── ci.yml
│ ├── gettext.yml
│ └── release.yml
├── .gitignore
├── .valalintignore
├── AUTHORS
├── LICENSE
├── README.md
├── data
├── css.gresource.xml
├── database
│ ├── README.md
│ ├── cpu_bugs.csv
│ └── cpu_features.csv
├── icons
│ ├── 16
│ │ └── io.elementary.monitor.svg
│ ├── 24
│ │ └── io.elementary.monitor.svg
│ ├── 32
│ │ └── io.elementary.monitor.svg
│ ├── 48
│ │ └── io.elementary.monitor.svg
│ ├── 64
│ │ └── io.elementary.monitor.svg
│ ├── 128
│ │ └── io.elementary.monitor.svg
│ ├── cpu-symbolic.svg
│ ├── extra
│ │ ├── 16
│ │ │ ├── bash.svg
│ │ │ └── docker.svg
│ │ ├── 48
│ │ │ ├── bash.svg
│ │ │ └── docker.svg
│ │ └── 64
│ │ │ ├── bash.svg
│ │ │ └── docker.svg
│ ├── file-deleted-symbolic.svg
│ ├── gpu-symbolic.svg
│ ├── gpu-vram-symbolic.svg
│ ├── icons.indicator.gresource.xml
│ ├── ram-symbolic.svg
│ ├── swap-symbolic.svg
│ ├── temperature-gpu-symbolic.svg
│ └── temperature-sensor-symbolic.svg
├── io.elementary.monitor.appdata.xml.in
├── io.elementary.monitor.gschema.xml
├── meson.build
├── monitor.desktop.in
├── screenshots
│ ├── monitor-containers.png
│ ├── monitor-processes.png
│ └── monitor-system.png
└── stylesheet
│ ├── _index.scss
│ ├── _palette.scss
│ ├── monitor-dark.scss
│ ├── monitor-light.scss
│ └── monitor-retrofit.scss
├── design
├── GfknBzs.jpg
├── application_manager_by_nicekiwi-d698q3a.png
├── brainstorm
├── task_manager_by_mashnoon33-d7x4s3f.png
└── tasku.png
├── meson.build
├── meson
├── bump_version.py
├── get_cpu_features_and_bugs.py
├── list-app-src.sh
└── post_install.py
├── meson_options.txt
├── po
├── LINGUAS
├── POTFILES
├── aa.po
├── ab.po
├── ace.po
├── ae.po
├── af.po
├── ak.po
├── am.po
├── an.po
├── ar.po
├── as.po
├── ast.po
├── av.po
├── ay.po
├── az.po
├── ba.po
├── be.po
├── bg.po
├── bh.po
├── bi.po
├── bm.po
├── bn.po
├── bo.po
├── br.po
├── bs.po
├── ca.po
├── ca@valencia.po
├── ce.po
├── ch.po
├── ckb.po
├── co.po
├── cr.po
├── cs.po
├── cu.po
├── cv.po
├── cy.po
├── da.po
├── de.po
├── dv.po
├── dz.po
├── ee.po
├── el.po
├── en_AU.po
├── en_CA.po
├── en_GB.po
├── en_ZA.po
├── eo.po
├── es.po
├── et.po
├── eu.po
├── extra
│ ├── LINGUAS
│ ├── POTFILES
│ ├── aa.po
│ ├── ab.po
│ ├── ace.po
│ ├── ae.po
│ ├── af.po
│ ├── ak.po
│ ├── am.po
│ ├── an.po
│ ├── ar.po
│ ├── as.po
│ ├── ast.po
│ ├── av.po
│ ├── ay.po
│ ├── az.po
│ ├── ba.po
│ ├── be.po
│ ├── bg.po
│ ├── bh.po
│ ├── bi.po
│ ├── bm.po
│ ├── bn.po
│ ├── bo.po
│ ├── br.po
│ ├── bs.po
│ ├── ca.po
│ ├── ca@valencia.po
│ ├── ce.po
│ ├── ch.po
│ ├── ckb.po
│ ├── co.po
│ ├── cr.po
│ ├── cs.po
│ ├── cu.po
│ ├── cv.po
│ ├── cy.po
│ ├── da.po
│ ├── de.po
│ ├── dv.po
│ ├── dz.po
│ ├── ee.po
│ ├── el.po
│ ├── en_AU.po
│ ├── en_CA.po
│ ├── en_GB.po
│ ├── en_ZA.po
│ ├── eo.po
│ ├── es.po
│ ├── et.po
│ ├── eu.po
│ ├── extra.pot
│ ├── fa.po
│ ├── ff.po
│ ├── fi.po
│ ├── fil.po
│ ├── fj.po
│ ├── fo.po
│ ├── fr.po
│ ├── fr_CA.po
│ ├── frp.po
│ ├── fy.po
│ ├── ga.po
│ ├── gd.po
│ ├── gl.po
│ ├── gn.po
│ ├── gu.po
│ ├── gv.po
│ ├── ha.po
│ ├── he.po
│ ├── hi.po
│ ├── ho.po
│ ├── hr.po
│ ├── ht.po
│ ├── hu.po
│ ├── hy.po
│ ├── hz.po
│ ├── ia.po
│ ├── id.po
│ ├── id_ID.po
│ ├── ie.po
│ ├── ig.po
│ ├── ii.po
│ ├── ik.po
│ ├── io.po
│ ├── is.po
│ ├── it.po
│ ├── iu.po
│ ├── ja.po
│ ├── jv.po
│ ├── ka.po
│ ├── kg.po
│ ├── ki.po
│ ├── kj.po
│ ├── kk.po
│ ├── kl.po
│ ├── km.po
│ ├── kn.po
│ ├── ko.po
│ ├── kr.po
│ ├── ks.po
│ ├── ku.po
│ ├── kv.po
│ ├── kw.po
│ ├── ky.po
│ ├── la.po
│ ├── lb.po
│ ├── lg.po
│ ├── li.po
│ ├── ln.po
│ ├── lo.po
│ ├── lt.po
│ ├── lu.po
│ ├── lv.po
│ ├── meson.build
│ ├── mg.po
│ ├── mh.po
│ ├── mi.po
│ ├── mk.po
│ ├── ml.po
│ ├── mn.po
│ ├── mo.po
│ ├── mr.po
│ ├── ms.po
│ ├── mt.po
│ ├── my.po
│ ├── na.po
│ ├── nb.po
│ ├── nd.po
│ ├── ne.po
│ ├── ng.po
│ ├── nl.po
│ ├── nn.po
│ ├── no.po
│ ├── nr.po
│ ├── nv.po
│ ├── ny.po
│ ├── oc.po
│ ├── oj.po
│ ├── om.po
│ ├── or.po
│ ├── os.po
│ ├── pa.po
│ ├── pap.po
│ ├── pi.po
│ ├── pl.po
│ ├── ps.po
│ ├── pt.po
│ ├── pt_BR.po
│ ├── qu.po
│ ├── rm.po
│ ├── rn.po
│ ├── ro.po
│ ├── ru.po
│ ├── rue.po
│ ├── rw.po
│ ├── sa.po
│ ├── sc.po
│ ├── sco.po
│ ├── sd.po
│ ├── se.po
│ ├── sg.po
│ ├── si.po
│ ├── sk.po
│ ├── sl.po
│ ├── sm.po
│ ├── sma.po
│ ├── sn.po
│ ├── so.po
│ ├── sq.po
│ ├── sr.po
│ ├── sr@latin.po
│ ├── ss.po
│ ├── st.po
│ ├── su.po
│ ├── sv.po
│ ├── sw.po
│ ├── szl.po
│ ├── ta.po
│ ├── te.po
│ ├── tg.po
│ ├── th.po
│ ├── ti.po
│ ├── tk.po
│ ├── tl.po
│ ├── tn.po
│ ├── to.po
│ ├── tr.po
│ ├── ts.po
│ ├── tt.po
│ ├── tw.po
│ ├── ty.po
│ ├── ug.po
│ ├── uk.po
│ ├── ur.po
│ ├── uz.po
│ ├── ve.po
│ ├── vi.po
│ ├── vo.po
│ ├── wa.po
│ ├── wo.po
│ ├── xh.po
│ ├── yi.po
│ ├── yo.po
│ ├── za.po
│ ├── zh.po
│ ├── zh_HK.po
│ ├── zh_Hans.po
│ ├── zh_Hant.po
│ └── zu.po
├── fa.po
├── ff.po
├── fi.po
├── fil.po
├── fj.po
├── fo.po
├── fr.po
├── fr_CA.po
├── frp.po
├── fy.po
├── ga.po
├── gd.po
├── gl.po
├── gn.po
├── gu.po
├── gv.po
├── ha.po
├── he.po
├── hi.po
├── ho.po
├── hr.po
├── ht.po
├── hu.po
├── hy.po
├── hz.po
├── ia.po
├── id.po
├── id_ID.po
├── ie.po
├── ig.po
├── ii.po
├── ik.po
├── io.elementary.monitor.pot
├── io.po
├── is.po
├── it.po
├── iu.po
├── ja.po
├── jv.po
├── ka.po
├── kg.po
├── ki.po
├── kj.po
├── kk.po
├── kl.po
├── km.po
├── kn.po
├── ko.po
├── kr.po
├── ks.po
├── ku.po
├── kv.po
├── kw.po
├── ky.po
├── la.po
├── lb.po
├── lg.po
├── li.po
├── ln.po
├── lo.po
├── lt.po
├── lu.po
├── lv.po
├── meson.build
├── mg.po
├── mh.po
├── mi.po
├── mk.po
├── ml.po
├── mn.po
├── mo.po
├── mr.po
├── ms.po
├── mt.po
├── my.po
├── na.po
├── nb.po
├── nd.po
├── ne.po
├── ng.po
├── nl.po
├── nn.po
├── no.po
├── nr.po
├── nv.po
├── ny.po
├── oc.po
├── oj.po
├── om.po
├── or.po
├── os.po
├── pa.po
├── pap.po
├── pi.po
├── pl.po
├── ps.po
├── pt.po
├── pt_BR.po
├── qu.po
├── rm.po
├── rn.po
├── ro.po
├── ru.po
├── rue.po
├── rw.po
├── sa.po
├── sc.po
├── sco.po
├── sd.po
├── se.po
├── sg.po
├── si.po
├── sk.po
├── sl.po
├── sm.po
├── sma.po
├── sn.po
├── so.po
├── sq.po
├── sr.po
├── sr@latin.po
├── ss.po
├── st.po
├── su.po
├── sv.po
├── sw.po
├── szl.po
├── ta.po
├── te.po
├── tg.po
├── th.po
├── ti.po
├── tk.po
├── tl.po
├── tn.po
├── to.po
├── tr.po
├── ts.po
├── tt.po
├── tw.po
├── ty.po
├── ug.po
├── uk.po
├── ur.po
├── uz.po
├── ve.po
├── vi.po
├── vo.po
├── wa.po
├── wo.po
├── xh.po
├── yi.po
├── yo.po
├── za.po
├── zh.po
├── zh_HK.po
├── zh_Hans.po
├── zh_Hant.po
└── zu.po
├── src
├── Conf.vala.in
├── Indicator
│ ├── Indicator.vala
│ ├── Services
│ │ └── DBusClient.vala
│ ├── Widgets
│ │ ├── DisplayWidget.vala
│ │ ├── IndicatorWidget.vala
│ │ └── PopoverWidget.vala
│ └── meson.build
├── MainWindow.vala
├── Managers
│ ├── AppManager.vala
│ ├── Process.vala
│ ├── ProcessManager.vala
│ ├── ProcessStructs.vala
│ └── ProcessUtils.vala
├── Models
│ ├── OpenFilesTreeViewModel.vala
│ └── TreeViewModel.vala
├── Monitor.vala
├── PCIUtils.vala
├── Resources
│ ├── CPU.vala
│ ├── CPUCache.vala
│ ├── Cgroup
│ │ ├── Cgroup.vala
│ │ └── CgroupStructs.vala
│ ├── Core.vala
│ ├── Drive.vala
│ ├── GPU
│ │ ├── GPUAmd.vala
│ │ ├── GPUIntel.vala
│ │ ├── GPUNvidia.vala
│ │ └── IGPU.vala
│ ├── Hwmon
│ │ ├── HwmonFan.vala
│ │ ├── HwmonFrequency.vala
│ │ ├── HwmonPWM.vala
│ │ ├── HwmonPathsParser.vala
│ │ ├── HwmonPathsParserCPU.vala
│ │ ├── HwmonPathsParserGPU.vala
│ │ ├── HwmonPathsParserIwlwifi.vala
│ │ ├── HwmonPathsParserNVMe.vala
│ │ ├── HwmonPower.vala
│ │ ├── HwmonTemperature.vala
│ │ ├── HwmonVoltage.vala
│ │ └── IHwmonPathsParserInterface.vala
│ ├── Memory.vala
│ ├── Network.vala
│ ├── Resources.vala
│ ├── ResourcesSerialized.vala
│ ├── Storage
│ │ ├── Disk.vala
│ │ ├── Storage.vala
│ │ ├── StorageBlock.vala
│ │ ├── StorageParser.vala
│ │ └── Volume.vala
│ └── Swap.vala
├── Services
│ ├── Appearance.vala
│ └── DBusServer.vala
├── Utils.vala
├── Views
│ ├── PreferencesView.vala
│ ├── ProcessView
│ │ ├── ProcessInfoView
│ │ │ ├── OpenFilesTreeView.vala
│ │ │ ├── Preventor.vala
│ │ │ ├── ProcessInfoCPURAM.vala
│ │ │ ├── ProcessInfoHeader.vala
│ │ │ ├── ProcessInfoIOStats.vala
│ │ │ └── ProcessInfoView.vala
│ │ ├── ProcessTreeView
│ │ │ └── CPUProcessTreeView.vala
│ │ └── ProcessView.vala
│ └── SystemView
│ │ ├── SystemCPUInfoPopover.vala
│ │ ├── SystemCPUView.vala
│ │ ├── SystemGPUView.vala
│ │ ├── SystemMemoryView.vala
│ │ ├── SystemNetworkView.vala
│ │ ├── SystemStorageView.vala
│ │ └── SystemView.vala
├── Widgets
│ ├── Chart
│ │ └── Chart.vala
│ ├── Headerbar
│ │ └── Search.vala
│ ├── Labels
│ │ ├── LabelRoundy.vala
│ │ └── LabelVertical.vala
│ ├── Statusbar
│ │ └── Statusbar.vala
│ └── WidgetResource
│ │ └── WidgetResource.vala
└── meson.build
├── subprojects
└── live-chart.wrap
├── tests
├── list-src.sh
├── meson.build
├── runner.vala
└── test_statusbar.vala
├── uncrustify.cfg
└── vapi
├── flatpak.vapi
├── libgtop-2.0.vapi
├── libxnvctrl.vapi
└── pci.vapi
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig
2 | root = true
3 |
4 | # elementary defaults
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | indent_size = tab
9 | indent_style = space
10 | insert_final_newline = true
11 | max_line_length = 80
12 | tab_width = 4
13 |
14 | # Markup files
15 | [{*.html,*.xml,*.xml.in,*.yml}]
16 | tab_width = 2
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | types:
6 | - opened
7 | - reopened
8 | - synchronize
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | version: [stable, unstable, development-target]
18 | container:
19 | image: ghcr.io/elementary/docker:${{ matrix.version }}
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 | with:
24 | submodules: true
25 |
26 | - name: Install Dependencies
27 | run: |
28 | apt update
29 | apt install -y libgala-dev libgee-0.8-dev libglib2.0-dev libgranite-dev libgtk-3-dev libhandy-1-dev \
30 | libdbus-glib-1-dev libwnck-3-dev libgtop2-dev libwingpanel-3.0-dev libudisks2-dev \
31 | libxnvctrl0 libxnvctrl-dev libcurl4-gnutls-dev libflatpak-dev libjson-glib-dev \
32 | liblivechart-1-dev libpci-dev \
33 | meson valac sassc git
34 | - name: Build
35 | run: |
36 | meson setup -Dindicator-wingpanel=enabled build
37 | meson compile -C build
38 | # Tests disabled since it starts to test live-chart and some tests fail there
39 | # meson test -C build --print-errorlogs
40 | meson install -C build
41 |
42 | lint:
43 | runs-on: ubuntu-latest
44 |
45 | container:
46 | image: valalang/lint
47 |
48 | steps:
49 | - uses: actions/checkout@v4
50 | - name: Lint
51 | run: io.elementary.vala-lint -d .
52 |
--------------------------------------------------------------------------------
/.github/workflows/gettext.yml:
--------------------------------------------------------------------------------
1 | name: Gettext Updates
2 |
3 | on:
4 | push:
5 | branches: [main]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-22.04
10 | container:
11 | image: ghcr.io/elementary/docker:next-unstable
12 |
13 | steps:
14 | - name: Clone repository
15 | uses: actions/checkout@v4
16 | with:
17 | token: ${{ secrets.GIT_USER_TOKEN }}
18 | submodules: true
19 | - name: Update Translation Files
20 | uses: elementary/actions/gettext-template@main
21 | env:
22 | GIT_USER_TOKEN: ${{ secrets.GIT_USER_TOKEN }}
23 | GIT_USER_NAME: "elementaryBot"
24 | GIT_USER_EMAIL: "builds@elementary.io"
25 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 | on:
3 | pull_request:
4 | branches: [main]
5 | types: closed
6 | jobs:
7 | release:
8 | runs-on: ubuntu-latest
9 | if: github.event.pull_request.merged == true && true == contains(join(github.event.pull_request.labels.*.name), 'Release')
10 | steps:
11 | - uses: actions/checkout@v4
12 | with:
13 | submodules: true
14 | - uses: elementary/actions/release@main
15 | env:
16 | GIT_USER_TOKEN: "${{ secrets.GIT_USER_TOKEN }}"
17 | GIT_USER_NAME: "elementaryBot"
18 | GIT_USER_EMAIL: "builds@elementary.io"
19 | with:
20 | release_branch: 'noble'
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | builddir
3 | .atom-dbg.cson
4 | .vscode
5 | *~
6 | .goutputstream-*
7 | *.css
8 | obj-*-linux-gnu
9 | *.debhelper.log
10 | *.substvars
11 | *.debhelper
12 | debian/io.elementary.monitor
13 | debian/files
14 | # subprojects/*/
15 | .flatpak-builder
16 | *.tar.gz
17 | *.rpm
18 |
--------------------------------------------------------------------------------
/.valalintignore:
--------------------------------------------------------------------------------
1 | build
2 | builddir
3 | data
4 | subprojects
5 | po
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Michael Starkweather
2 | Stanisław Dac
3 |
4 | Icons:
5 | Paulo Galardi
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Monitor
4 |
5 |
6 | Manage processes and monitor system resources
7 |
8 | []()
9 | []()
10 | [](https://l10n.elementary.io/engage/desktop/)
11 |
12 | 
13 | 
14 |
15 | ## Install
16 |
17 | ### elementary OS 7 Horus
18 |
19 | If you have never added a PPA on your system before, you might need to run this command first:
20 |
21 | ```bash
22 | sudo apt install -y software-properties-common
23 | ```
24 |
25 | Add the PPA of Monitor and then install it:
26 |
27 | ```bash
28 | sudo add-apt-repository ppa:stsdc/monitor
29 | sudo apt install com.github.stsdc.monitor
30 | ```
31 |
32 | Monitor will be available from the Applications menu.
33 |
34 | ## Development
35 |
36 | ### Install dependencies
37 |
38 | If you plan to install WITH a wingpanel-indicator
39 |
40 | ```bash
41 | sudo apt install build-essential cmake sassc valac libgtk-3-dev libgee-0.8-dev libgranite-dev libgtop2-dev libwnck-3-dev libhandy-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libxnvctrl-dev liblivechart-1-dev libpci-dev libwingpanel-dev
42 | ```
43 |
44 | Alternatively, if you plan to install WITHOUT a wingpanel-indicator
45 |
46 | ```bash
47 | sudo apt install build-essential cmake sassc valac libgtk-3-dev libgee-0.8-dev libgranite-dev libgtop2-dev libwnck-3-dev libhandy-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libxnvctrl-dev liblivechart-1-dev libpci-dev
48 | ```
49 |
50 |
51 | ### Clone, Build & Install
52 |
53 | 1. Clone:
54 | ```bash
55 | git clone https://github.com/elementary/monitor
56 | cd monitor
57 | ```
58 |
59 | 2. To build with the wingpanel indicator:
60 | ```bash
61 | meson setup -Dindicator-wingpanel=enabled build
62 | ```
63 | Alternatively, to build without the wingpanel indicator:
64 | ```bash
65 | meson setup build
66 | ```
67 |
68 | 3. Install:
69 | ```bash
70 | cd builddir
71 | sudo ninja install
72 | ```
73 |
74 | ### Debug logging
75 |
76 | ```bash
77 | G_MESSAGES_DEBUG=all GTK_DEBUG=interactive io.elementary.monitor
78 | ```
79 |
--------------------------------------------------------------------------------
/data/css.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | monitor-light.css
5 | monitor-dark.css
6 |
7 |
--------------------------------------------------------------------------------
/data/database/README.md:
--------------------------------------------------------------------------------
1 | # The CPU features and bugs database
2 |
3 | The database contains information about the CPU features and bugs that were generated by script located in `meson/get_cpu_features_and_bugs.py`.
4 |
--------------------------------------------------------------------------------
/data/database/cpu_bugs.csv:
--------------------------------------------------------------------------------
1 | f00f,Intel F00F
2 | fdiv,FPU FDIV
3 | coma,Cyrix 6x86 coma
4 | amd_tlb_mmatch,tlb_mmatch AMD Erratum 383
5 | amd_apic_c1e,apic_c1e AMD Erratum 400
6 | 11ap,Bad local APIC aka 11AP
7 | fxsave_leak,FXSAVE leaks FOP/FIP/FOP
8 | clflush_monitor,"AAI65, CLFLUSH required before MONITOR"
9 | sysret_ss_attrs,SYSRET doesn't fix up SS attrs
10 | espfix.,ESPFIX. Make the define conditional
11 | espfix,IRET to 16-bit SS corrupts ESP/RSP high bits
12 | null_seg,Nulling a selector preserves the base
13 | swapgs_fence,SWAPGS without input dep on GS
14 | monitor,IPI required to wake up remote CPU
15 | amd_e400,CPU is among the affected by Erratum 400
16 | cpu_meltdown,CPU is affected by meltdown attack and needs kernel page table isolation
17 | spectre_v1,CPU is affected by Spectre variant 1 attack with conditional branches
18 | spectre_v2,CPU is affected by Spectre variant 2 attack with indirect branches
19 | spec_store_bypass,CPU is affected by speculative store bypass attack
20 | l1tf,CPU is affected by L1 Terminal Fault
21 | mds,CPU is affected by Microarchitectural data sampling
22 | msbds_only,CPU is only affected by the MSDBS variant of BUG_MDS
23 | swapgs,CPU is affected by speculation through SWAPGS
24 | taa,CPU is affected by TSX Async Abort(TAA)
25 | itlb_multihit,CPU may incur MCE during certain page attribute changes
26 | srbds,CPU may leak RNG bits if not mitigated
27 |
--------------------------------------------------------------------------------
/data/icons/file-deleted-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
98 |
--------------------------------------------------------------------------------
/data/icons/gpu-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
158 |
--------------------------------------------------------------------------------
/data/icons/icons.indicator.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | cpu-symbolic.svg
5 | gpu-symbolic.svg
6 | ram-symbolic.svg
7 | gpu-vram-symbolic.svg
8 | swap-symbolic.svg
9 | file-deleted-symbolic.svg
10 | temperature-sensor-symbolic.svg
11 | temperature-gpu-symbolic.svg
12 | extra/16/bash.svg
13 | extra/48/bash.svg
14 | extra/64/bash.svg
15 | extra/16/docker.svg
16 | extra/48/docker.svg
17 | extra/64/docker.svg
18 |
19 |
20 |
--------------------------------------------------------------------------------
/data/icons/ram-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/data/icons/swap-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
105 |
--------------------------------------------------------------------------------
/data/icons/temperature-gpu-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
50 |
--------------------------------------------------------------------------------
/data/icons/temperature-sensor-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/data/io.elementary.monitor.gschema.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | false
10 | Is window maximized or not
11 | Is window maximized or not
12 |
13 |
14 | 800
15 | Window width
16 | Window width
17 |
18 |
19 | 640
20 | Window height
21 | Window height
22 |
23 |
24 | false
25 | To show Monitor Indicator or not
26 | To show Monitor Indicator or not
27 |
28 |
29 | false
30 | To start Monitor in background or not
31 | To start Monitor in background or not
32 |
33 |
34 | true
35 | To show CPU usage in Monitor Indicator or not
36 | To show CPU usage in Monitor Indicator or not
37 |
38 |
39 | false
40 | To show CPU frequency in Monitor Indicator or not
41 | To show CPU frequency in Monitor Indicator or not
42 |
43 |
44 | true
45 | To show CPU temperature value in Monitor Indicator or not
46 | To show CPU temperature value in Monitor Indicator or not
47 |
48 |
49 | true
50 | To show memory usage in Monitor Indicator or not
51 | To show memory usage in Monitor Indicator or not
52 |
53 |
54 | false
55 | To show network up bandwidth data in Monitor Indicator or not
56 | To show network up bandwidth in Monitor Indicator or not
57 |
58 |
59 | false
60 | To show network down bandwidth in Monitor Indicator or not
61 | To show network down bandwidth in Monitor Indicator or not
62 |
63 |
64 | false
65 | To show GPU used percentage in Monitor Indicator or not
66 | To show GPU used percentage in Monitor Indicator or not
67 |
68 |
69 | false
70 | To show GPU memory usage in Monitor Indicator or not
71 | To show GPU memory usage in Monitor Indicator or not
72 |
73 |
74 | false
75 | To show GPU temperature in Monitor Indicator or not
76 | To show GPU temperature in Monitor Indicator or not
77 |
78 |
79 | true
80 | To enable smooth lines in charts
81 | To enable smooth lines in charts or not
82 |
83 |
84 | 'process_view'
85 | Opened view
86 | The last opened view
87 |
88 |
89 | 2
90 | Update time
91 | This value sets update time for updating data and charts.
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/data/meson.build:
--------------------------------------------------------------------------------
1 | icon_sizes = ['16', '24', '32', '48', '64', '128']
2 |
3 | foreach i : icon_sizes
4 | install_data(
5 | join_paths('icons', i, meson.project_name() + '.svg'),
6 | install_dir: join_paths(icondir, i + 'x' + i, 'apps')
7 | )
8 | install_data(
9 | join_paths('icons', i, meson.project_name() + '.svg'),
10 | install_dir: join_paths(icondir, i + 'x' + i + '@2', 'apps')
11 | )
12 | endforeach
13 |
14 | dbdir = join_paths(datadir, meson.project_name(), 'database')
15 | config_data.set('DBDIR', dbdir)
16 |
17 | install_data(
18 | join_paths('database', 'cpu_bugs.csv'),
19 | install_dir: dbdir
20 | )
21 |
22 | install_data(
23 | join_paths('database', 'cpu_features.csv'),
24 | install_dir: dbdir
25 | )
26 |
27 | install_data(
28 | meson.project_name() + '.gschema.xml',
29 | install_dir: join_paths(datadir, 'glib-2.0', 'schemas')
30 | )
31 |
32 | i18n.merge_file(
33 | input: 'monitor.desktop.in',
34 | output: meson.project_name() + '.desktop',
35 | po_dir: meson.source_root() / 'po' / 'extra',
36 | type: 'desktop',
37 | install: true,
38 | install_dir: datadir / 'applications'
39 | )
40 |
41 | i18n.merge_file(
42 | input: meson.project_name() + '.appdata.xml.in',
43 | output: meson.project_name() + '.appdata.xml',
44 | po_dir: join_paths(meson.source_root(), 'po', 'extra'),
45 | install: true,
46 | install_dir: join_paths(datadir, 'metainfo')
47 | )
48 |
49 |
50 | icons_gresource = gnome.compile_resources(
51 | 'gresource_icons', 'icons/icons.indicator.gresource.xml',
52 | source_dir: 'icons',
53 | c_name: 'as1'
54 | )
55 |
56 | sass_command = [
57 | sass,
58 | '@INPUT@',
59 | '@OUTPUT@'
60 | ]
61 |
62 | stylesheet_light = custom_target(
63 | 'theme-monitor-light',
64 | input : './stylesheet/monitor-light.scss',
65 | output : 'monitor-light.css',
66 | command : sass_command,
67 | build_by_default: true
68 | )
69 |
70 | stylesheet_dark = custom_target(
71 | 'theme-monitor-dark',
72 | input : './stylesheet/monitor-dark.scss',
73 | output : 'monitor-dark.css',
74 | command : sass_command,
75 | build_by_default: true
76 | )
77 |
78 | css_gresource = gnome.compile_resources(
79 | 'gresource_css',
80 | 'css.gresource.xml',
81 | source_dir: 'stylesheet',
82 | c_name: 'as2',
83 | dependencies: [stylesheet_dark, stylesheet_light],
84 |
85 | )
86 |
--------------------------------------------------------------------------------
/data/monitor.desktop.in:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=1.5
3 | Type=Application
4 |
5 | Name=Monitor
6 | Comment=Manage processes and monitor resource usage of the system
7 | Categories=System;Utility;
8 | Keywords=System monitor;System usage;Task manager;
9 |
10 | Icon=io.elementary.monitor
11 | Exec=io.elementary.monitor %U
12 | SingleMainWindow=true
13 | StartupNotify=true
14 | Terminal=false
15 |
16 | X-GNOME-UsesNotifications=false
17 |
--------------------------------------------------------------------------------
/data/screenshots/monitor-containers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/data/screenshots/monitor-containers.png
--------------------------------------------------------------------------------
/data/screenshots/monitor-processes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/data/screenshots/monitor-processes.png
--------------------------------------------------------------------------------
/data/screenshots/monitor-system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/data/screenshots/monitor-system.png
--------------------------------------------------------------------------------
/data/stylesheet/_palette.scss:
--------------------------------------------------------------------------------
1 | //@TODO: Could be removed, if Granite will provide palette
2 |
3 | // Internal Palette
4 | $STRAWBERRY_100: #ff8c82;
5 | $STRAWBERRY_300: #ed5353;
6 | $STRAWBERRY_500: #c6262e;
7 | $STRAWBERRY_700: #a10705;
8 | $STRAWBERRY_900: #7a0000;
9 |
10 | $ORANGE_100: #ffc27d;
11 | $ORANGE_300: #ffa154;
12 | $ORANGE_500: #f37329;
13 | $ORANGE_700: #cc3b02;
14 | $ORANGE_900: #a62100;
15 |
16 | $BANANA_100: #fff394;
17 | $BANANA_300: #ffe16b;
18 | $BANANA_500: #f9c440;
19 | $BANANA_700: #d48e15;
20 | $BANANA_900: #ad5f00;
21 |
22 | $LIME_100: #d1ff82;
23 | $LIME_300: #9bdb4d;
24 | $LIME_500: #68b723;
25 | $LIME_700: #3a9104;
26 | $LIME_900: #206b00;
27 |
28 | $MINT_100: #89ffdd;
29 | $MINT_300: #43d6b5;
30 | $MINT_500: #28bca3;
31 | $MINT_700: #0e9a83;
32 | $MINT_900: #007367;
33 |
34 | $BLUEBERRY_100: #8cd5ff;
35 | $BLUEBERRY_300: #64baff;
36 | $BLUEBERRY_500: #3689e6;
37 | $BLUEBERRY_700: #0d52bf;
38 | $BLUEBERRY_900: #002e99;
39 |
40 | $BUBBLEGUM_100: #fe9ab8;
41 | $BUBBLEGUM_300: #f4679d;
42 | $BUBBLEGUM_500: #de3e80;
43 | $BUBBLEGUM_700: #bc245d;
44 | $BUBBLEGUM_900: #910e38;
45 |
46 | $GRAPE_100: #e4c6fa;
47 | $GRAPE_300: #cd9ef7;
48 | $GRAPE_500: #a56de2;
49 | $GRAPE_700: #7239b3;
50 | $GRAPE_900: #452981;
51 |
52 | $COCOA_100: #a3907c;
53 | $COCOA_300: #8a715e;
54 | $COCOA_500: #715344;
55 | $COCOA_700: #57392d;
56 | $COCOA_900: #3d211b;
57 |
58 | $SILVER_100: #fafafa;
59 | $SILVER_300: #d4d4d4;
60 | $SILVER_500: #abacae;
61 | $SILVER_700: #7e8087;
62 | $SILVER_900: #555761;
63 |
64 | $SLATE_100: #95a3ab;
65 | $SLATE_300: #667885;
66 | $SLATE_500: #485a6c;
67 | $SLATE_700: #273445;
68 | $SLATE_900: #0e141f;
69 |
70 | $BLACK_100: #666;
71 | $BLACK_300: #4d4d4d;
72 | $BLACK_500: #333;
73 | $BLACK_700: #1a1a1a;
74 | $BLACK_900: #000;
75 |
76 | // Exported
77 | @define-color STRAWBERRY_100 #{$STRAWBERRY_100};
78 | @define-color STRAWBERRY_300 #{$STRAWBERRY_300};
79 | @define-color STRAWBERRY_500 #{$STRAWBERRY_500};
80 | @define-color STRAWBERRY_700 #{$STRAWBERRY_700};
81 | @define-color STRAWBERRY_900 #{$STRAWBERRY_900};
82 |
83 | @define-color ORANGE_100 #{$ORANGE_100};
84 | @define-color ORANGE_300 #{$ORANGE_300};
85 | @define-color ORANGE_500 #{$ORANGE_500};
86 | @define-color ORANGE_700 #{$ORANGE_700};
87 | @define-color ORANGE_900 #{$ORANGE_900};
88 |
89 | @define-color BANANA_100 #{$BANANA_100};
90 | @define-color BANANA_300 #{$BANANA_300};
91 | @define-color BANANA_500 #{$BANANA_500};
92 | @define-color BANANA_700 #{$BANANA_700};
93 | @define-color BANANA_900 #{$BANANA_900};
94 |
95 | @define-color LIME_100 #{$LIME_100};
96 | @define-color LIME_300 #{$LIME_300};
97 | @define-color LIME_500 #{$LIME_500};
98 | @define-color LIME_700 #{$LIME_700};
99 | @define-color LIME_900 #{$LIME_900};
100 |
101 | @define-color MINT_100 #{$MINT_100};
102 | @define-color MINT_300 #{$MINT_300};
103 | @define-color MINT_500 #{$MINT_500};
104 | @define-color MINT_700 #{$MINT_700};
105 | @define-color MINT_900 #{$MINT_900};
106 |
107 | @define-color BLUEBERRY_100 #{$BLUEBERRY_100};
108 | @define-color BLUEBERRY_300 #{$BLUEBERRY_300};
109 | @define-color BLUEBERRY_500 #{$BLUEBERRY_500};
110 | @define-color BLUEBERRY_700 #{$BLUEBERRY_700};
111 | @define-color BLUEBERRY_900 #{$BLUEBERRY_900};
112 |
113 | @define-color BUBBLEGUM_100 #{$BUBBLEGUM_100};
114 | @define-color BUBBLEGUM_300 #{$BUBBLEGUM_300};
115 | @define-color BUBBLEGUM_500 #{$BUBBLEGUM_500};
116 | @define-color BUBBLEGUM_700 #{$BUBBLEGUM_700};
117 | @define-color BUBBLEGUM_900 #{$BUBBLEGUM_900};
118 |
119 | @define-color GRAPE_100 #{$GRAPE_100};
120 | @define-color GRAPE_300 #{$GRAPE_300};
121 | @define-color GRAPE_500 #{$GRAPE_500};
122 | @define-color GRAPE_700 #{$GRAPE_700};
123 | @define-color GRAPE_900 #{$GRAPE_900};
124 |
125 | @define-color COCOA_100 #{$COCOA_100};
126 | @define-color COCOA_300 #{$COCOA_300};
127 | @define-color COCOA_500 #{$COCOA_500};
128 | @define-color COCOA_700 #{$COCOA_700};
129 | @define-color COCOA_900 #{$COCOA_900};
130 |
131 | @define-color SILVER_100 #{$SILVER_100};
132 | @define-color SILVER_300 #{$SILVER_300};
133 | @define-color SILVER_500 #{$SILVER_500};
134 | @define-color SILVER_700 #{$SILVER_700};
135 | @define-color SILVER_900 #{$SILVER_900};
136 |
137 | @define-color SLATE_100 #{$SLATE_100};
138 | @define-color SLATE_300 #{$SLATE_300};
139 | @define-color SLATE_500 #{$SLATE_500};
140 | @define-color SLATE_700 #{$SLATE_700};
141 | @define-color SLATE_900 #{$SLATE_900};
142 |
143 | @define-color BLACK_100 #{$BLACK_100};
144 | @define-color BLACK_300 #{$BLACK_300};
145 | @define-color BLACK_500 #{$BLACK_500};
146 | @define-color BLACK_700 #{$BLACK_700};
147 | @define-color BLACK_900 #{"" + $BLACK_900};
148 |
--------------------------------------------------------------------------------
/data/stylesheet/monitor-dark.scss:
--------------------------------------------------------------------------------
1 | $color-scheme: "dark";
2 |
3 | @import './index.scss';
--------------------------------------------------------------------------------
/data/stylesheet/monitor-light.scss:
--------------------------------------------------------------------------------
1 | $color-scheme: "light";
2 |
3 | @import './index.scss';
--------------------------------------------------------------------------------
/data/stylesheet/monitor-retrofit.scss:
--------------------------------------------------------------------------------
1 | @import "../../subprojects/stylesheet/src/gtk-3.0/palette";
2 |
3 | @define-color selected_bg_color @BLUEBERRY_500;
--------------------------------------------------------------------------------
/design/GfknBzs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/GfknBzs.jpg
--------------------------------------------------------------------------------
/design/application_manager_by_nicekiwi-d698q3a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/application_manager_by_nicekiwi-d698q3a.png
--------------------------------------------------------------------------------
/design/brainstorm:
--------------------------------------------------------------------------------
1 | -----------
2 |
3 | Have three different concepts:
4 |
5 | Applications (by which I mean graphical applications)
6 | Windows
7 | Processes
8 |
9 | An application is a group of windows and associated processes. We can use libbamf
10 | to enumerate applications (and their windows) as well as monitor for changes; we
11 | can also use libbamf's get_pid () function to grab associated Window->PIDs and
12 | group the related process trees (there may be several) underneath the application.
13 |
14 | -----------
15 |
16 | Listed in the main window, we will enumerate all applications under which we
17 | will list the windows and process trees (which we got using get_pid () on each
18 | window)
19 |
20 | Application
21 | Window1
22 | Window2
23 | Processes
24 | Process1
25 | Process2
26 | Process3
27 | Process4
28 | Process5
29 | Process6
30 |
31 |
32 | Process trees that are not grabbed by an application will be enumerated in a
33 | special category ("Background Processes", "Other", ?) located at the bottom of
34 | the application list. It may be that some processes are parents of other processes
35 | that have been moved up into an Application. In this case, the child process
36 | 'owned' by an Application will not be displayed as a child process -- in effect,
37 | the process will have been 'moved' up into the application.
38 |
39 | -----------
40 |
41 | We could also monitor network and disk resource usage. This may be out of scope.
42 |
43 | -----------
44 |
45 | Perhaps we should have a couple different view modes, because grouping processes
46 | into Applications is a touchy business (as sometimes windows can't be tied to a
47 | PID, and thus, Applications can't be tied to processes). View modes could include:
48 |
49 | Group by Application (default behavior)
50 | Group by Process Tree (shows only processes)
51 | No grouping (shows only processes)
52 |
53 | -----------
54 |
55 | What kind of data do we need to fetch and maintain?
56 |
57 | All running Bamf.Applications
58 | their Bamf.Windows
59 |
60 | All running processes
61 | their CPU load
62 | their memory load
63 |
64 | -----------
--------------------------------------------------------------------------------
/design/task_manager_by_mashnoon33-d7x4s3f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/task_manager_by_mashnoon33-d7x4s3f.png
--------------------------------------------------------------------------------
/design/tasku.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/tasku.png
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project('io.elementary.monitor', 'vala', 'c', version: '0.17.2')
2 |
3 | # these are Meson modules
4 | gnome = import('gnome')
5 | i18n = import('i18n')
6 | sass = find_program('sassc')
7 |
8 | # common dirs
9 | prefix = get_option('prefix')
10 | datadir = join_paths(prefix, get_option('datadir'))
11 | libdir = join_paths(prefix, get_option('libdir'))
12 | icondir = join_paths(datadir, 'icons', 'hicolor')
13 | vapidir = meson.current_source_dir() / 'vapi/'
14 |
15 | add_global_arguments('-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()), language: 'c')
16 |
17 | add_project_arguments(['--vapidir', vapidir], language: 'vala')
18 | add_project_arguments(['-DWNCK_I_KNOW_THIS_IS_UNSTABLE', '-w'], language: 'c')
19 |
20 | # subprojects should be skipped: https://mesonbuild.com/Release-notes-for-0-58-0.html#skip-subprojects-installation
21 | # needs meson 0.58.0
22 | # elementary_stylesheet = subproject('stylesheet')
23 |
24 | app_dependencies = [
25 | dependency('granite', version: '>= 5.2.0'),
26 | dependency('glib-2.0'),
27 | dependency('gtk+-3.0'),
28 | dependency('gee-0.8'),
29 | dependency('gio-2.0'),
30 | dependency('gobject-2.0'),
31 | dependency('libgtop-2.0'),
32 | dependency('libwnck-3.0'),
33 | dependency('libhandy-1', version: '>=0.90.0'),
34 | dependency('gdk-x11-3.0'),
35 | dependency('x11'),
36 | dependency('udisks2'),
37 | dependency('json-glib-1.0'),
38 | dependency('flatpak'),
39 |
40 | # FIXME Bump required version to >= 1.10.0 when GTK 4 porting
41 | dependency(
42 | 'livechart',
43 | version: '< 1.10.0',
44 | fallback: ['live-chart', 'livechart_dep'],
45 | ),
46 |
47 | meson.get_compiler('c').find_library('m', required: false),
48 | meson.get_compiler('vala').find_library('posix'),
49 | meson.get_compiler('c').find_library('X11'),
50 |
51 | # PCI needs lower version limit '>= 3.8.0'
52 | meson.get_compiler('c').find_library('pci'),
53 | meson.get_compiler('vala').find_library('pci', dirs: vapidir),
54 |
55 | meson.get_compiler('c').find_library('XNVCtrl'),
56 | meson.get_compiler('vala').find_library('libxnvctrl', dirs: vapidir),
57 | ]
58 |
59 | config_data = configuration_data()
60 | config_data.set('GETTEXT_PACKAGE', meson.project_name())
61 |
62 | subdir('data')
63 |
64 | config_data.set('VCS_TAG', '@VCS_TAG@')
65 | project_config = vcs_tag(
66 | input: configure_file(
67 | input: 'src/Conf.vala.in',
68 | output: 'Conf.vala.in',
69 | configuration: config_data,
70 | ),
71 | output: 'Conf.vala',
72 | command: ['git', 'describe', '--tags', '--dirty'],
73 | )
74 |
75 | subdir('src')
76 |
77 | # Add in a post install script
78 | meson.add_install_script('meson/post_install.py')
79 |
80 | subdir('po')
81 | # subdir('tests')
82 |
--------------------------------------------------------------------------------
/meson/bump_version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | '''
4 | Bump all the versionsss!!!
5 | '''
6 |
7 | import sys
8 | import datetime
9 |
10 | print ('Bumping everything to: ' + sys.argv[1])
11 |
12 | def bump_spec():
13 | SPEC_FILENAME = "../io.elementary.monitor.spec"
14 | spec_content = ''
15 | with open(SPEC_FILENAME, 'r') as f_spec:
16 | print('Reading spec file: ' + SPEC_FILENAME)
17 | for line in f_spec.readlines():
18 | if 'Version:' in line:
19 | line = 'Version: ' + sys.argv[1] + '\n'
20 | spec_content += line
21 |
22 | with open(SPEC_FILENAME, 'w') as f_spec:
23 | print('Writing spec file: ' + SPEC_FILENAME)
24 | f_spec.write(spec_content)
25 |
26 | def bump_meson():
27 | MESON_FILENAME = "../meson.build"
28 | meson_content = ''
29 | with open(MESON_FILENAME, 'r') as f_meson:
30 | print('Reading meson file: ' + MESON_FILENAME)
31 | for line in f_meson.readlines():
32 | if 'version: ' in line and 'project' in line:
33 | # line = 'version: "' + sys.argv[1] + '"\n'
34 | splitted = line.split('version: ')
35 | line = splitted[0] + "version: '" + sys.argv[1] + "')\n"
36 |
37 | meson_content += line
38 |
39 | with open(MESON_FILENAME, 'w') as f_meson:
40 | print('Writing meson file: ' + MESON_FILENAME)
41 | f_meson.write(meson_content)
42 |
43 | def bump_deb_changelog():
44 | DEB_CHANGELOG_FILENAME = "../debian/changelog"
45 | now = datetime.datetime.now()
46 | deb_changelog_content = f"""io.elementary.monitor ({sys.argv[1]}) jammy; urgency=low\n
47 | * \n -- Stanisław Dac {now.strftime("%a, %d %b %Y %H:%M:%S %z")} +0000\n\n"""
48 |
49 | with open(DEB_CHANGELOG_FILENAME, 'r+') as f_deb_changelog:
50 | content = f_deb_changelog.read()
51 | f_deb_changelog.seek(0)
52 | print('Writing deb changelog file: ' + DEB_CHANGELOG_FILENAME)
53 | f_deb_changelog.write(deb_changelog_content + content)
54 |
55 | bump_spec()
56 | bump_meson()
57 | bump_deb_changelog()
--------------------------------------------------------------------------------
/meson/get_cpu_features_and_bugs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | '''
4 | This script is used to generate the list of available CPU features by parsing Linux sources.
5 | '''
6 |
7 | import urllib.request
8 | import csv
9 |
10 | cpu_features = list()
11 | cpu_bugs = list()
12 |
13 | with urllib.request.urlopen('https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/arch/x86/include/asm/cpufeatures.h') as f:
14 | html = f.read().decode('utf-8')
15 |
16 | for line in html.split('\n'):
17 | if 'X86_FEATURE_' in line and not line.startswith('/*'):
18 | flag_name = line.split('X86_FEATURE_')[1].split('\t')[0].split(' ')[0]
19 | flag_description = line.split('X86_FEATURE_')[1].split('\t')[-1].split('/*')[-1].strip('*/').replace('""', '').strip().replace('"', '')
20 | print(flag_name, flag_description)
21 | cpu_features.append([flag_name.lower(), flag_description])
22 |
23 | if 'X86_BUG_' in line and not line.startswith('/*'):
24 | flag_name = line.split('X86_BUG_')[1].split('\t')[0].split(' ')[0]
25 | flag_description = line.split('X86_BUG_')[1].split('\t')[-1].split('/*')[-1].strip('*/').replace('""', '').strip().replace('"', '')
26 | print(flag_name, flag_description)
27 | cpu_bugs.append([flag_name.lower(), flag_description])
28 |
29 | with open('cpu_features.csv', 'w') as f:
30 | # create the csv writer
31 | writer = csv.writer(f)
32 | writer.writerows(cpu_features)
33 |
34 | with open('cpu_bugs.csv', 'w') as f:
35 | # create the csv writer
36 | writer = csv.writer(f)
37 | writer.writerows(cpu_bugs)
--------------------------------------------------------------------------------
/meson/list-app-src.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | find . -name "*.vala"
--------------------------------------------------------------------------------
/meson/post_install.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import os
4 | import subprocess
5 |
6 | schema_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas')
7 | icon_cache_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'icons', 'hicolor')
8 |
9 | if not os.environ.get('DESTDIR'):
10 | print('Compiling gsettings schemas…')
11 | subprocess.call(['glib-compile-schemas', schema_dir])
12 |
13 | print('Updating desktop icon cache…')
14 | subprocess.call(['gtk-update-icon-cache', '-qtf', icon_cache_dir])
15 |
--------------------------------------------------------------------------------
/meson_options.txt:
--------------------------------------------------------------------------------
1 | option('indicator-wingpanel', type : 'feature', value : 'disabled', description : 'Enables the Indicator for Wingpanel.')
--------------------------------------------------------------------------------
/po/LINGUAS:
--------------------------------------------------------------------------------
1 | aa ab ace ae af ak am an ar as ast av ay az ba be bg bh bi bm bn bo br bs ca ca@valencia ce ch ckb co cr cs cu cv cy da de dv dz ee el en_AU en_CA en_GB en_ZA eo es et eu fa ff fi fil fj fo fr fr_CA frp fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id id_ID ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mo mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pap pi pl ps pt pt_BR qu rm rn ro ru rue rw sa sc sco sd se sg si sk sl sm sma sn so sq sr sr@latin ss st su sv sw szl ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zh_HK zh_Hans zh_Hant zu
2 |
--------------------------------------------------------------------------------
/po/POTFILES:
--------------------------------------------------------------------------------
1 | src/Monitor.vala
2 | src/MainWindow.vala
3 | src/Utils.vala
4 | src/Indicator/Widgets/PopoverWidget.vala
5 | src/Views/ProcessView/ProcessInfoView/Preventor.vala
6 | src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala
7 | src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala
8 | src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala
9 | src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala
10 | src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala
11 | src/Views/PreferencesView.vala
12 | src/Views/SystemView/SystemCPUView.vala
13 | src/Views/SystemView/SystemCPUInfoPopover.vala
14 | src/Views/SystemView/SystemMemoryView.vala
15 | src/Views/SystemView/SystemNetworkView.vala
16 | src/Views/SystemView/SystemStorageView.vala
17 | src/Views/SystemView/SystemGPUView.vala
18 | src/Widgets/Headerbar/Search.vala
19 | src/Widgets/Statusbar/Statusbar.vala
20 | src/Widgets/WidgetResource/WidgetResource.vala
21 |
--------------------------------------------------------------------------------
/po/extra/LINGUAS:
--------------------------------------------------------------------------------
1 | aa ab ace ae af ak am an ar as ast av ay az ba be bg bh bi bm bn bo br bs ca ca@valencia ce ch ckb co cr cs cu cv cy da de dv dz ee el en_AU en_CA en_GB en_ZA eo es et eu fa ff fi fil fj fo fr fr_CA frp fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id id_ID ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mo mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pap pi pl ps pt pt_BR qu rm rn ro ru rue rw sa sc sco sd se sg si sk sl sm sma sn so sq sr sr@latin ss st su sv sw szl ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zh_HK zh_Hans zh_Hant zu
2 |
--------------------------------------------------------------------------------
/po/extra/POTFILES:
--------------------------------------------------------------------------------
1 | data/io.elementary.monitor.appdata.xml.in
2 | data/monitor.desktop.in
3 |
--------------------------------------------------------------------------------
/po/extra/meson.build:
--------------------------------------------------------------------------------
1 | i18n.gettext('extra', preset: 'glib', install: false)
2 |
--------------------------------------------------------------------------------
/po/meson.build:
--------------------------------------------------------------------------------
1 | i18n.gettext(meson.project_name(), preset: 'glib')
2 |
3 | subdir ('extra')
4 |
--------------------------------------------------------------------------------
/src/Conf.vala.in:
--------------------------------------------------------------------------------
1 | namespace Monitor {
2 | public const string DBDIR = "@DBDIR@";
3 | public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
4 | public const string VCS_TAG = "@VCS_TAG@";
5 | }
--------------------------------------------------------------------------------
/src/Indicator/Services/DBusClient.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | [DBus (name = "io.elementary.monitor")]
7 | public interface Monitor.DBusClientInterface : Object {
8 | public abstract void quit_monitor () throws Error;
9 | public abstract void show_monitor () throws Error;
10 | public signal void update (ResourcesSerialized data);
11 | public signal void indicator_state (bool state);
12 | public signal void indicator_cpu_state (bool state);
13 | public signal void indicator_cpu_frequency_state (bool state);
14 | public signal void indicator_cpu_temperature_state (bool state);
15 | public signal void indicator_memory_state (bool state);
16 | public signal void indicator_network_up_state (bool state);
17 | public signal void indicator_network_down_state (bool state);
18 | public signal void indicator_gpu_state (bool state);
19 | public signal void indicator_gpu_memory_state (bool state);
20 | public signal void indicator_gpu_temperature_state (bool state);
21 |
22 | }
23 |
24 | public class Monitor.DBusClient : Object {
25 | public DBusClientInterface ? interface = null;
26 |
27 | private static GLib.Once instance;
28 | public static unowned DBusClient get_default () {
29 | return instance.once (() => { return new DBusClient (); });
30 | }
31 |
32 | public signal void monitor_vanished ();
33 | public signal void monitor_appeared ();
34 |
35 | construct {
36 | try {
37 | interface = Bus.get_proxy_sync (
38 | BusType.SESSION,
39 | "io.elementary.monitor",
40 | "/io/elementary/monitor"
41 | );
42 |
43 | Bus.watch_name (
44 | BusType.SESSION,
45 | "io.elementary.monitor",
46 | BusNameWatcherFlags.NONE,
47 | () => monitor_appeared (),
48 | () => monitor_vanished ()
49 | );
50 | } catch (IOError e) {
51 | error ("Monitor Indicator DBus: %s\n", e.message);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Indicator/Widgets/DisplayWidget.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Widgets.DisplayWidget : Gtk.Grid {
7 | public IndicatorWidget cpu_widget = new IndicatorWidget ("cpu-symbolic");
8 | public IndicatorWidget cpu_frequency_widget = new IndicatorWidget ("cpu-symbolic");
9 | public IndicatorWidget cpu_temperature_widget = new IndicatorWidget ("temperature-sensor-symbolic");
10 |
11 | public IndicatorWidget memory_widget = new IndicatorWidget ("ram-symbolic");
12 |
13 | public IndicatorWidget network_up_widget = new IndicatorWidget ("go-up-symbolic");
14 | public IndicatorWidget network_down_widget = new IndicatorWidget ("go-down-symbolic");
15 |
16 | public IndicatorWidget gpu_widget = new IndicatorWidget ("gpu-symbolic");
17 | public IndicatorWidget gpu_memory_widget = new IndicatorWidget ("gpu-vram-symbolic");
18 | public IndicatorWidget gpu_temperature_widget = new IndicatorWidget ("temperature-gpu-symbolic");
19 |
20 | construct {
21 | valign = Gtk.Align.CENTER;
22 |
23 | add (cpu_widget);
24 | add (cpu_frequency_widget);
25 | add (cpu_temperature_widget);
26 | add (memory_widget);
27 | add (gpu_widget);
28 | add (gpu_memory_widget);
29 | add (gpu_temperature_widget);
30 | add (network_up_widget);
31 | add (network_down_widget);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Indicator/Widgets/IndicatorWidget.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.IndicatorWidget : Gtk.Box {
7 |
8 | public string icon_name { get; construct; }
9 |
10 | public uint state_percentage {
11 | set {
12 | label.label = "%u%%".printf (value);
13 | label.get_style_context ().remove_class ("monitor-indicator-label-warning");
14 | label.get_style_context ().remove_class ("monitor-indicator-label-critical");
15 |
16 | if (value > 80) {
17 | label.get_style_context ().add_class ("monitor-indicator-label-warning");
18 | }
19 | if (value > 90) {
20 | label.get_style_context ().add_class ("monitor-indicator-label-critical");
21 | }
22 | }
23 | }
24 |
25 | public int state_temperature {
26 | set {
27 | label.label = "%i℃".printf (value);
28 | }
29 | }
30 |
31 | public double state_frequency {
32 | set {
33 | label.label = ("%.2f %s").printf (value, _("GHz"));
34 | }
35 | }
36 |
37 | public uint64 state_bandwidth {
38 | set {
39 | label.label = format_size (value);
40 | }
41 | }
42 |
43 | private Gtk.Label label = new Gtk.Label (Utils.NOT_AVAILABLE);
44 |
45 | public IndicatorWidget (string icon_name) {
46 | Object (
47 | orientation: Gtk.Orientation.HORIZONTAL,
48 | icon_name: icon_name,
49 | visible: false
50 | );
51 | }
52 |
53 | construct {
54 | var icon = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.SMALL_TOOLBAR);
55 | label.margin = 2;
56 | label.width_chars = 4;
57 | pack_start (icon);
58 | pack_start (label);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Indicator/Widgets/PopoverWidget.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Widgets.PopoverWidget : Gtk.Grid {
7 | /* Button to hide the indicator */
8 | private Gtk.ModelButton show_monitor_button;
9 | private Gtk.ModelButton quit_monitor_button;
10 |
11 | public signal void quit_monitor ();
12 | public signal void show_monitor ();
13 |
14 | construct {
15 | orientation = Gtk.Orientation.VERTICAL;
16 |
17 | show_monitor_button = new Gtk.ModelButton ();
18 | show_monitor_button.text = _("Show Monitor");
19 | show_monitor_button.hexpand = true;
20 | quit_monitor_button = new Gtk.ModelButton ();
21 | quit_monitor_button.text = _("Quit Monitor");
22 | quit_monitor_button.hexpand = true;
23 | show_monitor_button.clicked.connect (() => show_monitor ());
24 | quit_monitor_button.clicked.connect (() => quit_monitor ());
25 |
26 | add (show_monitor_button);
27 | add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
28 | add (quit_monitor_button);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Indicator/meson.build:
--------------------------------------------------------------------------------
1 | source_indicator_files = [
2 | 'Indicator.vala',
3 | 'Services/DBusClient.vala',
4 | 'Widgets/DisplayWidget.vala',
5 | 'Widgets/IndicatorWidget.vala',
6 | 'Widgets/PopoverWidget.vala',
7 |
8 | meson.project_source_root() / 'src' / 'Resources/ResourcesSerialized.vala',
9 | meson.project_source_root() / 'src' / 'Utils.vala',
10 | ]
11 |
12 | wingpanel_dep = dependency('wingpanel', version: '>=2.1.0')
13 |
14 | indicator_dependencies = [
15 | wingpanel_dep
16 | ]
17 |
18 | shared_module(
19 | 'monitor',
20 | source_indicator_files,
21 | icons_gresource,
22 | dependencies: indicator_dependencies,
23 | install: true,
24 | install_dir : wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir]),
25 | )
26 |
--------------------------------------------------------------------------------
/src/MainWindow.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.MainWindow : Hdy.ApplicationWindow {
7 | private Resources resources;
8 |
9 | // Widgets
10 | public Search search { get; private set; }
11 |
12 | public ProcessView process_view;
13 | public SystemView system_view;
14 | private Gtk.Stack stack;
15 |
16 | private Statusbar statusbar;
17 |
18 | public DBusServer dbusserver;
19 |
20 |
21 | // Constructs a main window
22 | public MainWindow (MonitorApp app) {
23 | this.set_application (app);
24 |
25 | setup_window_state ();
26 |
27 | title = _("Monitor");
28 |
29 | get_style_context ().add_class ("rounded");
30 |
31 | resources = new Resources ();
32 |
33 | process_view = new ProcessView ();
34 | system_view = new SystemView (resources);
35 |
36 | stack = new Gtk.Stack ();
37 | stack.set_transition_type (Gtk.StackTransitionType.SLIDE_LEFT_RIGHT);
38 | stack.add_titled (process_view, "process_view", _("Processes"));
39 | stack.add_titled (system_view, "system_view", _("System"));
40 |
41 |
42 | Gtk.StackSwitcher stack_switcher = new Gtk.StackSwitcher ();
43 | stack_switcher.valign = Gtk.Align.CENTER;
44 | stack_switcher.set_stack (stack);
45 |
46 | var sv = new PreferencesView ();
47 | sv.show_all ();
48 |
49 | var preferences_popover = new Gtk.Popover (null) {
50 | child = sv
51 | };
52 |
53 | var preferences_button = new Gtk.MenuButton () {
54 | image = new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR),
55 | popover = preferences_popover,
56 | tooltip_text = (_("Settings"))
57 | };
58 |
59 | search = new Search (this) {
60 | valign = CENTER
61 | };
62 |
63 | var search_revealer = new Gtk.Revealer () {
64 | child = search,
65 | transition_type = SLIDE_LEFT
66 | };
67 |
68 | var headerbar = new Hdy.HeaderBar () {
69 | has_subtitle = false,
70 | show_close_button = true,
71 | title = _("Monitor")
72 | };
73 | headerbar.pack_start (search_revealer);
74 | headerbar.set_custom_title (stack_switcher);
75 | headerbar.pack_end (preferences_button);
76 |
77 | statusbar = new Statusbar ();
78 |
79 | var grid = new Gtk.Grid () {
80 | orientation = Gtk.Orientation.VERTICAL
81 | };
82 |
83 | grid.add (headerbar);
84 | grid.add (stack);
85 | grid.add (statusbar);
86 |
87 | add (grid);
88 |
89 | show_all ();
90 |
91 | dbusserver = DBusServer.get_default ();
92 |
93 | search_revealer.set_reveal_child (stack.visible_child_name == "process_view");
94 | stack.notify["visible-child-name"].connect (() => {
95 | search_revealer.set_reveal_child (stack.visible_child_name == "process_view");
96 | });
97 |
98 | new Thread ("upd", () => {
99 | Timeout.add_seconds (MonitorApp.settings.get_int ("update-time"), () => {
100 | process_view.update ();
101 |
102 | Idle.add (() => {
103 | system_view.update ();
104 | dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state"));
105 | var res = resources.serialize ();
106 | statusbar.update (res);
107 | dbusserver.update (res);
108 | return false;
109 | });
110 | return true;
111 | });
112 | });
113 |
114 |
115 | dbusserver.quit.connect (() => app.quit ());
116 | dbusserver.show.connect (() => {
117 | this.deiconify ();
118 | this.present ();
119 | setup_window_state ();
120 | this.show_all ();
121 | });
122 |
123 | key_press_event.connect (search.handle_event);
124 |
125 | this.delete_event.connect (() => {
126 | int window_width, window_height;
127 | get_size (out window_width, out window_height);
128 | MonitorApp.settings.set_int ("window-width", window_width);
129 | MonitorApp.settings.set_int ("window-height", window_height);
130 | MonitorApp.settings.set_boolean ("is-maximized", this.is_maximized);
131 |
132 | MonitorApp.settings.set_string ("opened-view", stack.visible_child_name);
133 |
134 | if (MonitorApp.settings.get_boolean ("indicator-state")) {
135 | this.hide_on_delete ();
136 | } else {
137 | dbusserver.indicator_state (false);
138 | app.quit ();
139 | }
140 |
141 | return true;
142 | });
143 |
144 | dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state"));
145 | stack.visible_child_name = MonitorApp.settings.get_string ("opened-view");
146 |
147 | var search_action = new GLib.SimpleAction ("search", null);
148 | search_action.activate.connect (() => search.activate_entry ());
149 |
150 | add_action (search_action);
151 | }
152 |
153 | private void setup_window_state () {
154 | int window_width = MonitorApp.settings.get_int ("window-width");
155 | int window_height = MonitorApp.settings.get_int ("window-height");
156 | this.set_default_size (window_width, window_height);
157 |
158 | if (MonitorApp.settings.get_boolean ("is-maximized")) {
159 | this.maximize ();
160 | }
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/src/Managers/ProcessStructs.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // For more info look at: http://man7.org/linux/man-pages/man5/proc.5.html
7 |
8 | public struct Monitor.ProcessIO {
9 | // characters read
10 | public uint64 rchar;
11 |
12 | // characters written
13 | public uint64 wchar;
14 |
15 | // read syscalls
16 | public uint64 syscr;
17 |
18 | // write syscalls
19 | public uint64 syscw;
20 |
21 | // Attempt to count the number of bytes which this process
22 | // really did cause to be fetched from the storage layer
23 | public uint64 read_bytes;
24 |
25 | // Attempt to count the number of bytes which this process
26 | // caused to be sent to the storage layer.
27 | public uint64 write_bytes;
28 |
29 | public uint64 cancelled_write_bytes;
30 | }
31 |
32 | public struct Monitor.ProcessStatusMemory {
33 | // total program size (pages) (same as VmSize in status)
34 | public uint64 size;
35 |
36 | // size of memory portions (pages) (same as VmRSS in status)
37 | public uint64 resident;
38 |
39 | // number of pages that are shared
40 | // (i.e. backed by a file, same as RssFile+RssShmem in status)
41 | public uint64 shared;
42 |
43 | // number of pages that are 'code' (not including libs; broken,
44 | // includes data segment)
45 | public uint64 trs;
46 |
47 | // number of pages of library (always 0 on 2.6)
48 | public uint64 lrs;
49 |
50 | // number of pages of data/stack (including libs; broken,
51 | // includes library text)
52 | public uint64 drs;
53 |
54 | // number of dirty pages (always 0 on 2.6)
55 | public uint64 dt;
56 | }
57 |
58 | public struct Monitor.ProcessStatus {
59 | // process ID
60 | public int pid;
61 |
62 | // The filename of the executable, in parentheses.
63 | // This is visible whether or not the executable is
64 | // swapped out.
65 | public string comm;
66 |
67 | // Should contain one of the following value:
68 | // D uninterruptible sleep (usually IO)
69 | // I Idle kernel thread
70 | // R running or runnable (on run queue)
71 | // S interruptible sleep (waiting for an event to complete)
72 | // T stopped by job control signal
73 | // t stopped by debugger during the tracing
74 | // W paging (not valid since the 2.6.xx kernel)
75 | // X dead (should never be seen)
76 | // Z defunct ("zombie") process, terminated but not reaped by its parent
77 | public string state;
78 |
79 | // The PID of the parent of this process.
80 | public int ppid;
81 |
82 | // The process group ID of the process.
83 | public int pgrp;
84 |
85 | // The session ID of the process.
86 | public uint session;
87 |
88 | // The controlling terminal of the process.
89 | // (The minor device number is contained in
90 | // the combination of bits 31 to 20 and 7 to 0;
91 | // the major device number is in bits 15 to 8.)
92 | public uint tty_nr;
93 |
94 | // The ID of the foreground process group of the con‐
95 | // trolling terminal of the process.
96 | public uint tpgid;
97 |
98 | // The nice value, a value in the
99 | // range 19 (low priority) to -20 (high priority).
100 | public int nice;
101 |
102 | public int priority;
103 |
104 | // Number of threads in this process
105 | public int num_threads;
106 |
107 | // The time the process started after system boot.
108 | public uint64 starttime;
109 | }
110 |
--------------------------------------------------------------------------------
/src/Managers/ProcessUtils.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.ProcessUtils {
7 | // checks if it is run by shell
8 | public static bool is_shell (string chunk) {
9 | return "sh" == chunk || "bash" == chunk || "zsh" == chunk;
10 | }
11 |
12 | public static bool is_python (string chunk) {
13 | return chunk.contains ("python");
14 | }
15 |
16 | public static string sanitize_commandline (string ? commandline) {
17 | if (commandline == null) return "";
18 |
19 | // splitting command; might include many options
20 | var splitted_commandline = commandline.split (" ");
21 |
22 | // check if started by any shell
23 | if (is_shell (splitted_commandline[0]) || is_python (splitted_commandline[0]) ) {
24 | return commandline;
25 | }
26 |
27 | // if (!splitted_commandline[0].contains ("/")) {
28 | // return commandline;
29 | // }
30 |
31 | return splitted_commandline[0];
32 | }
33 |
34 | public static string ? read_file (string path) {
35 | var file = File.new_for_path (path);
36 |
37 | /* make sure that it exists, not an error if it doesn't */
38 | if (!file.query_exists ()) {
39 | return null;
40 | }
41 | var text = new StringBuilder ();
42 | try {
43 | var dis = new DataInputStream (file.read ());
44 |
45 | // Doing this because of cmdline file.
46 | // cmdline is a single line file with each arg separated by a null character ('\0')
47 | string line = dis.read_upto ("\0", 1, null);
48 | while (line != null) {
49 | text.append (line);
50 | text.append (" ");
51 | dis.skip (1);
52 | line = dis.read_upto ("\0", 1, null);
53 | }
54 |
55 | return text.str;
56 | } catch (Error e) {
57 | warning ("Error reading cmdline file '%s': %s\n", file.get_path (), e.message);
58 | return null;
59 | }
60 | }
61 |
62 | public static Icon ? get_default_icon () {
63 | try {
64 | return Icon.new_for_string ("application-x-executable");
65 | } catch (Error e) {
66 | warning (e.message);
67 | return null;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Models/OpenFilesTreeViewModel.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.OpenFilesTreeViewModel : Gtk.TreeStore {
7 | private Gee.Map open_files_paths = new Gee.HashMap ();
8 |
9 | private Process _process;
10 |
11 | public Process ? process {
12 | get {
13 | return _process;
14 | }
15 | set {
16 | _process = value;
17 |
18 | // repopulating
19 | open_files_paths.clear ();
20 | clear ();
21 | add_paths ();
22 | }
23 | }
24 |
25 | construct {
26 | set_column_types (new Type[] {
27 | typeof (string),
28 | typeof (string),
29 | });
30 |
31 | }
32 |
33 | public void add_paths () {
34 | foreach (var path in process.open_files_paths) {
35 | add_path (path);
36 | }
37 | }
38 |
39 | private bool add_path (string path) {
40 | if (path.substring (0, 1) == "/") {
41 | Gtk.TreeIter iter;
42 | append (out iter, null);
43 |
44 | set (iter,
45 | Column.NAME, path,
46 | -1);
47 |
48 | // open_files_paths.set (path, iter);
49 | return true;
50 | }
51 | return false;
52 | }
53 |
54 | public void update_model (Process process) {
55 | if (process.open_files_paths.size > 0) {
56 | foreach (var path in process.open_files_paths) {
57 |
58 | // print("sdsd");
59 | // Gtk.TreeIter iter = open_files_paths[path];
60 | print (path);
61 | //// display only real paths
62 | //// probably should be done in process class
63 | // if (path.substring (0, 1) == "/") {
64 | // set (iter,
65 | // Column.NAME, path,
66 | // -1);
67 | // }
68 | }
69 | }
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/Models/TreeViewModel.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public enum Monitor.Column {
7 | ICON,
8 | NAME,
9 | CPU,
10 | MEMORY,
11 | PID,
12 | CMD
13 | }
14 |
15 | public class Monitor.TreeViewModel : Gtk.TreeStore {
16 | public ProcessManager process_manager;
17 | private Gee.Map process_rows;
18 | public signal void added_first_row ();
19 |
20 | construct {
21 | process_rows = new Gee.HashMap ();
22 |
23 | set_column_types (new Type[] {
24 | typeof (string),
25 | typeof (string),
26 | typeof (double),
27 | typeof (int64),
28 | typeof (int),
29 | typeof (string),
30 | });
31 |
32 | process_manager = ProcessManager.get_default ();
33 | process_manager.process_added.connect ((process) => add_process (process));
34 | process_manager.process_removed.connect ((pid) => remove_process (pid));
35 | process_manager.updated.connect (update_model);
36 |
37 | Idle.add (() => { add_running_processes (); return false; });
38 | }
39 |
40 | private void add_running_processes () {
41 | debug ("add_running_processes");
42 | var running_processes = process_manager.get_process_list ();
43 | foreach (var process in running_processes.values) {
44 | add_process (process);
45 | }
46 | }
47 |
48 | private bool add_process (Process process) {
49 | if (process != null && !process_rows.has_key (process.stat.pid)) {
50 | debug ("Add process %d Parent PID: %d", process.stat.pid, process.stat.ppid);
51 | // add the process to the model
52 | Gtk.TreeIter iter;
53 | append (out iter, null); // null means top-level
54 |
55 | // donno what is going on, but maybe just use a string instead of Icon ??
56 | // coz it lagz
57 | // string icon_name = process.icon.to_string ();
58 |
59 | set (iter,
60 | Column.NAME, process.application_name,
61 | Column.ICON, process.icon.to_string (),
62 | Column.PID, process.stat.pid,
63 | Column.CMD, process.command,
64 | -1);
65 | if (process_rows.size < 1) {
66 | added_first_row ();
67 | }
68 | // add the process to our cache of process_rows
69 | process_rows.set (process.stat.pid, iter);
70 | return true;
71 | }
72 | return false;
73 | }
74 |
75 | private void update_model () {
76 | foreach (int pid in process_rows.keys) {
77 | Process process = process_manager.get_process (pid);
78 | Gtk.TreeIter iter = process_rows[pid];
79 | set (iter,
80 | Column.CPU, process.cpu_percentage,
81 | Column.MEMORY, process.mem_usage,
82 | -1);
83 | }
84 | }
85 |
86 | private void remove_process (int pid) {
87 | debug ("remove process %d from model".printf (pid));
88 | // if process rows has pid
89 | if (process_rows.has_key (pid)) {
90 | var cached_iter = process_rows.get (pid);
91 | remove (ref cached_iter);
92 | process_rows.unset (pid);
93 | }
94 | }
95 |
96 | public void kill_process (int pid) {
97 | if (pid > 0) {
98 | var process = process_manager.get_process (pid);
99 | process.kill ();
100 | info ("Kill:%d", process.stat.pid);
101 | }
102 | }
103 |
104 | public void end_process (int pid) {
105 | if (pid > 0) {
106 | var process = process_manager.get_process (pid);
107 | process.end ();
108 | info ("End:%d", process.stat.pid);
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/Monitor.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | namespace Monitor {
7 | public class MonitorApp : Gtk.Application {
8 | public static Settings settings;
9 | private MainWindow window = null;
10 | public string[] args;
11 |
12 | private static bool start_in_background = false;
13 | private static bool status_background = false;
14 | private const GLib.OptionEntry[] CMD_OPTIONS = {
15 | // --start-in-background
16 | { "start-in-background", 'b', 0, OptionArg.NONE, ref start_in_background, "Start in background with wingpanel indicator", null },
17 | // list terminator
18 | { null }
19 | };
20 |
21 | // constructor replacement, flags added
22 | public MonitorApp (bool status_indicator) {
23 | Object (
24 | application_id: "io.elementary.monitor",
25 | flags : ApplicationFlags.FLAGS_NONE
26 | );
27 | status_background = status_indicator;
28 | }
29 |
30 | static construct {
31 | settings = new Settings ("io.elementary.monitor.settings");
32 | }
33 |
34 | public override void startup () {
35 | base.startup ();
36 |
37 | Hdy.init ();
38 |
39 | Appearance.set_prefered_style ();
40 |
41 | // Controls the direction of the sort indicators
42 | Gtk.Settings.get_default ().set ("gtk-alternative-sort-arrows", true, null);
43 |
44 | var quit_action = new SimpleAction ("quit", null);
45 | add_action (quit_action);
46 | quit_action.activate.connect (() => {
47 | if (window != null) {
48 | window.destroy ();
49 | }
50 | });
51 |
52 | set_accels_for_action ("app.quit", { "q" });
53 | set_accels_for_action ("win.search", { "f" });
54 | set_accels_for_action ("process.end", { "e" });
55 | set_accels_for_action ("process.kill", { "k" });
56 | }
57 |
58 | public override void activate () {
59 | // only have one window
60 | if (get_windows () != null) {
61 | window.show_all ();
62 | window.present ();
63 | return;
64 | }
65 |
66 | window = new MainWindow (this);
67 |
68 | // start in background with indicator
69 | if (status_background || MonitorApp.settings.get_boolean ("background-state")) {
70 | if (!MonitorApp.settings.get_boolean ("indicator-state")) {
71 | MonitorApp.settings.set_boolean ("indicator-state", true);
72 | }
73 | // if (!MonitorApp.settings.get_boolean ("indicator-cpu-state")) {
74 | // MonitorApp.settings.set_boolean ("indicator-cpu-state", true);
75 | // }
76 | // if (!MonitorApp.settings.get_boolean ("indicator-memory-state")) {
77 | // MonitorApp.settings.set_boolean ("indicator-memory-state", true);
78 | // }
79 | // if (!MonitorApp.settings.get_boolean ("indicator-temperature-state")) {
80 | // MonitorApp.settings.set_boolean ("indicator-temperature-state", true);
81 | // }
82 | // if (!MonitorApp.settings.get_boolean ("indicator-network-upload-state")) {
83 | // MonitorApp.settings.set_boolean ("indicator-network-upload-state", false);
84 | // }
85 | // if (!MonitorApp.settings.get_boolean ("indicator-network-download-state")) {
86 | // MonitorApp.settings.set_boolean ("indicator-network-download-state", false);
87 | // }
88 |
89 | window.hide ();
90 | MonitorApp.settings.set_boolean ("background-state", true);
91 | } else {
92 | window.show_all ();
93 | }
94 |
95 | window.process_view.process_tree_view.focus_on_first_row ();
96 | }
97 |
98 | public static int main (string[] args) {
99 | Intl.setlocale ();
100 | print ("\n");
101 | print (" Monitor %s \n", VCS_TAG);
102 | print ("\n");
103 |
104 | print (
105 | "LibPCI ver: %d.%d.%d \n",
106 | PCIUtils.LIBPCI_MAJOR_VER,
107 | PCIUtils.LIBPCI_MINOR_VER,
108 | PCIUtils.LIBPCI_PATCH_VER
109 | );
110 |
111 | // add command line options
112 | try {
113 | var opt_context = new OptionContext ("");
114 | opt_context.set_help_enabled (true);
115 | opt_context.add_main_entries (CMD_OPTIONS, null);
116 | opt_context.parse (ref args);
117 | } catch (OptionError e) {
118 | print ("Error: %s\n", e.message);
119 | print ("Run '%s --help' to see a full list of available command line options.\n\n", args[0]);
120 | return 0;
121 | }
122 |
123 | var app = new MonitorApp (start_in_background);
124 |
125 | return app.run (args);
126 | }
127 |
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/PCIUtils.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | namespace Monitor.PCIUtils {
7 | const int LIBPCI_MAJOR_VER = (Pci.LIB_VERSION & 0xFF0000) >> 16;
8 | const int LIBPCI_MINOR_VER = (Pci.LIB_VERSION & 0x00FF00) >> 8;
9 | const int LIBPCI_PATCH_VER = (Pci.LIB_VERSION & 0x0000FF) >> 0;
10 | }
11 |
--------------------------------------------------------------------------------
/src/Resources/CPUCache.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This struct holds paths to cpu cache data
7 | // Learn more: https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
8 | [Compact]
9 | public class Monitor.CPUCache : Object {
10 | //
11 | // allocation_policy:
12 | // - WriteAllocate:
13 | // allocate a memory location to a cache line
14 | // on a cache miss because of a write
15 | // - ReadAllocate:
16 | // allocate a memory location to a cache line
17 | // on a cache miss because of a read
18 | // - ReadWriteAllocate:
19 | // both writeallocate and readallocate
20 | public string allocation_policy;
21 |
22 | // LEGACY used only on IA64 and is same as write_policy
23 | public string attributes;
24 |
25 | // the minimum amount of data in bytes that gets
26 | // transferred from memory to cache
27 | public string coherency_line_size;
28 |
29 | // the cache hierarchy in the multi-level cache configuration
30 | public string level;
31 |
32 | // Etotal number of sets in the cache, a set is a
33 | // collection of cache lines with the same cache index
34 | public string number_of_sets;
35 |
36 | // number of physical cache line per cache tag
37 | public string physical_line_partition;
38 |
39 | // the list of logical cpus sharing the cache
40 | public string shared_cpu_list;
41 |
42 | // logical cpu mask containing the list of cpus sharing
43 | // the cache
44 | public string shared_cpu_map;
45 |
46 | // the total cache size in kB
47 | public string size;
48 |
49 | // - Instruction: cache that only holds instructions
50 | // - Data: cache that only caches data
51 | // - Unified: cache that holds both data and instructions
52 | public string type;
53 |
54 | // degree of freedom in placing a particular block
55 | // of memory in the cache
56 | public string ways_of_associativity;
57 |
58 | // - WriteThrough:
59 | // data is written to both the cache line
60 | // and to the block in the lower-level memory
61 | // - WriteBack:
62 | // data is written only to the cache line and
63 | // the modified cache line is written to main
64 | // memory only when it is replaced
65 | public string write_policy;
66 | }
67 |
--------------------------------------------------------------------------------
/src/Resources/Cgroup/Cgroup.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Cgroup : GLib.Object {
7 | /**
8 | * This class only parses necessary values from cgroup files.
9 | * @TODO: Properly parse all values in files.
10 | */
11 | public string id;
12 | public string memory_usage_by_bytes {
13 | owned get {
14 | return open_file ("/sys/fs/cgroup/memory/docker/%s/memory.usage_in_bytes".printf (id), read_memory_usage_in_bytes) ?? "0";
15 | } private set {
16 | }
17 | }
18 |
19 | public string memory_stat_total_inactive_file {
20 | owned get {
21 | return open_file ("/sys/fs/cgroup/memory/docker/%s/memory.stat".printf (id), read_memory_stat_total_inactive_file) ?? "0";
22 | } private set {
23 | }
24 | }
25 |
26 | public string cpuaact_usage_sys {
27 | owned get {
28 | return open_file ("/sys/fs/cgroup/cpuacct/docker/%s/memory.usage_in_bytes".printf (id), read_cpuacct_usage_sys) ?? "0";
29 | } private set {
30 | }
31 | }
32 |
33 | // public CgroupMemoryStat memory_stat;
34 | public Cgroup (string _id) {
35 | id = _id;
36 | }
37 |
38 | delegate string DelegateReadFileFunc (File file);
39 |
40 | private string open_file (string path, DelegateReadFileFunc read_file) {
41 | File file = File.new_for_path (path);
42 |
43 | /* make sure that it exists, not an error if it doesn't */
44 | if (!file.query_exists ()) {
45 | warning ("File doesn't exist ???");
46 | return "";
47 | }
48 | return read_file (file);
49 | }
50 |
51 | private string read_memory_usage_in_bytes (File file) {
52 | try {
53 | var dis = new DataInputStream (file.read ());
54 | return dis.read_line ();
55 | } catch (Error e) {
56 | warning ("Error reading file '%s': %s\n", file.get_path (), e.message);
57 | return "";
58 | }
59 | }
60 |
61 | // Reads very specific value from a file. Should basically read whole file
62 | // but am too lazy
63 | private string read_memory_stat_total_inactive_file (File file) {
64 | try {
65 | var dis = new DataInputStream (file.read ());
66 | string ? line;
67 | while ((line = dis.read_line ()) != null) {
68 | var splitted_line = line.split (":");
69 | if (splitted_line[0] == "total_inactive_file") {
70 | return splitted_line[1];
71 | }
72 | }
73 | return "";
74 | } catch (Error e) {
75 | warning ("Error reading file '%s': %s\n", file.get_path (), e.message);
76 | return "";
77 | }
78 | }
79 |
80 | private string read_cpuacct_usage_sys (File file) {
81 | try {
82 | var dis = new DataInputStream (file.read ());
83 | return dis.read_line ();
84 | } catch (Error e) {
85 | warning ("Error reading file '%s': %s\n", file.get_path (), e.message);
86 | return "";
87 | }
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/Resources/Cgroup/CgroupStructs.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // Read more: https://docs.docker.com/config/containers/runmetrics/
7 |
8 | public struct Monitor.CgroupMemoryStat {
9 | public uint64 cache;
10 | public uint64 rss;
11 | public uint64 rss_huge;
12 | public uint64 shmem;
13 | public uint64 mapped_file;
14 | public uint64 dirty;
15 | public uint64 writeback;
16 | public uint64 swap;
17 | public uint64 pgpgin;
18 | public uint64 pgpgout;
19 | public uint64 pgfault;
20 | public uint64 pgmajfault;
21 | public uint64 inactive_anon;
22 | public uint64 active_anon;
23 | public uint64 inactive_file;
24 | public uint64 active_file;
25 | public uint64 unevictable;
26 | public uint64 hierarchical_memory_limit;
27 | public uint64 hierarchical_memsw_limit;
28 | public uint64 total_cache;
29 | public uint64 total_rss;
30 | public uint64 total_rss_huge;
31 | public uint64 total_shmem;
32 | public uint64 total_mapped_file;
33 | public uint64 total_dirty;
34 | public uint64 total_writeback;
35 | public uint64 total_swap;
36 | public uint64 total_pgpgin;
37 | public uint64 total_pgpgout;
38 | public uint64 total_pgfault;
39 | public uint64 total_pgmajfault;
40 | public uint64 total_inactive_anon;
41 | public uint64 total_active_anon;
42 | public uint64 total_inactive_file;
43 | public uint64 total_active_file;
44 | public uint64 total_unevictable;
45 | }
46 |
--------------------------------------------------------------------------------
/src/Resources/Drive.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2020 Dirli
4 | * 2021 stsdc
5 | */
6 |
7 | public struct Monitor.DriveSmart {
8 | public bool enabled;
9 | public uint64 updated;
10 | public bool failing;
11 | public uint64 power_seconds;
12 | public uint64 power_counts;
13 | public string selftest_status;
14 | public uint life_left;
15 | }
16 |
17 | public struct Monitor.DriveVolume {
18 | public string device;
19 | public string label;
20 | public string type;
21 | public string uuid;
22 | public string mount_point;
23 | public uint64 size;
24 | public uint64 free;
25 | public uint64 offset;
26 | }
27 |
28 | public class Monitor.DiskDrive : GLib.Object {
29 | public string model;
30 | public uint64 size;
31 | public uint64 free;
32 | public string revision;
33 | public string id;
34 | public string device;
35 | public string partition;
36 | public GLib.Icon drive_icon;
37 |
38 |
39 |
40 | private Gee.ArrayList volumes;
41 |
42 | private DriveSmart? smart = null;
43 | public bool has_smart {
44 | get {
45 | return smart != null;
46 | }
47 | }
48 |
49 | public DiskDrive () {
50 | free = 0;
51 | volumes = new Gee.ArrayList ();
52 | }
53 |
54 | public DriveSmart? get_smart () {
55 | return smart;
56 | }
57 |
58 | public void add_smart (DriveSmart _smart) {
59 | smart = _smart;
60 | }
61 |
62 | public void add_volume (DriveVolume vol) {
63 | volumes.add (vol);
64 | free = free + vol.free;
65 | }
66 |
67 | public Gee.ArrayList get_volumes () {
68 | var volumes_arr = new Gee.ArrayList ();
69 |
70 | volumes.foreach ((vol) => {
71 |
72 | volumes_arr.add (vol);
73 |
74 | return true;
75 | });
76 |
77 | volumes_arr.sort (compare_volumes);
78 |
79 | return volumes_arr;
80 | }
81 |
82 | private int compare_volumes (DriveVolume? vol1, DriveVolume? vol2) {
83 | if (vol1 == null) {
84 | return (vol2 == null) ? 0 : -1;
85 | }
86 |
87 | if (vol2 == null) {
88 | return 1;
89 | }
90 |
91 | return GLib.strcmp (vol1.device, vol2.device);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Resources/GPU/GPUAmd.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.GPUAmd : IGPU, Object {
7 |
8 | public Gee.HashMap hwmon_temperatures { get; set; }
9 |
10 | public string hwmon_module_name { get; set; }
11 |
12 | public string name { get; set; }
13 |
14 | public int percentage { get; protected set; }
15 |
16 | public int memory_percentage { get; protected set; }
17 |
18 | public double memory_vram_used { get; protected set; }
19 |
20 | public double memory_vram_total { get; set; }
21 |
22 | public double temperature { get; protected set; }
23 |
24 | protected string sysfs_path { get; set; }
25 |
26 | public GPUAmd (Pci.Access pci_access, Pci.Dev pci_device) {
27 | name = pci_parse_name (pci_access, pci_device);
28 | name = "AMD® " + name;
29 |
30 | sysfs_path = pci_parse_sysfs_path (pci_access, pci_device);
31 | }
32 |
33 | private void update_temperature () {
34 | temperature = double.parse (hwmon_temperatures.get ("edge").input) / 1000;
35 | }
36 |
37 | private void update_memory_vram_used () {
38 | memory_vram_used = double.parse (get_sysfs_value (sysfs_path + "/mem_info_vram_used"));
39 | }
40 |
41 | private void update_memory_vram_total () {
42 | memory_vram_total = double.parse (get_sysfs_value (sysfs_path + "/mem_info_vram_total"));
43 | }
44 |
45 | private void update_memory_percentage () {
46 | memory_percentage = (int) (Math.round ((memory_vram_used / memory_vram_total) * 100));
47 | }
48 |
49 | private void update_percentage () {
50 | percentage = int.parse (get_sysfs_value (sysfs_path + "/gpu_busy_percent"));
51 | }
52 |
53 | public void update () {
54 | update_temperature ();
55 | update_memory_vram_used ();
56 | update_memory_vram_total ();
57 | update_memory_percentage ();
58 | update_percentage ();
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/Resources/GPU/GPUIntel.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.GPUIntel : IGPU, Object {
7 |
8 | public Gee.HashMap hwmon_temperatures { get; set; }
9 |
10 | public string hwmon_module_name { get; set; }
11 |
12 | public string name { get; set; }
13 |
14 | public int percentage { get; protected set; }
15 |
16 | public int memory_percentage { get; protected set; }
17 |
18 | public double memory_vram_used { get; protected set; }
19 |
20 | public double memory_vram_total { get; set; }
21 |
22 | public double temperature { get; protected set; }
23 |
24 | protected string sysfs_path { get; set; }
25 |
26 | public GPUIntel (Pci.Access pci_access, Pci.Dev pci_device) {
27 | name = pci_parse_name (pci_access, pci_device);
28 | name = "Intel® " + name;
29 |
30 | sysfs_path = pci_parse_sysfs_path (pci_access, pci_device);
31 | }
32 |
33 | private void update_temperature () {
34 | // @TODO: Intel GPU temperature retrieval needs implementation.
35 | temperature = 0;
36 | }
37 |
38 | private void update_memory_vram_used () {
39 | // @TODO: Intel GPU used VRAM retrieval needs implementation.
40 | memory_vram_used = 0;
41 | }
42 |
43 | private void update_memory_vram_total () {
44 | // @TODO: Intel GPU total VRAM retrieval needs implementation.
45 | memory_vram_total = 0;
46 | }
47 |
48 | private void update_memory_percentage () {
49 | // @TODO: Intel GPU memory percentage needs implementation.
50 | memory_percentage = 0;
51 | }
52 |
53 | private void update_percentage () {
54 | // @TODO: Intel GPU usage percentage needs implementation.
55 | percentage = 0;
56 | }
57 |
58 | public void update () {
59 | update_temperature ();
60 | update_memory_vram_used ();
61 | update_memory_vram_total ();
62 | update_memory_percentage ();
63 | update_percentage ();
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/Resources/GPU/GPUNvidia.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.GPUNvidia : IGPU, Object {
7 |
8 | public Gee.HashMap hwmon_temperatures { get; set; }
9 |
10 | public string hwmon_module_name { get; set; }
11 |
12 | public string name { get; set; }
13 |
14 | public int percentage { get; protected set; }
15 |
16 | public int memory_percentage { get; protected set; }
17 |
18 | public int fb_percentage { get; protected set; }
19 |
20 | public double memory_vram_used { get; protected set; }
21 |
22 | public double memory_vram_total { get; set; }
23 |
24 | public double temperature { get; protected set; }
25 |
26 | protected string sysfs_path { get; set; }
27 |
28 | public int nvidia_temperature = 0;
29 |
30 | public int nvidia_memory_vram_used = 0;
31 |
32 | public int nvidia_memory_vram_total = 0;
33 |
34 | public int nvidia_memory_percentage = 0;
35 |
36 | public int nvidia_fb_percentage = 0;
37 |
38 | public int nvidia_percentage = 0;
39 |
40 | public char * nvidia_used = "";
41 |
42 | public bool nvidia_resources_temperature;
43 |
44 | public bool nvidia_resources_vram_used;
45 |
46 | public bool nvidia_resources_vram_total;
47 |
48 | public bool nvidia_resources_used;
49 |
50 | public X.Display nvidia_display;
51 |
52 | public GPUNvidia (Pci.Access pci_access, Pci.Dev pci_device) {
53 | name = pci_parse_name (pci_access, pci_device);
54 | name = "nVidia® " + name;
55 |
56 | sysfs_path = pci_parse_sysfs_path (pci_access, pci_device);
57 | }
58 |
59 | construct {
60 | nvidia_display = new X.Display ();
61 | }
62 |
63 | private void update_nv_resources () {
64 | nvidia_resources_temperature = NVCtrl.XNVCTRLQueryAttribute (
65 | nvidia_display,
66 | 0,
67 | 0,
68 | NV_CTRL_GPU_CORE_TEMPERATURE,
69 | &nvidia_temperature
70 | );
71 |
72 | if (!nvidia_resources_temperature) {
73 | warning ("Could not query NV_CTRL_GPU_CORE_TEMPERATURE attribute!\n");
74 | return;
75 | }
76 |
77 | nvidia_resources_vram_used = NVCtrl.XNVCTRLQueryTargetAttribute (
78 | nvidia_display,
79 | NV_CTRL_TARGET_TYPE_GPU,
80 | 0,
81 | 0,
82 | NV_CTRL_USED_DEDICATED_GPU_MEMORY,
83 | &nvidia_memory_vram_used
84 | );
85 |
86 | if (!nvidia_resources_vram_used) {
87 | warning ("Could not query NV_CTRL_USED_DEDICATED_GPU_MEMORY attribute!\n");
88 | return;
89 | }
90 |
91 | nvidia_resources_vram_total = NVCtrl.XNVCTRLQueryTargetAttribute (
92 | nvidia_display,
93 | NV_CTRL_TARGET_TYPE_GPU,
94 | 0,
95 | 0,
96 | NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY,
97 | &nvidia_memory_vram_total
98 | );
99 |
100 | if (!nvidia_resources_vram_total) {
101 | warning ("Could not query NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY attribute!\n");
102 | return;
103 | }
104 |
105 | nvidia_resources_used = NVCtrl.XNVCTRLQueryTargetStringAttribute (
106 | nvidia_display,
107 | NV_CTRL_TARGET_TYPE_GPU,
108 | 0,
109 | 0,
110 | NV_CTRL_STRING_GPU_UTILIZATION,
111 | &nvidia_used
112 | );
113 |
114 | // var str_used = (string)nvidia_used;
115 | nvidia_percentage = int.parse (((string) nvidia_used).split_set ("=,")[1]);
116 | nvidia_fb_percentage = int.parse (((string) nvidia_used).split_set ("=,")[3]);
117 | debug ("USED_GRAPHICS: %d%\n", nvidia_percentage);
118 | debug ("USED_FB_MEMORY: %d%\n", nvidia_fb_percentage);
119 |
120 | if (!nvidia_resources_used) {
121 | warning ("Could not query NV_CTRL_STRING_GPU_UTILIZATION attribute!\n");
122 | return;
123 | }
124 |
125 | }
126 |
127 | private void update_temperature () {
128 | temperature = nvidia_temperature;
129 | }
130 |
131 | private void update_memory_vram_used () {
132 | memory_vram_used = (double) nvidia_memory_vram_used * 1000000.0;
133 | }
134 |
135 | private void update_memory_vram_total () {
136 | memory_vram_total = (double) nvidia_memory_vram_total * 1000000.0;
137 | }
138 |
139 | private void update_memory_percentage () {
140 | memory_percentage = (int) (Math.round ((memory_vram_used / memory_vram_total) * 100));
141 | }
142 |
143 | private void update_fb_percentage () {
144 | fb_percentage = nvidia_fb_percentage;
145 | }
146 |
147 | private void update_percentage () {
148 | percentage = nvidia_percentage;
149 | }
150 |
151 | public void update () {
152 | update_nv_resources ();
153 | update_temperature ();
154 | update_memory_vram_used ();
155 | update_memory_vram_total ();
156 | update_memory_percentage ();
157 | update_percentage ();
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/src/Resources/GPU/IGPU.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public interface Monitor.IGPU : Object {
7 |
8 | public abstract Gee.HashMap hwmon_temperatures { get; set; }
9 |
10 | public abstract string hwmon_module_name { get; protected set; }
11 |
12 | public abstract string name { get; protected set; }
13 |
14 | public abstract int percentage { get; protected set; }
15 |
16 | public abstract int memory_percentage { get; protected set; }
17 |
18 | public abstract double memory_vram_used { get; protected set; }
19 |
20 | public abstract double memory_vram_total { get; protected set; }
21 |
22 | public abstract double temperature { get; protected set; }
23 |
24 | protected abstract string sysfs_path { get; protected set; }
25 |
26 | public abstract void update_temperature ();
27 |
28 | public abstract void update_memory_vram_used ();
29 |
30 | public abstract void update_memory_vram_total ();
31 |
32 | public abstract void update_memory_percentage ();
33 |
34 | public abstract void update_percentage ();
35 |
36 | public abstract void update ();
37 |
38 | protected virtual string pci_parse_name (Pci.Access pci_access, Pci.Dev pci_device) {
39 | char namebuf[256];
40 | return pci_access.lookup_name (namebuf, Pci.LookupMode.DEVICE, pci_device.vendor_id, pci_device.device_id);
41 | }
42 |
43 | protected virtual string pci_parse_sysfs_path (Pci.Access pci_access, Pci.Dev pci_device) {
44 | string pci_path_domain_bus = "%04x:%02x".printf (pci_device.domain_16, pci_device.bus);
45 | string pci_path_dev_func = "%02x.%d".printf (pci_device.dev, pci_device.func);
46 | string path = "/sys/class/pci_bus/%s/device/%s:%s".printf (pci_path_domain_bus, pci_path_domain_bus, pci_path_dev_func);
47 | debug ("GPU path: %s", path);
48 |
49 | return path;
50 | }
51 |
52 | public virtual string get_sysfs_value (string path) {
53 | string content;
54 | try {
55 | FileUtils.get_contents (path, out content);
56 | } catch (Error e) {
57 | warning (e.message);
58 | content = "0";
59 | }
60 | return content;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonFan.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This struct holds paths to temperature data
7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces
8 |
9 | [Compact]
10 | public class Monitor.HwmonFan : Object {
11 | // fan speed in RPM
12 | public string input;
13 |
14 | // an minimum value Unit: revolution/min (RPM)
15 | public string min;
16 |
17 | // an maximum value Unit: revolution/min (RPM)
18 | public string max;
19 |
20 | // Desired fan speed Unit: revolution/min (RPM)
21 | public string target;
22 |
23 | // Enable or disable the sensors.1: Enable 0: Disable
24 | public string enable;
25 | }
26 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonFrequency.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This struct holds paths to temperature data
7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces
8 |
9 | [Compact]
10 | public class Monitor.HwmonFrequency : Object {
11 | // freq channel label
12 | public string label;
13 |
14 | // freq1_input: the gfx/compute clock in hertz
15 | // freq2_input: the memory clock in hertz
16 | public string input;
17 | }
18 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonPWM.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This struct holds paths to temperature data
7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces
8 |
9 | [Compact]
10 | public class Monitor.HwmonPWM : Object {
11 | // pulse width modulation fan level (0-255)
12 | public string pwm;
13 |
14 | // pulse width modulation fan control minimum level (0)
15 | public string min;
16 |
17 | // pulse width modulation fan control maximum level (255)
18 | public string max;
19 |
20 | // pulse width modulation fan control method
21 | // 0: no fan speed control,
22 | // 1: manual fan speed control using pwm interface,
23 | // 2: automatic fan speed control
24 | public string enable;
25 | }
26 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonPathsParser.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | class Monitor.HwmonPathParser : Object {
7 | private const string HWMON_PATH = "/sys/class/hwmon";
8 |
9 | public HwmonPathsParserGPU gpu_paths_parser = new HwmonPathsParserGPU ();
10 | public HwmonPathsParserNVMe nvme_paths_parser = new HwmonPathsParserNVMe ();
11 | public HwmonPathsParserIwlwifi iwlwifi_paths_parser = new HwmonPathsParserIwlwifi ();
12 | public HwmonPathsParserCPU cpu_paths_parser = new HwmonPathsParserCPU ();
13 |
14 | // public double cpu {
15 | // get {
16 | // double total_temperature = 0;
17 | // // this should handle null
18 | // foreach (var path in cpu_temp_paths) {
19 | // total_temperature += double.parse (open_file (path));
20 | // }
21 | // return total_temperature / cpu_temp_paths.size;
22 | // }
23 | // }
24 |
25 | construct {
26 | // cpu_temp_paths = new Gee.ArrayList ();
27 | detect_sensors ();
28 | }
29 |
30 | private void detect_sensors () {
31 | try {
32 | Dir hwmon_dir = Dir.open (HWMON_PATH, 0);
33 |
34 | string ? hwmonx = null;
35 | while ((hwmonx = hwmon_dir.read_name ()) != null) {
36 | string hwmonx_name = Path.build_filename (HWMON_PATH, hwmonx, "name");
37 |
38 | string interface_name = open_file (hwmonx_name);
39 |
40 | // thank u, next
41 | if (interface_name == "") continue;
42 |
43 | if (interface_name == "coretemp" ||
44 | interface_name == "k10temp" ||
45 | interface_name == "cpu_thermal"
46 | ) {
47 | debug ("Found HWMON CPU Interface: %s in: %s", interface_name, hwmonx_name);
48 | this.parse (cpu_paths_parser, hwmonx);
49 |
50 | } else if (interface_name == "amdgpu") {
51 | debug ("Found HWMON GPU Interface: %s", interface_name);
52 | this.parse (gpu_paths_parser, hwmonx);
53 |
54 | } else if (interface_name == "nvme") {
55 | debug ("Found HWMON NVMe Interface: %s", interface_name);
56 | this.parse (nvme_paths_parser, hwmonx);
57 |
58 | } else if (interface_name == "iwlwifi_1") {
59 | debug ("Found HWMON iwlwifi Interface: %s", interface_name);
60 | this.parse (iwlwifi_paths_parser, hwmonx);
61 |
62 | } else {
63 | debug ("Found unknown HWMON Interface: %s", interface_name);
64 | }
65 | }
66 | } catch (FileError e) {
67 | warning ("Could not open dir: %s", e.message);
68 | }
69 | }
70 |
71 | private void parse (IHwmonPathsParserInterface parser, string hwmonx) {
72 | try {
73 | string ? hwmonx_prop = null;
74 | Dir hwmonx_dir = Dir.open (Path.build_filename (HWMON_PATH, hwmonx), 0);
75 |
76 | while (( hwmonx_prop = hwmonx_dir.read_name ()) != null) {
77 | parser.add_path (Path.build_filename (HWMON_PATH, hwmonx, hwmonx_prop));
78 | }
79 | parser.parse ();
80 |
81 | } catch (FileError e) {
82 | warning ("Could not open dir: %s", e.message);
83 | }
84 |
85 | }
86 |
87 | private string open_file (string filename) {
88 | try {
89 | string read;
90 | if (!FileUtils.test (filename, FileTest.IS_REGULAR)) return "";
91 | FileUtils.get_contents (filename, out read);
92 | return read.replace ("\n", "");
93 | } catch (FileError e) {
94 | warning ("%s", e.message);
95 | return "";
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonPathsParserCPU.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.HwmonPathsParserCPU : Object, IHwmonPathsParserInterface {
7 |
8 | public string name { get; protected set; }
9 |
10 | private Gee.HashMap _temperatures = new Gee.HashMap ();
11 | public Gee.HashMap temperatures = new Gee.HashMap ();
12 |
13 | protected Gee.HashSet all_paths { get; protected set; }
14 |
15 | construct {
16 | all_paths = new Gee.HashSet ();
17 | }
18 |
19 | public void parse () {
20 | foreach (var path in all_paths) {
21 | var basename = Path.get_basename (path);
22 | if (basename.contains ("name")) {
23 | this.name = open_file (path);
24 | } else if (basename.contains ("temp")) {
25 | debug ("Found HWMON CPU temperature interface path: %s", basename);
26 | if (!_temperatures.has_key (basename[4])) {
27 | _temperatures.set (basename[4], new HwmonTemperature ());
28 | }
29 |
30 | if (basename.contains ("label")) {
31 | _temperatures.get (basename[4]).label = open_file (path);
32 | } else if (basename.contains ("input")) {
33 | _temperatures.get (basename[4]).input = path;
34 | } else if (basename.contains ("crit")) {
35 | _temperatures.get (basename[4]).crit = path;
36 | } else if (basename.contains ("crit_hyst")) {
37 | _temperatures.get (basename[4]).crit_hyst = path;
38 | } else if (basename.contains ("emergency")) {
39 | _temperatures.get (basename[4]).emergency = path;
40 | } else if (basename.contains ("max")) {
41 | _temperatures.get (basename[4]).max = path;
42 | } else if (basename.contains ("min")) {
43 | _temperatures.get (basename[4]).min = path;
44 | }
45 | }
46 | }
47 |
48 | foreach (var holder in _temperatures.values) {
49 | if (holder.label != null) {
50 | this.temperatures.set (holder.label, holder);
51 | debug ("🌡️ Parsed HWMON CPU temperature interface: %s", holder.label);
52 | } else {
53 |
54 | temperatures.set (this.name, holder);
55 | debug ("🌡️ Parsed HWMON CPU temperature interface %s", this.name);
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonPathsParserIwlwifi.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.HwmonPathsParserIwlwifi : Object, IHwmonPathsParserInterface {
7 |
8 | public string name { get; protected set; }
9 |
10 | private Gee.HashMap _temperatures = new Gee.HashMap ();
11 | public Gee.HashMap temperatures = new Gee.HashMap ();
12 |
13 | protected Gee.HashSet all_paths { get; protected set; }
14 |
15 | construct {
16 | all_paths = new Gee.HashSet ();
17 | }
18 |
19 | public void parse () {
20 | foreach (var path in all_paths) {
21 | var basename = Path.get_basename (path);
22 | if (basename.contains ("name")) {
23 | this.name = open_file (path);
24 | } else if (basename.contains ("temp")) {
25 | debug ("Found HWMON iwlwifi temperature interface path: %s", basename);
26 | if (!_temperatures.has_key (basename[4])) {
27 | _temperatures.set (basename[4], new HwmonTemperature ());
28 | }
29 |
30 | if (basename.contains ("label")) {
31 | _temperatures.get (basename[4]).label = open_file (path);
32 | } else if (basename.contains ("input")) {
33 | _temperatures.get (basename[4]).input = path;
34 | } else if (basename.contains ("crit")) {
35 | _temperatures.get (basename[4]).crit = path;
36 | } else if (basename.contains ("crit_hyst")) {
37 | _temperatures.get (basename[4]).crit_hyst = path;
38 | } else if (basename.contains ("emergency")) {
39 | _temperatures.get (basename[4]).emergency = path;
40 | } else if (basename.contains ("max")) {
41 | _temperatures.get (basename[4]).max = path;
42 | } else if (basename.contains ("min")) {
43 | _temperatures.get (basename[4]).min = path;
44 | }
45 | }
46 | }
47 |
48 | foreach (var paths_holder in _temperatures.values) {
49 | if (paths_holder.label != null) {
50 | this.temperatures.set (paths_holder.label, paths_holder);
51 | debug ("🌡️ Parsed HWMON iwlwifi temperature interface: %s", paths_holder.label);
52 |
53 | } else {
54 | // let's just hope that there is always one temp_input per iwlwifi
55 | temperatures.set (this.name, paths_holder);
56 | debug ("🌡️ Parsed HWMON iwlwifi temperature interface: %s", this.name);
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonPathsParserNVMe.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.HwmonPathsParserNVMe : Object, IHwmonPathsParserInterface {
7 |
8 | public string name { get; protected set; }
9 |
10 | private Gee.HashMap _temperatures = new Gee.HashMap ();
11 | public Gee.HashMap temperatures = new Gee.HashMap ();
12 |
13 | protected Gee.HashSet all_paths { get; protected set; }
14 |
15 | construct {
16 | all_paths = new Gee.HashSet ();
17 | }
18 |
19 | public void parse () {
20 | foreach (var path in all_paths) {
21 | var basename = Path.get_basename (path);
22 | if (basename.contains ("name")) {
23 | this.name = basename;
24 | } else if (basename.contains ("temp")) {
25 | debug ("Found HWMON NVMe temperature interface path: %s", basename);
26 | if (!_temperatures.has_key (basename[4])) {
27 | _temperatures.set (basename[4], new HwmonTemperature ());
28 | }
29 |
30 | if (basename.contains ("label")) {
31 | _temperatures.get (basename[4]).label = open_file (path);
32 | } else if (basename.contains ("input")) {
33 | _temperatures.get (basename[4]).input = path;
34 | } else if (basename.contains ("crit")) {
35 | _temperatures.get (basename[4]).crit = path;
36 | } else if (basename.contains ("crit_hyst")) {
37 | _temperatures.get (basename[4]).crit_hyst = path;
38 | } else if (basename.contains ("emergency")) {
39 | _temperatures.get (basename[4]).emergency = path;
40 | } else if (basename.contains ("max")) {
41 | _temperatures.get (basename[4]).max = path;
42 | } else if (basename.contains ("min")) {
43 | _temperatures.get (basename[4]).min = path;
44 | }
45 | }
46 | }
47 |
48 | foreach (var paths_holder in _temperatures.values) {
49 | temperatures.set (paths_holder.label, paths_holder);
50 | debug ("🌡️ Parsed HWMON NVMe temperature interface: %s", paths_holder.label);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonPower.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This struct holds paths to temperature data
7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces
8 |
9 | [Compact]
10 | public class Monitor.HwmonPower : Object {
11 | // average power used by the GPU in microWatts
12 | public string average;
13 |
14 | // average power used by the GPU in microWatts
15 | public string cap_min;
16 |
17 | // maximum cap supported in microWatts
18 | public string cap_max;
19 |
20 | // selected power cap in microWatts
21 | public string cap;
22 | }
23 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonTemperature.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This class holds paths to temperature data
7 | // returns contents of the file as a string
8 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces
9 |
10 | [Compact]
11 | public class Monitor.HwmonTemperature : Object {
12 | // temperature channel label
13 | // temp2_label and temp3_label are supported on SOC15 dGPUs only
14 | public string _label;
15 | public string label {
16 | get {
17 | if (_label == null) return "";
18 | return _label;
19 | }
20 | set {
21 | _label = value;
22 | }
23 | }
24 | // the on die temperature in millidegrees Celsius
25 | // temp2_input and temp3_input are supported on SOC15 dGPUs only
26 | private string _input;
27 | public string input {
28 | owned get {
29 | return open_file (_input);
30 | }
31 | set {
32 | _input = value;
33 | }
34 | }
35 |
36 | // temperature critical max value in millidegrees Celsius
37 | // temp2_crit and temp3_crit are supported on SOC15 dGPUs only
38 | public string ? crit;
39 |
40 | // temperature hysteresis for critical limit in millidegrees Celsius
41 | // temp2_crit_hyst and temp3_crit_hyst are supported on SOC15 dGPUs only
42 | public string ? crit_hyst;
43 |
44 | // temperature emergency max value(asic shutdown) in millidegrees Celsius
45 | // these are supported on SOC15 dGPUs only
46 | public string ? emergency;
47 |
48 | // Temperature max value.
49 | public string ? max;
50 |
51 | // Temperature min value.
52 | public string ? min;
53 |
54 | public string open_file (string filename) {
55 | try {
56 | string read;
57 | FileUtils.get_contents (filename, out read);
58 | return read.replace ("\n", "");
59 | } catch (FileError e) {
60 | warning ("%s", e.message);
61 | return "";
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/HwmonVoltage.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | // This struct holds paths to temperature data
7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces
8 |
9 | [Compact]
10 | public class Monitor.HwmonVoltage : Object {
11 | // voltage channel label
12 | public string label;
13 |
14 | // in0_input: the voltage on the GPU in millivolts
15 | // in1_input: the voltage on the Northbridge in millivolts
16 | public string input;
17 | }
18 |
--------------------------------------------------------------------------------
/src/Resources/Hwmon/IHwmonPathsParserInterface.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public interface Monitor.IHwmonPathsParserInterface : Object {
7 |
8 | public abstract string name { get; protected set; }
9 |
10 | protected abstract Gee.HashSet all_paths { get; protected set; }
11 |
12 | public abstract void parse ();
13 |
14 | public virtual void add_path (string path) {
15 | all_paths.add (path);
16 | }
17 |
18 | public virtual string open_file (string filename) {
19 | try {
20 | string read;
21 | FileUtils.get_contents (filename, out read);
22 | return read.replace ("\n", "");
23 | } catch (FileError e) {
24 | warning ("%s", e.message);
25 | return "";
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Resources/Memory.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | namespace Monitor {
7 | public class Memory : Object {
8 | public double total = 0;
9 | public double used = 0;
10 | public double shared;
11 | public double buffer;
12 | public double cached;
13 | public double locked;
14 |
15 | private GTop.Memory mem;
16 |
17 | public uint used_percentage {
18 | get {
19 | return (uint) (Math.round ((used / total) * 100));
20 | }
21 | }
22 |
23 | public uint shared_percentage {
24 | get {
25 | return (uint) (Math.round ((shared / used) * 100));
26 | }
27 | }
28 |
29 | public uint buffer_percentage {
30 | get {
31 | return (uint) (Math.round ((buffer / used) * 100));
32 | }
33 | }
34 |
35 | public uint cached_percentage {
36 | get {
37 | return (uint) (Math.round ((cached / used) * 100));
38 | }
39 | }
40 |
41 | public uint locked_percentage {
42 | get {
43 | return (uint) (Math.round ((locked / used) * 100));
44 | }
45 | }
46 |
47 | public void update () {
48 | GTop.get_mem (out mem);
49 | total = (double) (mem.total);
50 | used = (double) mem.user;
51 | shared = (double) (mem.shared);
52 | buffer = (double) (mem.buffer);
53 | cached = (double) (mem.cached);
54 | locked = (double) (mem.locked);
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Resources/Network.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: LGPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2020 Tudor Plugaru
4 | * 2020 stsdc
5 | *
6 | * Authored by: Tudor Plugaru
7 | */
8 |
9 | public class Monitor.Network : GLib.Object {
10 | public int bytes_in;
11 | private int bytes_in_old;
12 |
13 | public int bytes_out;
14 | private int bytes_out_old;
15 |
16 | // flag first run
17 | // bc first calculasion is wrong
18 | private bool dumb_flag;
19 |
20 | public Network () {
21 | bytes_in = 0;
22 | bytes_in_old = 0;
23 | bytes_out = 0;
24 | bytes_out_old = 0;
25 | dumb_flag = true;
26 | }
27 |
28 | public void update () {
29 | GTop.NetList netlist;
30 | GTop.NetLoad netload;
31 |
32 | var devices = GTop.get_netlist (out netlist);
33 | var bytes_out_new = 0;
34 | var bytes_in_new = 0;
35 | for (uint j = 0; j < netlist.number; ++j) {
36 | var device = devices[j];
37 | if (device != "lo" && device.substring (0, 3) != "tun") {
38 | GTop.get_netload (out netload, device);
39 |
40 | bytes_out_new += (int) netload.bytes_out;
41 | bytes_in_new += (int) netload.bytes_in;
42 | }
43 | }
44 |
45 | if (!dumb_flag) {
46 | bytes_out = (bytes_out_new - bytes_out_old) / MonitorApp.settings.get_int ("update-time");
47 | bytes_in = (bytes_in_new - bytes_in_old) / MonitorApp.settings.get_int ("update-time");
48 | }
49 |
50 | bytes_out_old = bytes_out_new;
51 | bytes_in_old = bytes_in_new;
52 |
53 |
54 | dumb_flag = false;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/Resources/Resources.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Resources : Object {
7 | public CPU cpu;
8 | public Memory memory;
9 | public Swap swap;
10 | public Network network;
11 | public Storage storage;
12 | public Gee.ArrayList gpu_list = new Gee.ArrayList ();
13 | private HwmonPathParser hwmon_path_parser;
14 |
15 | construct {
16 | hwmon_path_parser = new HwmonPathParser ();
17 |
18 | memory = new Memory ();
19 | cpu = new CPU ();
20 | swap = new Swap ();
21 | network = new Network ();
22 | storage = new Storage ();
23 |
24 | detect_gpu_pci_devices ();
25 |
26 | cpu.temperatures = hwmon_path_parser.cpu_paths_parser.temperatures;
27 |
28 | update ();
29 | }
30 |
31 | public void update () {
32 | Timeout.add_seconds (MonitorApp.settings.get_int ("update-time"), () => {
33 | new Thread ("update-resources", () => {
34 | cpu.update ();
35 | memory.update ();
36 | network.update ();
37 | storage.update ();
38 |
39 | foreach (var gpu in gpu_list) {
40 | gpu.update ();
41 | }
42 | });
43 | return true;
44 | });
45 | }
46 |
47 | private void detect_gpu_pci_devices () {
48 | Pci.Access pci_access = new Pci.Access ();
49 |
50 | pci_access.init ();
51 | pci_access.scan_bus ();
52 |
53 | char namebuf[1024];
54 |
55 | for (unowned Pci.Dev pci_device = pci_access.devices; pci_device != null; pci_device = pci_device.next) {
56 | pci_device.fill_info (Pci.FILL_IDENT | Pci.FILL_BASES | Pci.FILL_CLASS_EXT | Pci.FILL_LABEL | Pci.FILL_CLASS);
57 | string name = pci_access.lookup_name (namebuf, Pci.LookupMode.DEVICE, pci_device.vendor_id, pci_device.device_id);
58 |
59 | // Looking for a specific PCI device class
60 | if (pci_device.device_class == Utils.PCI_CLASS_VGA_CONTROLLER || pci_device.device_class == Utils.PCI_CLASS_3D_CONTROLLER) {
61 | // print (" %04x:%02x:%02x.%d\n", pci_device.domain_16, pci_device.bus, pci_device.dev, pci_device.func);
62 |
63 | switch (pci_device.vendor_id) {
64 | case Utils.PCI_VENDOR_ID_INTEL:
65 | debug ("PCI device: GPU: Intel %s", name);
66 | IGPU gpu = new GPUIntel (pci_access, pci_device);
67 | gpu_list.add (gpu);
68 | break;
69 |
70 | case Utils.PCI_VENDOR_ID_NVIDIA:
71 | debug ("PCI device: GPU: nVidia %s", name);
72 | IGPU gpu = new GPUNvidia (pci_access, pci_device);
73 | gpu_list.add (gpu);
74 | break;
75 |
76 | case Utils.PCI_VENDOR_ID_AMD:
77 | debug ("PCI device: GPU: AMD %s", name);
78 | IGPU gpu = new GPUAmd (pci_access, pci_device);
79 | gpu.hwmon_temperatures = hwmon_path_parser.gpu_paths_parser.temperatures;
80 | gpu_list.add (gpu);
81 | break;
82 |
83 | default:
84 | warning ("GPU: Unknown: 0x%llX : %s", pci_device.vendor_id, name);
85 | break;
86 | }
87 | } else {
88 | debug ("PCI device: vendor: 0x%llX class:0x%llX %s", pci_device.vendor_id, pci_device.device_class, name);
89 | }
90 | }
91 | }
92 |
93 | public ResourcesSerialized serialize () {
94 |
95 | // quick fix; so no need to comment out GPU
96 | // code for Indicator and Preferences
97 | IGPU gpu = gpu_list.size > 0 ? gpu_list.first () : null;
98 |
99 | return ResourcesSerialized () {
100 | cpu_percentage = cpu.percentage,
101 | cpu_frequency = cpu.frequency,
102 | cpu_temperature = cpu.temperature_mean,
103 | memory_percentage = memory.used_percentage,
104 | memory_used = memory.used,
105 | memory_total = memory.total,
106 | swap_percentage = swap.percentage,
107 | swap_used = swap.used,
108 | swap_total = swap.total,
109 | network_up = network.bytes_out,
110 | network_down = network.bytes_in,
111 | gpu_percentage = gpu != null ? gpu.percentage : 0,
112 | gpu_memory_percentage = gpu != null ? gpu.memory_percentage : 0,
113 | gpu_memory_used = gpu != null ? gpu.memory_vram_used : 0,
114 | gpu_memory_total = gpu != null ? gpu.memory_vram_total : 0,
115 | gpu_temperature = gpu != null ? gpu.temperature : 0
116 | };
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/Resources/ResourcesSerialized.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public struct ResourcesSerialized {
7 | public int cpu_percentage;
8 | public double cpu_frequency;
9 | public double cpu_temperature;
10 | public uint memory_percentage;
11 | public double memory_used;
12 | public double memory_total;
13 | public int swap_percentage;
14 | public double swap_used;
15 | public double swap_total;
16 | public int network_up;
17 | public int network_down;
18 | public int gpu_percentage;
19 | public uint gpu_memory_percentage;
20 | public double gpu_memory_used;
21 | public double gpu_memory_total;
22 | public double gpu_temperature;
23 | }
24 |
--------------------------------------------------------------------------------
/src/Resources/Storage/Disk.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2021 Dirli
4 | * 2021 stsdc
5 | */
6 |
7 | public class Monitor.Disk : GLib.Object {
8 | public string model;
9 | public uint64 size;
10 | public uint64 free;
11 | public string revision;
12 | public string id;
13 | public string device;
14 | public string partition;
15 | public GLib.Icon drive_icon;
16 |
17 | private Gee.ArrayList volumes = new Gee.ArrayList ();
18 |
19 | public Disk (UDisks.Drive drive) {
20 | model = drive.model;
21 | size = drive.size;
22 | revision = drive.revision;
23 | id = drive.id;
24 | free = 0;
25 | }
26 |
27 | public void add_volume (Volume vol) {
28 | volumes.add (vol);
29 | free = free + vol.free;
30 | }
31 |
32 | public Gee.ArrayList get_volumes () {
33 | var volumes_arr = new Gee.ArrayList ();
34 |
35 | volumes.foreach ((vol) => {
36 |
37 | volumes_arr.add (vol);
38 |
39 | return true;
40 | });
41 |
42 | volumes_arr.sort (compare_volumes);
43 |
44 | return volumes_arr;
45 | }
46 |
47 | private int compare_volumes (Volume? vol1, Volume? vol2) {
48 | if (vol1 == null) {
49 | return (vol2 == null) ? 0 : -1;
50 | }
51 |
52 | if (vol2 == null) {
53 | return 1;
54 | }
55 |
56 | return GLib.strcmp (vol1.device, vol2.device);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Resources/Storage/StorageBlock.vala:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/src/Resources/Storage/StorageBlock.vala
--------------------------------------------------------------------------------
/src/Resources/Storage/StorageParser.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | class Monitor.StorageParser : Object {
7 | private const string BLOCKS_PATH = "/sys/block";
8 |
9 | public Gee.ArrayList get_slaves_names (string volume_name) {
10 | Gee.ArrayList slaves_names = new Gee.ArrayList ();
11 |
12 | try {
13 | Dir slaves_dir = Dir.open (Path.build_filename (BLOCKS_PATH, volume_name, "slaves"), 0);
14 |
15 | string ? slave = null;
16 |
17 | while ((slave = slaves_dir.read_name ()) != null) {
18 | debug ("Found slave: " + slave);
19 | slaves_names.add (slave);
20 | }
21 |
22 | } catch (FileError e) {
23 | warning ("%s", e.message);
24 | }
25 |
26 | return slaves_names;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/Resources/Storage/Volume.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | [Compact]
7 | public class Monitor.Volume : Object {
8 | public string device;
9 | public string label;
10 | public string type;
11 | public string uuid;
12 | public string mount_point;
13 | public uint64 size;
14 | public uint64 free;
15 | public uint64 offset;
16 |
17 | // means the volume is only on one physical disk
18 | public bool strict_affiliation { public get; private set; }
19 |
20 | public Gee.ArrayList slaves = new Gee.ArrayList ();
21 |
22 |
23 | public Volume (UDisks.Block block) {
24 | device = block.device;
25 | label = block.id_label;
26 | type = block.id_type;
27 | size = block.size;
28 | uuid = block.id_uuid;
29 | }
30 |
31 | public void add_slave (string? new_slave) {
32 | check_affiliation (new_slave);
33 | slaves.add (new_slave);
34 | }
35 |
36 | private void check_affiliation (string new_slave) {
37 | if (slaves.size > 0) {
38 | foreach (string slave in slaves) {
39 | if (slave.contains (new_slave[0:3])) {
40 | strict_affiliation = true;
41 | debug ("Slave volume %s of %s is on the same disk as all other slave volumes", new_slave, device);
42 | } else {
43 | strict_affiliation = false;
44 | debug ("Slave volume %s of %s is on the same disk as all other slave volumes", new_slave, device);
45 | }
46 | }
47 | } else {
48 | debug ("First slave: %s", new_slave);
49 | strict_affiliation = true;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Resources/Swap.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Swap : Object {
7 | public double total { get; private set; default = 0; }
8 | public double used { get; private set; default = 0; }
9 |
10 | private GTop.Swap swap;
11 |
12 | public int percentage {
13 | get {
14 | update ();
15 |
16 | // The total amount of the swap is 0 when it is unavailable
17 | if (total == 0) {
18 | return 0;
19 | } else {
20 | return (int) (Math.round ((used / total) * 100));
21 | }
22 | }
23 | }
24 |
25 | public Swap () {
26 | }
27 |
28 | private void update () {
29 | GTop.get_swap (out swap);
30 | total = (double) (swap.total / 1024 / 1024) / 1000;
31 | used = (double) (swap.used / 1024 / 1024) / 1000;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/Services/Appearance.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Appearance : Object {
7 | public static void set_prefered_style () {
8 | var granite_settings = Granite.Settings.get_default ();
9 | var gtk_settings = Gtk.Settings.get_default ();
10 |
11 | bool is_dark = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK;
12 | gtk_settings.gtk_application_prefer_dark_theme = is_dark;
13 |
14 |
15 | var provider = new Gtk.CssProvider ();
16 |
17 | if (is_dark) {
18 | provider.load_from_resource ("/io/elementary/monitor/monitor-dark.css");
19 | } else {
20 | provider.load_from_resource ("/io/elementary/monitor/monitor-light.css");
21 | }
22 |
23 | Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
24 |
25 | // We listen to changes in Granite.Settings and update our app if the user changes their preference
26 | granite_settings.notify["prefers-color-scheme"].connect (() => {
27 | is_dark = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK;
28 | gtk_settings.gtk_application_prefer_dark_theme = is_dark;
29 |
30 | if (is_dark) {
31 | provider.load_from_resource ("/io/elementary/monitor/monitor-dark.css");
32 | } else {
33 | provider.load_from_resource ("/io/elementary/monitor/monitor-light.css");
34 | }
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Services/DBusServer.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | [DBus (name = "io.elementary.monitor")]
7 | public class Monitor.DBusServer : Object {
8 | private const string DBUS_NAME = "io.elementary.monitor";
9 | private const string DBUS_PATH = "/io/elementary/monitor";
10 |
11 | private static GLib.Once instance;
12 |
13 | public static unowned DBusServer get_default () {
14 | return instance.once (() => { return new DBusServer (); });
15 | }
16 |
17 | public signal void update (ResourcesSerialized data);
18 | public signal void indicator_state (bool state);
19 | public signal void indicator_cpu_state (bool state);
20 | public signal void indicator_cpu_frequency_state (bool state);
21 | public signal void indicator_cpu_temperature_state (bool state);
22 | public signal void indicator_memory_state (bool state);
23 | public signal void indicator_network_up_state (bool state);
24 | public signal void indicator_network_down_state (bool state);
25 | public signal void indicator_gpu_state (bool state);
26 | public signal void indicator_gpu_memory_state (bool state);
27 | public signal void indicator_gpu_temperature_state (bool state);
28 | public signal void quit ();
29 | public signal void show ();
30 |
31 | construct {
32 | Bus.own_name (
33 | BusType.SESSION,
34 | DBUS_NAME,
35 | BusNameOwnerFlags.NONE,
36 | (connection) => on_bus_aquired (connection),
37 | () => {},
38 | null
39 | );
40 | }
41 |
42 | public void quit_monitor () throws IOError, DBusError {
43 | quit ();
44 | }
45 |
46 | public void show_monitor () throws IOError, DBusError {
47 | show ();
48 | }
49 |
50 | private void on_bus_aquired (DBusConnection conn) {
51 | try {
52 | debug ("DBus registered!");
53 | conn.register_object ("/io/elementary/monitor", get_default ());
54 | } catch (Error e) {
55 | error (e.message);
56 | }
57 | }
58 |
59 | }
60 |
61 | [DBus (name = "io.elementary.monitor")]
62 | public errordomain DBusServerError {
63 | SOME_ERROR
64 | }
65 |
--------------------------------------------------------------------------------
/src/Views/ProcessView/ProcessInfoView/OpenFilesTreeView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.OpenFilesTreeView : Gtk.TreeView {
7 | public new OpenFilesTreeViewModel model;
8 | private Gtk.TreeViewColumn path_column;
9 | private Regex ? regex;
10 |
11 | public signal void process_selected (Process process);
12 |
13 | public OpenFilesTreeView (OpenFilesTreeViewModel model) {
14 | this.model = model;
15 | /* *INDENT-OFF* */
16 | regex = /(?i:^.*\.(xpm|png)$)/; // vala-lint=space-before-paren,
17 | /* *INDENT-ON* */
18 |
19 | show_expanders = false;
20 |
21 | // setup name column
22 | path_column = new Gtk.TreeViewColumn ();
23 | path_column.title = _("Opened files");
24 | path_column.expand = true;
25 | path_column.min_width = 250;
26 | path_column.set_sort_column_id (Column.NAME);
27 |
28 | var icon_cell = new Gtk.CellRendererPixbuf ();
29 | path_column.pack_start (icon_cell, false);
30 | // path_column.add_attribute (icon_cell, "icon_name", Column.ICON);
31 | path_column.set_cell_data_func (icon_cell, icon_cell_layout);
32 |
33 | var name_cell = new Gtk.CellRendererText ();
34 | name_cell.ellipsize = Pango.EllipsizeMode.END;
35 | name_cell.set_fixed_height_from_font (1);
36 | path_column.pack_start (name_cell, false);
37 | path_column.add_attribute (name_cell, "text", Column.NAME);
38 | insert_column (path_column, -1);
39 |
40 | // resize all of the columns
41 | columns_autosize ();
42 |
43 | set_model (model);
44 |
45 | hadjustment = null;
46 | vadjustment = null;
47 | vexpand = true;
48 |
49 | }
50 |
51 | public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) {
52 | try {
53 | var icon = Icon.new_for_string ("emblem-documents-symbolic");
54 | ((Gtk.CellRendererPixbuf)icon_cell).icon_name = icon.to_string ();
55 | } catch (Error e) {
56 | warning (e.message);
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/Views/ProcessView/ProcessInfoView/Preventor.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.Preventor : Gtk.Stack {
7 | private Gtk.Box preventive_action_bar;
8 | private Gtk.Label confirmation_label;
9 | private Gtk.Button confirm_button;
10 | private Gtk.Button deny_button;
11 |
12 | private Gtk.Widget child_widget;
13 |
14 | public signal void confirmed (bool is_confirmed);
15 |
16 | construct {
17 | valign = Gtk.Align.END;
18 |
19 | preventive_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
20 | preventive_action_bar.valign = Gtk.Align.START;
21 | preventive_action_bar.halign = Gtk.Align.END;
22 | preventive_action_bar.margin_top = 10;
23 |
24 |
25 | confirmation_label = new Gtk.Label (_("Are you sure you want to do this?"));
26 | confirmation_label.margin_end = 10;
27 |
28 | confirm_button = new Gtk.Button.with_label (_("Yes"));
29 | confirm_button.margin_end = 10;
30 | confirm_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
31 |
32 | deny_button = new Gtk.Button.with_label (_("No"));
33 |
34 | preventive_action_bar.add (confirmation_label);
35 | preventive_action_bar.add (confirm_button);
36 | preventive_action_bar.add (deny_button);
37 | }
38 |
39 | public Preventor (Gtk.Widget _child, string name) {
40 | child_widget = _child;
41 | add_named (child_widget, name);
42 | add_named (preventive_action_bar, "preventive_action_bar");
43 |
44 | deny_button.clicked.connect (() => {
45 | set_transition_type (Gtk.StackTransitionType.SLIDE_UP);
46 | set_visible_child (child_widget);
47 | confirmed (false);
48 | });
49 |
50 | confirm_button.clicked.connect (() => {
51 | set_transition_type (Gtk.StackTransitionType.SLIDE_UP);
52 | set_visible_child (child_widget);
53 | confirmed (true);
54 | });
55 | }
56 |
57 | public void set_prevention (string confirmation_text) {
58 | set_transition_type (Gtk.StackTransitionType.SLIDE_DOWN);
59 | confirmation_label.set_text (_(confirmation_text));
60 | set_visible_child (preventive_action_bar);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.ProcessInfoCPURAM : Gtk.Grid {
7 | private Gtk.Label cpu_label;
8 | private Gtk.Label ram_label;
9 |
10 | private Chart cpu_chart;
11 | private Chart ram_chart;
12 |
13 | construct {
14 | column_spacing = 6;
15 | row_spacing = 6;
16 | vexpand = false;
17 | column_homogeneous = true;
18 | row_homogeneous = false;
19 |
20 | cpu_chart = new Chart (1);
21 | cpu_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300));
22 | ram_chart = new Chart (1);
23 | ram_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300));
24 |
25 | cpu_chart.height_request = 60;
26 | ram_chart.height_request = 60;
27 |
28 | var cpu_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
29 | cpu_graph_box.add (cpu_chart);
30 |
31 | var mem_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
32 | mem_graph_box.add (ram_chart);
33 |
34 | cpu_label = new Gtk.Label ("CPU: " + Utils.NO_DATA);
35 | cpu_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
36 | cpu_label.halign = Gtk.Align.START;
37 |
38 | ram_label = new Gtk.Label ("RAM: " + Utils.NO_DATA);
39 | ram_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
40 | ram_label.halign = Gtk.Align.START;
41 |
42 | attach (cpu_label, 0, 0, 1, 1);
43 | attach (ram_label, 1, 0, 1, 1);
44 |
45 | attach (cpu_graph_box, 0, 1, 1, 1);
46 | attach (mem_graph_box, 1, 1, 1, 1);
47 | }
48 |
49 | public void set_charts_data (Process process) {
50 | cpu_chart.preset_data (0, process.cpu_percentage_history);
51 | ram_chart.preset_data (0, process.mem_percentage_history);
52 | }
53 |
54 | public void update (Process process) {
55 | cpu_label.set_text ((_("CPU: %.1f%%")).printf (process.cpu_percentage));
56 | ram_label.set_text ((_("RAM: %.1f%%")).printf (process.mem_percentage));
57 |
58 | cpu_chart.update (0, process.cpu_percentage);
59 | ram_chart.update (0, process.mem_percentage);
60 | }
61 |
62 | public void clear_graphs () {
63 | cpu_chart.clear ();
64 | ram_chart.clear ();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.ProcessInfoHeader : Gtk.Grid {
7 | private Gtk.Image icon;
8 | public Gtk.Label state;
9 | public Gtk.Label application_name;
10 | public LabelRoundy pid;
11 |
12 | public LabelRoundy ppid;
13 | public LabelRoundy pgrp;
14 | public LabelRoundy nice;
15 | public LabelRoundy priority;
16 | public LabelRoundy num_threads;
17 | public LabelRoundy username;
18 |
19 | private Regex ? regex;
20 |
21 | construct {
22 | column_spacing = 12;
23 |
24 | /* *INDENT-OFF* */
25 | regex = /(?i:^.*\.(xpm|png)$)/; // vala-lint=space-before-paren,
26 | /* *INDENT-ON* */
27 |
28 | icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG);
29 | icon.set_pixel_size (64);
30 | icon.valign = Gtk.Align.END;
31 |
32 | state = new Gtk.Label ("?");
33 | state.halign = Gtk.Align.START;
34 | state.get_style_context ().add_class ("state_badge");
35 |
36 | var icon_container = new Gtk.Fixed ();
37 | icon_container.put (icon, 0, 0);
38 | icon_container.put (state, -5, 48);
39 |
40 | application_name = new Gtk.Label (_("N/A"));
41 | application_name.get_style_context ().add_class ("h2");
42 | application_name.ellipsize = Pango.EllipsizeMode.END;
43 | application_name.tooltip_text = _("N/A");
44 | application_name.halign = Gtk.Align.START;
45 | application_name.valign = Gtk.Align.START;
46 |
47 | pid = new LabelRoundy (_("PID"));
48 | nice = new LabelRoundy (_("NI"));
49 | priority = new LabelRoundy (_("PRI"));
50 | num_threads = new LabelRoundy (_("THR"));
51 | // ppid = new LabelRoundy (_("PPID"));
52 | // pgrp = new LabelRoundy (_("PGRP"));
53 |
54 | // TODO: tooltip_text UID
55 | username = new LabelRoundy ("");
56 |
57 | var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
58 | wrapper.add (pid);
59 | wrapper.add (priority);
60 | wrapper.add (nice);
61 | wrapper.add (num_threads);
62 | wrapper.add (username);
63 |
64 | attach (icon_container, 0, 0, 1, 2);
65 | attach (application_name, 1, 0, 3, 1);
66 | attach (wrapper, 1, 1, 1, 1);
67 | }
68 |
69 | public void update (Process process) {
70 | application_name.set_text (process.application_name);
71 | application_name.tooltip_text = process.command;
72 | pid.set_text (process.stat.pid.to_string ());
73 | nice.set_text (process.stat.nice.to_string ());
74 | priority.set_text (process.stat.priority.to_string ());
75 |
76 | if (process.uid == 0) {
77 | username.val.get_style_context ().add_class ("username-root");
78 | username.val.get_style_context ().remove_class ("username-other");
79 | username.val.get_style_context ().remove_class ("username-current");
80 | } else if (process.uid == (int) Posix.getuid ()) {
81 | username.val.get_style_context ().add_class ("username-current");
82 | username.val.get_style_context ().remove_class ("username-other");
83 | username.val.get_style_context ().remove_class ("username-root");
84 | } else {
85 | username.val.get_style_context ().add_class ("username-other");
86 | username.val.get_style_context ().remove_class ("username-root");
87 | username.val.get_style_context ().remove_class ("username-current");
88 | }
89 |
90 | username.set_text (process.username);
91 | username.tooltip_text = process.uid.to_string ();
92 | num_threads.set_text (process.stat.num_threads.to_string ());
93 | state.set_text (process.stat.state);
94 | state.tooltip_text = set_state_tooltip ();
95 | num_threads.set_text (process.stat.num_threads.to_string ());
96 | set_icon (process);
97 | }
98 |
99 | private void set_icon (Process process) {
100 | // this construction should be somewhere else
101 | var icon_name = process.icon.to_string ();
102 |
103 | if (!regex.match (icon_name)) {
104 | icon.set_from_icon_name (icon_name, Gtk.IconSize.DIALOG);
105 | } else {
106 | try {
107 | var pixbuf = new Gdk.Pixbuf.from_file_at_size (icon_name, 48, -1);
108 | icon.set_from_pixbuf (pixbuf);
109 | } catch (Error e) {
110 | warning (e.message);
111 | }
112 | }
113 | }
114 |
115 | private string set_state_tooltip () {
116 | switch (state.label) {
117 | case "D":
118 | return _("The app is waiting in an uninterruptible disk sleep");
119 | case "I":
120 | return _("Idle kernel thread");
121 | case "R":
122 | return _("The process is running or runnable (on run queue)");
123 | case "S":
124 | return _("The process is in an interruptible sleep; waiting for an event to complete");
125 | case "T":
126 | return _("The process is stopped by a job control signal");
127 | case "t":
128 | return _("The process is stopped by a debugger during the tracing");
129 | case "Z":
130 | return _("The app is terminated but not reaped by its parent");
131 | default:
132 | return "";
133 | }
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.ProcessInfoIOStats : Gtk.Grid {
7 | private Gtk.Label rchar_label;
8 | private Gtk.Label wchar_label;
9 | private Gtk.Label syscr_label;
10 | private Gtk.Label syscw_label;
11 | private Gtk.Label write_bytes_label;
12 | private Gtk.Label read_bytes_label;
13 | private Gtk.Label cancelled_write_bytes_label;
14 |
15 | public OpenFilesTreeView open_files_tree_view;
16 |
17 | construct {
18 | column_spacing = 6;
19 | row_spacing = 6;
20 | column_homogeneous = true;
21 | row_homogeneous = false;
22 |
23 | var opened_files_label = create_label (_("Opened files"));
24 | opened_files_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
25 | opened_files_label.margin_top = 24;
26 |
27 | var characters_label = create_label (_("Characters"));
28 | characters_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
29 | rchar_label = create_label (_("N/A"));
30 | wchar_label = create_label (_("N/A"));
31 |
32 | var system_calls_label = create_label (_("System calls"));
33 | system_calls_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
34 | syscr_label = create_label (_("N/A"));
35 | syscw_label = create_label (_("N/A"));
36 |
37 | var io_label = create_label (_("Read/Written"));
38 | io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
39 | write_bytes_label = create_label (_("N/A"));
40 | read_bytes_label = create_label (_("N/A"));
41 |
42 | var cancelled_write_label = create_label (_("Cancelled write"));
43 | cancelled_write_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL);
44 |
45 | cancelled_write_bytes_label = create_label (Utils.NO_DATA);
46 |
47 | attach (io_label, 0, 1, 1, 1);
48 | attach (create_label_with_icon (read_bytes_label, "go-up-symbolic"), 0, 2, 1, 1);
49 | attach (create_label_with_icon (write_bytes_label, "go-down-symbolic"), 0, 3, 1, 1);
50 |
51 | attach (cancelled_write_label, 1, 1, 1, 1);
52 | attach (cancelled_write_bytes_label, 1, 2, 1, 1);
53 |
54 | // attach (opened_files_label, 0, 3, 3, 1);
55 |
56 | var model = new OpenFilesTreeViewModel ();
57 | var open_files_tree_view_scrolled = new Gtk.ScrolledWindow (null, null);
58 | open_files_tree_view = new OpenFilesTreeView (model);
59 | open_files_tree_view_scrolled.add (open_files_tree_view);
60 | attach (open_files_tree_view_scrolled, 0, 4, 3, 1);
61 | }
62 |
63 | public void update (Process process) {
64 | write_bytes_label.set_text (format_size ((uint64) process.io.write_bytes, IEC_UNITS));
65 | read_bytes_label.set_text (format_size ((uint64) process.io.read_bytes, IEC_UNITS));
66 | cancelled_write_bytes_label.set_text (format_size ((uint64) process.io.cancelled_write_bytes, IEC_UNITS));
67 | }
68 |
69 | private Gtk.Label create_label (string text) {
70 | var label = new Gtk.Label (text);
71 | label.halign = Gtk.Align.START;
72 | return label;
73 | }
74 |
75 | private Gtk.Image create_icon (string icon_name) {
76 | var icon = new Gtk.Image ();
77 | icon.gicon = new ThemedIcon (icon_name);
78 | icon.halign = Gtk.Align.START;
79 | icon.pixel_size = 16;
80 | return icon;
81 | }
82 |
83 | private Gtk.Grid create_label_with_icon (Gtk.Label label, string icon_name) {
84 | var grid = new Gtk.Grid ();
85 | grid.column_spacing = 2;
86 | grid.attach (create_icon (icon_name), 0, 0, 1, 1);
87 | grid.attach (label, 1, 0, 1, 1);
88 | return grid;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/Views/ProcessView/ProcessView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.ProcessView : Gtk.Box {
7 | public TreeViewModel treeview_model;
8 | public CPUProcessTreeView process_tree_view;
9 |
10 | public ProcessInfoView process_info_view;
11 |
12 | construct {
13 | process_info_view = new ProcessInfoView ();
14 |
15 | // hide on startup
16 | process_info_view.no_show_all = true;
17 | }
18 |
19 | public ProcessView () {
20 | treeview_model = new TreeViewModel ();
21 |
22 | process_tree_view = new CPUProcessTreeView (treeview_model);
23 | process_tree_view.process_selected.connect ((process) => on_process_selected (process));
24 |
25 | // making tree view scrollable
26 | var process_tree_view_scrolled = new Gtk.ScrolledWindow (null, null);
27 | process_tree_view_scrolled.add (process_tree_view);
28 |
29 | var paned = new Gtk.Paned (Gtk.Orientation.HORIZONTAL);
30 | paned.pack1 (process_tree_view_scrolled, true, false);
31 | paned.pack2 (process_info_view, false, false);
32 | // paned.set_min_position (200);
33 | paned.set_position (paned.max_position);
34 | paned.set_hexpand (true);
35 |
36 | add (paned);
37 | }
38 |
39 | public void on_process_selected (Process process) {
40 | process_info_view.process = process;
41 | process_info_view.no_show_all = false;
42 | // process_info_view.show_all ();
43 | }
44 |
45 | public void update () {
46 | new Thread ("update-processes", () => {
47 | Idle.add (() => {
48 | process_info_view.update ();
49 | treeview_model.process_manager.update_processes.begin ();
50 |
51 | return false;
52 | });
53 | return true;
54 | });
55 |
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/Views/SystemView/SystemCPUInfoPopover.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.SystemCPUInfoPopover : Gtk.Box {
7 | private CPU cpu;
8 |
9 | construct {
10 | margin = 12;
11 | orientation = Gtk.Orientation.VERTICAL;
12 | }
13 |
14 |
15 | public SystemCPUInfoPopover (CPU _cpu) {
16 |
17 | cpu = _cpu;
18 |
19 | var stack = new Gtk.Stack () {
20 | transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT,
21 | height_request = 300,
22 | width_request = 400,
23 | margin_top = 12,
24 | };
25 |
26 | stack.add_titled (general_page (), "general_page", _("General"));
27 | stack.add_titled (features_page (), "features_page", _("Features"));
28 | stack.add_titled (bugs_page (), "bugs_page", _("Bugs"));
29 |
30 | Gtk.StackSwitcher stack_switcher = new Gtk.StackSwitcher () {
31 | valign = Gtk.Align.CENTER,
32 | halign = Gtk.Align.CENTER,
33 | };
34 | stack_switcher.set_stack (stack);
35 |
36 | add (stack_switcher);
37 | add (stack);
38 | }
39 |
40 | private Gtk.Label label (string text) {
41 | var label = new Gtk.Label (text) {
42 | halign = Gtk.Align.START,
43 | valign = Gtk.Align.CENTER,
44 | wrap = true,
45 | margin = 6,
46 | };
47 |
48 | return label;
49 | }
50 |
51 | private Gtk.ListBox general_page () {
52 | var listbox = new Gtk.ListBox () {
53 | activate_on_single_click = false
54 | };
55 |
56 | listbox.add (label (_("Model:") + " " + cpu.model));
57 | listbox.add (label (_("Family:") + " " + cpu.family));
58 | listbox.add (label (_("Microcode ver.:") + " " + cpu.microcode));
59 | listbox.add (label (_("Bogomips:") + " " + cpu.bogomips));
60 |
61 | if (cpu.core_list[0].caches.has_key ("L1Instruction")) {
62 | var value = cpu.cache_multipliers["L1Instruction"].to_string () + "×" + cpu.core_list[0].caches["L1Instruction"].size;
63 | listbox.add (label (_("L1 Instruction cache: ") + value));
64 | }
65 | if (cpu.core_list[0].caches.has_key ("L1Data")) {
66 | var value = cpu.cache_multipliers["L1Data"].to_string () + "×" + cpu.core_list[0].caches["L1Data"].size;
67 | listbox.add (label (_("L1 Data cache: ") + value));
68 | }
69 | if (cpu.core_list[0].caches.has_key ("L1")) {
70 | var value = cpu.cache_multipliers["L1"].to_string () + "×" + cpu.core_list[0].caches["L1"].size;
71 | listbox.add (label (_("L1 cache: ") + value));
72 | }
73 | if (cpu.core_list[0].caches.has_key ("L2")) {
74 | listbox.add (label (_("L2 Cache size: ") + cpu.cache_multipliers["L2"].to_string () + "×" + cpu.core_list[0].caches["L2"].size));
75 | }
76 | if (cpu.core_list[0].caches.has_key ("L3")) {
77 | listbox.add (label (_("L3 Cache size: ") + cpu.cache_multipliers["L3"].to_string () + "×" + cpu.core_list[0].caches["L3"].size));
78 | }
79 |
80 | listbox.add (label (_("Address sizes: ") + cpu.address_sizes));
81 |
82 | return listbox;
83 | }
84 |
85 | private Gtk.Widget features_page () {
86 | var listbox = new Gtk.ListBox () {
87 | activate_on_single_click = false
88 | };
89 |
90 | foreach (var feature in cpu.features) {
91 | listbox.add (create_row (feature.key, feature.value));
92 | }
93 |
94 | var scrolled_window = new Gtk.ScrolledWindow (null, null);
95 | scrolled_window.add (listbox);
96 |
97 | return scrolled_window;
98 | }
99 |
100 | private Gtk.Widget bugs_page () {
101 | var listbox = new Gtk.ListBox () {
102 | activate_on_single_click = false
103 | };
104 |
105 | foreach (var bug in cpu.bugs) {
106 | listbox.add (create_row (bug.key, bug.value));
107 | }
108 |
109 | var scrolled_window = new Gtk.ScrolledWindow (null, null);
110 | scrolled_window.add (listbox);
111 |
112 | return scrolled_window;
113 | }
114 |
115 | private Gtk.ListBoxRow create_row (string flag, string flag_description) {
116 | var row = new Gtk.ListBoxRow ();
117 | var grid = new Gtk.Grid () {
118 | column_spacing = 2,
119 | };
120 |
121 | var flag_label = new Gtk.Label (flag) {
122 | halign = Gtk.Align.START,
123 | valign = Gtk.Align.CENTER,
124 | wrap = true,
125 | margin = 6,
126 | };
127 | flag_label.get_style_context ().add_class ("flags_badge");
128 |
129 |
130 | grid.attach (flag_label, 0, 0, 1, 1);
131 | grid.attach (label (flag_description), 1, 0, 1, 1);
132 | row.add (grid);
133 |
134 | return row;
135 | }
136 |
137 | }
138 |
139 | // public class Monitor.X : Gtk.ListBoxRow {
140 | // construct {
141 | // get_style_context ().add_class ("open_files_list_box_row");
142 | // }
143 | // public X (string _text) {
144 | // var text = _text;
145 | // var grid = new Gtk.Grid ();
146 | // grid.column_spacing = 2;
147 |
148 | // Gtk.Label label = new Gtk.Label (text);
149 | // label.halign = Gtk.Align.START;
150 | // grid.attach (label, 1, 0, 1, 1);
151 |
152 | // add (grid);
153 | // }
154 | // }
155 |
--------------------------------------------------------------------------------
/src/Views/SystemView/SystemGPUView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.SystemGPUView : Monitor.WidgetResource {
7 | private Chart gpu_chart;
8 | private Chart gpu_vram_percentage_chart;
9 | private Chart gpu_temperature_chart;
10 | private IGPU gpu;
11 |
12 | private LabelRoundy gpu_vram_percentage_label;
13 | private LabelRoundy gpu_temperature_label;
14 |
15 |
16 | construct {
17 | gpu_vram_percentage_label = new LabelRoundy (_("VRAM"));
18 | gpu_vram_percentage_label.margin = 6;
19 | gpu_vram_percentage_label.margin_top = 2;
20 |
21 | gpu_temperature_label = new LabelRoundy (_("TEMPERATURE"));
22 | gpu_temperature_label.margin = 6;
23 | gpu_temperature_label.margin_top = 2;
24 |
25 | gpu_vram_percentage_chart = new Chart (1);
26 | gpu_vram_percentage_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500));
27 | gpu_vram_percentage_chart.height_request = -1;
28 | gpu_vram_percentage_chart.config.y_axis.fixed_max = 100.0;
29 | gpu_temperature_chart = new Chart (1);
30 | gpu_temperature_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500));
31 | gpu_temperature_chart.height_request = -1;
32 |
33 | var grid_frequency_info = new Gtk.Grid ();
34 | grid_frequency_info.attach (gpu_vram_percentage_label, 0, 0, 1, 1);
35 | grid_frequency_info.attach (gpu_vram_percentage_chart, 0, 0, 1, 1);
36 |
37 | var grid_temperature_info = new Gtk.Grid ();
38 | grid_temperature_info.attach (gpu_temperature_label, 0, 0, 1, 1);
39 | grid_temperature_info.attach (gpu_temperature_chart, 0, 0, 1, 1);
40 |
41 |
42 |
43 | var smol_charts_container = new Gtk.Grid ();
44 | smol_charts_container.width_request = 200;
45 | smol_charts_container.hexpand = false;
46 | smol_charts_container.halign = Gtk.Align.START;
47 | smol_charts_container.attach (grid_frequency_info, 0, 0, 1, 1);
48 | smol_charts_container.attach (grid_temperature_info, 0, 1, 1, 1);
49 | smol_charts_container.row_spacing = 6;
50 | smol_charts_container.margin_start = 6;
51 |
52 | add_charts_container (smol_charts_container);
53 | }
54 |
55 | public SystemGPUView (IGPU _gpu) {
56 | gpu = _gpu;
57 |
58 | title = gpu.name;
59 |
60 | gpu_chart = new Chart (1);
61 | gpu_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500));
62 | set_main_chart (gpu_chart);
63 |
64 | set_main_chart_overlay (gpu_usage_grid ());
65 | }
66 |
67 | private Gtk.Grid gpu_usage_grid () {
68 | Gtk.Grid grid = new Gtk.Grid () {
69 | column_spacing = 8,
70 | row_spacing = 4,
71 | margin = 6
72 | };
73 |
74 | return grid;
75 | }
76 |
77 | public void update () {
78 | label_vertical_main_metric = (("%d%%").printf (gpu.percentage));
79 | gpu_chart.update (0, gpu.percentage);
80 |
81 | gpu_vram_percentage_chart.update (0, gpu.memory_percentage);
82 | gpu_temperature_chart.update (0, gpu.temperature);
83 | gpu_vram_percentage_label.set_text (("%.2f %s").printf (gpu.memory_percentage, "%"));
84 | gpu_temperature_label.set_text (("%.2f %s").printf (gpu.temperature, _("℃")));
85 |
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/Views/SystemView/SystemMemoryView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.SystemMemoryView : Monitor.WidgetResource {
7 | private Chart memory_chart;
8 | private Memory memory;
9 |
10 | private LabelRoundy memory_buffered_label = new LabelRoundy (_("Buffered"));
11 | private LabelRoundy memory_cached_label = new LabelRoundy (_("Cached"));
12 | private LabelRoundy memory_locked_label = new LabelRoundy (_("Locked"));
13 | private LabelRoundy memory_total_label = new LabelRoundy (_("Total"));
14 | private LabelRoundy memory_used_label = new LabelRoundy (_("Used"));
15 | private LabelRoundy memory_shared_label = new LabelRoundy (_("Shared"));
16 |
17 | construct {
18 | title = (_("Memory"));
19 |
20 | }
21 |
22 | public SystemMemoryView (Memory _memory) {
23 | memory = _memory;
24 |
25 | memory_chart = new Chart (1);
26 | memory_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300));
27 | // memory_used_label.set_color ("grape_500");
28 |
29 | // memory_chart.set_serie_color (1, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300));
30 | // memory_shared_label.set_color ("blueberry_100");
31 |
32 | // memory_chart.set_serie_color (2, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500));
33 | // memory_chart.set_serie_color (3, Utils.Colors.get_rgba_color (Utils.Colors.LIME_700));
34 | // memory_chart.set_serie_color (4, Utils.Colors.get_rgba_color (Utils.Colors.LIME_900));
35 | set_main_chart (memory_chart);
36 |
37 | set_main_chart_overlay (memory_usage_grid ());
38 | }
39 |
40 | private Gtk.Grid memory_usage_grid () {
41 | Gtk.Grid grid = new Gtk.Grid () {
42 | column_spacing = 8,
43 | row_spacing = 4,
44 | margin = 6
45 | };
46 |
47 | grid.attach (memory_used_label, 0, 0, 1, 1);
48 | grid.attach (memory_total_label, 0, 1, 1, 1);
49 | grid.attach (memory_shared_label, 1, 0, 1, 1);
50 | grid.attach (memory_buffered_label, 1, 1, 1, 1);
51 | grid.attach (memory_cached_label, 2, 0, 1, 1);
52 | grid.attach (memory_locked_label, 2, 1, 1, 1);
53 |
54 | return grid;
55 | }
56 |
57 | public void update () {
58 | label_vertical_main_metric = (("%u%%").printf (memory.used_percentage));
59 | memory_chart.update (0, memory.used_percentage);
60 | // memory_chart.update (1, memory.shared_percentage);
61 | // memory_chart.update (2, memory.shared_percentage + memory.buffer_percentage);
62 | // memory_chart.update (3, memory.shared_percentage + memory.buffer_percentage + memory.cached_percentage);
63 | // memory_chart.update (3, memory.shared_percentage + memory.buffer_percentage + memory.cached_percentage + memory.locked_percentage);
64 |
65 | memory_total_label.set_text (format_size ((uint64) memory.total, IEC_UNITS));
66 | memory_used_label.set_text (format_size ((uint64) memory.used, IEC_UNITS));
67 | memory_buffered_label.set_text (format_size ((uint64) memory.buffer, IEC_UNITS));
68 | memory_cached_label.set_text (format_size ((uint64) memory.cached, IEC_UNITS));
69 | memory_locked_label.set_text (format_size ((uint64) memory.locked, IEC_UNITS));
70 |
71 | memory_shared_label.set_text (format_size ((uint64) memory.shared, IEC_UNITS));
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/Views/SystemView/SystemNetworkView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.SystemNetworkView : Gtk.Grid {
7 | private Chart network_chart;
8 | private Network network;
9 |
10 | private Granite.HeaderLabel network_name_label;
11 | private LabelRoundy network_upload_label;
12 | private LabelRoundy network_download_label;
13 |
14 | construct {
15 | margin = 12;
16 | column_spacing = 12;
17 | set_vexpand (false);
18 | }
19 |
20 | public SystemNetworkView (Network _network) {
21 | network = _network;
22 |
23 | network_name_label = new Granite.HeaderLabel (_("Network"));
24 |
25 | network_download_label = new LabelRoundy (_("DOWN"));
26 | network_download_label.val.set_width_chars (7);
27 | network_download_label.set_color ("blue");
28 |
29 | network_upload_label = new LabelRoundy (_("UP"));
30 | network_upload_label.val.set_width_chars (7);
31 | network_upload_label.set_color ("green");
32 |
33 | network_chart = new Chart (2);
34 | network_chart.config.y_axis.fixed_max = null;
35 |
36 | network_chart.set_serie_color (0, { 155 / 255.0, 219 / 255.0, 77 / 255.0, 1.0 });
37 | network_chart.set_serie_color (1, { 100 / 255.0, 186 / 255.0, 255 / 255.0, 1.0 });
38 |
39 | var labels_grid = new Gtk.Grid ();
40 | labels_grid.row_spacing = 6;
41 | labels_grid.column_spacing = 6;
42 | labels_grid.margin = 6;
43 | labels_grid.attach (network_download_label, 0, 0, 1, 1);
44 | labels_grid.attach (network_upload_label, 1, 0, 1, 1);
45 |
46 | attach (network_name_label, 0, 0, 1, 1);
47 | attach (labels_grid, 0, 1, 2, 2);
48 | attach (network_chart, 0, 1, 2, 2);
49 | }
50 |
51 | public void update () {
52 | double up_bytes = network.bytes_out;
53 | double down_bytes = network.bytes_in;
54 | if (up_bytes >= 0 && down_bytes >= 0) {
55 | network_download_label.set_text (("%s/s").printf (format_size ((uint64) down_bytes, IEC_UNITS)));
56 | network_upload_label.set_text (("%s/s").printf (format_size ((uint64) up_bytes, IEC_UNITS)));
57 | network_chart.update (0, up_bytes);
58 | network_chart.update (1, down_bytes);
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/Views/SystemView/SystemStorageView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.SystemStorageView : Gtk.Grid {
7 | private Chart storage_chart;
8 | private Storage storage;
9 |
10 | private Granite.HeaderLabel storage_name_label;
11 | private LabelRoundy storage_read_label;
12 | private LabelRoundy storage_write_label;
13 |
14 | private Gtk.Box drive_cards_container;
15 |
16 | construct {
17 | margin = 12;
18 | column_spacing = 12;
19 | set_vexpand (false);
20 | }
21 |
22 | public SystemStorageView (Storage _storage) {
23 | storage = _storage;
24 |
25 | storage_name_label = new Granite.HeaderLabel (_("Storage"));
26 |
27 | storage_write_label = new LabelRoundy (_("WRITE"));
28 | storage_write_label.val.set_width_chars (7);
29 | storage_write_label.set_color ("blue");
30 |
31 | storage_read_label = new LabelRoundy (_("READ"));
32 | storage_read_label.val.set_width_chars (7);
33 | storage_read_label.set_color ("green");
34 |
35 | storage_chart = new Chart (2);
36 | storage_chart.config.y_axis.fixed_max = null;
37 | storage_chart.set_serie_color (0, { 155 / 255.0, 219 / 255.0, 77 / 255.0, 1.0 });
38 | storage_chart.set_serie_color (1, { 100 / 255.0, 186 / 255.0, 255 / 255.0, 1.0 });
39 |
40 | var labels_grid = new Gtk.Grid ();
41 | labels_grid.row_spacing = 6;
42 | labels_grid.column_spacing = 6;
43 | labels_grid.margin = 6;
44 | labels_grid.attach (storage_write_label, 0, 0, 1, 1);
45 | labels_grid.attach (storage_read_label, 1, 0, 1, 1);
46 |
47 | drive_cards_container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
48 |
49 | storage.get_drives ().foreach (add_drive_card);
50 |
51 | attach (storage_name_label, 0, 0, 1, 1);
52 | attach (drive_cards_container, 0, 1, 1, 1);
53 | attach (labels_grid, 0, 2, 2, 2);
54 | attach (storage_chart, 0, 2, 2, 2);
55 | }
56 |
57 | private bool add_drive_card (owned Disk ? drive) {
58 | drive_cards_container.add (build_drive_card (drive.model, drive.device, drive.size, drive.free));
59 | return true;
60 | }
61 |
62 | private Gtk.Box build_drive_card (string model, string device, uint64 size, uint64 free) {
63 | var drive_card = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
64 | drive_card.get_style_context ().add_class ("card");
65 | drive_card.get_style_context ().add_class ("rounded");
66 |
67 | drive_card.halign = Gtk.Align.START;
68 | drive_card.margin_end = 12;
69 | drive_card.margin_top = 6;
70 | drive_card.margin_bottom = 12;
71 |
72 | var drive_grid = new Gtk.Grid ();
73 | // drive_grid.row_spacing = 6;
74 | drive_grid.column_spacing = 6;
75 | drive_grid.margin = 6;
76 |
77 | var drive_name_label = new Gtk.Label (model);
78 | drive_name_label.get_style_context ().add_class ("h3");
79 | drive_name_label.margin = 6;
80 | drive_name_label.margin_bottom = 0;
81 | drive_name_label.halign = Gtk.Align.START;
82 |
83 | string size_string = format_size ((uint64) size, IEC_UNITS);
84 | string used_string = format_size ((uint64) (size - free), IEC_UNITS);
85 |
86 | string drive_block_name_and_size_string = "%s 𐄁 %s / %s".printf (device, used_string, size_string);
87 |
88 | if (free == 0)drive_block_name_and_size_string = "%s 𐄁 %s".printf (device, size_string);
89 |
90 | var drive_block_name_and_size_label = new Gtk.Label (drive_block_name_and_size_string);
91 | drive_block_name_and_size_label.get_style_context ().add_class ("h4");
92 | drive_block_name_and_size_label.get_style_context ().add_class ("text-secondary");
93 | drive_block_name_and_size_label.margin = 6;
94 | drive_block_name_and_size_label.margin_top = 0;
95 | drive_block_name_and_size_label.halign = Gtk.Align.START;
96 |
97 | var drive_not_mounted_label = new Gtk.Label (_("Not mounted"));
98 | drive_not_mounted_label.halign = Gtk.Align.START;
99 | drive_not_mounted_label.get_style_context ().add_class ("h4");
100 | drive_not_mounted_label.margin_start = 6;
101 |
102 | var usagebar = new Gtk.LevelBar ();
103 | usagebar.get_style_context ().add_class ("flat");
104 | usagebar.margin = 6;
105 | usagebar.margin_top = 0;
106 | usagebar.set_max_value (100.0);
107 | usagebar.set_min_value (0.0);
108 | usagebar.set_value (100.0 * (size - free) / size);
109 |
110 | drive_grid.attach (drive_name_label, 0, 0, 1, 1);
111 | drive_grid.attach (drive_block_name_and_size_label, 0, 1, 1, 1);
112 | if (free == 0) {
113 | drive_grid.attach (drive_not_mounted_label, 0, 2, 1, 1);
114 | } else {
115 | drive_grid.attach (usagebar, 0, 2, 1, 1);
116 | }
117 | drive_card.add (drive_grid);
118 |
119 | return drive_card;
120 | }
121 |
122 | public void update () {
123 | double up_bytes = storage.bytes_read;
124 | double down_bytes = storage.bytes_write;
125 | if (up_bytes >= 0 && down_bytes >= 0) {
126 | storage_write_label.set_text (("%s/s").printf (format_size ((uint64) down_bytes, IEC_UNITS)));
127 | storage_read_label.set_text (("%s/s").printf (format_size ((uint64) up_bytes, IEC_UNITS)));
128 | storage_chart.update (0, up_bytes);
129 | storage_chart.update (1, down_bytes);
130 | }
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/Views/SystemView/SystemView.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.SystemView : Gtk.Box {
7 | private Resources resources;
8 |
9 | private SystemCPUView cpu_view;
10 | private SystemMemoryView memory_view;
11 | private SystemNetworkView network_view;
12 | private SystemStorageView storage_view;
13 | private GLib.List gpu_views = new GLib.List ();
14 |
15 | construct {
16 | orientation = Gtk.Orientation.VERTICAL;
17 | hexpand = true;
18 | }
19 |
20 | public SystemView (Resources _resources) {
21 | resources = _resources;
22 |
23 | cpu_view = new SystemCPUView (resources.cpu);
24 | memory_view = new SystemMemoryView (resources.memory);
25 | network_view = new SystemNetworkView (resources.network);
26 | storage_view = new SystemStorageView (resources.storage);
27 |
28 | var scrolled_window = new Gtk.ScrolledWindow (null, null);
29 | var wrapper = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
30 | wrapper.expand = true;
31 | scrolled_window.add (wrapper);
32 |
33 |
34 | wrapper.add (cpu_view);
35 | wrapper.add (memory_view);
36 | wrapper.add (network_view);
37 | wrapper.add (storage_view);
38 |
39 | foreach (IGPU gpu in resources.gpu_list) {
40 | if (gpu is GPUIntel || gpu is GPUNvidia) {
41 | wrapper.add (build_no_support_label (gpu.name));
42 | } else {
43 | var gpu_view = new SystemGPUView (gpu);
44 | gpu_views.append (gpu_view);
45 | wrapper.add (gpu_view);
46 | }
47 | }
48 |
49 | add (scrolled_window);
50 | }
51 |
52 | public void update () {
53 | cpu_view.update ();
54 | memory_view.update ();
55 | network_view.update ();
56 | storage_view.update ();
57 | gpu_views.foreach ((gpu_view) => gpu_view.update ());
58 | }
59 |
60 | private Granite.HeaderLabel build_no_support_label (string gpu_name) {
61 | string notification_text = _("The %s GPU was detected, but is not yet supported.").printf (gpu_name);
62 | return new Granite.HeaderLabel (notification_text) {
63 | margin = 12,
64 | };
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/Widgets/Chart/Chart.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Chart : Gtk.Box {
7 | private LiveChart.Chart live_chart;
8 | private uint series_quantity;
9 | private Utils.Colors colors = new Utils.Colors ();
10 | public LiveChart.Config config;
11 |
12 |
13 | construct {
14 | get_style_context ().add_class ("graph");
15 |
16 | vexpand = true;
17 | height_request = 120;
18 |
19 | config = new LiveChart.Config ();
20 | config.y_axis.unit = "%";
21 | config.y_axis.tick_interval = 25;
22 | config.y_axis.fixed_max = 100.0;
23 | config.y_axis.labels.visible = false;
24 | config.x_axis.labels.visible = false;
25 |
26 | config.padding = LiveChart.Padding () {
27 | smart = LiveChart.AutoPadding.NONE,
28 | top = 0,
29 | right = 0,
30 | bottom = 0,
31 | left = -1
32 | };
33 |
34 | live_chart = new LiveChart.Chart (config);
35 | live_chart.expand = true;
36 | live_chart.legend.visible = false;
37 | live_chart.grid.visible = true;
38 | live_chart.background.visible = false;
39 | // live_chart.background.color = Gdk.RGBA () {
40 | // red = 1, green = 1, blue = 1, alpha = 1
41 | // }; // White background
42 | }
43 |
44 | public Chart (uint _series_quantity, bool smooth = true, double renderer_area_alfa = 0.2) {
45 | series_quantity = _series_quantity;
46 |
47 | if (smooth) {
48 | with_smooth_line (renderer_area_alfa);
49 | } else {
50 | with_straight_line (renderer_area_alfa);
51 | }
52 | }
53 |
54 | private Chart with_smooth_line (double renderer_area_alfa = 0.2) {
55 | for (int i = 0; i < series_quantity; i++) {
56 | var renderer = new LiveChart.SmoothLineArea (new LiveChart.Values (1000));
57 | renderer.area_alpha = renderer_area_alfa;
58 | var serie = new LiveChart.Serie (("Serie %d").printf (i), renderer);
59 |
60 | // The idea is to make area a bit less darker or lighter then the base line color
61 | // var color = colors.get_color_by_index (i);
62 | // renderer.region = new LiveChart.Region.between(0, double.MAX).with_line_color(color).with_area_color(color);
63 |
64 | serie.line.color = colors.get_color_by_index (i);
65 |
66 | live_chart.add_serie (serie);
67 | }
68 | add (live_chart);
69 | return this;
70 | }
71 |
72 | private Chart with_straight_line (double renderer_area_alfa = 0.5) {
73 | for (int i = 0; i < series_quantity; i++) {
74 | var renderer = new LiveChart.LineArea (new LiveChart.Values (1000));
75 | renderer.area_alpha = renderer_area_alfa;
76 | var serie = new LiveChart.Serie (("Serie %d").printf (i), renderer);
77 |
78 | serie.line.color = colors.get_color_by_index (i);
79 | live_chart.add_serie (serie);
80 | }
81 | add (live_chart);
82 | return this;
83 | }
84 |
85 | public void set_serie_color (int serie_number, Gdk.RGBA color) {
86 | try {
87 | live_chart.series[serie_number].line.color = color;
88 | } catch (LiveChart.ChartError e) {
89 | error (e.message);
90 | }
91 | }
92 |
93 | public void update (int serie_number, double value) {
94 | try {
95 | live_chart.series[serie_number].add (value);
96 | } catch (LiveChart.ChartError e) {
97 | error (e.message);
98 | }
99 | }
100 |
101 | public void preset_data (int serie_number, Gee.ArrayList history) {
102 | var refresh_rate_in_ms = 2000;
103 | try {
104 | live_chart.add_unaware_timestamp_collection_by_index (serie_number, history, refresh_rate_in_ms);
105 | } catch (LiveChart.ChartError e) {
106 | error (e.message);
107 | }
108 | }
109 |
110 | public void clear () {
111 | // var series = live_chart.series;
112 | foreach (var serie in live_chart.series) {
113 | serie.clear ();
114 | }
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/Widgets/Headerbar/Search.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: GPL-3.0-or-later
3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4 | */
5 |
6 | public class Monitor.Search : Gtk.SearchEntry {
7 | public MainWindow window { get; construct; }
8 | private Gtk.TreeModelFilter filter_model;
9 | private CPUProcessTreeView process_tree_view;
10 |
11 | public Search (MainWindow window) {
12 | Object (window: window);
13 | }
14 |
15 | construct {
16 | this.process_tree_view = window.process_view.process_tree_view;
17 | this.placeholder_text = _("Search Process");
18 | this.tooltip_markup = Granite.markup_accel_tooltip ({ "F" }, _("Type process name or PID to search"));
19 |
20 | filter_model = new Gtk.TreeModelFilter (window.process_view.treeview_model, null);
21 | connect_signal ();
22 | filter_model.set_visible_func (filter_func);
23 | // process_tree_view.set_model (filter_model);
24 |
25 | var sort_model = new Gtk.TreeModelSort.with_model (filter_model);
26 | process_tree_view.set_model (sort_model);
27 | }
28 |
29 | private void connect_signal () {
30 | this.search_changed.connect (() => {
31 | // collapse tree only when search is focused and changed
32 | if (this.is_focus) {
33 | process_tree_view.collapse_all ();
34 | }
35 |
36 | filter_model.refilter ();
37 |
38 | // focus on child row to avoid the app crashes by clicking "Kill/End Process" buttons in headerbar
39 | process_tree_view.focus_on_child_row ();
40 | this.grab_focus ();
41 |
42 | if (this.text != "") {
43 | this.insert_at_cursor ("");
44 | }
45 | });
46 |
47 | activate.connect (() => {
48 | window.process_view.process_tree_view.focus_on_first_row ();
49 | });
50 | }
51 |
52 | private bool filter_func (Gtk.TreeModel model, Gtk.TreeIter iter) {
53 | string name_haystack;
54 | int pid_haystack;
55 | string cmd_haystack;
56 | bool found = false;
57 | var needle = this.text;
58 |
59 | // should help with assertion errors, donno
60 | // if (needle == null) return true;
61 |
62 | if (needle.length == 0) {
63 | return true;
64 | }
65 |
66 | model.get (iter, Column.NAME, out name_haystack, -1);
67 | model.get (iter, Column.PID, out pid_haystack, -1);
68 | model.get (iter, Column.CMD, out cmd_haystack, -1);
69 |
70 | // sometimes name_haystack is null
71 | if (name_haystack != null) {
72 | bool name_found = name_haystack.casefold ().contains (needle.casefold ()) || false;
73 | bool pid_found = pid_haystack.to_string ().casefold ().contains (needle.casefold ()) || false;
74 | bool cmd_found = cmd_haystack.casefold ().contains (needle.casefold ()) || false;
75 | found = name_found || pid_found || cmd_found;
76 | }
77 |
78 |
79 | Gtk.TreeIter child_iter;
80 | bool child_found = false;
81 |
82 | if (model.iter_children (out child_iter, iter)) {
83 | do {
84 | child_found = filter_func (model, child_iter);
85 | } while (model.iter_next (ref child_iter) && !child_found);
86 | }
87 |
88 | if (child_found && needle.length > 0) {
89 | process_tree_view.expand_all ();
90 | }
91 |
92 | return found || child_found;
93 | }
94 |
95 | // reset filter, grab focus and insert the character
96 | public void activate_entry (string search_text = "") {
97 | this.text = "";
98 | this.search_changed ();
99 | this.insert_at_cursor (search_text);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/Widgets/Labels/LabelRoundy.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.LabelRoundy : Gtk.Fixed {
7 | public Gtk.Label val;
8 | public Gtk.Label desc;
9 |
10 | public LabelRoundy (string description) {
11 | val = new Gtk.Label (Utils.NO_DATA) {
12 | selectable = true
13 | };
14 | val.get_style_context ().add_class ("roundy-label");
15 |
16 | desc = new Gtk.Label (description.up ());
17 | desc.get_style_context ().add_class ("small-text");
18 |
19 | put (val, 0, 12);
20 | put (desc, 6, 0);
21 | }
22 |
23 | public void set_color (string colorname) {
24 | val.get_style_context ().add_class (colorname);
25 | }
26 |
27 | public void set_text (string text) {
28 | val.set_text (text);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/Widgets/Labels/LabelVertical.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.LabelVertical : Gtk.EventBox {
7 | private Gtk.Grid grid;
8 |
9 | public signal void clicked ();
10 |
11 | public Gtk.Label val;
12 | public Gtk.Label desc;
13 |
14 | construct {
15 | grid = new Gtk.Grid ();
16 | margin_start = 12;
17 | margin_top = 6;
18 |
19 | get_style_context ().add_class ("label-vertical");
20 | }
21 |
22 | public LabelVertical (string description) {
23 | val = new Gtk.Label (Utils.NO_DATA);
24 | val.get_style_context ().add_class (Granite.STYLE_CLASS_H2_LABEL);
25 |
26 | desc = new Gtk.Label (description.up ());
27 | desc.get_style_context ().add_class ("small-text");
28 |
29 | grid.attach (desc, 0, 0, 1, 1);
30 | grid.attach (val, 0, 1, 1, 1);
31 |
32 | add (grid);
33 |
34 | events |= Gdk.EventMask.BUTTON_RELEASE_MASK;
35 |
36 | button_release_event.connect ((event) => {
37 | clicked ();
38 | return false;
39 | });
40 | }
41 |
42 | public void set_text (string text) {
43 | val.set_text (text);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/Widgets/Statusbar/Statusbar.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.Statusbar : Gtk.ActionBar {
7 | Gtk.Label cpu_usage_label;
8 | Gtk.Label memory_usage_label;
9 | Gtk.Label swap_usage_label;
10 | Gtk.Label gpu_usage_label;
11 |
12 | construct {
13 | var cpu_icon = new Gtk.Image.from_icon_name ("cpu-symbolic", Gtk.IconSize.SMALL_TOOLBAR) {
14 | tooltip_text = _("CPU")
15 | };
16 |
17 | var ram_icon = new Gtk.Image.from_icon_name ("ram-symbolic", Gtk.IconSize.SMALL_TOOLBAR) {
18 | tooltip_text = _("Memory")
19 | };
20 |
21 | var swap_icon = new Gtk.Image.from_icon_name ("swap-symbolic", Gtk.IconSize.SMALL_TOOLBAR) {
22 | tooltip_text = _("Swap")
23 | };
24 |
25 | var gpu_icon = new Gtk.Image.from_icon_name ("gpu-symbolic", Gtk.IconSize.SMALL_TOOLBAR) {
26 | tooltip_text = _("GPU")
27 | };
28 |
29 | cpu_usage_label = new Gtk.Label (_("Calculating…"));
30 | cpu_usage_label.set_width_chars (4);
31 | cpu_usage_label.xalign = 0;
32 | pack_start (cpu_icon);
33 | pack_start (cpu_usage_label);
34 |
35 | memory_usage_label = new Gtk.Label (_("Calculating…"));
36 | memory_usage_label.set_width_chars (4);
37 | memory_usage_label.xalign = 0;
38 | ram_icon.margin_start = 6;
39 | pack_start (ram_icon);
40 | pack_start (memory_usage_label);
41 |
42 | swap_usage_label = new Gtk.Label (_("Calculating…"));
43 | swap_usage_label.set_width_chars (4);
44 | swap_usage_label.xalign = 0;
45 | swap_icon.margin_start = 6;
46 | pack_start (swap_icon);
47 | pack_start (swap_usage_label);
48 |
49 | gpu_usage_label = new Gtk.Label (_("Calculating…"));
50 | gpu_usage_label.set_width_chars (4);
51 | gpu_usage_label.xalign = 0;
52 | gpu_icon.margin_start = 6;
53 | pack_start (gpu_icon);
54 | pack_start (gpu_usage_label);
55 |
56 | var support_ua_label = new Gtk.LinkButton.with_label ("http://stand-with-ukraine.pp.ua/", _("🇺🇦"));
57 | var github_label = new Gtk.LinkButton.with_label ("https://github.com/elementary/monitor", _("Check on Github"));
58 |
59 | var version_label = new Gtk.Label ("%s".printf (VCS_TAG)) {
60 | selectable = true
61 | };
62 | version_label.get_style_context ().add_class ("dim-label");
63 |
64 | // pack_end (build_separator_middot ());
65 | pack_end (github_label);
66 | pack_end (build_separator_middot ());
67 | pack_end (version_label);
68 | pack_end (build_separator_middot ());
69 | pack_end (support_ua_label);
70 |
71 | }
72 |
73 | private Gtk.Label build_separator_middot () {
74 | var label = new Gtk.Label ("𐄁") {
75 | margin_end = 6,
76 | margin_start = 6,
77 | };
78 | label.get_style_context ().add_class ("dim-label");
79 | return label;
80 | }
81 |
82 | public bool update (ResourcesSerialized sysres) {
83 | cpu_usage_label.set_text (("%d%%").printf (sysres.cpu_percentage));
84 | memory_usage_label.set_text (("%u%%").printf (sysres.memory_percentage));
85 | gpu_usage_label.set_text (("%d%%").printf (sysres.gpu_percentage));
86 |
87 | string cpu_tooltip_text = ("%.2f %s").printf (sysres.cpu_frequency, _("GHz"));
88 | cpu_usage_label.tooltip_text = cpu_tooltip_text;
89 |
90 | string memory_tooltip_text = ("%s / %s").printf (
91 | format_size ((uint64) sysres.memory_used, IEC_UNITS),
92 | format_size ((uint64) sysres.memory_total, IEC_UNITS)
93 | );
94 | memory_usage_label.tooltip_text = memory_tooltip_text;
95 |
96 | // The total amount of the swap is 0 when it is unavailable
97 | if (sysres.swap_total == 0) {
98 | swap_usage_label.set_text ("N/A");
99 | } else {
100 | swap_usage_label.set_text (("%d%%").printf (sysres.swap_percentage));
101 | string swap_tooltip_text = ("%.1f %s / %.1f %s").printf (sysres.swap_used, _("GiB"), sysres.swap_total, _("GiB"));
102 | swap_usage_label.tooltip_text = swap_tooltip_text;
103 | }
104 |
105 | return true;
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/src/Widgets/WidgetResource/WidgetResource.vala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 elementary, Inc. (https://elementary.io)
3 | * SPDX-License-Identifier: GPL-3.0-or-later
4 | */
5 |
6 | public class Monitor.WidgetResource : Gtk.Box {
7 | private Granite.HeaderLabel _title = new Granite.HeaderLabel (Utils.NO_DATA);
8 |
9 | public string title {
10 | set {
11 | _title.label = value;
12 | }
13 | }
14 |
15 | public Gtk.Popover popover_more_info;
16 | private LabelVertical _label_vertical_main_metric = new LabelVertical (_("UTILIZATION"));
17 |
18 | public string label_vertical_main_metric {
19 | set {
20 | _label_vertical_main_metric.set_text (value);
21 | }
22 | }
23 |
24 | private Gtk.Box charts_container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
25 |
26 | private Gtk.Grid grid_main_chart_container;
27 | private Gtk.Grid grid_main_onchart_info_container;
28 | private Gtk.Grid grid_header;
29 |
30 |
31 | construct {
32 | margin = 12;
33 | margin_top = 6;
34 | set_vexpand (false);
35 | orientation = Gtk.Orientation.VERTICAL;
36 |
37 |
38 |
39 | grid_header = new Gtk.Grid () {
40 | column_spacing = 6,
41 | };
42 | grid_header.attach (_title, 0, 0, 1, 1);
43 | add (grid_header);
44 |
45 |
46 | grid_main_chart_container = new Gtk.Grid ();
47 | grid_main_chart_container.attach (build_grid_main_onchart_info_container (), 0, 0, 1, 1);
48 |
49 | charts_container.pack_start (grid_main_chart_container, true, true, 0);
50 |
51 | add (charts_container);
52 |
53 | }
54 |
55 | private Gtk.Grid build_grid_main_onchart_info_container () {
56 | grid_main_onchart_info_container = new Gtk.Grid () {
57 | column_spacing = 6,
58 | margin = 6,
59 | valign = Gtk.Align.START,
60 | halign = Gtk.Align.START,
61 | };
62 |
63 | grid_main_onchart_info_container.get_style_context ().add_class ("usage-label-container");
64 | grid_main_onchart_info_container.attach (_label_vertical_main_metric, 0, 0, 1, 1);
65 |
66 | return grid_main_onchart_info_container;
67 | }
68 |
69 | public void set_main_chart (Chart chart) {
70 | grid_main_chart_container.attach (chart, 0, 0, 1, 1);
71 | }
72 |
73 | public void set_main_chart_overlay (Gtk.Widget widget) {
74 | grid_main_onchart_info_container.attach (widget, 1, 0, 1, 1);
75 | }
76 |
77 | public void add_charts_container (Gtk.Widget widget) {
78 | charts_container.pack_start (widget, false, false, 0);
79 | }
80 |
81 | public void set_popover_more_info (Gtk.Widget widget) {
82 | var button_more_info = new Gtk.ToggleButton () {
83 | has_focus = false,
84 | valign = Gtk.Align.START,
85 | halign = Gtk.Align.START
86 | };
87 | button_more_info.get_style_context ().add_class ("circular");
88 | // button_more_info.get_style_context ().add_class ("popup");
89 | var icon = new Gtk.Image ();
90 | icon.gicon = new ThemedIcon ("dialog-information");
91 | icon.pixel_size = 16;
92 | button_more_info.set_image (icon);
93 |
94 | popover_more_info = new Gtk.Popover (button_more_info) {
95 | position = Gtk.PositionType.BOTTOM,
96 | modal = true,
97 | visible = false,
98 | };
99 | popover_more_info.closed.connect (() => { button_more_info.set_active (false); });
100 | button_more_info.clicked.connect (() => { popover_more_info.show_all (); });
101 |
102 | popover_more_info.add (widget);
103 |
104 | grid_header.attach (button_more_info, 1, 0, 1, 1);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | source_app_files = [
2 | 'Monitor.vala',
3 | 'MainWindow.vala',
4 | 'Utils.vala',
5 | 'PCIUtils.vala',
6 |
7 | # Views
8 | 'Views/ProcessView/ProcessView.vala',
9 | 'Views/ProcessView/ProcessInfoView/ProcessInfoView.vala',
10 | 'Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala',
11 |
12 | 'Views/PreferencesView.vala',
13 |
14 | 'Views/SystemView/SystemView.vala',
15 | 'Views/SystemView/SystemCPUView.vala',
16 | 'Views/SystemView/SystemCPUInfoPopover.vala',
17 | 'Views/SystemView/SystemMemoryView.vala',
18 | 'Views/SystemView/SystemNetworkView.vala',
19 | 'Views/SystemView/SystemStorageView.vala',
20 | 'Views/SystemView/SystemGPUView.vala',
21 |
22 | # Widgets related only to ProcessInfoView
23 | 'Views/ProcessView/ProcessInfoView/Preventor.vala',
24 | 'Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala',
25 | 'Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala',
26 | 'Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala',
27 | 'Views/ProcessView/ProcessInfoView/OpenFilesTreeView.vala',
28 |
29 | # Widgets
30 | 'Widgets/Headerbar/Search.vala',
31 | 'Widgets/Statusbar/Statusbar.vala',
32 | 'Widgets/Labels/LabelVertical.vala',
33 | 'Widgets/Labels/LabelRoundy.vala',
34 | 'Widgets/Chart/Chart.vala',
35 | 'Widgets/WidgetResource/WidgetResource.vala',
36 |
37 | # Models
38 | 'Models/TreeViewModel.vala',
39 | 'Models/OpenFilesTreeViewModel.vala',
40 |
41 | # Other
42 | # 'Managers/AppManager.vala',
43 | 'Managers/ProcessManager.vala',
44 | 'Managers/Process.vala',
45 | 'Managers/ProcessStructs.vala',
46 | 'Managers/ProcessUtils.vala',
47 |
48 | # Services
49 | 'Services/DBusServer.vala',
50 | 'Services/Appearance.vala',
51 |
52 | # Resources
53 | 'Resources/Resources.vala',
54 | 'Resources/ResourcesSerialized.vala',
55 | 'Resources/CPU.vala',
56 | 'Resources/CPUCache.vala',
57 | 'Resources/Core.vala',
58 | 'Resources/Memory.vala',
59 | 'Resources/Swap.vala',
60 | 'Resources/Network.vala',
61 | 'Resources/Cgroup/Cgroup.vala',
62 | 'Resources/Cgroup/CgroupStructs.vala',
63 |
64 | 'Resources/Storage/Storage.vala',
65 | 'Resources/Storage/StorageParser.vala',
66 | 'Resources/Storage/Disk.vala',
67 | 'Resources/Storage/Volume.vala',
68 |
69 | 'Resources/GPU/IGPU.vala',
70 | 'Resources/GPU/GPUAmd.vala',
71 | 'Resources/GPU/GPUNvidia.vala',
72 | 'Resources/GPU/GPUIntel.vala',
73 |
74 | 'Resources/Hwmon/HwmonPathsParser.vala',
75 | 'Resources/Hwmon/IHwmonPathsParserInterface.vala',
76 | 'Resources/Hwmon/HwmonPathsParserCPU.vala',
77 | 'Resources/Hwmon/HwmonPathsParserGPU.vala',
78 | 'Resources/Hwmon/HwmonPathsParserIwlwifi.vala',
79 | 'Resources/Hwmon/HwmonPathsParserNVMe.vala',
80 | 'Resources/Hwmon/HwmonTemperature.vala',
81 | 'Resources/Hwmon/HwmonVoltage.vala',
82 | 'Resources/Hwmon/HwmonFrequency.vala',
83 | 'Resources/Hwmon/HwmonFan.vala',
84 | 'Resources/Hwmon/HwmonPWM.vala',
85 | 'Resources/Hwmon/HwmonPower.vala',
86 |
87 | ]
88 |
89 | executable(
90 | meson.project_name(),
91 | icons_gresource,
92 | css_gresource,
93 | source_app_files,
94 | project_config,
95 | dependencies: app_dependencies,
96 | install: true
97 | )
98 |
99 | if get_option('indicator-wingpanel').enabled()
100 | message ('Indicator Wingpanel will be built')
101 | subdir('Indicator')
102 | endif
103 |
--------------------------------------------------------------------------------
/subprojects/live-chart.wrap:
--------------------------------------------------------------------------------
1 | [wrap-git]
2 | url = https://github.com/elementary/live-chart.git
3 | revision = 5a690045f2e3df1d78ff0ea1e5df6470a6760639
4 | depth = 1
5 |
6 | [provide]
7 | livechart = livechart_static_dep
8 |
--------------------------------------------------------------------------------
/tests/list-src.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | find . -name "*.vala"
--------------------------------------------------------------------------------
/tests/meson.build:
--------------------------------------------------------------------------------
1 | test_sources = files(run_command('list-src.sh', check: true).stdout().strip().split('\n'))
2 |
3 |
4 | test(
5 | 'monitor-statusbar-test',
6 | executable('monitor-statusbar-test', test_sources, [
7 | meson.source_root() / 'src/Widgets/Statusbar/Statusbar.vala',
8 | meson.source_root() / 'src/Resources/ResourcesSerialized.vala',
9 | meson.source_root() / 'src/Utils.vala'
10 | ],
11 | project_config,
12 | dependencies: app_dependencies)
13 | )
--------------------------------------------------------------------------------
/tests/runner.vala:
--------------------------------------------------------------------------------
1 | void main (string[] args) {
2 |
3 | Test.init (ref args);
4 | Gtk.init (ref args);
5 |
6 | test_statusbar ();
7 |
8 | Test.run ();
9 | }
10 |
--------------------------------------------------------------------------------
/tests/test_statusbar.vala:
--------------------------------------------------------------------------------
1 | using Monitor;
2 |
3 | private void test_statusbar () {
4 |
5 | Test.add_func ("/Monitor/Widgets/Statusbar/Statusbar#Statusbar", () => {
6 |
7 | var statusbar = new Monitor.Statusbar ();
8 | ResourcesSerialized sysres = ResourcesSerialized () {
9 | cpu_percentage = 99,
10 | cpu_frequency = 1.44,
11 | cpu_temperature = 34.0,
12 | memory_percentage = 99,
13 | memory_used = 2.0,
14 | memory_total = 4.0,
15 | swap_percentage = 1,
16 | swap_used = 0.1,
17 | swap_total = 1.0,
18 | network_up = 12,
19 | network_down = 23,
20 | gpu_percentage = 20
21 | gpu_memory_percentage = 10
22 | gpu_temperature = 31.0
23 | };
24 |
25 | bool update_result = statusbar.update (sysres);
26 |
27 | assert (update_result == true);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/vapi/libxnvctrl.vapi:
--------------------------------------------------------------------------------
1 | namespace NVCtrl {
2 | [CCode (cheader_filename = "NVCtrl/NVCtrlLib.h", cname = "XNVCTRLQueryAttribute", cprefix = "nv_ctrl_lib_", has_type_id = false)]
3 | public static bool XNVCTRLQueryAttribute (
4 | X.Display *dpy,
5 | int screen,
6 | uint display_mask,
7 | uint attribute,
8 | int *value
9 | );
10 |
11 | [CCode (cheader_filename = "NVCtrl/NVCtrlLib.h", cname = "XNVCTRLQueryTargetAttribute", cprefix = "nv_ctrl_lib_", has_type_id = false)]
12 | public static bool XNVCTRLQueryTargetAttribute (
13 | X.Display *dpy,
14 | int target_Type,
15 | int target_id,
16 | uint display_mask,
17 | uint attribute,
18 | int *value
19 | );
20 |
21 | [CCode (cheader_filename = "NVCtrl/NVCtrlLib.h", cname = "XNVCTRLQueryTargetStringAttribute", cprefix = "nv_ctrl_lib_", has_type_id = false)]
22 | public static bool XNVCTRLQueryTargetStringAttribute (
23 | X.Display *dpy,
24 | int target_type,
25 | int target_id,
26 | uint display_mask,
27 | uint attribute,
28 | char **ptr
29 | );
30 | }
31 |
32 | [CCode (cheader_filename = "NVCtrl/NVCtrl.h")]
33 | public const uint NV_CTRL_GPU_CORE_TEMPERATURE;
34 | public const uint NV_CTRL_GPU_CURRENT_CLOCK_FREQS;
35 | public const uint NV_CTRL_TOTAL_GPU_MEMORY;
36 | public const uint NV_CTRL_STRING_GPU_UTILIZATION;
37 | public const uint NV_CTRL_USED_DEDICATED_GPU_MEMORY;
38 | public const uint NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY;
39 | public const uint NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS;
40 | public const uint NV_CTRL_STRING_PRODUCT_NAME;
41 | public const uint NV_CTRL_PCI_ID;
42 | public const int NV_CTRL_TARGET_TYPE_GPU;
43 |
--------------------------------------------------------------------------------