58 Commits

Author SHA1 Message Date
piotr
33e0032725 bump to 0.4.1 2023-11-18 01:41:53 +01:00
Piotr Miller
c05fff189d Merge pull request #103 from gouvinb/main
Change command execution logic and use `/usr/bin/env` command
2023-11-18 01:40:09 +01:00
gouvinb
57d130ca51 Restore the code to trim % and everything that follows 2023-11-09 15:49:50 +01:00
gouvinb
954a6ba9c9 change command execution logic and use env command 2023-11-09 04:24:41 +01:00
piotr
67b16ea6a6 bump to 0.4.0 2023-11-08 02:30:01 +01:00
piotr
3a02b16761 update versions 2023-11-08 02:25:43 +01:00
piotr
c67fef6671 fix line formatting 2023-11-08 02:24:41 +01:00
Piotr Miller
444617865e Merge pull request #102 from gouvinb/main
add support to hyprlandctl
2023-11-08 01:01:10 +01:00
gouvinb
e3de9cc67b make better log with -wm flag 2023-11-07 10:32:23 +01:00
gouvinb
1c11329581 Reworked command building.
Typical shell-supported command sets:

- `cmd`
- `cmd --arg`
- `cmd --arg=value`
- `ENV_VAR="value" cmd`
- `ENV_VAR="value" cmd --arg`
- `ENV_VAR="value" cmd --arg=value`

The listed commands above are now better managed.

Initially, the command types `cmd --arg=value` or `ENV_VAR="value" cmd --arg=value` were not correctly parsed. After finding a solution to this problem, I conducted further tests and discovered cases that were not currently handled. These cases are as follows:

