├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── desktop-directories
├── audio-video.directory
├── development.directory
├── game.directory
├── graphics.directory
├── internet-and-network.directory
├── office.directory
├── other.directory
├── system-tools.directory
└── utility.directory
├── go.mod
├── go.sum
├── main.go
├── menu-start.css
├── nwg-menu
├── tools.go
└── uicomponents.go
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: nwg-piotr
2 | liberapay: nwg
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Binaries built with make
15 | bin
16 | nwg-menu
17 |
18 | /.idea
19 |
20 | # Dependency directories (remove the comment below to include it)
21 | # vendor/
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Piotr Miller
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PREFIX ?= /usr
2 | DESTDIR ?=
3 |
4 | get:
5 | go get github.com/gotk3/gotk3
6 | go get github.com/gotk3/gotk3/gdk
7 | go get github.com/gotk3/gotk3/glib
8 | go get github.com/dlasky/gotk3-layershell/layershell
9 | go get github.com/joshuarubin/go-sway
10 | go get github.com/allan-simon/go-singleinstance
11 |
12 | build:
13 | go build -v -o bin/nwg-menu *.go
14 |
15 | install:
16 | mkdir -p $(DESTDIR)$(PREFIX)/share/nwg-menu
17 | mkdir -p $(DESTDIR)$(PREFIX)/bin
18 | cp -r desktop-directories $(DESTDIR)$(PREFIX)/share/nwg-menu
19 | cp menu-start.css $(DESTDIR)$(PREFIX)/share/nwg-menu
20 | cp bin/nwg-menu $(DESTDIR)$(PREFIX)/bin/nwg-menu
21 |
22 | uninstall:
23 | rm -f $(DESTDIR)$(PREFIX)/bin/nwg-menu
24 | rm -fr $(DESTDIR)$(PREFIX)/share/nwg-menu
25 |
26 | run:
27 | go run *.go
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nwg-menu
2 |
3 | This code provides the [MenuStart plugin](https://github.com/nwg-piotr/nwg-panel/wiki/plugins:-MenuStart)
4 | to [nwg-panel](https://github.com/nwg-piotr/nwg-panel). It also may be used standalone, however, with a little help from command line arguments.
5 |
6 | The `nwg-menu` command displays the system menu with simplified [freedesktop main categories](https://specifications.freedesktop.org/menu-spec/latest/apa.html) (8 instead of 13).
7 | It also provides the search entry, to look for installed application on the basis of .desktop files, and for files in
8 | XDG user directories.
9 |
10 | You may pin applications by right-clicking them. Pinned items will appear above the categories list. Right-click
11 | a pinned item to unpin it. The pinned items cache is shared with the `nwggrid` command, which is a part of
12 | [nwg-launchers](https://github.com/nwg-piotr/nwg-launchers).
13 |
14 | In the bottom-right corner of the window you'll also see a set of buttons: logout, lock screen, restart and shutdown.
15 | The commands attached to them may be defined in the nwg-panel settings or given as the arguments.
16 |
17 | 
18 |
19 | To use the menu standalone (e.g. with another panel/bar or with a key binding), take a look at arguments:
20 |
21 | ```text
22 | $ nwg-menu -h
23 | Usage of nwg-menu:
24 | -cmd-lock string
25 | screen lock command (default "swaylock -f -c 000000")
26 | -cmd-logout string
27 | logout command (default "swaymsg exit")
28 | -cmd-restart string
29 | reboot command (default "systemctl reboot")
30 | -cmd-shutdown string
31 | shutdown command (default "systemctl -i poweroff")
32 | -d auto-hiDe: close window when left
33 | -fm string
34 | File Manager (default "thunar")
35 | -ha string
36 | Horizontal Alignment: "left" or "right" (default "left")
37 | -height int
38 | window height
39 | -isl int
40 | Icon Size Large (default 32)
41 | -iss int
42 | Icon Size Small (default 16)
43 | -lang string
44 | force lang, e.g. "en", "pl"
45 | -mb int
46 | Margin Bottom
47 | -ml int
48 | Margin Left
49 | -mr int
50 | Margin Right
51 | -mt int
52 | Margin Top
53 | -o string
54 | name of the Output to display the menu on
55 | -padding uint
56 | vertical item padding (default 2)
57 | -s string
58 | Styling: css file name (default "menu-start.css")
59 | -term string
60 | Terminal emulator (default "alacritty")
61 | -v display Version information
62 | -va string
63 | Vertical Alignment: "bottom" or "top" (default "bottom")
64 | -width int
65 | window width
66 | -wm string
67 | use swaymsg exec (with 'sway' argument) or hyprctl dispatch exec (with 'hyprland') or riverctl spawn (with 'river') to launch programs
68 | ```
69 |
70 | ## Installation
71 |
72 | [](https://repology.org/project/nwg-menu/versions)
73 |
74 | ### Dependencies
75 |
76 | - go 1.16 (just to build)
77 | - gtk3
78 | - gtk-layer-shell
79 |
80 | Optional (recommended):
81 |
82 | - thunar
83 | - alacritty
84 |
85 | You may use another file manager and terminal emulator, but for now the program has not yet been tested with anything
86 | but the two mentioned above.
87 |
88 | ### Steps
89 |
90 | 1. Clone the repository, cd into it.
91 | 2. Install necessary golang libraries with `make get`.
92 | 3. `make build`
93 | 4. `sudo make install`
94 |
95 | ## Running
96 |
97 | Plugin integration and the config GUI has been available in the nwg-panel since the 0.3.1 version, see
98 | [Wiki](https://github.com/nwg-piotr/nwg-panel/wiki/plugins:-MenuStart). You may also start the menu from another panel
99 | or a key binding.
100 |
101 | ## Styling
102 |
103 | Edit `~/.config/nwg-panel/menu-start.css` to your taste.
104 |
105 | ## Credits
106 |
107 | This program uses some great libraries:
108 |
109 | - [gotk3](https://github.com/gotk3/gotk3) Copyright (c) 2013-2014 Conformal Systems LLC,
110 | Copyright (c) 2015-2018 gotk3 contributors
111 | - [gotk3-layershell](https://github.com/dlasky/gotk3-layershell) by [@dlasky](https://github.com/dlasky/gotk3-layershell/commits?author=dlasky) - many thanks for writing this software, and for patience with my requests!
112 | - [go-sway](https://github.com/joshuarubin/go-sway) Copyright (c) 2019 Joshua Rubin
113 | - [go-singleinstance](github.com/allan-simon/go-singleinstance) Copyright (c) 2015 Allan Simon
114 |
115 | The nwg-shell logo (which is also the menu button graphics) created by [SGSE](https://github.com/sgse), licensed
116 | under the terms of the Creative Commons license [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.en).
117 |
--------------------------------------------------------------------------------
/desktop-directories/audio-video.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Sound & Video
3 | Name[af]=Klank & video
4 | Name[ar]=الصّوتيات والمرئيّات
5 | Name[as]=শব্দ ও ভিডিও
6 | Name[ast]=Soníu y Vídeu
7 | Name[be]=Аўдыё і відэа
8 | Name[be@latin]=Aŭdyjo j videa
9 | Name[bg]=Видео и звук
10 | Name[bn]=শব্দ ও ভিডিও
11 | Name[bn_IN]=শব্দ ও ভিডিও
12 | Name[br]=Son ha video
13 | Name[ca]=So i Vídeo
14 | Name[cs]=Zvuk a video
15 | Name[cy]=Sain a Fideo
16 | Name[da]=Lyd og video
17 | Name[de]=Unterhaltungsmedien
18 | Name[dz]=སྒྲ་སྐད་དང་གཟུགས་བརྙན།
19 | Name[el]=Ήχος & βίντεο
20 | Name[en_CA]=Sound & Video
21 | Name[en_GB]=Sound & Video
22 | Name[eo]=Sono kaj video
23 | Name[es]=Sonido y vídeo
24 | Name[es_VE]=Sonido y vídeo
25 | Name[et]=Audio ja video
26 | Name[eu]=Soinua eta bideoa
27 | Name[fa]=صدا و تصویر
28 | Name[fi]=Ääni & video
29 | Name[fo]=Ljóð og video
30 | Name[fr]=Son et vidéo
31 | Name[frp]=Son é Videó
32 | Name[fur]=Audio e video
33 | Name[ga]=Fuaim & Fís
34 | Name[gl]=Son e vídeo
35 | Name[gn]=Jaexaa, Porai Nhaendua
36 | Name[gu]=સાઉન્ડ & વીડિયો
37 | Name[he]=צליל ווידאו
38 | Name[hi]=ध्वनि व वीडियो
39 | Name[hr]=Zvuk & Video
40 | Name[hu]=Hang és videó
41 | Name[hy]=Ձայն և Վիդեո
42 | Name[id]=Suara & Video
43 | Name[io]=Sono ed Video
44 | Name[is]=Hljóð og mynd
45 | Name[it]=Audio e video
46 | Name[ja]=サウンドとビデオ
47 | Name[ka]=ხმა და ვიდეო
48 | Name[kk]=Аудио және видео
49 | Name[km]=សម្លេង & វីដេអូ
50 | Name[kn]=ಧ್ವನಿ ಹಾಗು ದೃಶ್ಯ
51 | Name[ko]=음악과 비디오
52 | Name[ku]=Deng & Vîdeo
53 | Name[ky]=Аудио и видео
54 | Name[lg]=Ddoboozi & Vidiyo
55 | Name[lt]=Garsas ir vaizdas
56 | Name[lv]=Skaņas un Video
57 | Name[mai]=ध्वनि आ वीडियो
58 | Name[mg]=Feo sy sarimihetsika
59 | Name[mk]=Звук и видео
60 | Name[ml]=ശബ്ദവും ചലച്ചിത്രവും
61 | Name[mn]=Дуу & Видео
62 | Name[mr]=आवाज व चलचित्र
63 | Name[ms]=Bunyi & Video
64 | Name[nb]=Lyd og bilde
65 | Name[ne]=ध्वनि र भिडियो
66 | Name[nl]=Muziek en video
67 | Name[nn]=Lyd og film
68 | Name[oc]=Son e vidèo
69 | Name[or]=ଧ୍ବନି ଏବଂ ଭିଡିଓ
70 | Name[pa]=ਸਾਊਂਡ ਅਤੇ ਵੀਡਿਓ
71 | Name[pl]=Dźwięk i wideo
72 | Name[ps]=غږ او وېډيو
73 | Name[pt]=Som e vídeo
74 | Name[pt_BR]=Multimídia
75 | Name[ro]=Multimedia
76 | Name[ru]=Аудио и видео
77 | Name[si]=ශබ්ද සහ දෘශ්ය
78 | Name[sk]=Zvuk a video
79 | Name[sl]=Zvok in video
80 | Name[sq]=Zë & Video
81 | Name[sr]=Звук и покретне слике
82 | Name[sr@latin]=Zvuk i pokretne slike
83 | Name[sv]=Ljud och video
84 | Name[ta]=ஒலி மற்றும் படக்காட்சி
85 | Name[te]=ధ్వని మరియు దృశ్యం
86 | Name[th]=เสียงและวีดิทัศน์
87 | Name[tr]=Ses ve Video
88 | Name[tt_RU]=Аудио һәм видео
89 | Name[ug]=ئۈن ۋە سىن
90 | Name[uk]=Звук та відео
91 | Name[ur]=آواز اور ویڈیو
92 | Name[ur_PK]=آواز اور ویڈیو
93 | Name[uz@cyrillic]=Товуш ва видео
94 | Name[vi]=Âm thanh và Ảnh động
95 | Name[xh]=Isandi neVidiyo
96 | Name[zh_CN]=影音
97 | Name[zh_HK]=影音
98 | Name[zh_TW]=影音
99 | Comment=Multimedia menu
100 | Comment[af]=Multimediakieslys
101 | Comment[ar]=قائمة الوسائط المتعدّدة
102 | Comment[as]=মাল্টি-মিডিয়া তালিকা
103 | Comment[ast]=Menú multimedia
104 | Comment[be]=Мультымедыя
105 | Comment[be@latin]=Multymedyi
106 | Comment[bg]=Меню за мултимедия
107 | Comment[bn]=মাল্টিমিডিয়া মেনু
108 | Comment[bn_IN]=মাল্টি-মিডিয়া মেনু
109 | Comment[br]=Liesvedia
110 | Comment[ca]=Menú multimèdia
111 | Comment[cs]=Nabídka multimédií
112 | Comment[cy]=Dewislen amlgyfrwng
113 | Comment[da]=Multimediemenu
114 | Comment[de]=Multimedia-Menü
115 | Comment[dz]=སྣ་མང་བརྡ་ལམ་དཀར་ཆག།
116 | Comment[el]=Μενού πολυμέσων
117 | Comment[en_CA]=Multimedia menu
118 | Comment[en_GB]=Multimedia menu
119 | Comment[eo]=Plurmedia menuo
120 | Comment[es]=Menú multimedia
121 | Comment[es_VE]=Menú multimedia
122 | Comment[et]=Multimeediamenüü
123 | Comment[eu]=Multimedia menua
124 | Comment[fa]=منوی چندرسانهای
125 | Comment[fi]=Multimediavalikko
126 | Comment[fo]=Margmiðla-valmynd
127 | Comment[fr]=Multimédia
128 | Comment[frp]=Menû multimedia
129 | Comment[fur]=Menu multimediâl
130 | Comment[ga]=Roghchlár ilmheán
131 | Comment[gl]=Menú multimedia
132 | Comment[gn]=Baemo Jaexaa, Nhaendua
133 | Comment[gu]=મલ્ટીમીડિયા મેનુ
134 | Comment[he]=תפריט מולטימדיה
135 | Comment[hi]=मल्टीमीडिया मेनू
136 | Comment[hr]=Multimedijski izbornik
137 | Comment[hu]=Multimédia menü
138 | Comment[hy]=Համասփյուռ ծրագրերի ցանկ
139 | Comment[id]=Menu multimedia
140 | Comment[is]=Margmiðlun
141 | Comment[it]=Menu multimedia
142 | Comment[ja]=マルチメディア関連のプログラムです
143 | Comment[ka]=მულტიმედიის მენუ
144 | Comment[kk]=Мультимедиа
145 | Comment[km]=ម៉ឺនុយពហុព័ត៌មាន
146 | Comment[kn]=ಮಲ್ಟಿಮೀಡಿಯಾ ಅಂಶಪಟ್ಟಿ
147 | Comment[ko]=멀티미디어 메뉴
148 | Comment[ku]=Pêşeka multîmedya
149 | Comment[ky]=Мультимедиа
150 | Comment[lg]=Menyu eya mediya y'ekintabuli
151 | Comment[lt]=Daugialypės terpės meniu
152 | Comment[lv]=Multimediju izvēlne
153 | Comment[mai]=मल्टीमीडिया मेनू
154 | Comment[mg]=Karazan-tsafidin'ny haino aman-jery
155 | Comment[mk]=Мени со мултимедија
156 | Comment[ml]=മള്ട്ടീമീഡിയ മെനു
157 | Comment[mn]=Мультимедиа цэс
158 | Comment[mr]=विविध-वाहिन्यांचा मेनु
159 | Comment[ms]=Menu Multimedia
160 | Comment[nb]=Multimedia
161 | Comment[ne]=मल्टिमिडिया मेनु
162 | Comment[nl]=Multimedia-menu
163 | Comment[nn]=Multimedieprogram
164 | Comment[oc]=Multimèdia
165 | Comment[or]=ବହୁମାଧ୍ଯମ ତାଲିକା
166 | Comment[pa]=ਮਲਟੀਮੀਡਿਆ ਮੇਨੂ
167 | Comment[pl]=Menu multimediów
168 | Comment[ps]=ګڼرسنۍ غورنۍ
169 | Comment[pt]=Menu multimédia
170 | Comment[pt_BR]=Menu multimídia
171 | Comment[ro]=Meniul multimedia
172 | Comment[ru]=Мультимедиа
173 | Comment[si]=බහුමාද්ය මෙනුව
174 | Comment[sk]=Ponuka multimédií
175 | Comment[sl]=Predstavni meni
176 | Comment[sq]=Menu multimediale
177 | Comment[sr]=Мени за мултимедију
178 | Comment[sr@latin]=Meni za multimediju
179 | Comment[sv]=Multimediameny
180 | Comment[ta]=பல்முனை ஊடகப் பட்டியல்
181 | Comment[te]=బహుళమాధ్యమాల జాబితా
182 | Comment[th]=เมนูระบบสื่อผสม
183 | Comment[tr]=Çokluortam menüsü
184 | Comment[tt_RU]=Мультимедия менюсы
185 | Comment[ug]=كۆپ ۋاسىتە تىزىملىكى
186 | Comment[uk]=Меню мультимедіа
187 | Comment[ur]=ملٹی میڈیا فہرست
188 | Comment[ur_PK]=ملٹی میڈیا فہرست
189 | Comment[uz@cyrillic]=Мултимедиа менюси
190 | Comment[vi]=Trình đơn đa phương tiện
191 | Comment[xh]=Imenu Yezixhobo eziphathekayo zokugcina ulwazi ngokuphinda-phindeneyo
192 | Comment[zh_CN]=多媒体菜单
193 | Comment[zh_HK]=多媒體選單
194 | Comment[zh_TW]=多媒體選單
195 | Icon=applications-multimedia
196 | Type=Directory
197 |
--------------------------------------------------------------------------------
/desktop-directories/development.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Programming
3 | Name[af]=Programmering
4 | Name[ar]=البرمجة
5 | Name[as]=প্ৰোগ্ৰামিং
6 | Name[ast]=Programación
7 | Name[be]=Праграмаванне
8 | Name[be@latin]=Prahramavańnie
9 | Name[bg]=Разработка
10 | Name[bn]=প্রোগ্রামিং
11 | Name[bn_IN]=প্রোগ্রামিং
12 | Name[br]=Gouleviñ
13 | Name[ca]=Programació
14 | Name[cs]=Programování
15 | Name[cy]=Rhaglennu
16 | Name[da]=Programmering
17 | Name[de]=Entwicklung
18 | Name[dz]=ལས་རིམ་བཟོ་བ།
19 | Name[el]=Προγραμματισμός
20 | Name[en_CA]=Programming
21 | Name[en_GB]=Programming
22 | Name[eo]=Programado
23 | Name[es]=Programación
24 | Name[es_VE]=Programación
25 | Name[et]=Programmeerimine
26 | Name[eu]=Programazioa
27 | Name[fa]=برنامهسازی
28 | Name[fi]=Ohjelmointi
29 | Name[fo]=Forritan
30 | Name[fr]=Programmation
31 | Name[frp]=Programacion
32 | Name[fur]=Programazion
33 | Name[ga]=Ríomhchlárú
34 | Name[gl]=Programación
35 | Name[gn]=Jaja Poa
36 | Name[gu]=પ્રોગ્રામીંગ
37 | Name[he]=תכנות
38 | Name[hi]=प्रोग्रामिंग
39 | Name[hr]=Programiranje
40 | Name[hu]=Programozás
41 | Name[hy]=Ծրագրավորում
42 | Name[id]=Pemrograman
43 | Name[io]=Programado
44 | Name[is]=Forritun
45 | Name[it]=Programmazione
46 | Name[ja]=プログラミング
47 | Name[ka]=პროგრამირება
48 | Name[kk]=Бағдарламалау
49 | Name[km]=ការធ្វើកម្មវិធី
50 | Name[kn]=ಪ್ರೊಗ್ರಾಮಿಂಗ್
51 | Name[ko]=개발
52 | Name[ku]=Bernamekirin
53 | Name[ky]=Программалоо
54 | Name[lg]=Kuwandika puloguramu
55 | Name[lt]=Programavimas
56 | Name[lv]=Programmēšanas
57 | Name[mai]=प्रोग्रामिंग
58 | Name[mg]=Famolavolavolana
59 | Name[mk]=Програмирање
60 | Name[ml]=പ്രോഗ്രാമിങ്
61 | Name[mn]=Програмчилал
62 | Name[mr]=प्रोग्रामिंग
63 | Name[ms]=Pengaturcaraan
64 | Name[nb]=Utvikling
65 | Name[ne]=प्रोग्रामिङ
66 | Name[nl]=Programmeren
67 | Name[nn]=Programmering
68 | Name[oc]=Desvolopament
69 | Name[or]=ପ୍ରୋଗ୍ରାମିଙ୍ଗ
70 | Name[pa]=ਪਰੋਗਰਾਮਿੰਗ
71 | Name[pl]=Programowanie
72 | Name[ps]=پروګرامونه
73 | Name[pt]=Desenvolvimento
74 | Name[pt_BR]=Desenvolvimento
75 | Name[ro]=Programare
76 | Name[ru]=Программирование
77 | Name[si]=කේතරචනය
78 | Name[sk]=Programovanie
79 | Name[sl]=Programiranje
80 | Name[sq]=Programim
81 | Name[sr]=Програмирање
82 | Name[sr@latin]=Programiranje
83 | Name[sv]=Programmering
84 | Name[ta]=நிரலாக்கம்
85 | Name[te]=ప్రోగ్రామింగ్
86 | Name[th]=เขียนโปรแกรม
87 | Name[tr]=Programlama
88 | Name[tt_RU]=Программалау
89 | Name[ug]=پروگراممىچىلىق
90 | Name[uk]=Програмування
91 | Name[ur]=پروگرامنگ
92 | Name[ur_PK]=پروگرامنگ
93 | Name[uz@cyrillic]=Дастурлаш
94 | Name[vi]=Lập trình
95 | Name[xh]=Ukwenziwa kweenkqubo
96 | Name[zh_CN]=编程
97 | Name[zh_HK]=軟件開發
98 | Name[zh_TW]=軟體開發
99 | Comment=Tools for software development
100 | Comment[af]=Gereedskap vir sagtewareontwikkeling
101 | Comment[ar]=أدوات لتطوير البرامج
102 | Comment[as]=চালনাজ্ঞান উন্নয়নৰ সামগ্ৰী
103 | Comment[ast]=Ferramientes pa desendolcu de programes
104 | Comment[be]=Інструменты для распрацоўкі праграм
105 | Comment[be@latin]=Pryłady prahramavańnia
106 | Comment[bg]=Инструменти за разработка на софтуер
107 | Comment[bn]=সফটওয়্যার ডেভেলপমেন্টের টুল
108 | Comment[bn_IN]=সফ্টওয়্যার ডিভেলপমেন্টের সামগ্রী
109 | Comment[br]=Ar binvioù da ziorren ar poelladoù
110 | Comment[ca]=Eines per a desenvolupament de programari
111 | Comment[cs]=Nástroje na vývoj softwaru
112 | Comment[cy]=Offer ar gyfer datblygu meddalwedd
113 | Comment[da]=Værktøjer til programudvikling
114 | Comment[de]=Werkzeuge zur Software-Entwicklung
115 | Comment[dz]=མཉེན་ཆས་བཟོ་ནིའི་ལག་ཆས།
116 | Comment[el]=Εργαλεία για ανάπτυξη λογισμικού
117 | Comment[en_CA]=Tools for software development
118 | Comment[en_GB]=Tools for software development
119 | Comment[eo]=Iloj por programado
120 | Comment[es]=Herramientas para el desarrollo del software
121 | Comment[es_VE]=Herramientas para el desarrollo del software
122 | Comment[et]=Tarkvaraarenduse tööriistad
123 | Comment[eu]=Softwarea garatzeko tresnak
124 | Comment[fa]=ابزارهای تولید نرمافزار
125 | Comment[fi]=Työkaluja sovelluskehitykseen
126 | Comment[fo]=Amboð til ritbúnaðarmenning
127 | Comment[fr]=Outils de développement logiciel
128 | Comment[frp]=Utils de developament de programos
129 | Comment[fur]=Imprescj par il svilup dal software
130 | Comment[ga]=Uirlisí d'fhorbairt bogearraí
131 | Comment[gl]=Ferramentas para o desenvolvemento de software
132 | Comment[gn]=Jaja Poa
133 | Comment[gu]=સોફ્ટવેર વિકાસ સાધનો
134 | Comment[he]=כלים לפיתוח תוכנה
135 | Comment[hi]=सॉफ्टवेयर विकास के औजार
136 | Comment[hr]=Alati za razvoj softvera
137 | Comment[hu]=Szoftverfejlesztési eszközök
138 | Comment[hy]=Ծրագրերի մշակման գործիքներ
139 | Comment[id]=Perkakas untuk pengembangan perangkat lunak
140 | Comment[is]=Þróunarverkfæri
141 | Comment[it]=Strumenti per lo sviluppo software
142 | Comment[ja]=ソフトウェア開発者向けのツールです
143 | Comment[ka]=პროგრამირების ხელსაწყოები
144 | Comment[kk]=Бағдарламаларды жасауға арналған құралдар
145 | Comment[km]=ឧបករណ៍សំរាប់អភិវឌ្ឍន៍កម្មវិធីផ្នែកទន់
146 | Comment[kn]=ತಂತ್ರಾಂಶ ಅಭಿವೃದ್ದಿಗೆ ಉಪಕರಣಗಳು
147 | Comment[ko]=소프트웨어 개발을 위한 도구
148 | Comment[ku]=Amûrên ji bo pêşdebirina nivîsbariyê
149 | Comment[ky]=Программа иштеп чыгуу аспаптары
150 | Comment[lg]=Ebikozesebwa mu ku kokola sofutiweya
151 | Comment[lt]=Programinės įrangos kūrimo įrankiai
152 | Comment[lv]=Programmatūras izstrādes rīki
153 | Comment[mai]=साफ्टवेयर विकासक लेल अओजार
154 | Comment[mg]=Fitaovana ho an'ny mpamolavola rindran'asa
155 | Comment[mk]=Алатки за развој на софтвер
156 | Comment[ml]=സോഫ്റ്റ്വെയര് വികസനത്തിനു് ആവശ്യമുളള പണിയായുധങ്ങള്
157 | Comment[mn]=Програм хөгжүүлэлийн хэрэгслүүд
158 | Comment[mr]=सॉफ्टवेयर बनवण्यासाटीचे अौजार
159 | Comment[ms]=Alatan untuk pembangunan perisian
160 | Comment[nb]=Verktøy for programvareutvikling
161 | Comment[ne]=सफ्टवेर विकासका लागि उपकरण
162 | Comment[nl]=Gereedschap voor programmatuurontwikkeling
163 | Comment[nn]=Verktøy for programutvikling
164 | Comment[oc]=Espleches per desvolopar de logicials
165 | Comment[or]=ସଫଟୱେର ବିକାଶ ପାଇଁ ଉପକରଣ
166 | Comment[pa]=ਸਾਫਟਵੇਅਰ ਦੇ ਵਿਕਾਸ ਲਈ ਸੰਦ
167 | Comment[pl]=Narzędzia do tworzenia oprogramowania
168 | Comment[ps]=د ساوترو جوړولو لپاره توکي
169 | Comment[pt]=Ferramentas para desenvolvimento de aplicações
170 | Comment[pt_BR]=Ferramentas para desenvolvimento de software
171 | Comment[ro]=Unelte pentru dezvoltarea de software
172 | Comment[ru]=Средства для разработки программ
173 | Comment[si]=මෘදුකාංග සංවර්ධන මෙවලම්
174 | Comment[sk]=Nástroje na vývoj softvéru
175 | Comment[sl]=Orodja za razvijanje programske opreme
176 | Comment[sq]=Vegla për zhvillim programesh
177 | Comment[sr]=Алати за развој софтвера
178 | Comment[sr@latin]=Alati za razvoj softvera
179 | Comment[sv]=Verktyg för programutveckling
180 | Comment[ta]=மென்பொருள் உற்பத்திக்கான கருவிகள்
181 | Comment[te]=సాఫ్ట్వేర్ అభివృద్ధిచేయుట కొరకు పనిముట్లు
182 | Comment[th]=เครื่องมือพัฒนาซอฟต์แวร์
183 | Comment[tr]=Yazılım geliştirme için araçlar
184 | Comment[tt_RU]=Кушымталар төзү өчен кораллар
185 | Comment[ug]=يۇمشاق دېتال ئىجادىيەت قوراللىرى
186 | Comment[uk]=Засоби розробки програм
187 | Comment[ur]=اوزار برائے سوفٹ ویئر ترقی
188 | Comment[ur_PK]=اوزار برائے سوفٹ ویئر ترقی
189 | Comment[uz@cyrillic]=Дастурлаш учун воситалар
190 | Comment[vi]=Công cụ phát triển phần mềm
191 | Comment[xh]=Izixhobo zokuphuhlisa ubucukubhede bekhompyutha
192 | Comment[zh_CN]=软件开发工具
193 | Comment[zh_HK]=軟件開發工具
194 | Comment[zh_TW]=軟體開發工具
195 | Icon=applications-development
196 | Type=Directory
197 |
--------------------------------------------------------------------------------
/desktop-directories/game.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Games
3 | Name[af]=Speletjies
4 | Name[ar]=الألعاب
5 | Name[as]=খেলা
6 | Name[ast]=Xuegos
7 | Name[be]=Гульні
8 | Name[be@latin]=Hulni
9 | Name[bg]=Игри
10 | Name[bn]=খেলা
11 | Name[bn_IN]=খেলা
12 | Name[br]=C'hoarioù
13 | Name[ca]=Jocs
14 | Name[cs]=Hry
15 | Name[cy]=Gemau
16 | Name[da]=Spil
17 | Name[de]=Spiele
18 | Name[dz]=རྩེད་རིགས།
19 | Name[el]=Παιχνίδια
20 | Name[en_CA]=Games
21 | Name[en_GB]=Games
22 | Name[eo]=Ludoj
23 | Name[es]=Juegos
24 | Name[es_VE]=Juegos
25 | Name[et]=Mängud
26 | Name[eu]=Jokoak
27 | Name[fa]=بازیها
28 | Name[fi]=Pelit
29 | Name[fo]=Spøl
30 | Name[fr]=Jeux
31 | Name[frp]=Joys
32 | Name[fur]=Zûcs
33 | Name[ga]=Cluichí
34 | Name[gl]=Xogos
35 | Name[gn]=Jaugaa
36 | Name[gu]=રમતો
37 | Name[he]=משחקים
38 | Name[hi]=खेल
39 | Name[hr]=Igre
40 | Name[hu]=Játékok
41 | Name[hy]=Խաղեր
42 | Name[id]=Permainan
43 | Name[io]=Ludi
44 | Name[is]=Leikir
45 | Name[it]=Giochi
46 | Name[ja]=ゲーム
47 | Name[ka]=თამაშები
48 | Name[kk]=Ойындар
49 | Name[km]=ល្បែង
50 | Name[kn]=ಆಟಗಳು
51 | Name[ko]=게임
52 | Name[ku]=Lîstik
53 | Name[ky]=Оюндар
54 | Name[lg]=Mizannyo
55 | Name[lt]=Žaidimai
56 | Name[lv]=Spēles
57 | Name[mai]=खेल
58 | Name[mg]=Lalao
59 | Name[mk]=Игри
60 | Name[ml]=കളികള്
61 | Name[mn]=Тоглоом
62 | Name[mr]=खेळ
63 | Name[ms]=Permainan
64 | Name[nb]=Spill
65 | Name[ne]=खेल
66 | Name[nl]=Spelletjes
67 | Name[nn]=Spel
68 | Name[oc]=Jòcs
69 | Name[or]=ଖେଳ
70 | Name[pa]=ਖੇਡਾਂ
71 | Name[pl]=Gry
72 | Name[ps]=لوبې
73 | Name[pt]=Jogos
74 | Name[pt_BR]=Jogos
75 | Name[ro]=Jocuri
76 | Name[ru]=Игры
77 | Name[si]=ක්රිඩා
78 | Name[sk]=Hry
79 | Name[sl]=Igre
80 | Name[sq]=Lojra
81 | Name[sr]=Игре
82 | Name[sr@latin]=Igre
83 | Name[sv]=Spel
84 | Name[ta]=விளையாட்டுகள்
85 | Name[te]=ఆటలు
86 | Name[th]=เกม
87 | Name[tr]=Oyunlar
88 | Name[tt_RU]=Уеннар
89 | Name[ug]=ئويۇنلار
90 | Name[uk]=Ігри
91 | Name[ur]=گیم
92 | Name[ur_PK]=گیم
93 | Name[uz@cyrillic]=Ўйинлар
94 | Name[vi]=Trò chơi
95 | Name[xh]=Imidlalo
96 | Name[zh_CN]=游戏
97 | Name[zh_HK]=遊戲
98 | Name[zh_TW]=遊戲
99 | Comment=Games and amusements
100 | Comment[af]=Speletjies en vermaak
101 | Comment[ar]=الألعاب والتّسلية
102 | Comment[as]=খেলা ও বিনোদন
103 | Comment[ast]=Xuegos y entretenimientu
104 | Comment[be]=Гульні і забавы
105 | Comment[be@latin]=Hulni j zabavy
106 | Comment[bg]=Игри и забавления
107 | Comment[bn]=খেলা ও বিনোদন
108 | Comment[bn_IN]=খেলা ও বিনোদন
109 | Comment[br]=C'hoarioù ha diduelloù
110 | Comment[ca]=Jocs i entreteniments
111 | Comment[cs]=Hry a zábava
112 | Comment[cy]=Gemau a difyrrwch
113 | Comment[da]=Spil og underholdning
114 | Comment[de]=Spiel und Spaß
115 | Comment[dz]=རྩེད་རིགས་དང་ དགོད་བྲ་ཚུ།
116 | Comment[el]=Παιχνίδια και διασκέδαση
117 | Comment[en_CA]=Games and amusements
118 | Comment[en_GB]=Games and Amusements
119 | Comment[eo]=Ludoj kaj amuzoj
120 | Comment[es]=Juegos y distracciones
121 | Comment[es_VE]=Juegos y distracciones
122 | Comment[et]=Mängud ja meelelahutus
123 | Comment[eu]=Jokoak eta denbora-pasak
124 | Comment[fa]=بازی و سرگرمی
125 | Comment[fi]=Pelit ja viihde
126 | Comment[fo]=Spøl og skemt
127 | Comment[fr]=Jeux et divertissements
128 | Comment[frp]=Joys é amusaments
129 | Comment[fur]=Zûcs e golosets
130 | Comment[ga]=Cluichí agus siamsaíochtaí
131 | Comment[gl]=Xogos e pasatempos
132 | Comment[gn]=Jaugaty
133 | Comment[gu]=રમતો અને મનોરંજકો
134 | Comment[he]=משחקים ושעשועים
135 | Comment[hi]=खेल व मनोरंजन
136 | Comment[hr]=Igre i zabava
137 | Comment[hu]=Játék és szórakozás
138 | Comment[hy]=Խաղեր և զվարճություններ
139 | Comment[id]=Permainan dan hiburan
140 | Comment[io]=Ludi ed amuzi
141 | Comment[is]=Leikir og gaman
142 | Comment[it]=Giochi e passatempi
143 | Comment[ja]=気晴しにゲームをどうぞ
144 | Comment[ka]=თამაშები და სხვა
145 | Comment[kk]=Ойын-сауық
146 | Comment[km]=ល្បែង និងការកំសាន្ដ
147 | Comment[kn]=ಆಟಗಳು ಹಾಗು ರಂಜನೆಗಳು
148 | Comment[ko]=게임 메뉴
149 | Comment[ku]=Lîstik û demxweşî
150 | Comment[ky]=Оюндар жана эс алуу
151 | Comment[lg]=Mizannyo n'eby'okwesanyusa
152 | Comment[lt]=Žaidimai ir pramogos
153 | Comment[lv]=Spēles un izklaides programmas
154 | Comment[mai]=खेल आ मनोरंजन
155 | Comment[mg]=lalao sy fialam-boly
156 | Comment[mk]=Игри и забава
157 | Comment[ml]=കളികളും വിനോദങ്ങളും
158 | Comment[mn]=Тоглоом, зугаа цэнгэл
159 | Comment[mr]=खेळ व मनोरंजन
160 | Comment[ms]=Permainan dan hiburan
161 | Comment[nb]=Spill og underholdning
162 | Comment[ne]=खेल र मनोरञ्जन
163 | Comment[nl]=Spelletjes en vermaak
164 | Comment[nn]=Spel og underhaldning
165 | Comment[oc]=Jòcs e divertiments
166 | Comment[or]=ଖେଳ ଏବଂ ମନୋରଞ୍ଜନ
167 | Comment[pa]=ਖੇਡਾਂ ਅਤੇ ਮਨੋਰੰਜਨ
168 | Comment[pl]=Gry i rozrywka
169 | Comment[ps]=لوبې او مهالتيري
170 | Comment[pt]=Jogos e diversões
171 | Comment[pt_BR]=Jogos e diversões
172 | Comment[ro]=Jocuri și amuzamente
173 | Comment[ru]=Игры и развлечения
174 | Comment[si]=ක්රිඩා සහ විනොදාශ්වාද
175 | Comment[sk]=Hry a zábava
176 | Comment[sl]=Igre in zabava
177 | Comment[sq]=Lojra dhe argëtime
178 | Comment[sr]=Игре и забава
179 | Comment[sr@latin]=Igre i zabava
180 | Comment[sv]=Spel och underhållning
181 | Comment[ta]=விளையாட்டுகள் மற்றும் பொழுதுப்போக்குகள்
182 | Comment[te]=ఆటలు మరియు వినోదకాలు
183 | Comment[th]=เกมและความบันเทิง
184 | Comment[tr]=Oyun ve eğlencelikler
185 | Comment[tt_RU]=Уеннар һәм күңел ачу
186 | Comment[ug]=ئويۇن ۋە كۆڭۈل ئېچىش پروگراممىلىرى
187 | Comment[uk]=Ігри та розваги
188 | Comment[ur]=گیم اور کھیل
189 | Comment[ur_PK]=گیم اور کھیل
190 | Comment[uz@cyrillic]=Ўйинлар ва кўнгилочар дастурлар
191 | Comment[vi]=Trò chơi và giải trí
192 | Comment[xh]=Imidlalo nokuzihlekisa
193 | Comment[zh_CN]=游戏和休闲
194 | Comment[zh_HK]=遊戲及娛樂
195 | Comment[zh_TW]=遊戲及娛樂
196 | Icon=applications-games
197 | Type=Directory
198 |
--------------------------------------------------------------------------------
/desktop-directories/graphics.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Graphics
3 | Name[af]=Grafika
4 | Name[ar]=الرّسوميّات
5 | Name[as]=গ্ৰাফিক্স
6 | Name[ast]=Gráficos
7 | Name[be]=Графіка
8 | Name[be@latin]=Hrafika
9 | Name[bg]=Графика
10 | Name[bn]=গ্রাফিক্স
11 | Name[bn_IN]=গ্রাফিক্স
12 | Name[br]=Grafikoù
13 | Name[ca]=Gràfics
14 | Name[cs]=Grafika
15 | Name[cy]=Graffeg
16 | Name[da]=Grafik
17 | Name[de]=Grafik
18 | Name[dz]=ཚད་རིས།
19 | Name[el]=Γραφικά
20 | Name[en_CA]=Graphics
21 | Name[en_GB]=Graphics
22 | Name[eo]=Grafikoj
23 | Name[es]=Gráficos
24 | Name[es_VE]=Gráficos
25 | Name[et]=Graafika
26 | Name[eu]=Irudiak
27 | Name[fa]=گرافیک
28 | Name[fi]=Grafiikka
29 | Name[fo]=Teknindi
30 | Name[fr]=Graphisme
31 | Name[frp]=Grafics
32 | Name[fur]=Grafiche
33 | Name[ga]=Grafaic
34 | Name[gl]=Gráficos
35 | Name[gn]=Baemo Ra'angaa Jajapoa
36 | Name[gu]=ગ્રાફિક્સ
37 | Name[he]=גרפיקה
38 | Name[hi]=आलेखी
39 | Name[hr]=Grafika
40 | Name[hu]=Grafika
41 | Name[hy]=Գրաֆիկա
42 | Name[id]=Grafis
43 | Name[io]=Grafikarti
44 | Name[is]=Myndefni
45 | Name[it]=Grafica
46 | Name[ja]=グラフィックス
47 | Name[ka]=გრაფიკა
48 | Name[kk]=Бейнелеу
49 | Name[km]=ក្រាហ្វិក
50 | Name[kn]=ಗ್ರಾಫಿಕ್ಸ್
51 | Name[ko]=그래픽
52 | Name[ku]=Grafîk
53 | Name[ky]=Графика
54 | Name[lg]=Eby'ebifaananyi
55 | Name[lt]=Grafika
56 | Name[lv]=Grafikas
57 | Name[mai]=आलेखी
58 | Name[mg]=Sary
59 | Name[mk]=Графика
60 | Name[ml]=ഗ്രാഫിക്സ്
61 | Name[mn]=График
62 | Name[mr]=चित्र-विज्ञान
63 | Name[ms]=Grafik
64 | Name[nb]=Grafikk
65 | Name[ne]=ग्राफिक्स
66 | Name[nl]=Grafisch
67 | Name[nn]=Bilete
68 | Name[oc]=Grafisme
69 | Name[or]=ଆଲେଖୀ
70 | Name[pa]=ਗਰਾਫ਼ਿਕਸ
71 | Name[pl]=Grafika
72 | Name[ps]=کښنيزونه
73 | Name[pt]=Gráficos
74 | Name[pt_BR]=Gráficos
75 | Name[ro]=Grafică
76 | Name[ru]=Графика
77 | Name[rw]=Ibishushanyo
78 | Name[si]=චිත්ර
79 | Name[sk]=Grafika
80 | Name[sl]=Grafika
81 | Name[sq]=Grafikë
82 | Name[sr]=Графика
83 | Name[sr@latin]=Grafika
84 | Name[sv]=Grafik
85 | Name[ta]=வரைகலை
86 | Name[te]=గ్రాఫిక్స్
87 | Name[th]=รูปภาพ
88 | Name[tr]=Grafik
89 | Name[tt_RU]=Графика
90 | Name[ug]=گرافىك
91 | Name[uk]=Графіка
92 | Name[ur]=گریفکس
93 | Name[ur_PK]=گریفکس
94 | Name[uz@cyrillic]=Графика
95 | Name[vi]=Đồ họa
96 | Name[xh]=Iimo zezibonakalisi-nkqubo
97 | Name[zh_CN]=图像
98 | Name[zh_HK]=美工繪圖
99 | Name[zh_TW]=美工繪圖
100 | Comment=Graphics applications
101 | Comment[af]=Grafika-toepassings
102 | Comment[ar]=تطبيقات الرّسوم
103 | Comment[as]=চাত্ৰাঙ্কিত অনুপ্ৰয়োগ
104 | Comment[ast]=Aplicaciones gráfiques
105 | Comment[be]=Графічныя праграмы
106 | Comment[be@latin]=Hrafičnyja aplikacyi
107 | Comment[bg]=Програми за работа с графика
108 | Comment[bn]=গ্রাফিক্স অ্যাপ্লিকেশন
109 | Comment[bn_IN]=গ্রাফিক্স অ্যাপ্লিকেশন
110 | Comment[br]=Poelladoù grafikoù
111 | Comment[ca]=Aplicacions gràfiques
112 | Comment[cs]=Aplikace pro grafiku
113 | Comment[cy]=Rhaglennu graffeg
114 | Comment[da]=Grafikprogrammer
115 | Comment[de]=Anwendungen zur Grafikbearbeitung
116 | Comment[dz]=ཚད་རིས་ཀྱི་གློག་རིམ།
117 | Comment[el]=Εφαρμογές γραφικών
118 | Comment[en_CA]=Graphics applications
119 | Comment[en_GB]=Graphics applications
120 | Comment[eo]=Grafikaj aplikaĵoj
121 | Comment[es]=Aplicaciones gráficas
122 | Comment[es_VE]=Aplicaciones gráficas
123 | Comment[et]=Graafikatöötlusprogrammid
124 | Comment[eu]=Irudi aplikazioak
125 | Comment[fa]=برنامههای گرافیکی
126 | Comment[fi]=Grafiikkasovellukset
127 | Comment[fo]=Teknindis nýtsluskipanir
128 | Comment[fr]=Applications graphiques
129 | Comment[frp]=Applicacions grafiques
130 | Comment[fur]=Aplicazions di grafiche
131 | Comment[ga]=Feidhmchláir grafaice
132 | Comment[gl]=Aplicacións de gráficos
133 | Comment[gn]=Baemo Ra'angaa Jajapoa Oia
134 | Comment[gu]=ગ્રાફિક્સ કાર્યક્રમો
135 | Comment[he]=יישומים גרפיים
136 | Comment[hi]=आलेखी अनुप्रयोग
137 | Comment[hr]=Grafičke aplikacije
138 | Comment[hu]=Grafikai alkalmazások
139 | Comment[hy]=Գրաֆիկական ծրագրեր
140 | Comment[id]=Aplikasi grafis
141 | Comment[io]=Programi pri grafikarti
142 | Comment[is]=Myndefnisforrit
143 | Comment[it]=Applicazioni grafiche
144 | Comment[ja]=グラフィックス関連のアプリケーションです
145 | Comment[ka]=გრაფიკული პროგრამები
146 | Comment[kk]=Графикалық қолданбалары
147 | Comment[km]=កម្មវិធីក្រាហ្វិក
148 | Comment[kn]=ಗ್ರಾಫಿಕ್ಸ್ ಅನ್ವಯಗಳು
149 | Comment[ko]=그래픽 응용프로그램
150 | Comment[ku]=Sepanên grafîkê
151 | Comment[ky]=Графикалык иштемелер
152 | Comment[lg]=Puloguramu ezikola ku bifaananyi
153 | Comment[lt]=Grafinės programos
154 | Comment[lv]=Grafikas programmas
155 | Comment[mai]=आलेखी अनुप्रयोगसभ
156 | Comment[mg]=Rindran'asa fanaovan-tsary
157 | Comment[mk]=Графички апликации
158 | Comment[ml]=ഗ്രാഫിക്സ് പ്രയോഗങ്ങള്
159 | Comment[mn]=График програмууд
160 | Comment[mr]=चित्र-विज्ञान उपकरणं
161 | Comment[ms]=Aplikasi Grafik
162 | Comment[nb]=Grafiske programmer
163 | Comment[ne]=ग्राफिक्स अनुप्रयोग
164 | Comment[nl]=Grafische toepassingen
165 | Comment[nn]=Biletprogram
166 | Comment[oc]=Logicials grafics
167 | Comment[or]=ଆଲେଖୀ ପ୍ରୟୋଗ
168 | Comment[pa]=ਗਰਾਫ਼ਿਕਸ ਕਾਰਜ
169 | Comment[pl]=Programy graficzne
170 | Comment[ps]=کښنيزونو کاريالونه
171 | Comment[pt]=Aplicações gráficas
172 | Comment[pt_BR]=Aplicativos gráficos
173 | Comment[ro]=Programe de grafică
174 | Comment[ru]=Графические приложения
175 | Comment[si]=චිත්රක යෙදුම්
176 | Comment[sk]=Grafické aplikácie
177 | Comment[sl]=Grafični programi
178 | Comment[sq]=Programe grafiku
179 | Comment[sr]=Графички програми
180 | Comment[sr@latin]=Grafički programi
181 | Comment[sv]=Grafikprogram
182 | Comment[ta]=வரைகலை பயன்பாடுகள்
183 | Comment[te]=గ్రాఫిక్స్ అనువర్తనాలు
184 | Comment[th]=โปรแกรมสำหรับรูปภาพ
185 | Comment[tr]=Grafik uygulamaları
186 | Comment[tt_RU]=График кушымталар
187 | Comment[ug]=گرافىك پروگراممىلىرى
188 | Comment[uk]=Графічні програми
189 | Comment[ur]=گریفکس اطلاقیہ جات
190 | Comment[ur_PK]=گریفکس اطلاقیہ جات
191 | Comment[uz@cyrillic]=Графика дастурлари
192 | Comment[vi]=Ứng dụng đồ họa
193 | Comment[xh]=Iinkqubo ngeemo zezibonakalisi-nkqubo
194 | Comment[zh_CN]=图像应用程序
195 | Comment[zh_HK]=繪圖工具
196 | Comment[zh_TW]=繪圖工具
197 | Icon=applications-graphics
198 | Type=Directory
199 |
--------------------------------------------------------------------------------
/desktop-directories/internet-and-network.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Internet and Network
3 | Name[af]=Internet en netwerk
4 | Name[ar]=الإنترنت والشّبكة
5 | Name[as]=ইন্টাৰনেট ও নেটৱৰ্ক
6 | Name[ast]=Internet y rede
7 | Name[be]=Інтэрнэт і сетка
8 | Name[be@latin]=Internet i sietka
9 | Name[bg]=Интернет и мрежа
10 | Name[bn]=ইন্টারনেট এবং নেটওয়ার্ক
11 | Name[bn_IN]=ইন্টারনেট ও নেটওয়ার্ক
12 | Name[ca]=Internet i xarxa
13 | Name[cs]=Internet a síť
14 | Name[da]=Internet og netværk
15 | Name[de]=Internet und Netzwerk
16 | Name[dz]=ཨིན་ཊར་ནེཊི་དང་ཡོངས་འབྲེལ་
17 | Name[el]=Διαδίκτυο και δίκτυο
18 | Name[en_GB]=Internet and Network
19 | Name[eo]=Interreto kaj reto
20 | Name[es]=Internet y red
21 | Name[es_VE]=Internet y red
22 | Name[et]=Internet ja võrk
23 | Name[eu]=Internet eta sarea
24 | Name[fa]=اینترنت و شبکه
25 | Name[fi]=Internet ja verkko
26 | Name[fo]=Alnet og net
27 | Name[fr]=Internet et réseau
28 | Name[frp]=Internet é Téla
29 | Name[fur]=Internet e Rêt
30 | Name[ga]=Idirlíon agus Líonra
31 | Name[gl]=Internet e rede
32 | Name[gu]=ઈન્ટરનેટ અને નેટવર્ક
33 | Name[he]=אינטרט ורשת
34 | Name[hi]=इंटरनेट व संजाल
35 | Name[hr]=Internet i Mreža
36 | Name[hu]=Internet és hálózat
37 | Name[hy]=Ինտերնետ և Ցանց
38 | Name[id]=Internet dan Jaringan
39 | Name[io]=Interreto e Reto
40 | Name[is]=Internet og netkerfi
41 | Name[it]=Internet e rete
42 | Name[ja]=インターネットとネットワーク
43 | Name[kk]=Интернет және желі
44 | Name[km]=អ៊ីនធឺណិត និងបណ្ដាញ
45 | Name[kn]=ಅಂತರ್ಜಾಲ ಹಾಗು ಜಾಲಬಂಧ
46 | Name[ko]=인터넷과 네트워크
47 | Name[ku]=Înternet û Tor
48 | Name[lg]=Ebya Yintaneti n'okuwulirizagana ne kompyuta ndala
49 | Name[lt]=Internetas ir tinklas
50 | Name[lv]=Internets un tīkli
51 | Name[mk]=Интернет и мрежа
52 | Name[ml]=ഇന്റര്നെറ്റും ശൃംഖലയും
53 | Name[mr]=महाजाळ व संजाळ
54 | Name[ms]=Internet dan Rangkaian
55 | Name[nb]=Internett og nettverk
56 | Name[ne]=इन्टरनेट र सञ्जाल
57 | Name[nl]=Internet en netwerk
58 | Name[nn]=Internett og nettverk
59 | Name[oc]=Internet e ret
60 | Name[or]=ଇନ୍ଟରନେଟ ଏବଂ ନେଟୱର୍କ
61 | Name[pa]=ਇੰਟਰਨੈੱਟ ਅਤੇ ਨੈੱਟਵਰਕ
62 | Name[pl]=Internet i sieć
63 | Name[ps]=اېنټرنېټ او ځال
64 | Name[pt]=Internet e rede
65 | Name[pt_BR]=Internet e rede
66 | Name[ro]=Internet și rețea
67 | Name[ru]=Интернет и сеть
68 | Name[si]=අන්තර්ජාලය සහ ජාලය
69 | Name[sk]=Internet a sieť
70 | Name[sl]=Internet in omrežje
71 | Name[sq]=Internet dhe Rrjet
72 | Name[sr]=Интернет и мрежа
73 | Name[sr@latin]=Internet i mreža
74 | Name[sv]=Internet och nätverk
75 | Name[ta]=இணையம் மற்றும் வலையமைப்பு
76 | Name[te]=అంతర్జాలం మరియు నెట్వర్క్
77 | Name[th]=อินเทอร์เน็ตและเครือข่าย
78 | Name[tr]=İnternet ve Ağ
79 | Name[tt_RU]=Интернет һәм Челтәр
80 | Name[ug]=ئىنتېرنېت ۋە تور
81 | Name[uk]=Інтернет та мережа
82 | Name[ur]=انٹرنیٹ اور نیٹ ورک
83 | Name[ur_PK]=انٹرنیٹ اور نیٹ ورک
84 | Name[uz@cyrillic]=Интернет ва тармоқ
85 | Name[vi]=Internet và mạng
86 | Name[zh_CN]=互联网和网络
87 | Name[zh_HK]=互聯網及網絡
88 | Name[zh_TW]=網際網路及網路
89 | Comment=Network-related settings
90 | Comment[af]=Netwerkverwante instellings
91 | Comment[ar]=الإعدادات المتعلّقة بالشّبكة
92 | Comment[as]=নেটৱৰ্ক সংক্ৰান্ত বৈশিষ্ট্য
93 | Comment[ast]=Opciones rellacionaes col trabayu en rede
94 | Comment[be]=Настаўленні сеткі
95 | Comment[be@latin]=Sietkavyja nałady
96 | Comment[bg]=Настройки за мрежата
97 | Comment[bn]=নেটওয়ার্ক সম্পর্কিত সেটিং
98 | Comment[bn_IN]=নেটওয়ার্ক সংক্রান্ত বৈশিষ্ট্য
99 | Comment[ca]=Paràmetres de xarxa
100 | Comment[cs]=Nastavení související se sítí
101 | Comment[da]=Netværksrelaterede indstillinger
102 | Comment[de]=Netzwerkbezogene Einstellungen
103 | Comment[dz]=ཡོང་འབྲེལ་དང་འབྲེལ་བའི་སྒྲིག་སྟངས་
104 | Comment[el]=Ρυθμίσεις για το δίκτυο
105 | Comment[en_GB]=Network-related settings
106 | Comment[eo]=Ret-rilataj agordoj
107 | Comment[es]=Propiedades relacionadas con la red
108 | Comment[es_VE]=Propiedades relacionadas con la red
109 | Comment[et]=Võrguga seotud sätted
110 | Comment[eu]=Sareko ezarpenak
111 | Comment[fa]=تنظیمات مربوط به شبکه
112 | Comment[fi]=Verkkoon liittyvät asetukset
113 | Comment[fo]=Net tengdar setingar
114 | Comment[fr]=Paramètres concernant le réseau
115 | Comment[frp]=Configuracion da Téla
116 | Comment[fur]=Impostazions de rêt
117 | Comment[ga]=Socruithe líonra-gaolta
118 | Comment[gl]=Configuracións relacionadas coa rede
119 | Comment[gu]=નેટવર્ક-સંબંધિત સુયોજનો
120 | Comment[he]=הגדרות רשת
121 | Comment[hi]=संजाल संबंधित सेटिंग
122 | Comment[hr]=Mrežne postavke
123 | Comment[hu]=Hálózattal kapcsolatos beállítások
124 | Comment[hy]=Ցանցային հատկություններ
125 | Comment[id]=Penataan terkait jaringan
126 | Comment[io]=Retala setuesi
127 | Comment[is]=Netkerfistengdar stillingar
128 | Comment[it]=Impostazioni relative alla rete
129 | Comment[ja]=ネットワークに関連する設定を行います
130 | Comment[kk]=Желіге байланысты баптаулар
131 | Comment[km]=ការកំណត់ដែលទាក់ទងជាមួយនឹងបណ្ដាញ
132 | Comment[kn]=ಜಾಲಬಂಧ-ಸಂಬಂಧಿತ ಸಂಯೋಜನೆಗಳು
133 | Comment[ko]=네트워크와 관련된 설정을 합니다
134 | Comment[ku]=Mîhengên têkildarî torê
135 | Comment[lg]=Entegeka ezifuga okuwulirizagana ne kompyuta ndala
136 | Comment[lt]=Su tinklu susiję nustatymai
137 | Comment[lv]=Ar tīklu saistīti iestatījumi
138 | Comment[mk]=Поставувања кои се однесуваат на мрежа
139 | Comment[ml]=ശൃംഖലയുമായി ബന്ധപ്പെട്ട സജ്ജീകരണങ്ങള്
140 | Comment[mr]=संजाळ-संबंधी संयोजना
141 | Comment[ms]=Tetapan rangkaian-berkaitan
142 | Comment[nb]=Nettverksrelaterte innstillinger
143 | Comment[ne]=सञ्जाल सम्बन्धि सेटिङ
144 | Comment[nl]=Netwerkgerelateerde instellingen
145 | Comment[nn]=Nettverksinnstillingar
146 | Comment[oc]=Paramètres en relacion amb la ret
147 | Comment[or]=ନେଟୱର୍କ ସମ୍ପର୍କୀୟ ବିନ୍ୟାସ
148 | Comment[pa]=ਨੈੱਟਵਰਕ ਨਾਲ ਸਬੰਧਤ ਸੈਟਿੰਗ
149 | Comment[pl]=Ustawienia związane z siecią
150 | Comment[ps]=ځال پورې تړلې امستنې
151 | Comment[pt]=Definições de rede
152 | Comment[pt_BR]=Configurações de rede
153 | Comment[ro]=Configurări pentru rețea
154 | Comment[ru]=Параметры, относящиеся к настройке сети
155 | Comment[si]=ජාලය සම්බන්ද සැකසුම්
156 | Comment[sk]=Nastavenia súvisiace so sieťou
157 | Comment[sl]=Nastavitve omrežja
158 | Comment[sq]=Rregullime lidhur me Rrjetin
159 | Comment[sr]=Мрежна подешавања
160 | Comment[sr@latin]=Mrežna podešavanja
161 | Comment[sv]=Nätverksrelaterade inställningar
162 | Comment[ta]=வலையமைப்பு சார்ந்த வடிவமைப்புகள்
163 | Comment[te]=నెట్వర్క్-సంబంధిత అమరికలు
164 | Comment[th]=ตั้งค่าเกี่ยวกับเครือข่าย
165 | Comment[tr]=Ağ ile ilgili ayarlar
166 | Comment[tt_RU]=Челтәргә бәйләнешле көйләүләр
167 | Comment[ug]=تورغا مۇناسىۋەتلىك تەڭشەك
168 | Comment[uk]=Мережні налаштування
169 | Comment[ur]=نیٹ ورک سے متعلقہ ترتیبات
170 | Comment[ur_PK]=نیٹ ورک سے متعلقہ ترتیبات
171 | Comment[uz@cyrillic]=Тармоққа оид мосламалар
172 | Comment[vi]=Thiết lập mạng
173 | Comment[zh_CN]=网络相关的设置
174 | Comment[zh_HK]=網絡相關設定
175 | Comment[zh_TW]=網路相關設定
176 | Icon=preferences-system-network
177 | Type=Directory
178 |
--------------------------------------------------------------------------------
/desktop-directories/office.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Office
3 | Name[af]=Kantoor
4 | Name[ar]=المكتب
5 | Name[as]=কাৰ্যালয়
6 | Name[ast]=Oficina
7 | Name[be]=Офіс
8 | Name[be@latin]=Ofis
9 | Name[bg]=Офис
10 | Name[bn]=অফিস
11 | Name[bn_IN]=অফিস
12 | Name[br]=Bureveg
13 | Name[ca]=Oficina
14 | Name[cs]=Kancelář
15 | Name[cy]=Swyddfa
16 | Name[da]=Kontor
17 | Name[de]=Büro
18 | Name[dz]=ཡིག་ཚང་།
19 | Name[el]=Γραφείο
20 | Name[en_CA]=Office
21 | Name[en_GB]=Office
22 | Name[eo]=Oficejo
23 | Name[es]=Oficina
24 | Name[es_VE]=Oficina
25 | Name[et]=Kontor
26 | Name[eu]=Bulegoa
27 | Name[fa]=اداری
28 | Name[fi]=Toimisto
29 | Name[fo]=Skrivstova
30 | Name[fr]=Bureautique
31 | Name[frp]=Oficio
32 | Name[fur]=Ufici
33 | Name[ga]=Oifig
34 | Name[gl]=Oficina
35 | Name[gn]=Nhamboparaa Regua
36 | Name[gu]=ઓફિસ
37 | Name[he]=משרד
38 | Name[hi]=कार्यालय
39 | Name[hr]=Ured
40 | Name[hu]=Iroda
41 | Name[hy]=Օֆիս
42 | Name[id]=Perkantoran
43 | Name[io]=Kontoro
44 | Name[is]=Skrifstofa
45 | Name[it]=Ufficio
46 | Name[ja]=オフィス
47 | Name[ka]=ოფისი
48 | Name[kk]=Кеңселік
49 | Name[km]=ការិយាល័យ
50 | Name[kn]=ಆಫೀಸ್
51 | Name[ko]=오피스
52 | Name[ku]=Nivîsgeh
53 | Name[ky]=Офис
54 | Name[lg]=Puloguramu ez'omu wofiisi
55 | Name[lt]=Raštinė
56 | Name[lv]=Biroja
57 | Name[mai]=कार्यालय
58 | Name[mg]=Office
59 | Name[mk]=Канцелариски
60 | Name[ml]=ഓഫീസ്
61 | Name[mn]=Бичиг хэрэг, офис
62 | Name[mr]=कार्यालय
63 | Name[ms]=Pejabat
64 | Name[nb]=Kontorstøtte
65 | Name[ne]=कार्यालय
66 | Name[nl]=Kantoor
67 | Name[nn]=Kontor
68 | Name[oc]=Burèu
69 | Name[or]=କାର୍ଯ୍ଯାଳୟ
70 | Name[pa]=ਦਫ਼ਤਰ
71 | Name[pl]=Biuro
72 | Name[ps]=افس
73 | Name[pt]=Produtividade
74 | Name[pt_BR]=Escritório
75 | Name[ro]=Birou
76 | Name[ru]=Офис
77 | Name[rw]=Ofise
78 | Name[si]=කාර්යයාලීය
79 | Name[sk]=Kancelária
80 | Name[sl]=Pisarna
81 | Name[sq]=Zyrë
82 | Name[sr]=Канцеларија
83 | Name[sr@latin]=Kancelarija
84 | Name[sv]=Kontor
85 | Name[ta]=அலுவலகம்
86 | Name[te]=కార్యాలయం
87 | Name[th]=สำนักงาน
88 | Name[tr]=Ofis
89 | Name[tt_RU]=Офис
90 | Name[ug]=ئىشخانا
91 | Name[uk]=Офіс
92 | Name[ur]=آفس
93 | Name[ur_PK]=آفس
94 | Name[uz@cyrillic]=Офис
95 | Name[vi]=Văn phòng
96 | Name[xh]=i-Ofisi
97 | Name[zh_CN]=办公
98 | Name[zh_HK]=辦公
99 | Name[zh_TW]=辦公
100 | Comment=Office Applications
101 | Comment[af]=Kantoortoepassings
102 | Comment[ar]=التّطبيقات المكتبيّة
103 | Comment[as]=কাৰ্যালয়ৰ অনুপ্ৰয়োগ
104 | Comment[ast]=Aplicaciones d'Oficina
105 | Comment[be]=Офісныя праграмы
106 | Comment[be@latin]=Ofisnyja prahramy
107 | Comment[bg]=Офисни програми
108 | Comment[bn]=অফিস অ্যাপলিকেশন
109 | Comment[bn_IN]=অফিস অ্যাপলিকেশন
110 | Comment[br]=Arloadoù bureveg all
111 | Comment[ca]=Aplicacions d'oficina
112 | Comment[cs]=Kancelářské aplikace
113 | Comment[cy]=Rhaglenni Swyddfa
114 | Comment[da]=Kontorprogrammer
115 | Comment[de]=Büroanwendungen
116 | Comment[dz]=ཡིག་ཚང་གི་གློག་རིམ།
117 | Comment[el]=Εφαρμογές γραφείου
118 | Comment[en_CA]=Office Applications
119 | Comment[en_GB]=Office Applications
120 | Comment[eo]=Oficejaj aplikaĵoj
121 | Comment[es]=Aplicaciones de oficina
122 | Comment[es_VE]=Aplicaciones de oficina
123 | Comment[et]=Kontoritarkvara
124 | Comment[eu]=Bulegorako aplikazioak
125 | Comment[fa]=برنامههای اداری
126 | Comment[fi]=Toimistosovellukset
127 | Comment[fo]=Skrivstovu nýtsluskipanir
128 | Comment[fr]=Applications bureautiques
129 | Comment[frp]=Aplicacions d'oficio
130 | Comment[fur]=Aplicazions di ufici
131 | Comment[ga]=Feidhmchláir Oifige
132 | Comment[gl]=Aplicacións de oficina
133 | Comment[gn]=Jaekaa Omboparaa
134 | Comment[gu]=ઓફિસ કાર્યક્રમો
135 | Comment[he]=יישומים משרדיים
136 | Comment[hi]=कार्यालय अनुप्रयोग
137 | Comment[hr]=Uredske Aplikacije
138 | Comment[hu]=Irodai alkalmazások
139 | Comment[hy]=Օֆիսային Ծրագրեր
140 | Comment[id]=Aplikasi Perkantoran
141 | Comment[io]=Kontorala Programi
142 | Comment[is]=Skrifstofuforrit
143 | Comment[it]=Applicazioni da ufficio
144 | Comment[ja]=オフィス・アプリケーションです
145 | Comment[ka]=საოფისე პროგრამები
146 | Comment[kk]=Кеңселік қолданбалар
147 | Comment[km]=កម្មវិធីការិយាល័យ
148 | Comment[kn]=ಆಫೀಸ್ ಅನ್ವಯಗಳು
149 | Comment[ko]=오피스 응용프로그램
150 | Comment[ku]=Sepandinên Ofîsê
151 | Comment[ky]=Офистик иштемелер
152 | Comment[lg]=Pulogurmau ez'omu wofiisi
153 | Comment[lt]=Raštinės programos
154 | Comment[lv]=Biroja aplikācijas
155 | Comment[mai]=कार्यालयक अनुप्रयोग
156 | Comment[mg]=Rindran'asa Office
157 | Comment[mk]=Канцелариски апликации
158 | Comment[ml]=ഓഫീസ് പ്രയോഗങ്ങള്
159 | Comment[mn]=Офисын програмууд
160 | Comment[mr]=कार्यालय संबंधित उपकरणं
161 | Comment[ms]=Aplikasi Pejabat
162 | Comment[nb]=Kontorstøtteprogrammer
163 | Comment[ne]=कार्यालय अनुप्रयोग
164 | Comment[nl]=Kantoortoepassingen
165 | Comment[nn]=Kontorprogramvare
166 | Comment[oc]=Logicials pel burèu
167 | Comment[or]=କାର୍ଯ୍ଯାଳୟ ପ୍ରୟୋଗ
168 | Comment[pa]=ਦਫ਼ਤਰ ਕਾਰਜ
169 | Comment[pl]=Programy biurowe
170 | Comment[ps]=د افس کاريالونه
171 | Comment[pt]=Aplicações de produtividade
172 | Comment[pt_BR]=Aplicativos de escritório
173 | Comment[ro]=Programe pentru birou
174 | Comment[ru]=Офисные приложения
175 | Comment[si]=කාර්යාලිය යෙදුම්
176 | Comment[sk]=Kancelárske aplikácie
177 | Comment[sl]=Pisarniški programi
178 | Comment[sq]=Programe Zyre
179 | Comment[sr]=Програми за канцеларију
180 | Comment[sr@latin]=Programi za kancelariju
181 | Comment[sv]=Kontorsprogram
182 | Comment[ta]=அலுவலகப் பயன்பாடுகள்
183 | Comment[te]=కార్యాలయ అనువర్తనాలు
184 | Comment[th]=โปรแกรมสำหรับสำนักงาน
185 | Comment[tr]=Ofis Uygulamaları
186 | Comment[tt_RU]=Офис кушымталары
187 | Comment[ug]=ئىشخانا پروگراممىلىرى
188 | Comment[uk]=Офісні програми
189 | Comment[ur]=آفس اطلاقیہ جات
190 | Comment[ur_PK]=آفس اطلاقیہ جات
191 | Comment[uz@cyrillic]=Офис дастурлари
192 | Comment[vi]=Ứng dụng văn phòng
193 | Comment[xh]=Iinkqubo ze-Ofisi
194 | Comment[zh_CN]=办公应用程序
195 | Comment[zh_HK]=辦公室軟件
196 | Comment[zh_TW]=辦公室軟體
197 | Icon=applications-office
198 | Type=Directory
199 |
--------------------------------------------------------------------------------
/desktop-directories/other.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Other
3 | Name[af]=Ander
4 | Name[ar]=أخرى
5 | Name[as]=অন্যান্য
6 | Name[ast]=Otres
7 | Name[be]=Іншыя
8 | Name[be@latin]=Inšyja
9 | Name[bg]=Други
10 | Name[bn]=অন্যান্য
11 | Name[bn_IN]=অন্যান্য
12 | Name[br]=All
13 | Name[ca]=Altres
14 | Name[cs]=Ostatní
15 | Name[cy]=Eraill
16 | Name[da]=Andre
17 | Name[de]=Sonstige
18 | Name[dz]=གཞན།
19 | Name[el]=Άλλα
20 | Name[en_CA]=Other
21 | Name[en_GB]=Other
22 | Name[eo]=Alia
23 | Name[es]=Otras
24 | Name[es_VE]=Otras
25 | Name[et]=Muu
26 | Name[eu]=Bestelakoak
27 | Name[fa]=غیره
28 | Name[fi]=Muut
29 | Name[fo]=Annað
30 | Name[fr]=Autre
31 | Name[frp]=Autres
32 | Name[fur]=Altri
33 | Name[ga]=Eile
34 | Name[gl]=Outros
35 | Name[gn]=Amboae
36 | Name[gu]=અન્ય
37 | Name[he]=אחר
38 | Name[hi]=अन्य
39 | Name[hr]=Ostalo
40 | Name[hu]=Egyéb
41 | Name[hy]=Այլ
42 | Name[id]=Lainnya
43 | Name[io]=Altra
44 | Name[is]=Aðrir
45 | Name[it]=Altro
46 | Name[ja]=その他
47 | Name[ka]=სხვა
48 | Name[kk]=Басқалар
49 | Name[km]=ផ្សេងៗ
50 | Name[kn]=ಇತರೆ
51 | Name[ko]=기타
52 | Name[ku]=Yên din
53 | Name[ky]=Башкалар
54 | Name[lg]=Ebirala
55 | Name[lt]=Kitos
56 | Name[lv]=Citas programmas
57 | Name[mai]=आन
58 | Name[mg]=Hafa
59 | Name[mk]=Други
60 | Name[ml]=മറ്റുളളവ
61 | Name[mn]=Бусад
62 | Name[mr]=अन्य
63 | Name[ms]=Lain-lain
64 | Name[nb]=Annet
65 | Name[ne]=अन्य
66 | Name[nl]=Overig
67 | Name[nn]=Andre
68 | Name[oc]=Autre
69 | Name[or]=ଅନ୍ଯାନ୍ଯ
70 | Name[pa]=ਹੋਰ
71 | Name[pl]=Inne
72 | Name[ps]=نور
73 | Name[pt]=Outras
74 | Name[pt_BR]=Outros
75 | Name[ro]=Altele
76 | Name[ru]=Прочие
77 | Name[rw]=Ikindi
78 | Name[si]=වෙනත්
79 | Name[sk]=Ostatné
80 | Name[sl]=Drugo
81 | Name[sq]=Tjetër
82 | Name[sr]=Остало
83 | Name[sr@latin]=Ostalo
84 | Name[sv]=Övriga
85 | Name[ta]=மற்றவை
86 | Name[te]=ఇతర
87 | Name[th]=อื่นๆ
88 | Name[tr]=Diğer
89 | Name[tt_RU]=Башкалар
90 | Name[ug]=باشقا
91 | Name[uk]=Інші
92 | Name[ur]=دیگر
93 | Name[ur_PK]=دیگر
94 | Name[uz@cyrillic]=Бошқа
95 | Name[vi]=Khác
96 | Name[xh]=Ezinye
97 | Name[zh_CN]=其它
98 | Name[zh_HK]=其它
99 | Name[zh_TW]=其他
100 | Comment=Applications that did not fit in other categories
101 | Comment[af]=Toepassings wat nie in ander kategorieë pas nie
102 | Comment[ar]=تطبيقات لا تندرج تحت الفئات الأخرى
103 | Comment[as]=অন্যান্য শ্ৰেণীত অন্তৰ্গত নকৰা অনুপ্ৰয়োগ
104 | Comment[ast]=Aplicaciones que nun encaxen n'otres estayes
105 | Comment[be]=Праграмы, якія не трапілі ў іншыя катэгорыі
106 | Comment[be@latin]=Prahramy, jakija nie ŭvajšli ŭ inšyja kategoryi
107 | Comment[bg]=Програми, които не принадлежат към друга категория
108 | Comment[bn]=অ্যাপ্লিকেশন যেগুলো অন্য কোন শ্রেণীভূক্ত নয়
109 | Comment[bn_IN]=অন্যান্য শ্রেণীর মধ্যে অন্তর্গত না করা অ্যাপ্লিকেশন
110 | Comment[br]=An arloadoù n'int ket staget ouzh ur rummad bennak all
111 | Comment[ca]=Aplicacions que no encaixen en altres categories
112 | Comment[cs]=Aplikace nepatřící do jiných kategorií
113 | Comment[cy]=Rhaglenni nad ydynt yn ffitio yng nghategorïau eraill
114 | Comment[da]=Programmer som ikke passer i andre katagorier
115 | Comment[de]=Anwendungen, die in keine andere Kategorie eingeordnet werden können
116 | Comment[dz]=དབྱེ་ཁག་གཞན་ནང་ ཚུད་སྒྲིག་མེད་པའི་གློག་རིམ།
117 | Comment[el]=Εφαρμογές που δεν ταιριάζουν στις άλλες κατηγορίες
118 | Comment[en_CA]=Applications that do not fit in other categories
119 | Comment[en_GB]=Applications that do not fit in other categories
120 | Comment[eo]=Aplikaĵoj neagordaj aliajn kategoriojn
121 | Comment[es]=Aplicaciones que no entran en otras categorías
122 | Comment[es_VE]=Aplicaciones que no entran en otras categorías
123 | Comment[et]=Rakendused, mis ei sobinud teistesse kategooriatesse
124 | Comment[eu]=Aurreko kategorietan sartzen ez diren aplikazioak
125 | Comment[fa]=برنامههایی که در مقولات دیگر جا نمیگیرند
126 | Comment[fi]=Muihin luokkiin sopimattomat sovellukset
127 | Comment[fo]=Nýtsluskipanir ið ikki passa í aðrar bólkar
128 | Comment[fr]=Applications qui n'entraient dans aucune autre catégorie
129 | Comment[frp]=Aplicacions que n'ant pâs trovâ de categorie
130 | Comment[fur]=Aplicazions ch'a no jentrin ta chês altres categoriis
131 | Comment[ga]=Feidhmchláir nár oiriúnaigh i gcatagóirí eile
132 | Comment[gl]=Aplicacións que non se axustan a outras categorías
133 | Comment[gn]=Amboae Regua Jaekaa
134 | Comment[gu]=કાર્યક્રમો કે જે અન્ય વર્ગોમાં નહિં બંધબેસે
135 | Comment[he]=יישומים שלא התאימו בקטגוריות אחרות
136 | Comment[hi]=अनुप्रयोग जो अन्य श्रेणी में सटीक नहीं बैठती है
137 | Comment[hr]=Aplikacije koje ne pripadaju ostalim kategorijama
138 | Comment[hu]=Más kategóriákba be nem sorolható alkalmazások
139 | Comment[hy]=Ծրագրեր, որոնք այլ կատեգորիաներին չեն համապատասխանում
140 | Comment[id]=Aplikasi yang tidak termasuk dalam kategori lain
141 | Comment[is]=Forrit sem passa ekki í aðra flokka
142 | Comment[it]=Applicazioni che non rientrano in altre categorie
143 | Comment[ja]=他のカテゴリにあてはまらないアプリケーション
144 | Comment[ka]=პროგრამები რომლებიც არც ერთ კატეგორიაში არ შედიან
145 | Comment[kk]=Басқа санаттарға жатпайтын қолданбалар
146 | Comment[km]=កម្មវិធីដែលមិនសម នឹងប្រភេទដទៃទៀត
147 | Comment[kn]=ಬೇರೆ ವರ್ಗಗಳಿಗೆ ಸೇರದೇ ಇರುವಂತಹ ಅನ್ವಯಗಳು
148 | Comment[ko]=어떤 범주에도 해당되지 않는 프로그램
149 | Comment[ku]=Sepanên ku nakevin kategoriyên din
150 | Comment[ky]=Эч бир категорияга туура келбеген иштемелер
151 | Comment[lg]=Puloguramu ezitalina kiti mwe zigwa
152 | Comment[lt]=Programos, kurios netiko kitose kategorijose
153 | Comment[lv]=Aplikācijas, kas neiederas nevienā citā kategorijā
154 | Comment[mai]=अनुप्रयोगसभ जे आन श्रेणीमे सटीक नहि छला
155 | Comment[mg]=Rindran'asa izay tsy tafiditra anaty sokajy hafa
156 | Comment[mk]=Апликации кои што не влегуваат во ниедна категорија
157 | Comment[ml]=മറ്റു് വിഭാഗങ്ങളില് ഉള്പ്പെടാത്ത പ്രയോഗങ്ങള്
158 | Comment[mn]=Бусад ангилалд тохирохгүй програмууд
159 | Comment[mr]=उपकरणं जे दुसरया कुठल्याही गटांत बसले नाही
160 | Comment[ms]=Aplikasi yang tak sesuai dalam kategori lain
161 | Comment[nb]=Programmer som ikke passer i andre kategorier
162 | Comment[ne]=अन्य कोटिमा नमिलेका अनुप्रयोग
163 | Comment[nl]=Toepassingen die niet passen in andere categorieën
164 | Comment[nn]=Program som ikkje passar i andre kategoriar
165 | Comment[oc]=Logicials que dintran pas dins las autras categorias
166 | Comment[or]=ପ୍ରୟୋଗ ଯାହାକି ଅନ୍ଯ କୌଣସି ଶ୍ରେଣୀ ସହିତ ଖାପ ଖାଇଲା ନାହିଁ
167 | Comment[pa]=ਕਾਰਜ, ਜੋ ਕਿ ਕਿਸੇ ਵਰਗ ਵਿੱਚ ਨਹੀਂ ਆਉਦੇ।
168 | Comment[pl]=Programy, które nie pasują do innych kategorii
169 | Comment[ps]=هغه کاريالونه چې په نورو ټولېو کې نه راځي
170 | Comment[pt]=Aplicações que não se enquadram em nenhuma outra categoria
171 | Comment[pt_BR]=Aplicativos que não se encaixam em outras categorias
172 | Comment[ro]=Programe ce nu se încadrează în alte categorii
173 | Comment[ru]=Приложения, не подпадающие ни под какие категории
174 | Comment[si]=වෙනත් ප්රභේද වලට අයත් නොවු යෙදුම්
175 | Comment[sk]=Aplikácie, ktoré nepatria do ostatných kategórií
176 | Comment[sl]=Programi, ki ne sodijo v druge kategorije
177 | Comment[sq]=Programe që nuk gjejnë vend në kategori të tjera
178 | Comment[sr]=Програми који не припадају осталим категоријама
179 | Comment[sr@latin]=Programi koji ne pripadaju ostalim kategorijama
180 | Comment[sv]=Program som inte passar in i någon annan kategori
181 | Comment[ta]=இதர இனங்களில் பொருந்தாத பயன்பாடுகள்
182 | Comment[te]=ఇతర విభాగాలలో ఇమడని అనువర్తనాలు
183 | Comment[th]=โปรแกรมที่ไม่อยู่ในหมวดอื่นๆ
184 | Comment[tr]=Diğer sınıflandırmalara girmeyen uygulamalar
185 | Comment[tt_RU]=Калган төркемнәргә кермәгән кушымталар
186 | Comment[ug]=باشقا تۈرلەرگە تەۋە بولمىغان پروگراممىلار
187 | Comment[uk]=Програми, що не входять до жодної категорії
188 | Comment[ur]=وہ اطلاقیہ جات جو کسی دوسرے زمرے میں نہیں آتے
189 | Comment[ur_PK]=وہ اطلاقیہ جات جو کسی دوسرے زمرے میں نہیں آتے
190 | Comment[uz@cyrillic]=Ҳеч қайси туркумга кирмайдиган дастурлар
191 | Comment[vi]=Chương trình chưa phân loại
192 | Comment[xh]=Iinkqubo ezingangeniyo kwezinye iindidi
193 | Comment[zh_CN]=无法分入其它类别的应用程序
194 | Comment[zh_HK]=不符合其它分類的軟件
195 | Comment[zh_TW]=不符合其他分類的軟體
196 | Icon=applications-other
197 | Type=Directory
198 |
--------------------------------------------------------------------------------
/desktop-directories/system-tools.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=System Tools
3 | Name[af]=Stelselgereedskap
4 | Name[ar]=أدوات النّظام
5 | Name[as]=ব্যৱস্থাপ্ৰণালীৰ বিভিন্ন সৰঞ্জাম
6 | Name[ast]=Ferramientes del Sistema
7 | Name[be]=Сістэмныя інструменты
8 | Name[be@latin]=Systemnaje pryładździe
9 | Name[bg]=Системни инструменти
10 | Name[bn]=সিস্টেম টুল
11 | Name[bn_IN]=সিস্টেমের বিভিন্ন সরঞ্জাম
12 | Name[br]=Binvioù reizhiad
13 | Name[ca]=Eines de sistema
14 | Name[cs]=Systémové nástroje
15 | Name[cy]=Offer System
16 | Name[da]=Systemværktøjer
17 | Name[de]=Systemwerkzeuge
18 | Name[dz]=རིམ་ལུགས་ལག་ཆས།
19 | Name[el]=Εργαλεία συστήματος
20 | Name[en_CA]=System Tools
21 | Name[en_GB]=System Tools
22 | Name[eo]=Sistemaj iloj
23 | Name[es]=Herramientas del sistema
24 | Name[es_VE]=Herramientas del sistema
25 | Name[et]=Süsteemi tööriistad
26 | Name[eu]=Sistemaren tresnak
27 | Name[fa]=ابزارهای سیستم
28 | Name[fi]=Järjestelmätyökalut
29 | Name[fo]=Kervis amboð
30 | Name[fr]=Outils système
31 | Name[frp]=Utils du sistemo
32 | Name[fur]=Imprescj di sisteme
33 | Name[ga]=Uirlisí Córais
34 | Name[gl]=Ferramentas do sistema
35 | Name[gu]=સિસ્ટમ સાધનો
36 | Name[he]=כלי מערכת
37 | Name[hi]=सिस्टम उपकरण
38 | Name[hr]=Alati Sustava
39 | Name[hu]=Rendszereszközök
40 | Name[hy]=Համակարգի գործիքներ
41 | Name[id]=Peralatan Sistem
42 | Name[io]=Sistemala Utensili
43 | Name[is]=Kerfistól
44 | Name[it]=Strumenti di sistema
45 | Name[ja]=システムツール
46 | Name[ka]=სისტემური ხელსაწყოები
47 | Name[kk]=Жүйелік саймандар
48 | Name[km]=ឧបករណ៍ប្រព័ន្ធ
49 | Name[kn]=ಗಣಕ ಉಪಕರಣಗಳು
50 | Name[ko]=시스템 도구
51 | Name[ku]=Amûrên Pergalê
52 | Name[ky]=Системалык аспаптар
53 | Name[lg]=Ebiyamba okufuga sisitemu
54 | Name[lt]=Sistemos įrankiai
55 | Name[lv]=Sistēma rīki
56 | Name[mai]=सिस्टम अओजार
57 | Name[mg]=Fitaovan'ny rafitra
58 | Name[mk]=Системски алатки
59 | Name[ml]=സിസ്റ്റത്തിലെ പണിയായുധങ്ങള്
60 | Name[mn]=Системийн хэрэгслүүд
61 | Name[mr]=यंत्रणे संबंधित अौजार
62 | Name[ms]=Alatan Sistem
63 | Name[nb]=Systemverktøy
64 | Name[ne]=प्रणाली उपकरण
65 | Name[nl]=Systeemgereedschap
66 | Name[nn]=Systemverktøy
67 | Name[oc]=Espleches sistèma
68 | Name[or]=ତନ୍ତ୍ର ଉପକରଣ
69 | Name[pa]=ਸਿਸਟਮ ਸੰਦ
70 | Name[pl]=Narzędzia systemowe
71 | Name[ps]=غونډال توکي
72 | Name[pt]=Ferramentas de sistema
73 | Name[pt_BR]=Sistema
74 | Name[ro]=Unelte de sistem
75 | Name[ru]=Системные
76 | Name[si]=පද්දති මෙවලම්
77 | Name[sk]=Systémové nástroje
78 | Name[sl]=Sistemska orodja
79 | Name[sq]=Vegla Sistemi
80 | Name[sr]=Системски алати
81 | Name[sr@latin]=Sistemski alati
82 | Name[sv]=Systemverktyg
83 | Name[ta]=கணிப்பொறிக் கருவிகள்
84 | Name[te]=వ్యవస్థ పనిముట్లు
85 | Name[th]=เครื่องมือระบบ
86 | Name[tr]=Sistem Araçları
87 | Name[tt_RU]=Система кораллары
88 | Name[ug]=سىستېما قوراللىرى
89 | Name[uk]=Системні утиліти
90 | Name[ur]=نظام اوزار
91 | Name[ur_PK]=نظام اوزار
92 | Name[uz@cyrillic]=Тизим воситалари
93 | Name[vi]=Công cụ hệ thống
94 | Name[xh]=Izixhobo Zeenkqubo
95 | Name[zh_CN]=系统工具
96 | Name[zh_HK]=系統工具
97 | Name[zh_TW]=系統工具
98 | Comment=System configuration and monitoring
99 | Comment[af]=Stelselopstelling en monitering
100 | Comment[ar]=ضبط النّظام ومراقبته
101 | Comment[as]=ব্যৱস্থাপ্ৰণালীৰ বৈশিষ্ট্যৰ বিন্যাস এবং নিৰীক্ষণ
102 | Comment[ast]=Configuración y monitorización del sistema
103 | Comment[be]=Канфігурацыя сістэмы і маніторынг
104 | Comment[be@latin]=Manitorynh i kanfihuracyja systemy
105 | Comment[bg]=Следене и настройване на системата
106 | Comment[bn]=সিস্টেম কনফিগারেশন এবং মনিটরিং
107 | Comment[bn_IN]=সিস্টেমের বৈশিষ্ট্য কনফিগারেশন এবং নিরীক্ষণ
108 | Comment[br]=Neuziadur hag eveshaerezh ar reizhiad
109 | Comment[ca]=Configuració i monitorització del sistema
110 | Comment[cs]=Nastavení a sledování systému
111 | Comment[cy]=Cyflunio a monitro system
112 | Comment[da]=Systemkonfiguration og -overvågning
113 | Comment[de]=Systemkonfiguration und -überwachung
114 | Comment[dz]=རིམ་ལུགས་རིམ་སྒྲིག་དང་ལྟ་རྟོག།
115 | Comment[el]=Ρύθμιση και έλεγχος συστήματος
116 | Comment[en_CA]=System configuration and monitoring
117 | Comment[en_GB]=System configuration and monitoring
118 | Comment[eo]=Agordi kaj kontroli sistemon
119 | Comment[es]=Configuración y monitorización del sistema
120 | Comment[es_VE]=Configuración y monitorización del sistema
121 | Comment[et]=Süsteemi seadistamine ja jälgimine
122 | Comment[eu]=Sistemaren konfigurazioa eta monitorizazioa
123 | Comment[fa]=پیکربندی و پایشگری سیستم
124 | Comment[fi]=Järjestelmäasetukset ja -seuranta
125 | Comment[fo]=Kervis samanseting og vøka
126 | Comment[fr]=Configuration et surveillance système
127 | Comment[fur]=Configurazion e monitoragjo di sisteme
128 | Comment[ga]=Cumraíocht agus monatóireacht an chórais
129 | Comment[gl]=Configuración e monitorización do sistema
130 | Comment[gu]=સિસ્ટમ રૂપરેખાંકન અને મોનિટરીંગ
131 | Comment[he]=הגדרת המערכת וניהול מעקב אחריה
132 | Comment[hi]=सिस्टम विन्यास व निरीक्षण
133 | Comment[hr]=Konfiguracija i nadzor sustava
134 | Comment[hu]=Rendszerbeállítás és megfigyelés
135 | Comment[hy]=Համակարգի կարգավորում և վերահսկում
136 | Comment[id]=Konfigurasi sistem dan pemantauan
137 | Comment[is]=Kerfisstillingar og vöktun
138 | Comment[it]=Configurazione e monitoraggio del sistema
139 | Comment[ja]=システムの設定と監視を行うプログラムです
140 | Comment[ka]=სისტემის კონფიგურაცია და მონიტორინგი
141 | Comment[kk]=Жүйелік баптаулар мен бақылау
142 | Comment[km]=ការកំណត់រចនាសម្ព័ន្ធ និង ការត្រួតពិនិត្យ
143 | Comment[kn]=ಗಣಕ ಸಂರಚನೆ ಹಾಗು ಪರಿವೀಕ್ಷಣೆ
144 | Comment[ko]=시스템 설정과 감시
145 | Comment[ku]=Avakirin û şopandina pergalê
146 | Comment[ky]=Системаны конфигурациялоо жана аны байкоо аспаптары
147 | Comment[lg]=Eby'okutegeka n'okukebera embeera ya sisitemu
148 | Comment[lt]=Sistemos konfigūravimas ir stebėjimas
149 | Comment[lv]=Sistēmas konfigurācija un pārraudzība
150 | Comment[mai]=सिस्टम बिन्यास आ निरीक्षण
151 | Comment[mg]=Fanefena sy fanaraha-maso ny rafitra
152 | Comment[mk]=Конфигурација и надгледување на системот
153 | Comment[ml]=സിസ്റ്റത്തിന്റെ ക്രമീകരണവും നിരീക്ഷണവും
154 | Comment[mn]=Системийн тохиргоо болон хяналт
155 | Comment[mr]=यंत्रणेचे सुसुत्रीकरण व संचलन
156 | Comment[ms]=Konfigurasi dan pemantauan sistem
157 | Comment[nb]=Systemkonfigurasjon og overvåking
158 | Comment[ne]=प्रणाली कन्फिगरेसन र अनुगमन
159 | Comment[nl]=Systeemconfiguratie en -controle
160 | Comment[nn]=Oppsett og overvaking av systemet
161 | Comment[oc]=Configuracion e susvelhança del sistèma
162 | Comment[or]=ତନ୍ତ୍ର ବିନ୍ଯାସ ଏବଂ ନିରୀକ୍ଷଣ
163 | Comment[pa]=ਸਿਸਟਮ ਸੰਰਚਨਾ ਅਤੇ ਨਿਗਰਾਨੀ
164 | Comment[pl]=Monitorowanie i konfiguracja systemu
165 | Comment[ps]=د غونډال سازونه او ليدنه
166 | Comment[pt]=Configuração de sistema e monitorização
167 | Comment[pt_BR]=Configuração e monitoramento do sistema
168 | Comment[ro]=Configurarea și monitorizarea sistemului
169 | Comment[ru]=Средства конфигурации и мониторинга системы
170 | Comment[si]=පද්දති සුසර කිරිම සහ නිරික්ෂණය
171 | Comment[sk]=Konfigurácia a sledovanie systému
172 | Comment[sl]=Nastavitve in nadzor nad sistemom
173 | Comment[sq]=Konfigurim dhe vëzhgim sistemi
174 | Comment[sr]=Подешавање и праћење система
175 | Comment[sr@latin]=Podešavanje i praćenje sistema
176 | Comment[sv]=Systemkonfiguration och systemövervakning
177 | Comment[ta]=கணிப்பொறி அமைப்பு மற்றும் கண்காணித்தல்
178 | Comment[te]=వ్యవస్థ స్వరూపణం మరియు పర్యవేక్షణ
179 | Comment[th]=ตั้งค่าและเฝ้าดูระบบ
180 | Comment[tr]=Sistem yapılandırma ve izleme
181 | Comment[tt_RU]=Системаны көйләү һәм күзәтү
182 | Comment[ug]=سىستېما سەپلەش ۋە كۆزىتىش
183 | Comment[uk]=Засоби налаштовування та контролю системи
184 | Comment[ur]=نظام کی وضع کاریاں اور معائنہ
185 | Comment[ur_PK]=نظام کی وضع کاریاں اور معائنہ
186 | Comment[uz@cyrillic]=Тизимни мослаш ва кузатиш
187 | Comment[vi]=Cấu hình và theo dõi hệ thống
188 | Comment[xh]=Umiselo-nkqubo lwendlela emisiweyo kunye nokuhlola
189 | Comment[zh_CN]=系统配置和监视
190 | Comment[zh_HK]=系統配置及監察
191 | Comment[zh_TW]=系統配置及監察
192 | Icon=applications-system
193 | Type=Directory
194 |
--------------------------------------------------------------------------------
/desktop-directories/utility.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Accessories
3 | Name[af]=Toebehore
4 | Name[ar]=الملحقات
5 | Name[as]=আনুষঙ্গিক
6 | Name[ast]=Accesorios
7 | Name[be]=Інструменты
8 | Name[be@latin]=Aksesuary
9 | Name[bg]=Помощни програми
10 | Name[bn]=আনুসাঙ্গিক
11 | Name[bn_IN]=আনুষঙ্গিক
12 | Name[br]=Mavegoù
13 | Name[ca]=Accessoris
14 | Name[cs]=Příslušenství
15 | Name[cy]=Ategolion
16 | Name[da]=Tilbehør
17 | Name[de]=Zubehör
18 | Name[dz]=ཡན་ལག་ཅ་ཆས།
19 | Name[el]=Βοηθήματα
20 | Name[en_CA]=Accessories
21 | Name[en_GB]=Accessories
22 | Name[eo]=Utilaĵoj
23 | Name[es]=Accesorios
24 | Name[es_VE]=Accesorios
25 | Name[et]=Tarvikud
26 | Name[eu]=Gehigarriak
27 | Name[fa]=لوازم
28 | Name[fi]=Apuohjelmat
29 | Name[fo]=Tilhoyr
30 | Name[fr]=Accessoires
31 | Name[frp]=Accesòres
32 | Name[fur]=Robutis
33 | Name[ga]=Oiriúintí
34 | Name[gl]=Accesorios
35 | Name[gn]=Nhamba'eapoa Pygua
36 | Name[gu]=સહાયક કાર્યક્રમો
37 | Name[he]=עזרים
38 | Name[hi]=संलग्नक
39 | Name[hr]=Pomagala
40 | Name[hu]=Kellékek
41 | Name[hy]=Աքսեսուարներ
42 | Name[id]=Aksesoris
43 | Name[io]=Acesori
44 | Name[is]=Aukahlutir
45 | Name[it]=Accessori
46 | Name[ja]=アクセサリ
47 | Name[ka]=აქსესუარები
48 | Name[kk]=Қалыпты
49 | Name[km]=ប្រដាប់ប្រដា
50 | Name[kn]=ಸಲಕರಣೆಗಳು
51 | Name[ko]=보조 프로그램
52 | Name[ku]=Bernameyên Alîkar
53 | Name[ky]=Стандарттык иштемелер
54 | Name[lg]=Ebigonz'emirimu
55 | Name[lt]=Reikmenys
56 | Name[lv]=Piederumi
57 | Name[mai]=संलग्नक
58 | Name[mg]=Fiasana
59 | Name[mk]=Услужни
60 | Name[ml]=ഉപകരണങ്ങള്
61 | Name[mn]=Нэмэлт төхөөрөмж
62 | Name[mr]=शिवाय उपकरणं
63 | Name[ms]=Aksesori
64 | Name[nb]=Tilbehør
65 | Name[ne]=सहायक उपकरण
66 | Name[nl]=Hulpmiddelen
67 | Name[nn]=Tilbehøyr
68 | Name[oc]=Accessòris
69 | Name[or]=ସହାୟକ ବସ୍ତୁ
70 | Name[pa]=ਸਹਾਇਕ
71 | Name[pl]=Akcesoria
72 | Name[ps]=ملتوکي
73 | Name[pt]=Acessórios
74 | Name[pt_BR]=Acessórios
75 | Name[ro]=Accesorii
76 | Name[ru]=Стандартные
77 | Name[si]=උපාංග
78 | Name[sk]=Príslušenstvo
79 | Name[sl]=Pripomočki
80 | Name[sq]=Aksesorë
81 | Name[sr]=Алатке
82 | Name[sr@latin]=Alatke
83 | Name[sv]=Tillbehör
84 | Name[ta]=துணைப்பொருள்கள்
85 | Name[te]=సహాయకాలు
86 | Name[th]=เครื่องใช้ไม้สอย
87 | Name[tr]=Donatılar
88 | Name[tt_RU]=Үрнәк кушымталар
89 | Name[ug]=قوشۇمچە دېتاللار
90 | Name[uk]=Стандартні
91 | Name[ur]=لوازمات
92 | Name[ur_PK]=لوازمات
93 | Name[vi]=Bổ trợ
94 | Name[xh]=Izinto ezongezelelwayo
95 | Name[zh_CN]=附件
96 | Name[zh_HK]=附屬應用程式
97 | Name[zh_TW]=附屬應用程式
98 | Comment=Desktop accessories
99 | Comment[af]=Werkskermtoebehore
100 | Comment[ar]=ملحقات سطح المكتب
101 | Comment[as]=ডেস্কটপৰ ব্যৱহৃত আনুষঙ্গিক বস্তু
102 | Comment[ast]=Accesorios d'Escritoriu
103 | Comment[be]=Інструменты працоўнага асяроддзя
104 | Comment[be@latin]=Aksesuary stała
105 | Comment[bg]=Набор от помощни програми
106 | Comment[bn]=ডেস্কটপের আনুসাঙ্গিক অ্যাপ্লিকেশন
107 | Comment[bn_IN]=ডেস্কটপের ব্যবহৃত আনুষঙ্গিক বস্তু
108 | Comment[br]=Mavegoù ar burev
109 | Comment[ca]=Accessoris d'escriptori
110 | Comment[cs]=Příslušenství prostředí pracovní plochy
111 | Comment[cy]=Ategolion penbwrdd
112 | Comment[da]=Skrivebordstilbehør
113 | Comment[de]=Desktop-Zubehör
114 | Comment[dz]=ཌེཀསི་ཊོཔ་གི་ ཡན་ལག་ཅ་ཆས།
115 | Comment[el]=Βοηθήματα επιφάνειας εργασίας
116 | Comment[en_CA]=Desktop accessories
117 | Comment[en_GB]=Desktop accessories
118 | Comment[eo]=Labortablaj utilaĵoj
119 | Comment[es]=Accesorios del escritorio
120 | Comment[es_VE]=Accesorios del escritorio
121 | Comment[et]=Töölaua tarvikud
122 | Comment[eu]=Mahaigainaren gehigarriak
123 | Comment[fa]=لوازم رومیزی
124 | Comment[fi]=Työpöydän apuohjelmat
125 | Comment[fo]=Skriviborðs-tilhoyr
126 | Comment[fr]=Accessoires du bureau
127 | Comment[frp]=Accesòres do Bureu
128 | Comment[fur]=Robutis dal desktop
129 | Comment[ga]=Oiriúintí deisce
130 | Comment[gl]=Accesorios do escritorio
131 | Comment[gn]=Nhamba'eapoa Regua
132 | Comment[gu]=ડેસ્કટોપ સહાયક કાર્યક્રમો
133 | Comment[he]=עזרי שולחן עבודה
134 | Comment[hi]=डेस्कटॉप संलग्नक
135 | Comment[hr]=Pomagala radne površine
136 | Comment[hu]=Asztali kellékek
137 | Comment[hy]=Աշխատասեղանի աքսեսուարներ
138 | Comment[id]=Aksesoris desktop
139 | Comment[io]=Pupitrosuprala acesori
140 | Comment[is]=Skjáborðs aukahlutir
141 | Comment[it]=Accessori del desktop
142 | Comment[ja]=デスクトップ用のアクセサリーです
143 | Comment[ka]=სამუშაო მაგიდის აქსესუარები
144 | Comment[kk]=Қалыпты қолданбалар
145 | Comment[km]=ប្រដាប់ប្រដាផ្ទៃតុ
146 | Comment[kn]=ಗಣಕತೆರೆಯ ಸಲಕರಣೆಗಳು
147 | Comment[ko]=바탕환경의 보조 프로그램
148 | Comment[ku]=Bernameyên alîkar ên sermaseyê
149 | Comment[ky]=Иш столунун иштемелери
150 | Comment[lg]=Ebigonz'emirimu awakolerwa
151 | Comment[lt]=Darbo aplinkos reikmenys
152 | Comment[lv]=Darbvirsmas piederumi
153 | Comment[mai]=डेस्कटाप संलग्नकसभ
154 | Comment[mg]=Fiasan'ny desktop
155 | Comment[mk]=Алатки за работната површина
156 | Comment[ml]=പണിയിടോപകരണങ്ങള്
157 | Comment[mn]=Дэлгэцийн нэмэлт төхөөрөмжүүд
158 | Comment[mr]=डेस्कटॉपशी निगडित शिवाय उपकरणं
159 | Comment[ms]=Aksesori Desktop
160 | Comment[nb]=Tilbehør for skrivebordet
161 | Comment[ne]=डेस्कटप सहायक उपकरण
162 | Comment[nl]=Bureaubladhulpmiddelen
163 | Comment[nn]=Tilbehøyr til skrivebordet
164 | Comment[oc]=Accessòris del burèu
165 | Comment[or]=ଡେସ୍କଟପ୍ ସହାୟକ ବସ୍ତୁ
166 | Comment[pa]=ਡੈਸਕਟਾਪ ਸਹਾਇਕ
167 | Comment[pl]=Akcesoria pulpitu
168 | Comment[ps]=د سرپاڼې ملتوکي
169 | Comment[pt]=Acessórios de área de trabalho
170 | Comment[pt_BR]=Acessórios da área de trabalho
171 | Comment[ro]=Accesorii pentru desktop
172 | Comment[ru]=Стандартные приложения
173 | Comment[si]=මූලික තිරය උපාංග
174 | Comment[sk]=Príslušenstvo pracovnej plochy
175 | Comment[sl]=Namizni pripomočki
176 | Comment[sq]=Aksesorë hapësire pune
177 | Comment[sr]=Алатке окружења
178 | Comment[sr@latin]=Alatke okruženja
179 | Comment[sv]=Skrivbordstillbehör
180 | Comment[ta]=மேஜை துணைப்பொருள்கள்
181 | Comment[te]=డెస్క్టాప్ సహాయకాలు
182 | Comment[th]=โปรแกรมเครื่องใช้ไม้สอยบนเดสก์ท็อป
183 | Comment[tr]=Masaüstü donatıları
184 | Comment[tt_RU]=Эш өстәле өчен үрнәк кушымталар
185 | Comment[ug]=ئۈستەلئۈستى قوشۇمچە دېتاللىرى
186 | Comment[uk]=Стандартні програми
187 | Comment[ur]=ڈیسک ٹاپ لوازمات
188 | Comment[ur_PK]=ڈیسک ٹاپ لوازمات
189 | Comment[vi]=Bổ trợ môi trường
190 | Comment[xh]=Izinto ezongezelelwayo ze-Desktop
191 | Comment[zh_CN]=桌面附件
192 | Comment[zh_HK]=桌面附屬應用程式
193 | Comment[zh_TW]=桌面附屬應用程式
194 | Icon=applications-accessories
195 | Type=Directory
196 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/nwg-piotr/nwg-menu
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.24.2
6 |
7 | require (
8 | github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37
9 | github.com/dlasky/gotk3-layershell v0.0.0-20240515133811-5c5115f0d774
10 | github.com/gotk3/gotk3 v0.6.5-0.20240618185848-ff349ae13f56
11 | github.com/joshuarubin/go-sway v1.2.0
12 | github.com/sirupsen/logrus v1.9.3
13 | )
14 |
15 | require (
16 | github.com/joshuarubin/lifecycle v1.1.4 // indirect
17 | go.uber.org/multierr v1.11.0 // indirect
18 | golang.org/x/sync v0.14.0 // indirect
19 | golang.org/x/sys v0.33.0 // indirect
20 | )
21 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 h1:28uU3TtuvQ6KRndxg9TrC868jBWmSKgh0GTXkACCXmA=
2 | github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37/go.mod h1:6AXRstqK+32jeFmw89QGL2748+dj34Av4xc/I9oo9BY=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/dlasky/gotk3-layershell v0.0.0-20240515133811-5c5115f0d774 h1:o87OVL4olQBlVwN3+NSVQpS6gj9FWUYtxOfHXWZigUE=
7 | github.com/dlasky/gotk3-layershell v0.0.0-20240515133811-5c5115f0d774/go.mod h1:JHLx2Wz4mAPVwn4PFhC69ydwyHP4A3wQvlg7HKVVc1U=
8 | github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
9 | github.com/gotk3/gotk3 v0.6.5-0.20240618185848-ff349ae13f56 h1:eR+xxC8qqKuPMTucZqaklBxLIT7/4L7dzhlwKMrDbj8=
10 | github.com/gotk3/gotk3 v0.6.5-0.20240618185848-ff349ae13f56/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
11 | github.com/joshuarubin/go-sway v1.2.0 h1:t3eqW504//uj9PDwFf0+IVfkD+WoOGaDX5gYIe0BHyM=
12 | github.com/joshuarubin/go-sway v1.2.0/go.mod h1:qcDd6f25vJ0++wICwA1BainIcRC67p2Mb4lsrZ0k3/k=
13 | github.com/joshuarubin/lifecycle v1.0.0/go.mod h1:sRy++ATvR9Ee21tkRdFkQeywAWvDsue66V70K0Dnl54=
14 | github.com/joshuarubin/lifecycle v1.1.4 h1:9ZjvYSsWax9DC3Jpz6vGf/0KnU8FNMjh0/vJ3SpSBRQ=
15 | github.com/joshuarubin/lifecycle v1.1.4/go.mod h1:QqHrqwMPMA9dbJY3XgIyVLhzHMSGOFrcCAQ59bke1mo=
16 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
17 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
18 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
19 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
20 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
21 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
22 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
23 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
24 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
25 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
26 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
27 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
28 | golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
29 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
30 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
31 | golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
32 | golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
33 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
34 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
35 | golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
36 | golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
37 | golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
38 | golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
39 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
40 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
41 | golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
42 | golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
43 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
44 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
45 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
46 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
47 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
48 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
49 | golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
50 | golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
51 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
52 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
53 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
54 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
55 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "os"
7 | "os/signal"
8 | "path/filepath"
9 | "strconv"
10 | "strings"
11 | "syscall"
12 | "time"
13 |
14 | log "github.com/sirupsen/logrus"
15 |
16 | "github.com/allan-simon/go-singleinstance"
17 | "github.com/dlasky/gotk3-layershell/layershell"
18 | "github.com/gotk3/gotk3/gdk"
19 | "github.com/gotk3/gotk3/glib"
20 | "github.com/gotk3/gotk3/gtk"
21 | )
22 |
23 | const version = "0.1.8"
24 |
25 | var (
26 | appDirs []string
27 | configDirectory string
28 | pinnedFile string
29 | pinned []string
30 | leftBox *gtk.Box
31 | rightBox *gtk.Box
32 | hyprlandMonitors []monitor
33 | src glib.SourceHandle
34 | id2entry map[string]desktopEntry
35 | )
36 |
37 | var categoryNames = [...]string{
38 | "utility",
39 | "development",
40 | "game",
41 | "graphics",
42 | "internet-and-network",
43 | "office",
44 | "audio-video",
45 | "system-tools",
46 | "other",
47 | }
48 |
49 | type category struct {
50 | Name string
51 | DisplayName string
52 | Icon string
53 | }
54 |
55 | var categories []category
56 |
57 | type desktopEntry struct {
58 | DesktopID string
59 | Name string
60 | NameLoc string
61 | Comment string
62 | CommentLoc string
63 | Icon string
64 | Exec string
65 | Terminal bool
66 | NoDisplay bool
67 | }
68 |
69 | // slices below will hold DesktopID strings
70 | var (
71 | listUtility []string
72 | listDevelopment []string
73 | listGame []string
74 | listGraphics []string
75 | listInternetAndNetwork []string
76 | listOffice []string
77 | listAudioVideo []string
78 | listSystemTools []string
79 | listOther []string
80 | )
81 |
82 | var desktopEntries []desktopEntry
83 |
84 | // UI elements
85 | var (
86 | categoriesListBox *gtk.ListBox
87 | userDirsListBox *gtk.ListBox
88 | pinnedListBox *gtk.ListBox
89 | resultWrapper *gtk.Box
90 | resultWindow *gtk.ScrolledWindow
91 | fileSearchResults map[string]string
92 | fileSearchResultWindow *gtk.ScrolledWindow
93 | backButton *gtk.Box
94 | searchEntry *gtk.SearchEntry
95 | phrase string
96 | resultListBox *gtk.ListBox
97 | fileSearchResultListBox *gtk.ListBox
98 | buttonsWrapper *gtk.Box
99 | buttonBox *gtk.EventBox
100 | confirmationBox *gtk.Box
101 | userDirsMap map[string]string
102 | )
103 |
104 | // Flags
105 | var cssFileName = flag.String("s", "menu-start.css", "Styling: css file name")
106 | var targetOutput = flag.String("o", "", "name of the Output to display the menu on")
107 | var displayVersion = flag.Bool("v", false, "display Version information")
108 | var autohide = flag.Bool("d", false, "auto-hiDe: close window when left")
109 | var valign = flag.String("va", "bottom", "Vertical Alignment: \"bottom\" or \"top\"")
110 | var halign = flag.String("ha", "left", "Horizontal Alignment: \"left\" or \"right\"")
111 | var marginTop = flag.Int("mt", 0, "Margin Top")
112 | var marginLeft = flag.Int("ml", 0, "Margin Left")
113 | var marginRight = flag.Int("mr", 0, "Margin Right")
114 | var marginBottom = flag.Int("mb", 0, "Margin Bottom")
115 | var iconSizeLarge = flag.Int("isl", 32, "Icon Size Large")
116 | var iconSizeSmall = flag.Int("iss", 16, "Icon Size Small")
117 | var sLen = flag.Int("slen", 80, "Search result length Limit")
118 | var itemPadding = flag.Uint("padding", 2, "vertical item padding")
119 | var lang = flag.String("lang", "", "force lang, e.g. \"en\", \"pl\"")
120 | var fileManager = flag.String("fm", "thunar", "File Manager")
121 | var term = flag.String("term", "foot", "Terminal emulator")
122 | var wm = flag.String("wm", "", "use swaymsg exec (with 'sway' argument) or hyprctl dispatch exec (with 'hyprland') or riverctl spawn (with 'river') to launch programs")
123 | var cmdLock = flag.String("cmd-lock", "swaylock -f -c 000000", "screen lock command")
124 | var cmdLogout = flag.String("cmd-logout", "swaymsg exit", "logout command")
125 | var cmdRestart = flag.String("cmd-restart", "systemctl reboot", "reboot command")
126 | var cmdShutdown = flag.String("cmd-shutdown", "systemctl -i poweroff", "shutdown command")
127 | var debug = flag.Bool("debug", false, "turn on Debug messages")
128 | var hover = flag.Bool("t", false, "hovering caTegories opens submenus")
129 |
130 | func main() {
131 | timeStart := time.Now()
132 | flag.Parse()
133 |
134 | if *debug {
135 | log.SetLevel(log.DebugLevel)
136 | }
137 |
138 | if *displayVersion {
139 | fmt.Printf("nwg-menu version %s\n", version)
140 | os.Exit(0)
141 | }
142 |
143 | // Gentle SIGTERM handler thanks to reiki4040 https://gist.github.com/reiki4040/be3705f307d3cd136e85
144 | signalChan := make(chan os.Signal, 1)
145 | signal.Notify(signalChan, syscall.SIGTERM)
146 | go func() {
147 | for {
148 | s := <-signalChan
149 | if s == syscall.SIGTERM {
150 | println("SIGTERM received, bye bye!")
151 | gtk.MainQuit()
152 | }
153 | }
154 | }()
155 |
156 | // We want the same key/mouse binding to turn the dock off: kill the running instance and exit.
157 | lockFileDir := runtimeDir()
158 | if lockFileDir == "" {
159 | lockFileDir = tempDir()
160 | }
161 | lockFilePath := fmt.Sprintf("%s/nwg-menu.lock", lockFileDir)
162 | lockFile, err := singleinstance.CreateLockFile(lockFilePath)
163 | if err != nil {
164 | pid, err := readTextFile(lockFilePath)
165 | if err == nil {
166 | i, err := strconv.Atoi(pid)
167 | if err == nil {
168 | /*if !*autohide {
169 | println("Running instance found, sending SIGTERM and exiting...")
170 | syscall.Kill(i, syscall.SIGTERM)
171 | } else {
172 | println("Already running")
173 | }*/
174 | log.Info("Running instance found, sending SIGTERM and exiting...")
175 | syscall.Kill(i, syscall.SIGTERM)
176 | }
177 | }
178 | os.Exit(0)
179 | }
180 | defer lockFile.Close()
181 |
182 | // LANGUAGE
183 | if *lang == "" && os.Getenv("LANG") != "" {
184 | *lang = strings.Split(os.Getenv("LANG"), ".")[0]
185 | }
186 | log.Infof("lang: %s", *lang)
187 |
188 | // ENVIRONMENT
189 | configDirectory = configDir()
190 |
191 | if !pathExists(filepath.Join(configDirectory, "menu-start.css")) {
192 | copyFile("/usr/share/nwg-menu/menu-start.css", filepath.Join(configDirectory, "menu-start.css"))
193 | }
194 |
195 | cacheDirectory := cacheDir()
196 | if cacheDirectory == "" {
197 | log.Panic("Couldn't determine cache directory location")
198 | }
199 |
200 | // DATA
201 | pinnedFile = filepath.Join(cacheDirectory, "nwg-pin-cache")
202 | pinned, err = loadTextFile(pinnedFile)
203 | if err != nil {
204 | pinned = nil
205 | }
206 |
207 | cssFile := filepath.Join(configDirectory, *cssFileName)
208 |
209 | appDirs = getAppDirs()
210 |
211 | setUpCategories()
212 |
213 | desktopFiles := listDesktopFiles()
214 | log.Infof("Found %v desktop files", len(desktopFiles))
215 |
216 | parseDesktopFiles(desktopFiles)
217 |
218 | // USER INTERFACE
219 | gtk.Init(nil)
220 |
221 | cssProvider, _ := gtk.CssProviderNew()
222 |
223 | err = cssProvider.LoadFromPath(cssFile)
224 | if err != nil {
225 | log.Warnf("ERROR: %s css file not found or erroneous. Using GTK styling.", cssFile)
226 | } else {
227 | log.Infof("Using style from %s", cssFile)
228 | screen, _ := gdk.ScreenGetDefault()
229 | gtk.AddProviderForScreen(screen, cssProvider, gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
230 | }
231 |
232 | win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
233 | if err != nil {
234 | log.Fatal("Unable to create window:", err)
235 | }
236 |
237 | layershell.InitForWindow(win)
238 |
239 | var output2mon map[string]*gdk.Monitor
240 | if *targetOutput != "" {
241 | // We want to assign layershell to a monitor, but we only know the output name!
242 | output2mon, err = mapOutputs()
243 | if err == nil {
244 | monitor := output2mon[*targetOutput]
245 | layershell.SetMonitor(win, monitor)
246 | log.Infof("Assigning window to output %s", *targetOutput)
247 |
248 | } else {
249 | log.Warnf("Couldn't list available outputs, %s", err)
250 | }
251 | }
252 |
253 | if *valign == "bottom" {
254 | layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_BOTTOM, true)
255 | } else {
256 | layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_TOP, true)
257 | }
258 |
259 | if *halign == "left" {
260 | layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_LEFT, true)
261 | } else {
262 | layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_RIGHT, true)
263 | }
264 |
265 | layershell.SetLayer(win, layershell.LAYER_SHELL_LAYER_TOP)
266 |
267 | layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_TOP, *marginTop)
268 | layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_LEFT, *marginLeft)
269 | layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_RIGHT, *marginRight)
270 | layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_BOTTOM, *marginBottom)
271 |
272 | layershell.SetKeyboardMode(win, layershell.LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND)
273 |
274 | win.Connect("destroy", func() {
275 | gtk.MainQuit()
276 | })
277 |
278 | win.Connect("key-release-event", func(window *gtk.Window, event *gdk.Event) {
279 | key := &gdk.EventKey{Event: event}
280 | if key.KeyVal() == gdk.KEY_Escape {
281 | s, _ := searchEntry.GetText()
282 | if s != "" {
283 | clearSearchResult()
284 | searchEntry.GrabFocus()
285 | searchEntry.SetText("")
286 | } else {
287 | if resultWindow == nil || !resultWindow.GetVisible() {
288 | gtk.MainQuit()
289 | } else {
290 | clearSearchResult()
291 | }
292 | }
293 | }
294 | })
295 |
296 | // Close the window on leave, but not immediately, to avoid accidental closes
297 | win.Connect("leave-notify-event", func() {
298 | if *autohide {
299 | src = glib.TimeoutAdd(uint(1000), func() bool {
300 | gtk.MainQuit()
301 | return false
302 | })
303 | }
304 | })
305 |
306 | win.Connect("enter-notify-event", func() {
307 | cancelClose()
308 | })
309 |
310 | outerBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
311 | win.Add(outerBox)
312 |
313 | alignmentBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
314 | //alignmentBox.SetHomogeneous(true)
315 | outerBox.PackStart(alignmentBox, true, true, 0)
316 |
317 | leftBox, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
318 | alignmentBox.PackStart(leftBox, false, false, 10)
319 |
320 | leftColumn, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
321 | leftBox.PackStart(leftColumn, false, false, 0)
322 |
323 | searchEntry = setUpSearchEntry()
324 | if *valign == "top" {
325 | leftColumn.PackStart(searchEntry, false, false, 10)
326 | }
327 |
328 | if *valign == "bottom" {
329 | pinnedListBox = setUpPinnedListBox()
330 | leftColumn.PackStart(pinnedListBox, false, false, 10)
331 | }
332 |
333 | categoriesListBox = setUpCategoriesListBox()
334 | leftColumn.PackStart(categoriesListBox, false, false, 10)
335 |
336 | if *valign == "top" {
337 | pinnedListBox = setUpPinnedListBox()
338 | leftColumn.PackStart(pinnedListBox, false, false, 10)
339 | }
340 |
341 | if *valign != "top" {
342 | leftColumn.PackEnd(searchEntry, false, false, 10)
343 | }
344 |
345 | rightBox, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
346 | alignmentBox.PackStart(rightBox, true, true, 10)
347 |
348 | rightColumn, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
349 |
350 | rightBox.PackStart(rightColumn, true, true, 0)
351 |
352 | userDirsListBox = setUpUserDirsList()
353 | rightColumn.PackStart(userDirsListBox, false, true, 10)
354 |
355 | backButton = setUpBackButton()
356 | rightColumn.PackStart(backButton, false, false, 10)
357 |
358 | resultWrapper, _ = gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
359 | rightColumn.PackStart(resultWrapper, true, true, 0)
360 |
361 | buttonsWrapper, _ = gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
362 |
363 | buttonBox = setUpButtonBox()
364 | buttonsWrapper.PackStart(buttonBox, false, false, 10)
365 | rightColumn.PackEnd(buttonsWrapper, false, true, 0)
366 |
367 | //win.SetSizeRequest(0, *windowHeigth)
368 |
369 | win.ShowAll()
370 |
371 | backButton.Hide()
372 |
373 | pinnedListBox.UnselectAll()
374 | categoriesListBox.UnselectAll()
375 | searchEntry.GrabFocus()
376 | t := time.Now()
377 | //println(fmt.Sprintf("UI created in %v ms. Thanks for watching.", t.Sub(timeStart).Milliseconds()))
378 | log.Infof("UI created in %v ms. Thanks for watching.", t.Sub(timeStart).Milliseconds())
379 | gtk.Main()
380 | }
381 |
--------------------------------------------------------------------------------
/menu-start.css:
--------------------------------------------------------------------------------
1 | window {
2 | background-color: rgba (36, 47, 79, 0.92);
3 | color: #eeeeee
4 | }
5 |
6 | list {
7 | background: none;
8 | border-radius: 15px
9 | }
10 |
11 | entry {
12 | background-color: rgba (0, 0, 0, 0.2)
13 | }
14 |
15 | button {
16 | background: none;
17 | border: none
18 | }
19 |
20 | button:hover {
21 | background-color: rgba (255, 255, 255, 0.1)
22 | }
--------------------------------------------------------------------------------
/nwg-menu:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwg-piotr/nwg-menu/7cd1702c862b9a52897beb973c58ef2465dc91b5/nwg-menu
--------------------------------------------------------------------------------
/tools.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "errors"
7 | "fmt"
8 | "github.com/joshuarubin/go-sway"
9 | log "github.com/sirupsen/logrus"
10 | "io"
11 | "io/fs"
12 | "net"
13 | "os"
14 | "os/exec"
15 | "path/filepath"
16 | "sort"
17 | "strings"
18 | "time"
19 |
20 | "github.com/gotk3/gotk3/gdk"
21 | "github.com/gotk3/gotk3/glib"
22 | "github.com/gotk3/gotk3/gtk"
23 | )
24 |
25 | type monitor struct {
26 | Id int `json:"id"`
27 | Name string `json:"name"`
28 | Description string `json:"description"`
29 | Make string `json:"make"`
30 | Model string `json:"model"`
31 | Serial string `json:"serial"`
32 | Width int `json:"width"`
33 | Height int `json:"height"`
34 | RefreshRate float64 `json:"refreshRate"`
35 | X int `json:"x"`
36 | Y int `json:"y"`
37 | ActiveWorkspace struct {
38 | Id int `json:"id"`
39 | Name string `json:"name"`
40 | } `json:"activeWorkspace"`
41 | Reserved []int `json:"reserved"`
42 | Scale float64 `json:"scale"`
43 | Transform int `json:"transform"`
44 | Focused bool `json:"focused"`
45 | DpmsStatus bool `json:"dpmsStatus"`
46 | Vrr bool `json:"vrr"`
47 | }
48 |
49 | /*
50 | Window on-leave-notify event hides the window with glib Timeout 1000 ms.
51 | We might have left the window by accident, so let's clear the timeout if window re-entered.
52 | Furthermore - hovering a widget triggers window on-leave-notify event, and the timeout
53 | needs to be cleared as well.
54 | */
55 | func cancelClose() {
56 | if src > 0 {
57 | glib.SourceRemove(src)
58 | src = 0
59 | }
60 | }
61 |
62 | func createPixbuf(icon string, size int) (*gdk.Pixbuf, error) {
63 | iconTheme, err := gtk.IconThemeGetDefault()
64 | if err != nil {
65 | log.Fatal("Couldn't get default theme: ", err)
66 | }
67 |
68 | if strings.Contains(icon, "/") {
69 | pixbuf, err := gdk.PixbufNewFromFileAtSize(icon, size, size)
70 | if err != nil {
71 | println(err)
72 | return nil, err
73 | }
74 | return pixbuf, nil
75 |
76 | } else if strings.HasSuffix(icon, ".svg") || strings.HasSuffix(icon, ".png") || strings.HasSuffix(icon, ".xpm") {
77 | // for enties like "Icon=netflix-desktop.svg"
78 | icon = strings.Split(icon, ".")[0]
79 | }
80 |
81 | pixbuf, err := iconTheme.LoadIcon(icon, size, gtk.ICON_LOOKUP_FORCE_SIZE)
82 |
83 | if err != nil {
84 | if strings.HasPrefix(icon, "/") {
85 | pixbuf, err := gdk.PixbufNewFromFileAtSize(icon, size, size)
86 | if err != nil {
87 | return nil, err
88 | }
89 | return pixbuf, nil
90 | }
91 |
92 | pixbuf, err := iconTheme.LoadIcon(icon, size, gtk.ICON_LOOKUP_FORCE_SIZE)
93 | if err != nil {
94 | return nil, err
95 | }
96 | return pixbuf, nil
97 | }
98 | return pixbuf, nil
99 | }
100 |
101 | func mapXdgUserDirs() map[string]string {
102 | result := make(map[string]string)
103 | home := os.Getenv("HOME")
104 |
105 | result["home"] = home
106 | result["documents"] = filepath.Join(home, "Documents")
107 | result["downloads"] = filepath.Join(home, "Downloads")
108 | result["music"] = filepath.Join(home, "Music")
109 | result["pictures"] = filepath.Join(home, "Pictures")
110 | result["videos"] = filepath.Join(home, "Videos")
111 |
112 | userDirsFile := filepath.Join(home, ".config/user-dirs.dirs")
113 | if pathExists(userDirsFile) {
114 | log.Infof("Using XDG user dirs from %s", userDirsFile)
115 | lines, _ := loadTextFile(userDirsFile)
116 | for _, l := range lines {
117 | if strings.HasPrefix(l, "XDG_DOCUMENTS_DIR") {
118 | result["documents"] = getUserDir(home, l)
119 | continue
120 | }
121 | if strings.HasPrefix(l, "XDG_DOWNLOAD_DIR") {
122 | result["downloads"] = getUserDir(home, l)
123 | continue
124 | }
125 | if strings.HasPrefix(l, "XDG_MUSIC_DIR") {
126 | result["music"] = getUserDir(home, l)
127 | continue
128 | }
129 | if strings.HasPrefix(l, "XDG_PICTURES_DIR") {
130 | result["pictures"] = getUserDir(home, l)
131 | continue
132 | }
133 | if strings.HasPrefix(l, "XDG_VIDEOS_DIR") {
134 | result["videos"] = getUserDir(home, l)
135 | }
136 | }
137 | } else {
138 | println(fmt.Sprintf("%s file not found, using defaults", userDirsFile))
139 | }
140 |
141 | return result
142 | }
143 |
144 | func getUserDir(home, line string) string {
145 | // line is supposed to look like XDG_DOCUMENTS_DIR="$HOME/Dokumenty"
146 | result := strings.Split(line, "=")[1]
147 | result = strings.Replace(result, "$HOME", home, 1)
148 |
149 | // trim ""
150 | return result[1 : len(result)-1]
151 | }
152 |
153 | func cacheDir() string {
154 | if os.Getenv("XDG_CACHE_HOME") != "" {
155 | return os.Getenv("XDG_CONFIG_HOME")
156 | }
157 | if os.Getenv("HOME") != "" && pathExists(filepath.Join(os.Getenv("HOME"), ".cache")) {
158 | p := filepath.Join(os.Getenv("HOME"), ".cache")
159 | return p
160 | }
161 | return ""
162 | }
163 |
164 | func runtimeDir() string {
165 | return os.Getenv("XDG_RUNTIME_DIR")
166 | }
167 |
168 | func tempDir() string {
169 | if os.Getenv("TMPDIR") != "" {
170 | return os.Getenv("TMPDIR")
171 | } else if os.Getenv("TEMP") != "" {
172 | return os.Getenv("TEMP")
173 | } else if os.Getenv("TMP") != "" {
174 | return os.Getenv("TMP")
175 | }
176 | return "/tmp"
177 | }
178 |
179 | func readTextFile(path string) (string, error) {
180 | bytes, err := os.ReadFile(path)
181 | if err != nil {
182 | return "", err
183 | }
184 |
185 | return string(bytes), nil
186 | }
187 |
188 | func configDir() string {
189 | if os.Getenv("XDG_CONFIG_HOME") != "" {
190 | dir := fmt.Sprintf("%s/nwg-panel", os.Getenv("XDG_CONFIG_HOME"))
191 | createDir(dir)
192 | return (fmt.Sprintf("%s/nwg-panel", os.Getenv("XDG_CONFIG_HOME")))
193 | }
194 | dir := fmt.Sprintf("%s/.config/nwg-panel", os.Getenv("HOME"))
195 | createDir(dir)
196 | return dir
197 | }
198 |
199 | func createDir(dir string) {
200 | if _, err := os.Stat(dir); os.IsNotExist(err) {
201 | err := os.MkdirAll(dir, os.ModePerm)
202 | if err == nil {
203 | fmt.Println("Creating dir:", dir)
204 | }
205 | }
206 | }
207 |
208 | func copyFile(src, dst string) error {
209 | fmt.Println("Copying file:", dst)
210 |
211 | var err error
212 | var srcfd *os.File
213 | var dstfd *os.File
214 | var srcinfo os.FileInfo
215 |
216 | if srcfd, err = os.Open(src); err != nil {
217 | return err
218 | }
219 | defer srcfd.Close()
220 |
221 | if dstfd, err = os.Create(dst); err != nil {
222 | return err
223 | }
224 | defer dstfd.Close()
225 |
226 | if _, err = io.Copy(dstfd, srcfd); err != nil {
227 | return err
228 | }
229 | if srcinfo, err = os.Stat(src); err != nil {
230 | return err
231 | }
232 | return os.Chmod(dst, srcinfo.Mode())
233 | }
234 |
235 | func getAppDirs() []string {
236 | var dirs []string
237 | xdgDataDirs := ""
238 |
239 | home := os.Getenv("HOME")
240 | xdgDataHome := os.Getenv("XDG_DATA_HOME")
241 | if os.Getenv("XDG_DATA_DIRS") != "" {
242 | xdgDataDirs = os.Getenv("XDG_DATA_DIRS")
243 | } else {
244 | xdgDataDirs = "/usr/local/share/:/usr/share/"
245 | }
246 | if xdgDataHome != "" {
247 | dirs = append(dirs, filepath.Join(xdgDataHome, "applications"))
248 | } else if home != "" {
249 | dirs = append(dirs, filepath.Join(home, ".local/share/applications"))
250 | }
251 | for _, d := range strings.Split(xdgDataDirs, ":") {
252 | dirs = append(dirs, filepath.Join(d, "applications"))
253 | }
254 | flatpakDirs := []string{filepath.Join(home, ".local/share/flatpak/exports/share/applications"),
255 | "/var/lib/flatpak/exports/share/applications"}
256 |
257 | for _, d := range flatpakDirs {
258 | if !isIn(dirs, d) {
259 | dirs = append(dirs, d)
260 | }
261 | }
262 | return dirs
263 | }
264 |
265 | func listFiles(dir string) ([]fs.DirEntry, error) {
266 | files, err := os.ReadDir(dir)
267 | if err == nil {
268 | return files, nil
269 | }
270 | return nil, err
271 | }
272 |
273 | func listDesktopFiles() []string {
274 | var paths []string
275 | for _, dir := range appDirs {
276 | dirs, err := listFiles(dir)
277 | if err == nil {
278 | for _, file := range dirs {
279 | parts := strings.Split(file.Name(), ".")
280 | if parts[len(parts)-1] == "desktop" {
281 | paths = append(paths, filepath.Join(dir, file.Name()))
282 | }
283 | }
284 | }
285 | }
286 | return paths
287 | }
288 |
289 | func setUpCategories() {
290 | path := "/usr/share/nwg-menu/desktop-directories"
291 | var other category
292 |
293 | for _, cName := range categoryNames {
294 | fileName := fmt.Sprintf("%s.directory", cName)
295 | lines, err := loadTextFile(filepath.Join(path, fileName))
296 | if err == nil {
297 | var cat category
298 | cat.Name = cName
299 |
300 | name := ""
301 | nameLoc := ""
302 | icon := ""
303 |
304 | for _, l := range lines {
305 | if strings.HasPrefix(l, "Name=") {
306 | name = strings.Split(l, "=")[1]
307 | continue
308 | }
309 | if strings.HasPrefix(l, fmt.Sprintf("Name[%s]=", strings.Split(*lang, "_")[0])) {
310 | nameLoc = strings.Split(l, "=")[1]
311 | continue
312 | }
313 | if strings.HasPrefix(l, "Icon=") {
314 | icon = strings.Split(l, "=")[1]
315 | continue
316 | }
317 | }
318 |
319 | if nameLoc == "" {
320 | for _, l := range lines {
321 | if strings.HasPrefix(l, fmt.Sprintf("Name[%s]=", *lang)) {
322 | nameLoc = strings.Split(l, "=")[1]
323 | break
324 | }
325 | }
326 | }
327 | if nameLoc != "" {
328 | cat.DisplayName = nameLoc
329 | } else {
330 | cat.DisplayName = name
331 | }
332 | cat.Icon = icon
333 |
334 | // We want "other" to be the last one. Let's append it when already sorted
335 | if fileName != "other.directory" {
336 | categories = append(categories, cat)
337 | } else {
338 | other = cat
339 | }
340 | }
341 | }
342 | sort.Slice(categories, func(i, j int) bool {
343 | return categories[i].DisplayName < categories[j].DisplayName
344 | })
345 | categories = append(categories, other)
346 | }
347 |
348 | func parseDesktopFiles(desktopFiles []string) {
349 | id2entry = make(map[string]desktopEntry)
350 | var added []string
351 | skipped := 0
352 | hidden := 0
353 | for _, file := range desktopFiles {
354 | lines, err := loadTextFile(file)
355 | if err == nil {
356 | parts := strings.Split(file, "/")
357 | desktopID := parts[len(parts)-1]
358 | name := ""
359 | nameLoc := ""
360 | comment := ""
361 | commentLoc := ""
362 | icon := ""
363 | exec := ""
364 | terminal := false
365 | noDisplay := false
366 |
367 | categories := ""
368 |
369 | for _, l := range lines {
370 | if strings.HasPrefix(l, "[") && l != "[Desktop Entry]" {
371 | break
372 | }
373 | if strings.HasPrefix(l, "Name=") {
374 | name = strings.Split(l, "=")[1]
375 | continue
376 | }
377 | if strings.HasPrefix(l, fmt.Sprintf("Name[%s]=", strings.Split(*lang, "_")[0])) {
378 | nameLoc = strings.Split(l, "=")[1]
379 | continue
380 | }
381 | if strings.HasPrefix(l, "Comment=") {
382 | comment = strings.Split(l, "=")[1]
383 | continue
384 | }
385 | if strings.HasPrefix(l, fmt.Sprintf("Comment[%s]=", strings.Split(*lang, "_")[0])) {
386 | commentLoc = strings.Split(l, "=")[1]
387 | continue
388 | }
389 | if strings.HasPrefix(l, "Icon=") {
390 | icon = strings.Split(l, "=")[1]
391 | continue
392 | }
393 | if strings.HasPrefix(l, "Exec=") {
394 | exec = strings.Split(l, "Exec=")[1]
395 | disallowed := [2]string{"\"", "'"}
396 | for _, char := range disallowed {
397 | exec = strings.Replace(exec, char, "", -1)
398 | }
399 | continue
400 | }
401 | if strings.HasPrefix(l, "Categories=") {
402 | categories = strings.Split(l, "Categories=")[1]
403 | continue
404 | }
405 | if l == "Terminal=true" {
406 | terminal = true
407 | continue
408 | }
409 | if l == "NoDisplay=true" {
410 | noDisplay = true
411 | hidden++
412 | continue
413 | }
414 | }
415 |
416 | // if name[ln] not found, let's try to find name[ln_LN]
417 | if nameLoc == "" {
418 | nameLoc = name
419 | }
420 | if commentLoc == "" {
421 | commentLoc = comment
422 | }
423 |
424 | if !isIn(added, desktopID) {
425 | added = append(added, desktopID)
426 |
427 | var entry desktopEntry
428 | entry.DesktopID = desktopID
429 | entry.Name = name
430 | entry.NameLoc = nameLoc
431 | entry.Comment = comment
432 | entry.CommentLoc = commentLoc
433 | entry.Icon = icon
434 | entry.Exec = exec
435 | entry.Terminal = terminal
436 | entry.NoDisplay = noDisplay
437 | desktopEntries = append(desktopEntries, entry)
438 |
439 | id2entry[entry.DesktopID] = entry
440 |
441 | assignToLists(entry.DesktopID, categories)
442 |
443 | } else {
444 | skipped++
445 | }
446 | }
447 | }
448 | log.Infof("Skipped %v duplicates; %v .desktop entries hidden by \"NoDisplay=true\"", skipped, hidden)
449 | }
450 |
451 | // freedesktop Main Categories list consists of 13 entries. Let's contract it to 8+1 ("Other").
452 | func assignToLists(desktopID, categories string) {
453 | cats := strings.Split(categories, ";")
454 | assigned := false
455 | for _, cat := range cats {
456 | if cat == "Utility" && !isIn(listUtility, desktopID) {
457 | listUtility = append(listUtility, desktopID)
458 | assigned = true
459 | continue
460 | }
461 | if cat == "Development" && !isIn(listDevelopment, desktopID) {
462 | listDevelopment = append(listDevelopment, desktopID)
463 | assigned = true
464 | continue
465 | }
466 | if cat == "Game" && !isIn(listGame, desktopID) {
467 | listGame = append(listGame, desktopID)
468 | assigned = true
469 | continue
470 | }
471 | if cat == "Graphics" && !isIn(listGraphics, desktopID) {
472 | listGraphics = append(listGraphics, desktopID)
473 | assigned = true
474 | continue
475 | }
476 | if cat == "Network" && !isIn(listInternetAndNetwork, desktopID) {
477 | listInternetAndNetwork = append(listInternetAndNetwork, desktopID)
478 | assigned = true
479 | continue
480 | }
481 | if isIn([]string{"Office", "Science", "Education"}, cat) && !isIn(listOffice, desktopID) {
482 | listOffice = append(listOffice, desktopID)
483 | assigned = true
484 | continue
485 | }
486 | if isIn([]string{"AudioVideo", "Audio", "Video"}, cat) && !isIn(listAudioVideo, desktopID) {
487 | listAudioVideo = append(listAudioVideo, desktopID)
488 | assigned = true
489 | continue
490 | }
491 | if isIn([]string{"Settings", "System", "DesktopSettings", "PackageManager"}, cat) && !isIn(listSystemTools, desktopID) {
492 | listSystemTools = append(listSystemTools, desktopID)
493 | assigned = true
494 | continue
495 | }
496 | }
497 | if categories != "" && !assigned && !isIn(listOther, desktopID) {
498 | listOther = append(listOther, desktopID)
499 | }
500 | }
501 |
502 | func isIn(slice []string, val string) bool {
503 | for _, item := range slice {
504 | if item == val {
505 | return true
506 | }
507 | }
508 | return false
509 | }
510 |
511 | func pathExists(name string) bool {
512 | if _, err := os.Stat(name); err != nil {
513 | if os.IsNotExist(err) {
514 | return false
515 | }
516 | }
517 | return true
518 | }
519 |
520 | func loadTextFile(path string) ([]string, error) {
521 | bytes, err := os.ReadFile(path)
522 | if err != nil {
523 | return nil, err
524 | }
525 | lines := strings.Split(string(bytes), "\n")
526 | var output []string
527 | for _, line := range lines {
528 | line = strings.TrimSpace(line)
529 | if line != "" {
530 | output = append(output, line)
531 | }
532 |
533 | }
534 | return output, nil
535 | }
536 |
537 | func pinItem(itemID string) {
538 | for _, item := range pinned {
539 | if item == itemID {
540 | println(item, "already pinned")
541 | return
542 | }
543 | }
544 | pinned = append(pinned, itemID)
545 | savePinned()
546 | println(itemID, "pinned")
547 |
548 | row := setUpPinnedListBoxRow(itemID)
549 | pinnedListBox.Add(row)
550 | pinnedListBox.ShowAll()
551 | }
552 |
553 | func unpinItem(itemID string) {
554 | if isIn(pinned, itemID) {
555 | pinned = remove(pinned, itemID)
556 | savePinned()
557 | println(itemID, "unpinned")
558 | }
559 | }
560 |
561 | func remove(s []string, r string) []string {
562 | for i, v := range s {
563 | if v == r {
564 | return append(s[:i], s[i+1:]...)
565 | }
566 | }
567 | return s
568 | }
569 |
570 | func savePinned() {
571 | f, err := os.OpenFile(pinnedFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
572 | if err != nil {
573 | log.Fatal(err)
574 | }
575 |
576 | defer f.Close()
577 |
578 | for _, line := range pinned {
579 | if line != "" {
580 | entry := id2entry[line]
581 | if entry.DesktopID == "" {
582 | log.Debugf("Pinned item doesn't seem to exist, removing: %s", line)
583 | continue
584 | }
585 |
586 | _, err := f.WriteString(line + "\n")
587 |
588 | if err != nil {
589 | println("Error saving pinned", err)
590 | }
591 | }
592 | }
593 | }
594 |
595 | func launch(command string, terminal bool) {
596 | // trim % and everything afterwards
597 | if strings.Contains(command, "%") {
598 | cutAt := strings.Index(command, "%")
599 | if cutAt != -1 {
600 | command = command[:cutAt-1]
601 | }
602 | }
603 |
604 | var elements = []string{"/usr/bin/env", "-S", command}
605 |
606 | cmd := exec.Command(elements[0], elements[1:]...)
607 |
608 | if terminal {
609 | var prefixCommand = *term
610 | var args []string
611 | if prefixCommand != "foot" {
612 | args = []string{"-e", command}
613 | } else {
614 | args = elements
615 | }
616 | cmd = exec.Command(prefixCommand, args...)
617 | } else if *wm == "sway" {
618 | cmd = exec.Command("swaymsg", "exec", strings.Join(elements, " "))
619 | } else if *wm == "hyprland" || *wm == "Hyprland" {
620 | cmd = exec.Command("hyprctl", "dispatch", "exec", strings.Join(elements, " "))
621 | } else if *wm == "river" {
622 | cmd = exec.Command("riverctl", "spawn", strings.Join(elements, " "))
623 | }
624 |
625 | msg := fmt.Sprintf("command: %q; args: %q\n", cmd.Args[0], cmd.Args[1:])
626 | println(msg)
627 |
628 | go cmd.Run()
629 |
630 | glib.TimeoutAdd(uint(150), func() bool {
631 | gtk.MainQuit()
632 | return false
633 | })
634 | }
635 |
636 | func open(filePath string) {
637 | cmd := exec.Command(*fileManager, filePath)
638 | go cmd.Run()
639 |
640 | glib.TimeoutAdd(uint(150), func() bool {
641 | gtk.MainQuit()
642 | return false
643 | })
644 | }
645 |
646 | // Returns map output name -> gdk.Monitor
647 | func mapOutputs() (map[string]*gdk.Monitor, error) {
648 | result := make(map[string]*gdk.Monitor)
649 |
650 | if os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") != "" {
651 | err := listHyprlandMonitors()
652 | if err == nil {
653 |
654 | display, err := gdk.DisplayGetDefault()
655 | if err != nil {
656 | return nil, err
657 | }
658 |
659 | num := display.GetNMonitors()
660 | for i := 0; i < num; i++ {
661 | mon, _ := display.GetMonitor(i)
662 | output := hyprlandMonitors[i]
663 | result[output.Name] = mon
664 | }
665 | } else {
666 | return nil, err
667 | }
668 |
669 | } else if os.Getenv("SWAYSOCK") != "" {
670 | ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
671 | defer cancel()
672 |
673 | client, err := sway.New(ctx)
674 | if err != nil {
675 | return nil, err
676 | }
677 |
678 | outputs, err := client.GetOutputs(ctx)
679 | if err != nil {
680 | return nil, err
681 | }
682 |
683 | display, err := gdk.DisplayGetDefault()
684 | if err != nil {
685 | return nil, err
686 | }
687 |
688 | num := display.GetNMonitors()
689 | for i := 0; i < num; i++ {
690 | mon, _ := display.GetMonitor(i)
691 | output := outputs[i]
692 | result[output.Name] = mon
693 | }
694 | } else {
695 | return nil, errors.New("output assignment only supported on sway and Hyprland")
696 | }
697 |
698 | return result, nil
699 | }
700 |
701 | func hyprctl(cmd string) ([]byte, error) {
702 | his := os.Getenv("HYPRLAND_INSTANCE_SIGNATURE")
703 | xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
704 | hyprDir := ""
705 | if xdgRuntimeDir != "" {
706 | hyprDir = fmt.Sprintf("%s/hypr", xdgRuntimeDir)
707 | } else {
708 | hyprDir = "/tmp/hypr"
709 | }
710 |
711 | socketFile := fmt.Sprintf("%s/%s/.socket.sock", hyprDir, his)
712 | conn, err := net.Dial("unix", socketFile)
713 | if err != nil {
714 | return nil, err
715 | }
716 |
717 | message := []byte(cmd)
718 | _, err = conn.Write(message)
719 | if err != nil {
720 | return nil, err
721 | }
722 |
723 | reply := make([]byte, 102400)
724 | n, err := conn.Read(reply)
725 | if err != nil {
726 | return nil, err
727 | }
728 |
729 | defer conn.Close()
730 |
731 | return reply[:n], nil
732 | }
733 |
734 | func listHyprlandMonitors() error {
735 | reply, err := hyprctl("j/monitors")
736 | if err != nil {
737 | return err
738 | } else {
739 | err = json.Unmarshal([]byte(reply), &hyprlandMonitors)
740 | }
741 | return err
742 | }
743 |
--------------------------------------------------------------------------------
/uicomponents.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | log "github.com/sirupsen/logrus"
6 | "io/fs"
7 | "path/filepath"
8 | "sort"
9 | "strings"
10 |
11 | "github.com/gotk3/gotk3/gdk"
12 | "github.com/gotk3/gotk3/gtk"
13 | )
14 |
15 | func setUpPinnedListBox() *gtk.ListBox {
16 | listBox, _ := gtk.ListBoxNew()
17 |
18 | if len(pinned) > 0 {
19 | for _, desktopID := range pinned {
20 | entry := id2entry[desktopID]
21 | if entry.DesktopID == "" {
22 | log.Debugf("Pinned item doesn't seem to exist: %s", desktopID)
23 | continue
24 | }
25 | row := setUpPinnedListBoxRow(desktopID)
26 | listBox.Add(row)
27 | }
28 | }
29 |
30 | listBox.Connect("enter-notify-event", func() {
31 | cancelClose()
32 | restoreButtonBox()
33 | })
34 |
35 | return listBox
36 | }
37 |
38 | func setUpPinnedListBoxRow(desktopID string) *gtk.ListBoxRow {
39 | entry := id2entry[desktopID]
40 |
41 | row, _ := gtk.ListBoxRowNew()
42 | row.SetSelectable(false)
43 | row.SetCanFocus(false)
44 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
45 |
46 | // We need gtk.EventBox to detect mouse event
47 | eventBox, _ := gtk.EventBoxNew()
48 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 6)
49 | eventBox.Add(hBox)
50 | vBox.PackStart(eventBox, false, false, *itemPadding)
51 |
52 | pixbuf, _ := createPixbuf(entry.Icon, *iconSizeLarge)
53 | img, err := gtk.ImageNewFromPixbuf(pixbuf)
54 | if err != nil {
55 | println(err, entry.Icon)
56 | }
57 | hBox.PackStart(img, false, false, 0)
58 | lbl, _ := gtk.LabelNew("")
59 | name := ""
60 | if entry.NameLoc != "" {
61 | name = entry.NameLoc
62 | } else {
63 | name = entry.Name
64 | }
65 | if len(name) > 35 {
66 | name = fmt.Sprintf("%s...", name[:32])
67 | }
68 | lbl.SetText(name)
69 | hBox.PackStart(lbl, false, false, 0)
70 | row.Add(vBox)
71 |
72 | row.Connect("activate", func() {
73 | launch(entry.Exec, entry.Terminal)
74 | })
75 |
76 | eventBox.Connect("button-release-event", func(row *gtk.ListBoxRow, e *gdk.Event) bool {
77 | btnEvent := gdk.EventButtonNewFromEvent(e)
78 | if btnEvent.Button() == 1 {
79 | launch(entry.Exec, entry.Terminal)
80 | return true
81 | } else if btnEvent.Button() == 3 {
82 | unpinItem(entry.DesktopID)
83 | row.Destroy()
84 | return true
85 | }
86 | return false
87 | })
88 |
89 | if *hover {
90 | eventBox.Connect("enter-notify-event", func(row *gtk.ListBoxRow, e *gdk.Event) bool {
91 | clearSearchResult()
92 | return true
93 | })
94 | }
95 |
96 | return row
97 | }
98 |
99 | func setUpCategoriesListBox() *gtk.ListBox {
100 | listBox, _ := gtk.ListBoxNew()
101 | for _, cat := range categories {
102 | if isSupposedToShowUp(cat.Name) {
103 | row, _ := gtk.ListBoxRowNew()
104 | row.SetCanFocus(false)
105 | row.SetSelectable(false)
106 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
107 | eventBox, _ := gtk.EventBoxNew()
108 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 6)
109 | eventBox.Add(hBox)
110 | vBox.PackStart(eventBox, false, false, *itemPadding)
111 |
112 | connectCategoryListBox(cat.Name, eventBox, row)
113 |
114 | pixbuf, _ := createPixbuf(cat.Icon, *iconSizeLarge)
115 | img, _ := gtk.ImageNewFromPixbuf(pixbuf)
116 | hBox.PackStart(img, false, false, 0)
117 |
118 | lbl, _ := gtk.LabelNew(cat.DisplayName)
119 | hBox.PackStart(lbl, false, false, 0)
120 |
121 | pixbuf, _ = createPixbuf("pan-end-symbolic", *iconSizeSmall)
122 | img, _ = gtk.ImageNewFromPixbuf(pixbuf)
123 | hBox.PackEnd(img, false, false, 0)
124 |
125 | row.Add(vBox)
126 | listBox.Add(row)
127 | }
128 | }
129 | listBox.Connect("enter-notify-event", func() {
130 | cancelClose()
131 | restoreButtonBox()
132 | })
133 | return listBox
134 | }
135 |
136 | func isSupposedToShowUp(catName string) bool {
137 | result := catName == "utility" && notEmpty(listUtility) ||
138 | catName == "development" && notEmpty(listDevelopment) ||
139 | catName == "game" && notEmpty(listGame) ||
140 | catName == "graphics" && notEmpty(listGraphics) ||
141 | catName == "internet-and-network" && notEmpty(listInternetAndNetwork) ||
142 | catName == "office" && notEmpty(listOffice) ||
143 | catName == "audio-video" && notEmpty(listAudioVideo) ||
144 | catName == "system-tools" && notEmpty(listSystemTools) ||
145 | catName == "other" && notEmpty(listOther)
146 |
147 | return result
148 | }
149 |
150 | func notEmpty(listCategory []string) bool {
151 | if len(listCategory) == 0 {
152 | return false
153 | }
154 | for _, desktopID := range listCategory {
155 | entry := id2entry[desktopID]
156 | if !entry.NoDisplay {
157 | return true
158 | }
159 | }
160 | return false
161 | }
162 |
163 | func connectCategoryListBox(catName string, eventBox *gtk.EventBox, row *gtk.ListBoxRow) {
164 | var listCategory []string
165 |
166 | switch catName {
167 | case "utility":
168 | listCategory = listUtility
169 | case "development":
170 | listCategory = listDevelopment
171 | case "game":
172 | listCategory = listGame
173 | case "graphics":
174 | listCategory = listGraphics
175 | case "internet-and-network":
176 | listCategory = listInternetAndNetwork
177 | case "office":
178 | listCategory = listOffice
179 | case "audio-video":
180 | listCategory = listAudioVideo
181 | case "system-tools":
182 | listCategory = listSystemTools
183 | default:
184 | listCategory = listOther
185 | }
186 |
187 | eventBox.Connect("button-release-event", func(eb *gtk.EventBox, e *gdk.Event) bool {
188 | btnEvent := gdk.EventButtonNewFromEvent(e)
189 | if btnEvent.Button() == 1 {
190 | searchEntry.SetText("")
191 | clearSearchResult()
192 | row.SetSelectable(true)
193 | row.SetCanFocus(false)
194 | categoriesListBox.SelectRow(row)
195 | listBox := setUpCategoryListBox(listCategory)
196 | if resultWindow != nil {
197 | resultWindow.Destroy()
198 | }
199 | resultWindow, _ = gtk.ScrolledWindowNew(nil, nil)
200 | resultWindow.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
201 | resultWindow.Connect("enter-notify-event", func() {
202 | cancelClose()
203 | })
204 | resultWrapper.PackStart(resultWindow, true, true, 0)
205 | resultWindow.Add(listBox)
206 |
207 | userDirsListBox.Hide()
208 | resultWindow.ShowAll()
209 |
210 | return true
211 | }
212 | return false
213 | })
214 |
215 | if *hover {
216 | eventBox.Connect("enter-notify-event", func(eb *gtk.EventBox, e *gdk.Event) bool {
217 | searchEntry.SetText("")
218 | clearSearchResult()
219 | row.SetSelectable(true)
220 | row.SetCanFocus(false)
221 | //categoriesListBox.SelectRow(row)
222 | listBox := setUpCategoryListBox(listCategory)
223 | if resultWindow != nil {
224 | resultWindow.Destroy()
225 | }
226 | resultWindow, _ = gtk.ScrolledWindowNew(nil, nil)
227 | resultWindow.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
228 | resultWindow.Connect("enter-notify-event", func() {
229 | cancelClose()
230 | })
231 | resultWrapper.PackStart(resultWindow, true, true, 0)
232 | resultWindow.Add(listBox)
233 |
234 | userDirsListBox.Hide()
235 | resultWindow.ShowAll()
236 |
237 | return true
238 | })
239 | }
240 | }
241 |
242 | func setUpBackButton() *gtk.Box {
243 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
244 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10)
245 | vBox.PackStart(hBox, false, false, 0)
246 | button, _ := gtk.ButtonNew()
247 | button.SetCanFocus(false)
248 | pixbuf, _ := createPixbuf("arrow-left", *iconSizeLarge)
249 | image, _ := gtk.ImageNewFromPixbuf(pixbuf)
250 | button.SetImage(image)
251 | button.SetAlwaysShowImage(true)
252 | button.Connect("enter-notify-event", func() {
253 | cancelClose()
254 | })
255 | button.Connect("clicked", func(btn *gtk.Button) {
256 | clearSearchResult()
257 | searchEntry.GrabFocus()
258 | searchEntry.SetText("")
259 | })
260 | hBox.PackEnd(button, false, true, 0)
261 |
262 | return vBox
263 | }
264 |
265 | func setUpCategoryListBox(listCategory []string) *gtk.ListBox {
266 | listBox, _ := gtk.ListBoxNew()
267 |
268 | for _, desktopID := range listCategory {
269 | entry := id2entry[desktopID]
270 | name := entry.NameLoc
271 | if name == "" {
272 | name = entry.Name
273 | }
274 | if len(name) > 30 {
275 | name = fmt.Sprintf("%s...", name[:27])
276 | }
277 | if !entry.NoDisplay {
278 | row, _ := gtk.ListBoxRowNew()
279 | row.SetSelectable(false)
280 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 10)
281 | eventBox, _ := gtk.EventBoxNew()
282 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 6)
283 | eventBox.Add(hBox)
284 | vBox.PackStart(eventBox, false, false, *itemPadding)
285 |
286 | ID := entry.DesktopID
287 | eventBox.Connect("button-release-event", func(row *gtk.ListBoxRow, e *gdk.Event) bool {
288 | btnEvent := gdk.EventButtonNewFromEvent(e)
289 | if btnEvent.Button() == 1 {
290 | launch(entry.Exec, entry.Terminal)
291 | return true
292 | } else if btnEvent.Button() == 3 {
293 | pinItem(ID)
294 | }
295 | return false
296 | })
297 |
298 | pixbuf, _ := createPixbuf(entry.Icon, *iconSizeLarge)
299 | img, _ := gtk.ImageNewFromPixbuf(pixbuf)
300 | hBox.PackStart(img, false, false, 0)
301 |
302 | lbl, _ := gtk.LabelNew(name)
303 | hBox.PackStart(lbl, false, false, 0)
304 |
305 | row.Add(vBox)
306 | listBox.Add(row)
307 | }
308 | }
309 | backButton.Show()
310 | return listBox
311 | }
312 |
313 | func setUpCategorySearchResult(searchPhrase string) *gtk.ListBox {
314 | listBox, _ := gtk.ListBoxNew()
315 |
316 | resultWindow, _ = gtk.ScrolledWindowNew(nil, nil)
317 | resultWindow.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
318 | resultWindow.Connect("enter-notify-event", func() {
319 | cancelClose()
320 | restoreButtonBox()
321 | })
322 | resultWrapper.PackStart(resultWindow, true, true, 0)
323 |
324 | counter := 0
325 | for _, entry := range desktopEntries {
326 | if len(searchPhrase) == 1 && counter > 9 {
327 | break
328 | } else if len(searchPhrase) == 2 && counter > 14 {
329 | break
330 | }
331 | if !entry.NoDisplay && (strings.Contains(strings.ToLower(entry.NameLoc), strings.ToLower(searchPhrase)) ||
332 | strings.Contains(strings.ToLower(entry.CommentLoc), strings.ToLower(searchPhrase)) ||
333 | strings.Contains(strings.ToLower(entry.Comment), strings.ToLower(searchPhrase)) ||
334 | strings.Contains(strings.ToLower(entry.Exec), strings.ToLower(searchPhrase))) {
335 |
336 | counter++
337 |
338 | row, _ := gtk.ListBoxRowNew()
339 | row.SetSelectable(false)
340 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 10)
341 | eventBox, _ := gtk.EventBoxNew()
342 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 6)
343 | eventBox.Add(hBox)
344 | vBox.PackStart(eventBox, false, false, *itemPadding)
345 |
346 | exec := entry.Exec
347 | term := entry.Terminal
348 | ID := entry.DesktopID
349 | row.Connect("activate", func() {
350 | launch(exec, term)
351 | })
352 | eventBox.Connect("button-release-event", func(row *gtk.EventBox, e *gdk.Event) bool {
353 | btnEvent := gdk.EventButtonNewFromEvent(e)
354 | if btnEvent.Button() == 1 {
355 | launch(exec, term)
356 | return true
357 | } else if btnEvent.Button() == 3 {
358 | pinItem(ID)
359 | }
360 | return false
361 | })
362 |
363 | pixbuf, _ := createPixbuf(entry.Icon, *iconSizeLarge)
364 | img, _ := gtk.ImageNewFromPixbuf(pixbuf)
365 | hBox.PackStart(img, false, false, 0)
366 |
367 | name := entry.NameLoc
368 | if len(name) > *sLen {
369 | name = fmt.Sprintf("%s…", name[:*sLen-2])
370 | }
371 |
372 | lbl, _ := gtk.LabelNew(name)
373 | hBox.PackStart(lbl, false, false, 0)
374 |
375 | row.Add(vBox)
376 | listBox.Add(row)
377 |
378 | }
379 | }
380 | resultWindow.Add(listBox)
381 | resultWindow.ShowAll()
382 | return listBox
383 | }
384 |
385 | func setUpFileSearchResult() *gtk.ListBox {
386 | listBox, _ := gtk.ListBoxNew()
387 | if fileSearchResultWindow != nil {
388 | fileSearchResultWindow.Destroy()
389 | }
390 | fileSearchResultWindow, _ = gtk.ScrolledWindowNew(nil, nil)
391 | fileSearchResultWindow.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
392 | fileSearchResultWindow.Connect("enter-notify-event", func() {
393 | cancelClose()
394 | restoreButtonBox()
395 | })
396 | resultWrapper.PackStart(fileSearchResultWindow, true, true, 0)
397 |
398 | fileSearchResultWindow.Add(listBox)
399 | fileSearchResultWindow.ShowAll()
400 |
401 | return listBox
402 | }
403 |
404 | func walk(path string, d fs.DirEntry, e error) error {
405 | if e != nil {
406 | return e
407 | }
408 | if !d.IsDir() {
409 | parts := strings.Split(path, "/")
410 | fileName := parts[len(parts)-1]
411 | if strings.Contains(strings.ToLower(fileName), strings.ToLower(phrase)) {
412 | fileSearchResults[fileName] = path
413 | }
414 | } else {
415 | if strings.Contains(strings.ToLower(path), strings.ToLower(phrase)) {
416 | fileSearchResults[path] = path
417 | }
418 | }
419 | return nil
420 | }
421 |
422 | func setUpSearchEntry() *gtk.SearchEntry {
423 | searchEntry, _ := gtk.SearchEntryNew()
424 | searchEntry.Connect("enter-notify-event", func() {
425 | cancelClose()
426 | restoreButtonBox()
427 | })
428 | //if *hover {
429 | // searchEntry.Connect("enter-notify-event", func(se *gtk.SearchEntry, e *gdk.Event) bool {
430 | // clearSearchResult()
431 | // return true
432 | // })
433 | //}
434 |
435 | searchEntry.Connect("search-changed", func() {
436 | phrase, _ = searchEntry.GetText()
437 | if len(phrase) > 0 {
438 | userDirsListBox.Hide()
439 | backButton.Show()
440 |
441 | if resultWindow != nil {
442 | resultWindow.Destroy()
443 | }
444 | resultListBox = setUpCategorySearchResult(phrase)
445 | if resultListBox.GetChildren().Length() == 0 {
446 | resultWindow.Hide()
447 | }
448 |
449 | if len(phrase) > 2 {
450 | if fileSearchResultWindow != nil {
451 | fileSearchResultWindow.Destroy()
452 | }
453 | fileSearchResultListBox = setUpFileSearchResult()
454 | for key := range userDirsMap {
455 | if key != "home" {
456 | searchUserDir(key)
457 | }
458 | }
459 | if fileSearchResultListBox.GetChildren().Length() == 0 {
460 | fileSearchResultWindow.Hide()
461 | }
462 | } else {
463 | if fileSearchResultWindow != nil {
464 | fileSearchResultWindow.Destroy()
465 | }
466 | }
467 |
468 | } else {
469 | clearSearchResult()
470 | userDirsListBox.ShowAll()
471 | }
472 |
473 | })
474 | searchEntry.Connect("focus-in-event", func() {
475 | searchEntry.SetText("")
476 | })
477 |
478 | return searchEntry
479 | }
480 |
481 | func searchUserDir(dir string) {
482 | fileSearchResults = make(map[string]string)
483 | filepath.WalkDir(userDirsMap[dir], walk)
484 | if len(fileSearchResults) > 0 {
485 | row := setUpUserDirsListRow(fmt.Sprintf("folder-%s", dir), "", dir, userDirsMap)
486 | fileSearchResultListBox.Add(row)
487 | fileSearchResultListBox.ShowAll()
488 |
489 | // The fileSearchResults map is unordered, but we need an order here.
490 | // Let's create a slice of file names, sort it, and read the map in this order.
491 |
492 | fileNames := make([]string, 0, len(fileSearchResults))
493 | for k := range fileSearchResults {
494 | fileNames = append(fileNames, k)
495 | }
496 | sort.Strings(fileNames)
497 |
498 | for _, name := range fileNames {
499 | path := fileSearchResults[name]
500 | isDir := false
501 | if strings.HasPrefix(name, userDirsMap[dir]) {
502 | isDir = true
503 | }
504 | row := setUpUserFileSearchResultRow(path, userDirsMap[dir], isDir)
505 | fileSearchResultListBox.Add(row)
506 | }
507 |
508 | fileSearchResultListBox.ShowAll()
509 | }
510 | }
511 |
512 | func setUpUserDirsList() *gtk.ListBox {
513 | listBox, _ := gtk.ListBoxNew()
514 | userDirsMap = mapXdgUserDirs()
515 |
516 | row := setUpUserDirsListRow("folder-home", "Home", "home", userDirsMap)
517 | listBox.Add(row)
518 | row = setUpUserDirsListRow("folder-documents", "", "documents", userDirsMap)
519 | listBox.Add(row)
520 | row = setUpUserDirsListRow("folder-downloads", "", "downloads", userDirsMap)
521 | listBox.Add(row)
522 | row = setUpUserDirsListRow("folder-music", "", "music", userDirsMap)
523 | listBox.Add(row)
524 | row = setUpUserDirsListRow("folder-pictures", "", "pictures", userDirsMap)
525 | listBox.Add(row)
526 | row = setUpUserDirsListRow("folder-videos", "", "videos", userDirsMap)
527 | listBox.Add(row)
528 |
529 | listBox.Connect("enter-notify-event", func() {
530 | cancelClose()
531 | restoreButtonBox()
532 | })
533 |
534 | return listBox
535 | }
536 |
537 | func setUpUserDirsListRow(iconName, displayName, entryName string, userDirsMap map[string]string) *gtk.ListBoxRow {
538 | if displayName == "" {
539 | parts := strings.Split(userDirsMap[entryName], "/")
540 | displayName = parts[(len(parts) - 1)]
541 | }
542 | row, _ := gtk.ListBoxRowNew()
543 | row.SetSelectable(false)
544 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
545 | eventBox, _ := gtk.EventBoxNew()
546 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 6)
547 | eventBox.Add(hBox)
548 | vBox.PackStart(eventBox, false, false, *itemPadding*3)
549 |
550 | img, _ := gtk.ImageNewFromIconName(iconName, gtk.ICON_SIZE_DND)
551 | hBox.PackStart(img, false, false, 0)
552 |
553 | if len(displayName) > *sLen {
554 | displayName = fmt.Sprintf("%s…", displayName[:*sLen-2])
555 | }
556 | lbl, _ := gtk.LabelNew(displayName)
557 | hBox.PackStart(lbl, false, false, 0)
558 | row.Add(vBox)
559 |
560 | row.Connect("activate", func() {
561 | launch(fmt.Sprintf("%s %s", *fileManager, userDirsMap[entryName]), false)
562 | })
563 |
564 | eventBox.Connect("button-release-event", func(row *gtk.ListBoxRow, e *gdk.Event) bool {
565 | btnEvent := gdk.EventButtonNewFromEvent(e)
566 | if btnEvent.Button() == 1 {
567 | launch(fmt.Sprintf("%s %s", *fileManager, userDirsMap[entryName]), false)
568 | return true
569 | }
570 | return false
571 | })
572 |
573 | return row
574 | }
575 |
576 | func setUpUserFileSearchResultRow(filePath, userDirPath string, isDir bool) *gtk.ListBoxRow {
577 | row, _ := gtk.ListBoxRowNew()
578 |
579 | row.SetSelectable(false)
580 | vBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
581 | eventBox, _ := gtk.EventBoxNew()
582 | hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
583 | eventBox.Add(hBox)
584 | vBox.PackStart(eventBox, false, false, *itemPadding)
585 |
586 | // split the leading part we don't want to see
587 | fileName := strings.Split(filePath, userDirPath)[1]
588 | if len(fileName) > 0 {
589 | // split leading slash
590 | fileName = fileName[1:]
591 | }
592 |
593 | if isDir {
594 | if len(fileName) > 0 {
595 | img, _ := gtk.ImageNewFromIconName("folder", gtk.ICON_SIZE_MENU)
596 | hBox.PackStart(img, false, false, 0)
597 | }
598 | }
599 |
600 | if len(fileName) > *sLen {
601 | fileName = fmt.Sprintf("%s…", fileName[:*sLen-2])
602 | }
603 | if fileName != "" {
604 | lbl, _ := gtk.LabelNew(fileName)
605 | hBox.PackStart(lbl, false, false, 0)
606 | }
607 |
608 | row.Add(vBox)
609 |
610 | row.Connect("activate", func() {
611 | open(filePath)
612 | })
613 |
614 | eventBox.Connect("button-release-event", func(row *gtk.ListBoxRow, e *gdk.Event) bool {
615 | btnEvent := gdk.EventButtonNewFromEvent(e)
616 | if btnEvent.Button() == 1 {
617 | open(filePath)
618 | return true
619 | }
620 | return false
621 | })
622 |
623 | return row
624 | }
625 |
626 | func setUpButtonBox() *gtk.EventBox {
627 | eventBox, _ := gtk.EventBoxNew()
628 | wrapperHbox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
629 | box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
630 | wrapperHbox.PackStart(box, false, true, 10)
631 | eventBox.Add(wrapperHbox)
632 |
633 | btn, _ := gtk.ButtonNew()
634 | pixbuf, _ := createPixbuf("system-lock-screen", *iconSizeLarge)
635 | img, _ := gtk.ImageNewFromPixbuf(pixbuf)
636 | btn.SetImage(img)
637 | btn.SetCanFocus(false)
638 | box.PackStart(btn, true, true, 6)
639 | btn.Connect("clicked", func() {
640 | launch(*cmdLock, false)
641 | //confirmationBox = setUpConfirmationBox("system-lock-screen", *cmdLock)
642 | buttonBox.Hide()
643 | })
644 |
645 | btn, _ = gtk.ButtonNew()
646 | pixbuf, _ = createPixbuf("system-log-out", *iconSizeLarge)
647 | img, _ = gtk.ImageNewFromPixbuf(pixbuf)
648 | btn.SetImage(img)
649 | btn.SetCanFocus(false)
650 | box.PackStart(btn, true, true, 6)
651 | btn.Connect("clicked", func() {
652 | confirmationBox = setUpConfirmationBox("system-log-out", *cmdLogout)
653 | buttonBox.Hide()
654 | })
655 |
656 | btn, _ = gtk.ButtonNew()
657 | pixbuf, _ = createPixbuf("system-reboot", *iconSizeLarge)
658 | img, _ = gtk.ImageNewFromPixbuf(pixbuf)
659 | btn.SetImage(img)
660 | btn.SetCanFocus(false)
661 | box.PackStart(btn, true, true, 6)
662 | btn.Connect("clicked", func() {
663 | confirmationBox = setUpConfirmationBox("system-reboot", *cmdRestart)
664 | buttonBox.Hide()
665 | })
666 |
667 | btn, _ = gtk.ButtonNew()
668 | pixbuf, _ = createPixbuf("system-shutdown", *iconSizeLarge)
669 | img, _ = gtk.ImageNewFromPixbuf(pixbuf)
670 | btn.SetImage(img)
671 | btn.SetCanFocus(false)
672 | box.PackStart(btn, true, true, 6)
673 | btn.Connect("clicked", func() {
674 | confirmationBox = setUpConfirmationBox("system-shutdown", *cmdShutdown)
675 | buttonBox.Hide()
676 | })
677 |
678 | eventBox.Connect("enter-notify-event", func() {
679 | cancelClose()
680 | })
681 |
682 | return eventBox
683 | }
684 |
685 | func setUpConfirmationBox(icon string, command string) *gtk.Box {
686 | box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
687 |
688 | btn, _ := gtk.ButtonNew()
689 | pixbuf, _ := createPixbuf(icon, *iconSizeLarge)
690 | img, _ := gtk.ImageNewFromPixbuf(pixbuf)
691 | btn.SetImage(img)
692 | btn.SetCanFocus(false)
693 | box.PackEnd(btn, false, false, 16)
694 | btn.Connect("clicked", func() {
695 | defer restoreButtonBox()
696 | launch(command, false)
697 |
698 | })
699 | btn.Connect("enter-notify-event", func() {
700 | cancelClose()
701 | })
702 |
703 | btn, _ = gtk.ButtonNew()
704 | pixbuf, _ = createPixbuf("dialog-cancel", *iconSizeLarge)
705 | img, _ = gtk.ImageNewFromPixbuf(pixbuf)
706 | btn.SetImage(img)
707 | btn.SetCanFocus(false)
708 | box.PackEnd(btn, false, false, 6)
709 | btn.Connect("clicked", func() {
710 | restoreButtonBox()
711 | })
712 | btn.Connect("enter-notify-event", func() {
713 | cancelClose()
714 | })
715 |
716 | buttonsWrapper.PackEnd(box, false, false, 10)
717 |
718 | box.ShowAll()
719 | w := buttonBox.GetAllocatedWidth()
720 | h := buttonBox.GetAllocatedHeight()
721 | box.SetSizeRequest(w, h)
722 | box.SetHExpand(false)
723 |
724 | return box
725 | }
726 |
727 | func restoreButtonBox() {
728 | if confirmationBox != nil {
729 | confirmationBox.Destroy()
730 | }
731 | if !buttonBox.IsVisible() {
732 | buttonBox.Show()
733 | }
734 | }
735 |
736 | func clearSearchResult() {
737 | if resultWindow != nil {
738 | resultWindow.Destroy()
739 | }
740 | if fileSearchResultWindow != nil {
741 | fileSearchResultWindow.Destroy()
742 | }
743 | if userDirsListBox != nil {
744 | userDirsListBox.ShowAll()
745 | }
746 | if categoriesListBox != nil {
747 | sr := categoriesListBox.GetSelectedRow()
748 | if sr != nil {
749 | categoriesListBox.GetSelectedRow().SetSelectable(false)
750 | }
751 | categoriesListBox.UnselectAll()
752 | }
753 | backButton.Hide()
754 |
755 | }
756 |
--------------------------------------------------------------------------------