- `cmd "arg with space"`
- `ENV_VAR="value with space" cmd`
2023-11-06 15:35:42 +01:00
gouvinb
87ee23afe2 print the correct executed command (prefix supported) 2023-11-06 12:40:10 +01:00
gouvinb
808fd032a0 fix prefix command with hypr or hyprland and update -wm description 2023-11-06 00:05:16 +01:00
gouvinb
1d3f023dc8 add support to hyprlandctl
BREAKING CHANGE: '-swaymsg' removed, use '-wm sway' instead
2023-11-05 23:36:18 +01:00
Piotr Miller
ccfe7776c6 Merge pull request #101 from gouvinb/main
Add the `swaymsg` flag to launch a program with `swaymsg exec` and prevent potential involuntary closing with Jetbrains IDEs
2023-11-05 14:03:26 +01:00
gouvinb
5a7dbefeb0 adds the "swaymsg" flag to launch a program with "swaymsg exec" and prevent potential involuntary closing with Jetbrains IDEs 2023-11-01 00:44:50 +01:00
piotr
fd26bb39e8 adjust help descriptions 2023-07-28 01:18:08 +02:00
piotr
bc74ebc927 update usage 2023-07-28 01:15:31 +02:00
piotr
d65d075bdb update usage 2023-07-28 01:13:57 +02:00
Piotr Miller
58ea8ea8db Merge pull request #95 from trinitronx/add-keyboard-mode-flag
Add keyboard mode flag to support both: "on-demand" & "exclusive" GTK layer-shell modes
2023-07-28 00:51:52 +02:00
Piotr Miller
94b8b8d7f0 Merge pull request #96 from nwg-piotr/theme
Force GTK_THEME for libadwaita apps
2023-07-28 00:49:47 +02:00
piotr
ebfaba1881 undo version bump 2023-07-28 00:47:27 +02:00
piotr
6656568c6a update -ft description 2023-07-27 03:44:29 +02:00
piotr
b3fa492b44 bump to 0.3.10 2023-07-27 03:27:56 +02:00
piotr
c0faecdb8b add -ft argument 2023-07-27 03:27:27 +02:00
James Cuzella
830edefa22 Refactor -k flag as Bool to toggle keyboard mode on-demand / exclusive 2023-07-24 20:48:35 -06:00
James Cuzella
aeeb4e4890 Fix warn messages for short -k flag 2023-07-23 22:49:52 -06:00
James Cuzella
6bbfbea1a8 Handle empty string passed to --keyboard/-k flag 2023-07-23 22:45:16 -06:00
James Cuzella
d88d9795d1 Document --keyboard/-k flag in README 2023-07-23 22:22:41 -06:00
James Cuzella
f85356bdc7 Drop keyboard mode: 'none' b/c it doesn't make sense with this app to not have keyboard input at all 2023-07-23 20:30:14 -06:00
James Cuzella
37c9c2d520 Add --keyboard/-k flag to set GTK layer shell keyboard mode (default: exclusive) 2023-07-23 20:26:09 -06:00
Piotr Miller
2903abd831 Merge pull request #94 from 6543-forks/smal_code_refactor
smal code refactors
2023-07-07 22:48:39 +02:00
Piotr Miller
9cc81fa38a Merge pull request #93 from 6543-forks/fix_lint_errors
log actual error message too
2023-07-07 22:45:03 +02:00
Piotr Miller
edf4c81f85 Merge pull request #92 from 6543-forks/reduce_syscalls
Save result of os.Getenv()
2023-07-07 22:43:50 +02:00
Piotr Miller
9582726cb9 Merge pull request #90 from 6543-forks/update_go_deps
update golang lib dependencies
2023-07-07 22:26:53 +02:00
6543
7a6ae82a75 log the unknown signal 2023-07-06 18:03:28 +02:00
6543
22ddb71603 declare unused var with _ and always name event the same 2023-07-06 17:56:40 +02:00
6543
ea7813761a gitignore vendor directory 2023-07-06 17:16:26 +02:00
6543
0cafb3c3ad save result of os.Getenv and use that if possible to reduce some syscalls 2023-07-06 17:15:49 +02:00
6543
89cffad81d log actual error message too 2023-07-06 17:14:55 +02:00
6543
1e854558cf update golang lib dependencies 2023-07-06 16:10:31 +02:00
Piotr Miller
3df7a30533 Update README.md 2023-03-11 02:10:14 +01:00
piotr
e383f7a470 bump to 0.3.9 (go 1.20) 2023-02-06 01:57:11 +01:00
Piotr Miller
820848d984 Merge pull request #85 from nwg-piotr/add84
Add `-i` flag to force an icon theme
2023-01-22 22:41:42 +01:00
piotr
fa01d5bb32 bump to 0.3.8 2023-01-22 22:35:00 +01:00
piotr
8be1fc1ea2 allow forcing icon theme #84 2023-01-22 22:30:09 +01:00
Piotr Miller
0e5d38907f Merge pull request #83 from nwg-piotr/fix82
fixed trimming strings on non-ASCII characters
2023-01-12 22:50:59 +01:00
piotr
7ba7abd817 bump to 0.3.7 2023-01-12 22:48:52 +01:00
piotr
cedcf8619f fix cutting utf-8 strings #82 2023-01-12 02:27:27 +01:00
Piotr Miller
8ff2d5c89c Create FUNDING.yml 2022-12-15 12:05:39 +01:00
Piotr Miller
c4629e0c28 Merge pull request #80 from nwg-piotr/lockfile
Move lock file to XDG_DATA_HOME/nwg-drawer/
2022-12-11 23:21:32 +01:00
piotr
ab5e2ea6ae move lock file to dataDir #79 2022-12-11 23:05:57 +01:00
piotr
63117e2605 bump to 0.3.6 2022-12-11 21:44:01 +01:00
Piotr Miller
d22609f403 Merge pull request #77 from nwg-piotr/debu68
fix #68
2022-12-01 00:12:46 +01:00
piotr
cb6a7f44fe go-sway -> 1.2.0 2022-12-01 00:03:17 +01:00
piotr
85cc2d78ee fix userDirsFile path #68 2022-11-28 23:39:36 +01:00
piotr
d3a0fd04a4 log if userDirsFile found #68 2022-11-28 23:26:19 +01:00
piotr
52e63667c9 print userDirsMap -> log.Debugf #68 2022-11-28 23:03:12 +01:00
piotr
f399f589fb add a line to debug #68 2022-11-18 01:40:50 +01:00
9 changed files with 192 additions and 115 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: nwg-piotr

2
.gitignore vendored
View File

@@ -18,4 +18,4 @@ nwg-drawer
/.idea /.idea
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ vendor/

View File

@@ -1,6 +1,8 @@
# nwg-drawer # nwg-drawer
This application is a part of the [nwg-shell](https://github.com/nwg-piotr/nwg-shell) project. This application is a part of the [nwg-shell](https://nwg-piotr.github.io/nwg-shell) project.
**Contributing:** please read the [general contributing rules for the nwg-shell project](https://nwg-piotr.github.io/nwg-shell/contribution).
Nwg-drawer is a golang replacement to the `nwggrid` command Nwg-drawer is a golang replacement to the `nwggrid` command
(a part of [nwg-launchers](https://github.com/nwg-piotr/nwg-launchers)). It's being developed with (a part of [nwg-launchers](https://github.com/nwg-piotr/nwg-launchers)). It's being developed with
@@ -32,7 +34,7 @@ To close the window w/o running a program, you may use `Esc` key, or right-click
### Dependencies ### Dependencies
- go >=1.16 (just to build) - go >=1.20 (just to build)
- gtk3 - gtk3
- gtk-layer-shell - gtk-layer-shell
- xdg-utils - xdg-utils
@@ -66,12 +68,25 @@ Usage of nwg-drawer:
File Search result COLumns (default 2) File Search result COLumns (default 2)
-fslen int -fslen int
File Search name LENgth Limit (default 80) File Search name LENgth Limit (default 80)
-ft
Force Theme for libadwaita apps, by adding 'GTK_THEME=<default-gtk-theme>' env var
-g string -g string
GTK theme name, eg. "Adwaita-dark" GTK theme name
-i string
GTK icon theme name
-is int -is int
Icon Size (default 64) Icon Size (default 64)
-k set GTK layer shell Keyboard interactivity to 'on-demand' mode
-lang string -lang string
force lang, e.g. "en", "pl" force lang, e.g. "en", "pl"
-mb int
Margin Bottom
-ml int
Margin Left
-mr int
Margin Right
-mt int
Margin Top
-nocats -nocats
Disable filtering by category Disable filtering by category
-nofs -nofs
@@ -86,7 +101,7 @@ Usage of nwg-drawer:
-spacing uint -spacing uint
icon spacing (default 20) icon spacing (default 20)
-term string -term string
Terminal emulator (default "alacritty") Terminal emulator (default "foot")
-v display Version information -v display Version information
``` ```

21
go.mod
View File

@@ -1,20 +1,19 @@
module github.com/nwg-piotr/nwg-drawer module github.com/nwg-piotr/nwg-drawer
go 1.18 go 1.21
require ( require (
github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37
github.com/dlasky/gotk3-layershell v0.0.0-20210827021656-e6ecab2731f7 github.com/dlasky/gotk3-layershell v0.0.0-20230802002603-b0c42cd8474f
github.com/fsnotify/fsnotify v1.5.1 github.com/fsnotify/fsnotify v1.7.0
github.com/gotk3/gotk3 v0.6.1 github.com/gotk3/gotk3 v0.6.2
github.com/joshuarubin/go-sway v0.0.4 github.com/joshuarubin/go-sway v1.2.0
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.9.3
) )
require ( require (
github.com/joshuarubin/lifecycle v1.0.0 // indirect github.com/joshuarubin/lifecycle v1.1.4 // indirect
go.uber.org/atomic v1.3.2 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/multierr v1.1.0 // indirect golang.org/x/sync v0.5.0 // indirect
golang.org/x/sync v0.0.0-20190412183630-56d357773e84 // indirect golang.org/x/sys v0.14.0 // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
) )

51
go.sum
View File

@@ -3,30 +3,45 @@ github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37/go.m
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlasky/gotk3-layershell v0.0.0-20210827021656-e6ecab2731f7 h1:LDo0kwt+oW9a4lWlj2OakIgMW1ySXXVRGFt8GHUdYYA= github.com/dlasky/gotk3-layershell v0.0.0-20221218201547-1f6674a3f872 h1:16qcNl+UgbvudN7wPv+zq4mmDSYJWdLv5jbVhS7+OVI=
github.com/dlasky/gotk3-layershell v0.0.0-20210827021656-e6ecab2731f7/go.mod h1:JHLx2Wz4mAPVwn4PFhC69ydwyHP4A3wQvlg7HKVVc1U= github.com/dlasky/gotk3-layershell v0.0.0-20221218201547-1f6674a3f872/go.mod h1:JHLx2Wz4mAPVwn4PFhC69ydwyHP4A3wQvlg7HKVVc1U=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/dlasky/gotk3-layershell v0.0.0-20230802002603-b0c42cd8474f h1:qDnUQAD7tVX/gnL6uSgouzfGNA4xXH+B/fd6Ko19GgM=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/dlasky/gotk3-layershell v0.0.0-20230802002603-b0c42cd8474f/go.mod h1:JHLx2Wz4mAPVwn4PFhC69ydwyHP4A3wQvlg7HKVVc1U=
github.com/gotk3/gotk3 v0.6.1 h1:GJ400a0ecEEWrzjBvzBzH+pB/esEMIGdB9zPSmBdoeo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q= github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
github.com/joshuarubin/go-sway v0.0.4 h1:dpmIwQ/LytG+oMrjmaVKdk1aPdW2feXK/+wAcLKIx4A= github.com/gotk3/gotk3 v0.6.2 h1:sx/PjaKfKULJPTPq8p2kn2ZbcNFxpOJqi4VLzMbEOO8=
github.com/joshuarubin/go-sway v0.0.4/go.mod h1:qcDd6f25vJ0++wICwA1BainIcRC67p2Mb4lsrZ0k3/k= github.com/gotk3/gotk3 v0.6.2/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
github.com/joshuarubin/lifecycle v1.0.0 h1:N/lPEC8f+dBZ1Tn99vShqp36LwB+LI7XNAiNadZeLUQ= github.com/joshuarubin/go-sway v1.2.0 h1:t3eqW504//uj9PDwFf0+IVfkD+WoOGaDX5gYIe0BHyM=
github.com/joshuarubin/go-sway v1.2.0/go.mod h1:qcDd6f25vJ0++wICwA1BainIcRC67p2Mb4lsrZ0k3/k=
github.com/joshuarubin/lifecycle v1.0.0/go.mod h1:sRy++ATvR9Ee21tkRdFkQeywAWvDsue66V70K0Dnl54= github.com/joshuarubin/lifecycle v1.0.0/go.mod h1:sRy++ATvR9Ee21tkRdFkQeywAWvDsue66V70K0Dnl54=
github.com/joshuarubin/lifecycle v1.1.4 h1:9ZjvYSsWax9DC3Jpz6vGf/0KnU8FNMjh0/vJ3SpSBRQ=
github.com/joshuarubin/lifecycle v1.1.4/go.mod h1:QqHrqwMPMA9dbJY3XgIyVLhzHMSGOFrcCAQ59bke1mo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84 h1:IqXQ59gzdXv58Jmm2xn0tSOR9i6HqroaOFRQ3wR/dJQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

58
main.go
View File

@@ -21,7 +21,7 @@ import (
"github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/gtk"
) )
const version = "0.3.4" const version = "0.4.1"
var ( var (
appDirs []string appDirs []string
@@ -104,7 +104,7 @@ var (
pinnedItemsChanged chan interface{} = make(chan interface{}, 1) pinnedItemsChanged chan interface{} = make(chan interface{}, 1)
) )
func defaultStringIfBlank(s, fallback string) string { func defaultTermIfBlank(s, fallback string) string {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
// os.Getenv("TERM") returns "linux" instead of empty string, if program has been started // os.Getenv("TERM") returns "linux" instead of empty string, if program has been started
// from a key binding defined in the config file. See #23. // from a key binding defined in the config file. See #23.
@@ -114,23 +114,42 @@ func defaultStringIfBlank(s, fallback string) string {
return s return s
} }
func defaultStringIfBlank(s, fallback string) string {
s = strings.TrimSpace(s)
if s == "" {
return fallback
}
return s
}
func validateWm() {
if !(*wm == "sway" || *wm == "hyprland") && *wm != "" {
*wm = ""
log.Warn("-wm argument supports only sway or hyprland string.")
}
}
// Flags // Flags
var cssFileName = flag.String("s", "drawer.css", "Styling: css file name") var cssFileName = flag.String("s", "drawer.css", "Styling: css file name")
var targetOutput = flag.String("o", "", "name of the Output to display the drawer on (sway only)") var targetOutput = flag.String("o", "", "name of the Output to display the drawer on (sway only)")
var displayVersion = flag.Bool("v", false, "display Version information") var displayVersion = flag.Bool("v", false, "display Version information")
var keyboard = flag.Bool("k", false, "set GTK layer shell Keyboard interactivity to 'on-demand' mode")
var overlay = flag.Bool("ovl", false, "use OVerLay layer") var overlay = flag.Bool("ovl", false, "use OVerLay layer")
var gtkTheme = flag.String("g", "", "GTK theme name") var gtkTheme = flag.String("g", "", "GTK theme name")
var gtkIconTheme = flag.String("i", "", "GTK icon theme name")
var iconSize = flag.Int("is", 64, "Icon Size") var iconSize = flag.Int("is", 64, "Icon Size")
var marginTop = flag.Int("mt", 0, "Margin Top") var marginTop = flag.Int("mt", 0, "Margin Top")
var marginLeft = flag.Int("ml", 0, "Margin Left") var marginLeft = flag.Int("ml", 0, "Margin Left")
var marginRight = flag.Int("mr", 0, "Margin Right") var marginRight = flag.Int("mr", 0, "Margin Right")
var marginBottom = flag.Int("mb", 0, "Margin Bottom") var marginBottom = flag.Int("mb", 0, "Margin Bottom")
var fsColumns = flag.Uint("fscol", 2, "File Search result COLumns") var fsColumns = flag.Uint("fscol", 2, "File Search result COLumns")
var forceTheme = flag.Bool("ft", false, "Force Theme for libadwaita apps, by adding 'GTK_THEME=<default-gtk-theme>' env var")
var columnsNumber = flag.Uint("c", 6, "number of Columns") var columnsNumber = flag.Uint("c", 6, "number of Columns")
var itemSpacing = flag.Uint("spacing", 20, "icon spacing") var itemSpacing = flag.Uint("spacing", 20, "icon spacing")
var lang = flag.String("lang", "", "force lang, e.g. \"en\", \"pl\"") var lang = flag.String("lang", "", "force lang, e.g. \"en\", \"pl\"")
var fileManager = flag.String("fm", "thunar", "File Manager") var fileManager = flag.String("fm", "thunar", "File Manager")
var term = flag.String("term", defaultStringIfBlank(os.Getenv("TERM"), "foot"), "Terminal emulator") var term = flag.String("term", defaultTermIfBlank(os.Getenv("TERM"), "foot"), "Terminal emulator")
var wm = flag.String("wm", defaultStringIfBlank(os.Getenv("XDG_CURRENT_DESKTOP"), ""), "Use swaymsg (with 'sway' argument) or hyprctl (with 'hyprland')")
var nameLimit = flag.Int("fslen", 80, "File Search name LENgth Limit") var nameLimit = flag.Int("fslen", 80, "File Search name LENgth Limit")
var noCats = flag.Bool("nocats", false, "Disable filtering by category") var noCats = flag.Bool("nocats", false, "Disable filtering by category")
var noFS = flag.Bool("nofs", false, "Disable file search") var noFS = flag.Bool("nofs", false, "Disable file search")
@@ -150,6 +169,8 @@ func main() {
os.Exit(0) os.Exit(0)
} }
validateWm()
// Gentle SIGTERM handler thanks to reiki4040 https://gist.github.com/reiki4040/be3705f307d3cd136e85 // Gentle SIGTERM handler thanks to reiki4040 https://gist.github.com/reiki4040/be3705f307d3cd136e85
// v0.2: we also need to support SIGUSR from now on // v0.2: we also need to support SIGUSR from now on
showWindowChannel := make(chan interface{}, 1) showWindowChannel := make(chan interface{}, 1)
@@ -179,7 +200,7 @@ func main() {
gtk.MainQuit() gtk.MainQuit()
} }
default: default:
log.Info("Unknown signal") log.Infof("Unknown signal: %s", s.String())
} }
} }
}() }()
@@ -189,7 +210,7 @@ func main() {
// Otherwise the command may behave in two ways: // Otherwise the command may behave in two ways:
// 1. kill the running non-residennt instance and exit; // 1. kill the running non-residennt instance and exit;
// 2. die if a resident instance found. // 2. die if a resident instance found.
lockFilePath := path.Join(tempDir(), "nwg-drawer.lock") lockFilePath := path.Join(dataDir(), "nwg-drawer.lock")
lockFile, err := singleinstance.CreateLockFile(lockFilePath) lockFile, err := singleinstance.CreateLockFile(lockFilePath)
if err != nil { if err != nil {
pid, err := readTextFile(lockFilePath) pid, err := readTextFile(lockFilePath)
@@ -326,6 +347,15 @@ func main() {
log.Info("Preferring dark theme variants") log.Info("Preferring dark theme variants")
} }
if *gtkIconTheme != "" {
err = settings.SetProperty("gtk-icon-theme-name", *gtkIconTheme)
if err != nil {
log.Error("Unable to set icon theme:", err)
} else {
log.Infof("User demanded icon theme: %s", *gtkIconTheme)
}
}
cssProvider, _ := gtk.CssProviderNew() cssProvider, _ := gtk.CssProviderNew()
err = cssProvider.LoadFromPath(*cssFileName) err = cssProvider.LoadFromPath(*cssFileName)
@@ -376,14 +406,21 @@ func main() {
layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_RIGHT, *marginRight) layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_RIGHT, *marginRight)
layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_BOTTOM, *marginBottom) layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_BOTTOM, *marginBottom)
layershell.SetKeyboardMode(win, layershell.LAYER_SHELL_KEYBOARD_MODE_EXCLUSIVE) if *keyboard {
log.Info("Setting GTK layer shell keyboard mode to: on-demand")
layershell.SetKeyboardMode(win, layershell.LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND)
} else {
log.Info("Setting GTK layer shell keyboard mode to default: exclusive")
layershell.SetKeyboardMode(win, layershell.LAYER_SHELL_KEYBOARD_MODE_EXCLUSIVE)
}
} }
win.Connect("destroy", func() { win.Connect("destroy", func() {
gtk.MainQuit() gtk.MainQuit()
}) })
win.Connect("key-release-event", func(window *gtk.Window, event *gdk.Event) bool { win.Connect("key-release-event", func(_ *gtk.Window, event *gdk.Event) bool {
key := &gdk.EventKey{Event: event} key := &gdk.EventKey{Event: event}
if key.KeyVal() == gdk.KEY_Escape { if key.KeyVal() == gdk.KEY_Escape {
s, _ := searchEntry.GetText() s, _ := searchEntry.GetText()
@@ -402,7 +439,7 @@ func main() {
return false return false
}) })
win.Connect("key-press-event", func(window *gtk.Window, event *gdk.Event) bool { win.Connect("key-press-event", func(_ *gtk.Window, event *gdk.Event) bool {
key := &gdk.EventKey{Event: event} key := &gdk.EventKey{Event: event}
switch key.KeyVal() { switch key.KeyVal() {
case gdk.KEY_downarrow, gdk.KEY_Up, gdk.KEY_Down, gdk.KEY_Left, gdk.KEY_Right, gdk.KEY_Tab, case gdk.KEY_downarrow, gdk.KEY_Up, gdk.KEY_Down, gdk.KEY_Left, gdk.KEY_Right, gdk.KEY_Tab,
@@ -457,8 +494,8 @@ func main() {
resultWindow.SetEvents(int(gdk.ALL_EVENTS_MASK)) resultWindow.SetEvents(int(gdk.ALL_EVENTS_MASK))
resultWindow.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) resultWindow.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
resultWindow.Connect("button-release-event", func(sw *gtk.ScrolledWindow, e *gdk.Event) bool { resultWindow.Connect("button-release-event", func(_ *gtk.ScrolledWindow, event *gdk.Event) bool {
btnEvent := gdk.EventButtonNewFromEvent(e) btnEvent := gdk.EventButtonNewFromEvent(event)
if btnEvent.Button() == 3 { if btnEvent.Button() == 3 {
if !*resident { if !*resident {
gtk.MainQuit() gtk.MainQuit()
@@ -490,6 +527,7 @@ func main() {
} }
userDirsMap = mapXdgUserDirs() userDirsMap = mapXdgUserDirs()
log.Debugf("User dirs map: %s", userDirsMap)
placeholder, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) placeholder, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
resultsWrapper.PackStart(placeholder, true, true, 0) resultsWrapper.PackStart(placeholder, true, true, 0)

129
tools.go
View File

@@ -78,8 +78,9 @@ func mapXdgUserDirs() map[string]string {
result["pictures"] = filepath.Join(home, "Pictures") result["pictures"] = filepath.Join(home, "Pictures")
result["videos"] = filepath.Join(home, "Videos") result["videos"] = filepath.Join(home, "Videos")
userDirsFile := filepath.Join(home, ".config/user-dirs.dirs") userDirsFile := filepath.Join(filepath.Join(os.Getenv("XDG_CONFIG_HOME"), "user-dirs.dirs"))
if pathExists(userDirsFile) { if pathExists(userDirsFile) {
log.Debugf("userDirsFile found: %s", userDirsFile)
log.Info(fmt.Sprintf("Using XDG user dirs from %s", userDirsFile)) log.Info(fmt.Sprintf("Using XDG user dirs from %s", userDirsFile))
lines, _ := loadTextFile(userDirsFile) lines, _ := loadTextFile(userDirsFile)
for _, l := range lines { for _, l := range lines {
@@ -104,7 +105,7 @@ func mapXdgUserDirs() map[string]string {
} }
} }
} else { } else {
log.Warnf("%s file not found, using defaults", userDirsFile) log.Warnf("userDirsFile %s not found, using defaults", userDirsFile)
} }
return result return result
@@ -120,27 +121,16 @@ func getUserDir(home, line string) string {
} }
func cacheDir() string { func cacheDir() string {
if os.Getenv("XDG_CACHE_HOME") != "" { if xdgCache := os.Getenv("XDG_CACHE_HOME"); xdgCache != "" {
return os.Getenv("XDG_CONFIG_HOME") return xdgCache
} }
if os.Getenv("HOME") != "" && pathExists(filepath.Join(os.Getenv("HOME"), ".cache")) { if home := os.Getenv("HOME"); home != "" && pathExists(filepath.Join(home, ".cache")) {
p := filepath.Join(os.Getenv("HOME"), ".cache") p := filepath.Join(home, ".cache")
return p return p
} }
return "" return ""
} }
func tempDir() string {
if os.Getenv("TMPDIR") != "" {
return os.Getenv("TMPDIR")
} else if os.Getenv("TEMP") != "" {
return os.Getenv("TEMP")
} else if os.Getenv("TMP") != "" {
return os.Getenv("TMP")
}
return "/tmp"
}
func readTextFile(path string) (string, error) { func readTextFile(path string) (string, error) {
bytes, err := os.ReadFile(path) bytes, err := os.ReadFile(path)
if err != nil { if err != nil {
@@ -151,11 +141,11 @@ func readTextFile(path string) (string, error) {
} }
func oldConfigDir() (string, error) { func oldConfigDir() (string, error) {
if os.Getenv("XDG_CONFIG_HOME") != "" { if xdgConfig := os.Getenv("XDG_CONFIG_HOME"); xdgConfig != "" {
dir := path.Join(os.Getenv("XDG_CONFIG_HOME"), "nwg-panel") dir := path.Join(xdgConfig, "nwg-panel")
return dir, nil return dir, nil
} else if os.Getenv("HOME") != "" { } else if home := os.Getenv("HOME"); home != "" {
dir := path.Join(os.Getenv("HOME"), ".config/nwg-panel") dir := path.Join(home, ".config/nwg-panel")
return dir, nil return dir, nil
} }
@@ -164,10 +154,10 @@ func oldConfigDir() (string, error) {
func configDir() string { func configDir() string {
var dir string var dir string
if os.Getenv("XDG_CONFIG_HOME") != "" { if xdgConfig := os.Getenv("XDG_CONFIG_HOME"); xdgConfig != "" {
dir = path.Join(os.Getenv("XDG_CONFIG_HOME"), "nwg-drawer") dir = path.Join(xdgConfig, "nwg-drawer")
} else if os.Getenv("HOME") != "" { } else if home := os.Getenv("HOME"); home != "" {
dir = path.Join(os.Getenv("HOME"), ".config/nwg-drawer") dir = path.Join(home, ".config/nwg-drawer")
} }
log.Infof("Config dir: %s", dir) log.Infof("Config dir: %s", dir)
@@ -176,6 +166,20 @@ func configDir() string {
return dir return dir
} }
func dataDir() string {
var dir string
if xdgData := os.Getenv("XDG_DATA_HOME"); xdgData != "" {
dir = path.Join(xdgData, "nwg-drawer")
} else if home := os.Getenv("HOME"); home != "" {
dir = path.Join(home, ".local/share/nwg-drawer")
}
log.Infof("Data dir: %s", dir)
createDir(dir)
return dir
}
func createDir(dir string) { func createDir(dir string) {
if _, err := os.Stat(dir); os.IsNotExist(err) { if _, err := os.Stat(dir); os.IsNotExist(err) {
err := os.MkdirAll(dir, os.ModePerm) err := os.MkdirAll(dir, os.ModePerm)
@@ -224,13 +228,11 @@ func copyFile(src, dst string) error {
func getAppDirs() []string { func getAppDirs() []string {
var dirs []string var dirs []string
xdgDataDirs := ""
home := os.Getenv("HOME") home := os.Getenv("HOME")
xdgDataHome := os.Getenv("XDG_DATA_HOME") xdgDataHome := os.Getenv("XDG_DATA_HOME")
if os.Getenv("XDG_DATA_DIRS") != "" { xdgDataDirs := os.Getenv("XDG_DATA_DIRS")
xdgDataDirs = os.Getenv("XDG_DATA_DIRS") if xdgDataDirs == "" {
} else {
xdgDataDirs = "/usr/local/share/:/usr/share/" xdgDataDirs = "/usr/local/share/:/usr/share/"
} }
if xdgDataHome != "" { if xdgDataHome != "" {
@@ -554,47 +556,40 @@ func launch(command string, terminal bool) {
} }
} }
elements := strings.Split(command, " ") themeToPrepend := ""
// add "GTK_THEME=<default_gtk_theme>" environment variable
// find prepended env variables, if any if *forceTheme {
envVarsNum := strings.Count(command, "=") settings, _ := gtk.SettingsGetDefault()
var envVars []string th, err := settings.GetProperty("gtk-theme-name")
if err == nil {
cmdIdx := -1 themeToPrepend = th.(string)
if envVarsNum > 0 {
for idx, item := range elements {
if strings.Contains(item, "=") {
envVars = append(envVars, item)
} else if !strings.HasPrefix(item, "-") && cmdIdx == -1 {
cmdIdx = idx
}
} }
} }
if cmdIdx == -1 {
cmdIdx = 0 if themeToPrepend != "" {
command = fmt.Sprintf("GTK_THEME=%q %s", themeToPrepend, command)
} }
cmd := exec.Command(elements[cmdIdx], elements[1+cmdIdx:]...) var elements = []string{"/usr/bin/env", "-S", command}
cmd := exec.Command(elements[0], elements[1:]...)
if terminal { if terminal {
var prefixCommand = *term
var args []string var args []string
if *term != "foot" { if prefixCommand != "foot" {
args = []string{"-e", elements[cmdIdx]} args = []string{"-e", command}
} else { } else {
args = []string{elements[cmdIdx]} args = elements
} }
cmd = exec.Command(prefixCommand, args...)
cmd = exec.Command(*term, args...) } else if *wm == "sway" {
cmd = exec.Command("swaymsg", "exec", strings.Join(elements, " "))
} else if *wm == "hyprland" {
cmd = exec.Command("hyprctl", "dispatch", "exec", strings.Join(elements, " "))
} }
// set env variables msg := fmt.Sprintf("command: %q; args: %q\n", cmd.Args[0], cmd.Args[1:])
if len(envVars) > 0 {
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, envVars...)
}
msg := fmt.Sprintf("env vars: %s; command: '%s'; args: %s\n", envVars, elements[cmdIdx], elements[1+cmdIdx:])
log.Info(msg) log.Info(msg)
cmd.SysProcAttr = &syscall.SysProcAttr{ cmd.SysProcAttr = &syscall.SysProcAttr{
@@ -687,3 +682,19 @@ func mapOutputs() (map[string]*gdk.Monitor, error) {
} }
return result, nil return result, nil
} }
// KAdot / https://stackoverflow.com/a/38537764/4040598 - thanks!
func substring(s string, start int, end int) string {
startStrIdx := 0
i := 0
for j := range s {
if i == start {
startStrIdx = j
}
if i == end {
return s[startStrIdx:j]
}
i++
}
return s[startStrIdx:]
}

View File

@@ -58,9 +58,8 @@ func setUpPinnedFlowBox() *gtk.FlowBox {
name = entry.Name name = entry.Name
} }
if len(name) > 20 { if len(name) > 20 {
r := []rune(name) r := substring(name, 0, 17)
name = string(r[:17]) name = fmt.Sprintf("%s…", string(r))
name = fmt.Sprintf("%s…", name)
} }
btn.SetLabel(name) btn.SetLabel(name)
@@ -252,9 +251,8 @@ func flowBoxButton(entry desktopEntry) *gtk.Button {
button.SetImagePosition(gtk.POS_TOP) button.SetImagePosition(gtk.POS_TOP)
name := entry.NameLoc name := entry.NameLoc
if len(name) > 20 { if len(name) > 20 {
r := []rune(name[:17]) r := substring(name, 0, 17)
name = string(r) name = fmt.Sprintf("%s…", string(r))
name = fmt.Sprintf("%s…", name)
} }
button.SetLabel(name) button.SetLabel(name)
@@ -263,9 +261,8 @@ func flowBoxButton(entry desktopEntry) *gtk.Button {
terminal := entry.Terminal terminal := entry.Terminal
desc := entry.CommentLoc desc := entry.CommentLoc
if len(desc) > 120 { if len(desc) > 120 {
r := []rune(desc[:117]) r := substring(desc, 0, 117)
desc = string(r) desc = fmt.Sprintf("%s…", string(r))
desc = fmt.Sprintf("%s…", desc)
} }
button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool { button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool {
btnEvent := gdk.EventButtonNewFromEvent(e) btnEvent := gdk.EventButtonNewFromEvent(e)
@@ -434,6 +431,7 @@ func searchUserDir(dir string) {
fileSearchResultFlowBox.Add(btn) fileSearchResultFlowBox.Add(btn)
for _, path := range fileSearchResults { for _, path := range fileSearchResults {
log.Debugf("Path: %s", path)
partOfPathToShow := strings.Split(path, userDirsMap[dir])[1] partOfPathToShow := strings.Split(path, userDirsMap[dir])[1]
if partOfPathToShow != "" { if partOfPathToShow != "" {
if !(strings.HasPrefix(path, "#is_dir#") && isExcluded(path)) { if !(strings.HasPrefix(path, "#is_dir#") && isExcluded(path)) {

View File

@@ -20,12 +20,12 @@ func watchFiles() {
defer watcher.Close() defer watcher.Close()
if err := watcher.Add(pinnedFile); err != nil { if err := watcher.Add(pinnedFile); err != nil {
log.Errorf("ERROR", err) log.Errorf("ERROR: %s", err)
} }
for _, fp := range appDirs { for _, fp := range appDirs {
if err := filepath.Walk(fp, watchDir); err != nil { if err := filepath.Walk(fp, watchDir); err != nil {
log.Errorf("ERROR", err) log.Errorf("ERROR: %s", err)
} }
} }
@@ -47,7 +47,7 @@ func watchFiles() {
} }
case err := <-watcher.Errors: case err := <-watcher.Errors:
log.Errorf("ERROR", err) log.Errorf("ERROR: %s", err)
} }
} }
}() }()