diff --git a/.github/workflows/platform_tests.yml b/.github/workflows/platform_tests.yml index 7e0f6c5b..90d00704 100644 --- a/.github/workflows/platform_tests.yml +++ b/.github/workflows/platform_tests.yml @@ -9,14 +9,14 @@ jobs: strategy: fail-fast: false matrix: - go-version: ['1.17', '1.20'] + go-version: ['1.19', '1.21'] os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: persist-credentials: false - - uses: WillAbides/setup-go-faster@v1.7.0 + - uses: WillAbides/setup-go-faster@v1.13.0 with: go-version: ${{ matrix.go-version }} @@ -41,4 +41,4 @@ jobs: uses: shogo82148/actions-goveralls@v1 with: path-to-profile: coverage.out - if: ${{ runner.os == 'Linux' && matrix.go-version == '1.17' }} + if: ${{ runner.os == 'Linux' && matrix.go-version == '1.19' }} diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index db9a704a..b4e0fa5b 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -8,9 +8,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: WillAbides/setup-go-faster@v1.13.0 with: - go-version: '1.19' + go-version: '1.21.x' - name: Get dependencies run: | @@ -37,4 +39,7 @@ jobs: - name: Staticcheck run: staticcheck -go 1.19 ./... +<<<<<<< HEAD +======= +>>>>>>> ca3bca0c40a833df8ac3a90b0d2021eb2304646b diff --git a/desk.go b/desk.go index 1d30348e..05a1ad50 100644 --- a/desk.go +++ b/desk.go @@ -9,6 +9,7 @@ type Desktop interface { RecentApps() []AppData Settings() DeskSettings ContentBoundsPixels(*Screen) (x, y, w, h uint32) + RootSizePixels() (w, h uint32) Screens() ScreenList IconProvider() ApplicationProvider diff --git a/go.mod b/go.mod index 6ca0c28c..5067d8df 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,7 @@ module fyshos.com/fynedesk go 1.17 require ( - fyne.io/fyne/v2 v2.4.0 - github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect - github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect + fyne.io/fyne/v2 v2.4.4-0.20240107115323-8458aff4b006 github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184 @@ -21,14 +19,16 @@ require ( ) require ( - fyne.io/systray v1.10.1-0.20230722100817-88df1e0ffa9a // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fredbi/uri v1.0.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + fyne.io/systray v1.10.1-0.20231230205326-d160fd363db9 // indirect + github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect + github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/fredbi/uri v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect - github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect + github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a // indirect github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect - github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7 // indirect github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 // indirect github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect @@ -36,18 +36,17 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pkg/errors v0.8.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rymdport/portal v0.0.0-20231123202536-da45518a87bb // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect - github.com/tevino/abool v1.2.0 // indirect github.com/yuin/goldmark v1.5.5 // indirect - golang.org/x/image v0.11.0 // indirect - golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda // indirect - golang.org/x/net v0.14.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/image v0.14.0 // indirect + golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect ) replace github.com/BurntSushi/xgbutil => github.com/fyne-io/xgbutil v0.0.0-20191220152344-7d838166824d diff --git a/go.sum b/go.sum index e52f76be..612135a3 100644 --- a/go.sum +++ b/go.sum @@ -37,10 +37,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -fyne.io/fyne/v2 v2.4.0 h1:LlyOyHmvkSo9IBm3aY+NVWSBIw+GMnssmyyIMK8F7zM= -fyne.io/fyne/v2 v2.4.0/go.mod h1:AWM1iPM2YfliduZ4u/kQzP9E6ARIWm0gg+57GpYzWro= -fyne.io/systray v1.10.1-0.20230722100817-88df1e0ffa9a h1:6Xf9fP3/mt72NrqlQhJWhQGcNf6GoG9X96NTaXr+K6A= -fyne.io/systray v1.10.1-0.20230722100817-88df1e0ffa9a/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= +fyne.io/fyne/v2 v2.4.4-0.20240107115323-8458aff4b006 h1:7zQ59DzG2vWbcHvE/ElPhrkP5Qy8CO15fJenSm22v74= +fyne.io/fyne/v2 v2.4.4-0.20240107115323-8458aff4b006/go.mod h1:lcFfOoGu75+eS+ERtXM8OZQy+czyIfHxohlc9wSCslE= +fyne.io/systray v1.10.1-0.20231230205326-d160fd363db9 h1:E/gHmMVyk8TuI6JIgNIv/Qu1JABMVFBIkQ8lYRa5gkQ= +fyne.io/systray v1.10.1-0.20231230205326-d160fd363db9/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA= github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= @@ -71,8 +71,9 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -83,15 +84,16 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fredbi/uri v1.0.0 h1:s4QwUAZ8fz+mbTsukND+4V5f+mJ/wjaTokwstGUAemg= -github.com/fredbi/uri v1.0.0/go.mod h1:1xC40RnIOGCaQzswaOvrzvG/3M3F0hyDVb3aO/1iGy0= +github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= +github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8= +github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -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/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4= github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg= -github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 h1:+31CdF/okdokeFNoy9L/2PccG3JFidQT3ev64/r4pYU= -github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504/go.mod h1:gLRWYfYnMA9TONeppRSikMdXlHQ97xVsPojddUv3b/E= +github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a h1:ybgRdYvAHTn93HW79bLiBiJwVL4jVeyGQRZMgImoeWs= +github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a/go.mod h1:gsGA2dotD4v0SR6PmPCYvS9JuOeMwAtmfvDE7mbYXMY= github.com/fyne-io/image v0.0.0-20221020213044-f609c6a24345 h1:ONkcbJmsWUOHyjUm0wlnkFc/uaacFFtStVbsG6qJfew= github.com/fyne-io/image v0.0.0-20221020213044-f609c6a24345/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0= github.com/fyne-io/xgbutil v0.0.0-20191220152344-7d838166824d h1:8+poQtDqiRfAZmeyYRlInuaIBsQEflmxtpJeZklvNuE= @@ -102,9 +104,8 @@ github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVin github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7 h1:7tf/0aw5DxRQjr7WaNqgtjidub6v21L2cogKIbMcTYw= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 h1:VkKnvzbvHqgEfm351rfr8Uclu5fnwq8HP2ximUzJsBM= github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8/go.mod h1:h29xCucjNsDcYb7+0rJokxVwYAq+9kQ19WiFuBKkYtc= github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a h1:VjN8ttdfklC0dnAdKbZqGNESdERUxtE3l8a/4Grgarc= @@ -172,6 +173,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -181,7 +183,6 @@ github.com/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60/go.mod h1:cz9oNY github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY= -github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -250,6 +251,7 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -259,6 +261,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/rymdport/portal v0.0.0-20231123202536-da45518a87bb h1:ejEomhJX7G4p8dFImv2zcQd2Oa0IpWIeB/FUZRnpQKg= +github.com/rymdport/portal v0.0.0-20231123202536-da45518a87bb/go.mod h1:RYYAnv4sssTQ7ceErKl7UD8auER/0yFV7CgmfS/uAD8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= @@ -279,7 +283,6 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -287,19 +290,15 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= -github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU= github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -323,7 +322,6 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -338,8 +336,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo= -golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= +golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -355,8 +353,8 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= -golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34= -golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -366,8 +364,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -405,10 +401,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -432,8 +426,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -479,15 +471,9 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -496,10 +482,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -556,8 +540,6 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -679,8 +661,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700= -honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/icon/fdo.go b/internal/icon/fdo.go index 4d18e55c..66edeb49 100644 --- a/internal/icon/fdo.go +++ b/internal/icon/fdo.go @@ -13,8 +13,6 @@ import ( "fyne.io/fyne/v2" "fyshos.com/fynedesk" - wmTheme "fyshos.com/fynedesk/theme" - _ "github.com/fyne-io/image/xpm" // load XPM icons to supported image format ) @@ -67,7 +65,7 @@ func (data *fdoApplicationData) Icon(theme string, size int) fyne.Resource { if path == "" { path = FdoLookupIconPath(theme, size, data.iconName) if path == "" { - return wmTheme.BrokenImageIcon + return nil } } @@ -362,8 +360,8 @@ func FdoLookupIconPathInTheme(iconSize string, dir string, parentDir string, ico } if len(inheritedThemes) > 0 { for _, theme := range inheritedThemes { - dir = filepath.Join(parentDir, "icons", theme) - iconPath := FdoLookupIconPathInTheme(iconSize, dir, parentDir, iconName) + childDir := filepath.Join(parentDir, "icons", theme) + iconPath := FdoLookupIconPathInTheme(iconSize, childDir, parentDir, iconName) if iconPath != "" { return iconPath } diff --git a/internal/icon/macos.go b/internal/icon/macos.go index 99ef8c15..9202910a 100644 --- a/internal/icon/macos.go +++ b/internal/icon/macos.go @@ -15,7 +15,6 @@ import ( "fyne.io/fyne/v2" "fyshos.com/fynedesk" - wmtheme "fyshos.com/fynedesk/theme" ) type macOSAppBundle struct { @@ -51,20 +50,20 @@ func (m *macOSAppBundle) Icon(_ string, _ int) fyne.Resource { src, err := os.Open(m.iconPath) if err != nil { fyne.LogError("Failed to read icon data for "+m.iconPath, err) - return wmtheme.BrokenImageIcon + return nil } icon, err := icns.Decode(src) if err != nil { fyne.LogError("Failed to parse icon data for "+m.iconPath, err) - return wmtheme.BrokenImageIcon + return nil } var data bytes.Buffer err = png.Encode(&data, icon) if err != nil { fyne.LogError("Failed to encode icon data for "+m.iconPath, err) - return wmtheme.BrokenImageIcon + return nil } iconName := filepath.Base(m.iconPath) diff --git a/internal/notify/desktop.go b/internal/notify/desktop.go new file mode 100644 index 00000000..1ed3ce33 --- /dev/null +++ b/internal/notify/desktop.go @@ -0,0 +1,6 @@ +package notify + +// DesktopNotify allows modules to be informed when user changes virtual desktop +type DesktopNotify interface { + DesktopChangeNotify(int) +} diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 75898dee..32d919b4 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -5,7 +5,10 @@ import ( "os/exec" "strconv" + "fyshos.com/fynedesk/internal/notify" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" deskDriver "fyne.io/fyne/v2/driver/desktop" @@ -46,13 +49,35 @@ func (l *desktop) Desktop() int { } func (l *desktop) SetDesktop(id int) { + diff := id - l.desk l.desk = id - for _, item := range l.wm.Windows() { - if item.Desktop() == id { - item.Uniconify() - } else { - item.Iconify() + _, height := l.RootSizePixels() + offPix := float32(diff * -int(height)) + wins := l.wm.Windows() + + starts := make([]fyne.Position, len(wins)) + deltas := make([]fyne.Delta, len(wins)) + for i, win := range wins { + starts[i] = win.Position() + + display := l.Screens().ScreenForWindow(win) + off := offPix / display.Scale + deltas[i] = fyne.NewDelta(0, off) + } + + fyne.NewAnimation(canvas.DurationStandard, func(f float32) { + for i, item := range l.wm.Windows() { + newX := starts[i].X + deltas[i].DX*f + newY := starts[i].Y + deltas[i].DY*f + + item.Move(fyne.NewPos(newX, newY)) + } + }).Start() + + for _, m := range l.Modules() { + if desk, ok := m.(notify.DesktopNotify); ok { + desk.DesktopChangeNotify(id) } } } @@ -171,6 +196,22 @@ func (l *desktop) ContentBoundsPixels(screen *fynedesk.Screen) (x, y, w, h uint3 return 0, 0, screenW, screenH } +func (l *desktop) RootSizePixels() (w, h uint32) { + for _, screen := range l.Screens().Screens() { + right := uint32(screen.X + screen.Width) + bottom := uint32(screen.Y + screen.Height) + + if right > w { + w = right + } + if bottom > h { + h = bottom + } + } + + return w, h +} + func (l *desktop) IconProvider() fynedesk.ApplicationProvider { return l.icons } @@ -330,13 +371,14 @@ func (l *desktop) Screens() fynedesk.ScreenList { // NewDesktop creates a new desktop in fullscreen for main usage. // The WindowManager passed in will be used to manage the screen it is loaded on. // An ApplicationProvider is used to lookup application icons from the operating system. -func NewDesktop(app fyne.App, wm fynedesk.WindowManager, icons fynedesk.ApplicationProvider, screenProvider fynedesk.ScreenList) fynedesk.Desktop { - desk := newDesktop(app, wm, icons) +func NewDesktop(app fyne.App, mgr fynedesk.WindowManager, icons fynedesk.ApplicationProvider, screenProvider fynedesk.ScreenList) fynedesk.Desktop { + desk := newDesktop(app, mgr, icons) desk.run = desk.runFull screenProvider.AddChangeListener(desk.setupRoot) desk.screens = screenProvider desk.setupRoot() + wm.StartAuthAgent() go desk.startXscreensaver() return desk } diff --git a/internal/ui/embed_wm.go b/internal/ui/embed_wm.go index f5efc2d8..3761a6aa 100644 --- a/internal/ui/embed_wm.go +++ b/internal/ui/embed_wm.go @@ -43,6 +43,12 @@ func (e *embededWM) ShowMenuOverlay(*fyne.Menu, fyne.Size, fyne.Position) { // no-op, handled by desktop in embed mode } +func (e *embededWM) ShowModal(w fyne.Window, s fyne.Size) { + w.Resize(s) + w.CenterOnScreen() + w.Show() +} + func (e *embededWM) TopWindow() fynedesk.Window { if len(e.windows) == 0 { return nil diff --git a/internal/ui/menu.go b/internal/ui/menu.go index 3ed29bc4..31983d59 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -1,12 +1,15 @@ package ui import ( + "image/color" "os" "sort" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" deskDriver "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" @@ -49,6 +52,47 @@ func (w *widgetPanel) appendAppCategories(acc *widget.Accordion, win fyne.Window acc.Refresh() } +func (w *widgetPanel) askLogout() { + win := fyne.CurrentApp().Driver().(deskDriver.Driver).CreateSplashWindow() + logout := widget.NewButtonWithIcon("Logout", theme.LogoutIcon(), func() { + win.Close() + w.desk.WindowManager().Close() + }) + logout.Importance = widget.DangerImportance + cancel := widget.NewButton("Cancel", func() { + win.Close() + }) + + header := widget.NewRichTextFromMarkdown("### Log out") + header.Truncation = fyne.TextTruncateEllipsis + bottomPad := canvas.NewRectangle(color.Transparent) + bottomPad.SetMinSize(fyne.NewSquareSize(10)) + content := container.NewBorder( + header, + container.NewVBox( + container.NewHBox(layout.NewSpacer(), + container.NewGridWithColumns(2, cancel, logout), + layout.NewSpacer()), bottomPad), + nil, nil, + widget.NewLabel("Are you sure you want to log out?")) + + r, g, b, _ := theme.OverlayBackgroundColor().RGBA() + bgCol := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230} + + bg := canvas.NewRectangle(bgCol) + icon := canvas.NewImageFromResource(theme.LogoutIcon()) + iconBox := container.NewWithoutLayout(icon) + icon.Resize(fyne.NewSize(92, 92)) + icon.Move(fyne.NewPos(280-92-theme.Padding(), theme.Padding())) + win.SetContent(container.NewStack( + iconBox, bg, + container.NewPadded(content))) + + win.Resize(fyne.NewSize(280, 150)) + win.CenterOnScreen() + win.Show() +} + func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { w2 := fyne.CurrentApp().Driver().(deskDriver.Driver).CreateSplashWindow() w2.Canvas().SetOnTypedKey(func(k *fyne.KeyEvent) { @@ -58,8 +102,8 @@ func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { }) items1 := []fyne.CanvasObject{ &widget.Button{Icon: theme.LogoutIcon(), Importance: widget.DangerImportance, OnTapped: func() { + w.askLogout() w2.Close() - w.desk.WindowManager().Close() }}} isEmbed := w.desk.(*desktop).root.Title() != RootWindowName if !isEmbed { diff --git a/internal/ui/notifications.go b/internal/ui/notifications.go index a907ca75..e12f716d 100644 --- a/internal/ui/notifications.go +++ b/internal/ui/notifications.go @@ -23,7 +23,7 @@ type notification struct { func (n *notification) show(list *fyne.Container) { title := widget.NewLabel(n.message.Title) title.TextStyle = fyne.TextStyle{Bold: true} - title.Wrapping = fyne.TextTruncate + title.Truncation = fyne.TextTruncateEllipsis text := widget.NewLabel(n.message.Body) text.Wrapping = fyne.TextWrapWord n.renderer = container.NewVBox(title, text) diff --git a/internal/ui/settings.go b/internal/ui/settings.go index d5887b91..8a5efae5 100644 --- a/internal/ui/settings.go +++ b/internal/ui/settings.go @@ -2,6 +2,7 @@ package ui import ( "os" + "runtime" "strings" "sync" @@ -234,13 +235,17 @@ func (d *deskSettings) load() { d.launcherZoomScale = 2.0 } - moduleNames := fyne.CurrentApp().Preferences().StringWithFallback("modulenames", "Battery|Brightness|Compositor|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops") + defaultModules := "Battery|Brightness|Compositor|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops|SystemTray" + if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { // testing + defaultModules = "Battery|Brightness|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops" + } + moduleNames := fyne.CurrentApp().Preferences().StringWithFallback("modulenames", defaultModules) if moduleNames != "" { d.moduleNames = strings.Split(moduleNames, "|") } d.modifier = fyne.KeyModifier(fyne.CurrentApp().Preferences().IntWithFallback("keyboardmodifier", int(fyne.KeyModifierSuper))) - d.narrowLeftLauncher = fyne.CurrentApp().Preferences().Bool("launchernarrowleft") - d.narrowPanel = fyne.CurrentApp().Preferences().Bool("narrowpanel") + d.narrowLeftLauncher = fyne.CurrentApp().Preferences().BoolWithFallback("launchernarrowleft", true) + d.narrowPanel = fyne.CurrentApp().Preferences().BoolWithFallback("narrowpanel", true) d.borderButtonPosition = fyne.CurrentApp().Preferences().StringWithFallback("borderbuttonposition", "Left") diff --git a/internal/ui/switcher.go b/internal/ui/switcher.go index 637d3941..6bd6dcaf 100644 --- a/internal/ui/switcher.go +++ b/internal/ui/switcher.go @@ -4,6 +4,8 @@ import ( "image/color" "time" + wmTheme "fyshos.com/fynedesk/theme" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" @@ -37,12 +39,15 @@ func (s *switchIcon) CreateRenderer() fyne.WidgetRenderer { } else { res = s.win.Properties().Icon() } + if res == nil { + res = wmTheme.BrokenImageIcon + } bg := canvas.NewRectangle(color.Transparent) bg.CornerRadius = theme.InputRadiusSize() img := canvas.NewImageFromResource(res) text := widget.NewLabelWithStyle(title, fyne.TextAlignCenter, fyne.TextStyle{}) - text.Wrapping = fyne.TextTruncate + text.Truncation = fyne.TextTruncateEllipsis return &switchIconRenderer{icon: s, bg: bg, img: img, text: text, objects: []fyne.CanvasObject{bg, img, text}} } diff --git a/internal/x11/win/client.go b/internal/x11/win/client.go index 996f0252..3106b6ba 100644 --- a/internal/x11/win/client.go +++ b/internal/x11/win/client.go @@ -6,14 +6,15 @@ package win import ( "image" - "fyne.io/fyne/v2" - "github.com/BurntSushi/xgb/xproto" "github.com/BurntSushi/xgbutil/ewmh" "github.com/BurntSushi/xgbutil/icccm" "github.com/BurntSushi/xgbutil/xevent" "github.com/BurntSushi/xgbutil/xprop" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyshos.com/fynedesk" "fyshos.com/fynedesk/internal/x11" "fyshos.com/fynedesk/wm" @@ -38,12 +39,9 @@ type client struct { // NewClient creates a new X11 client for the specified window ID and X window manager func NewClient(win xproto.Window, wm x11.XWM) x11.XWin { c := &client{win: win, wm: wm, desk: fynedesk.Instance().Desktop()} - err := xproto.ChangeWindowAttributesChecked(wm.Conn(), win, xproto.CwEventMask, + xproto.ChangeWindowAttributes(wm.Conn(), win, xproto.CwEventMask, []uint32{xproto.EventMaskPropertyChange | xproto.EventMaskEnterWindow | xproto.EventMaskLeaveWindow | - xproto.EventMaskVisibilityChange}).Check() - if err != nil { - fyne.LogError("Could not change window attributes", err) - } + xproto.EventMaskVisibilityChange}) windowAllowedActionsSet(wm.X(), win, x11.AllowedActions) initialHints := x11.WindowExtendedHintsGet(wm.X(), c.win) @@ -92,10 +90,7 @@ func (c *client) Close() { } if !askNicely { - err := xproto.DestroyWindowChecked(c.wm.Conn(), c.win).Check() - if err != nil { - fyne.LogError("Close Error", err) - } + xproto.DestroyWindow(c.wm.Conn(), c.win) return } @@ -118,10 +113,7 @@ func (c *client) Close() { return } - err = xproto.SendEventChecked(c.wm.Conn(), false, c.win, 0, string(cm.Bytes())).Check() - if err != nil { - fyne.LogError("Window Delete Error", err) - } + xproto.SendEvent(c.wm.Conn(), false, c.win, 0, string(cm.Bytes())) } func (c *client) Desktop() int { @@ -134,12 +126,20 @@ func (c *client) SetDesktop(id int) { } d := fynedesk.Instance() + diff := id - c.desk c.desk = id - if id == d.Desktop() { - c.Uniconify() - } else { - c.Iconify() - } + + _, height := d.RootSizePixels() + offPix := float32(diff * -int(height)) + display := d.Screens().ScreenForWindow(c) + off := offPix / display.Scale + + start := c.Position() + fyne.NewAnimation(canvas.DurationStandard, func(f float32) { + newY := start.Y + off*f + + c.Move(fyne.NewPos(start.X, newY)) + }).Start() } func (c *client) Expose() { @@ -202,6 +202,14 @@ func (c *client) Maximized() bool { return c.maximized } +func (c *client) Move(pos fyne.Position) { + screen := fynedesk.Instance().Screens().ScreenForWindow(c) + + targetX := int16(pos.X * screen.CanvasScale()) + targetY := int16(pos.Y * screen.CanvasScale()) + c.frame.updateGeometry(targetX, targetY, c.frame.width, c.frame.height, false) +} + func (c *client) NotifyBorderChange() { c.props.refreshCache() if c.Properties().Decorated() { @@ -316,11 +324,8 @@ func (c *client) RaiseAbove(win fynedesk.Window) { return } - err := xproto.ConfigureWindowChecked(c.wm.Conn(), c.id, xproto.ConfigWindowSibling|xproto.ConfigWindowStackMode, - []uint32{uint32(topID), uint32(xproto.StackModeAbove)}).Check() - if err != nil { - fyne.LogError("Restack Error", err) - } + xproto.ConfigureWindow(c.wm.Conn(), c.id, xproto.ConfigWindowSibling|xproto.ConfigWindowStackMode, + []uint32{uint32(topID), uint32(xproto.StackModeAbove)}) } func (c *client) RaiseToTop() { @@ -430,12 +435,9 @@ func (c *client) positionNewWindow() { decorated, fynedesk.Instance().Screens()) } - err = xproto.ConfigureWindowChecked(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, []uint32{uint32(x), uint32(y), - uint32(w), uint32(h)}).Check() - if err != nil { - fyne.LogError("", err) - } + uint32(w), uint32(h)}) } func (c *client) stateMessage(state int) { diff --git a/internal/x11/win/client_properties.go b/internal/x11/win/client_properties.go index d3578733..9b6a6c93 100644 --- a/internal/x11/win/client_properties.go +++ b/internal/x11/win/client_properties.go @@ -52,9 +52,11 @@ func (c *clientProperties) Icon() fyne.Resource { settings := fynedesk.Instance().Settings() iconSize := int(settings.LauncherIconSize() * settings.LauncherZoomScale()) xIcon := windowIcon(c.c.wm.X(), c.c.win, iconSize, iconSize) - if len(xIcon.Bytes()) != 0 { - c.iconCache = fyne.NewStaticResource(c.Title(), xIcon.Bytes()) + if xIcon == nil { + return nil } + + c.iconCache = fyne.NewStaticResource(c.Title(), xIcon.Bytes()) return c.iconCache } diff --git a/internal/x11/win/frame.go b/internal/x11/win/frame.go index 3cf7191b..5bcab777 100644 --- a/internal/x11/win/frame.go +++ b/internal/x11/win/frame.go @@ -155,12 +155,9 @@ func newFrame(c *client) *frame { } if full || maximized { - err = xproto.ConfigureWindowChecked(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(offsetX), uint32(offsetY), uint32(framed.childWidth), uint32(framed.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(offsetX), uint32(offsetY), uint32(framed.childWidth), uint32(framed.childHeight)}) } windowStateSet(c.wm.X(), c.win, icccm.StateNormal) @@ -194,20 +191,14 @@ func (f *frame) addBorder() { } f.applyTheme(true) - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(x), uint32(y), uint32(f.childWidth), uint32(f.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } - err = xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| + []uint32{uint32(x), uint32(y), uint32(f.childWidth), uint32(f.childHeight)}) + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(f.x), uint32(f.y), uint32(w), uint32(h)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(f.x), uint32(f.y), uint32(w), uint32(h)}) - err = ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: int(borderWidth), Right: int(borderWidth), Top: int(titleHeight), Bottom: int(borderWidth)}) + err := ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: int(borderWidth), Right: int(borderWidth), Top: int(titleHeight), Bottom: int(borderWidth)}) if err != nil { fyne.LogError("", err) } @@ -215,12 +206,9 @@ func (f *frame) addBorder() { } func (f *frame) applyBorderlessTheme() { - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(0), uint32(0), uint32(f.width), uint32(f.height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(0), uint32(0), uint32(f.width), uint32(f.height)}) } func (f *frame) applyTheme(force bool) { @@ -290,11 +278,8 @@ func (f *frame) copyDecorationPixels(width, height, xoff, yoff uint32, img image i += 4 } } - err := xproto.PutImageChecked(f.client.wm.Conn(), xproto.ImageFormatZPixmap, xproto.Drawable(pid), draw, - uint16(width), uint16(height), 0, int16(yoff), 0, depth, data).Check() - if err != nil { - fyne.LogError("Put image error", err) - } + xproto.PutImage(f.client.wm.Conn(), xproto.ImageFormatZPixmap, xproto.Drawable(pid), draw, + uint16(width), uint16(height), 0, int16(yoff), 0, depth, data) } func (f *frame) createPixmaps(depth byte) error { @@ -621,11 +606,8 @@ func (f *frame) mouseMotion(x, y int16) { if refresh { f.applyTheme(true) } - err := xproto.ChangeWindowAttributesChecked(f.client.wm.Conn(), f.client.id, xproto.CwCursor, - []uint32{uint32(cursor)}).Check() - if err != nil { - fyne.LogError("Set Cursor Error", err) - } + xproto.ChangeWindowAttributes(f.client.wm.Conn(), f.client.id, xproto.CwCursor, + []uint32{uint32(cursor)}) } func (f *frame) lookupResizeCursor(x, y int16) xproto.Cursor { @@ -802,20 +784,14 @@ func (f *frame) removeBorder() { } f.applyTheme(true) - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } - err = xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}) + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{0, 0, uint32(f.childWidth), uint32(f.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{0, 0, uint32(f.childWidth), uint32(f.childHeight)}) - err = ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: 0, Right: 0, Top: 0, Bottom: 0}) + err := ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: 0, Right: 0, Top: 0, Bottom: 0}) if err != nil { fyne.LogError("", err) } @@ -892,18 +868,12 @@ func (f *frame) updateGeometry(x, y int16, w, h uint16, force bool) { f.childWidth = uint16(innerW) f.childHeight = uint16(innerH) - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } - err = xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}) + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{innerX, innerY, uint32(f.childWidth), uint32(f.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{innerX, innerY, uint32(f.childWidth), uint32(f.childHeight)}) newScreen := fynedesk.Instance().Screens().ScreenForWindow(f.client) if newScreen != currentScreen { diff --git a/internal/x11/win/property.go b/internal/x11/win/property.go index 163de30d..a7b061b6 100644 --- a/internal/x11/win/property.go +++ b/internal/x11/win/property.go @@ -7,7 +7,6 @@ import ( "bytes" "math" - "fyne.io/fyne/v2" "github.com/BurntSushi/xgb/xproto" "github.com/BurntSushi/xgbutil" "github.com/BurntSushi/xgbutil/ewmh" @@ -16,6 +15,8 @@ import ( "github.com/BurntSushi/xgbutil/xgraphics" "github.com/BurntSushi/xgbutil/xprop" + "fyne.io/fyne/v2" + "fyshos.com/fynedesk" "fyshos.com/fynedesk/internal/x11" ) @@ -69,16 +70,18 @@ func windowCommand(x *xgbutil.XUtil, win xproto.Window) string { return command } -func windowIcon(x *xgbutil.XUtil, win xproto.Window, width int, height int) bytes.Buffer { - var w bytes.Buffer +func windowIcon(x *xgbutil.XUtil, win xproto.Window, width int, height int) *bytes.Buffer { img, err := xgraphics.FindIcon(x, win, width, height) if err != nil { - fyne.LogError("Could not get window icon", err) - return w + fyne.LogError("ICON: Could not get window icon", err) + return nil } - err = img.WritePng(&w) + + w := &bytes.Buffer{} + err = img.WritePng(w) if err != nil { - fyne.LogError("Could not convert icon to png", err) + fyne.LogError("ICON: Could not convert icon to png", err) + return nil } return w } diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index 8852683b..3b190a86 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -93,6 +93,8 @@ const ( keyCodeEnter = 108 keyCodeLeft = 113 keyCodeRight = 114 + keyCodeUp = 111 + keyCodeDown = 116 keyCodeBrightLess = 232 keyCodeBrightMore = 233 @@ -261,9 +263,34 @@ func (x *x11WM) ShowMenuOverlay(m *fyne.Menu, s fyne.Size, p fyne.Position) { pop.OnDismiss = win.Close pop.Show() pop.Resize(s) + go func() { + // TODO figure why sometimes this doesn't draw (size and minsize are correct) + // and then remove this workaround goroutine + time.Sleep(time.Second / 10) + pop.Resize(s) + time.Sleep(time.Second / 4) + pop.Resize(s) + }() x.ShowOverlay(win, s, p) } +func (x *x11WM) ShowModal(w fyne.Window, s fyne.Size) { + w.SetTitle(windowNameMenu) + w.SetFixedSize(true) + w.Resize(s) + w.CenterOnScreen() + + w.Show() + x.menuSize = s + + root := fynedesk.Instance().Screens().Primary() + scale := root.CanvasScale() + p := fyne.NewPos((float32(root.Width)/scale-s.Width)/2, (float32(root.Height)/scale-s.Height)/2) + + x.menuPos = p + x.menuWin = w +} + func (x *x11WM) X() *xgbutil.XUtil { return x.x } @@ -308,6 +335,10 @@ func (x *x11WM) keyNameToCode(n fyne.KeyName) xproto.Keycode { return keyCodeLeft case fyne.KeyRight: return keyCodeRight + case fyne.KeyUp: + return keyCodeUp + case fyne.KeyDown: + return keyCodeDown case deskDriver.KeyPrintScreen: return keyCodePrintScreen case fyne.KeyTab: @@ -461,20 +492,14 @@ func (x *x11WM) configureRoots() { xproto.SendEvent(x.x.Conn(), false, x.rootID, xproto.EventMaskStructureNotify, string(notifyEv.Bytes())) // we need to trigger a move so that the correct scale is picked up - err = xproto.ConfigureWindowChecked(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(screen.X + 1), uint32(screen.Y + 1), uint32(screen.Width - 2), uint32(screen.Height - 2)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(screen.X + 1), uint32(screen.Y + 1), uint32(screen.Width - 2), uint32(screen.Height - 2)}) // and then set the correct location - err = xproto.ConfigureWindowChecked(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(screen.X), uint32(screen.Y), uint32(screen.Width), uint32(screen.Height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(screen.X), uint32(screen.Y), uint32(screen.Width), uint32(screen.Height)}) } } @@ -530,12 +555,9 @@ func (x *x11WM) configureWindow(win xproto.Window, ev xproto.ConfigureRequestEve x.configureRoots() // we added a root window, so reconfigure return } - err := xproto.ConfigureWindowChecked(x.x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(xcoord), uint32(ycoord), uint32(width), uint32(height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(xcoord), uint32(ycoord), uint32(width), uint32(height)}) } func (x *x11WM) destroyWindow(win xproto.Window) { @@ -636,11 +658,8 @@ func (x *x11WM) setActiveScreenFromWindow(win fynedesk.Window) { } func (x *x11WM) setInitialWindowAttributes(win xproto.Window) { - err := xproto.ChangeWindowAttributesChecked(x.x.Conn(), win, xproto.CwCursor, - []uint32{uint32(x11.DefaultCursor)}).Check() - if err != nil { - fyne.LogError("Set Cursor Error", err) - } + xproto.ChangeWindowAttributes(x.x.Conn(), win, xproto.CwCursor, + []uint32{uint32(x11.DefaultCursor)}) } func (x *x11WM) setupBindings() { @@ -721,7 +740,7 @@ func (x *x11WM) showWindow(win xproto.Window, parent xproto.Window) { screen := fynedesk.Instance().Screens().Primary() w, h := x.menuSize.Width*screen.CanvasScale(), x.menuSize.Height*screen.CanvasScale() mx, my := screen.X+int(x.menuPos.X*screen.CanvasScale()), screen.Y+int(x.menuPos.Y*screen.CanvasScale()) - xproto.ConfigureWindowChecked(x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, []uint32{uint32(mx), uint32(my), uint32(w), uint32(h)}) diff --git a/internal/x11/wm/events.go b/internal/x11/wm/events.go index 1a9f51a3..b5420be0 100644 --- a/internal/x11/wm/events.go +++ b/internal/x11/wm/events.go @@ -45,11 +45,7 @@ func (x *x11WM) handleActiveWin(ev xproto.ClientMessageEvent) { } // ask for focus, when it is lost return to root window - err = xproto.SetInputFocusChecked(x.x.Conn(), 1, ev.Window, xproto.TimeCurrentTime).Check() - if err != nil { - fyne.LogError("Could not set focus", err) - return - } + xproto.SetInputFocus(x.x.Conn(), 1, ev.Window, xproto.TimeCurrentTime).Check() } if notifyFocus { protocolAtm, err := xprop.Atm(x.x, "WM_PROTOCOLS") @@ -228,11 +224,8 @@ func (x *x11WM) handleKeyRelease(ev xproto.KeyReleaseEvent) { } func (x *x11WM) handleMouseEnter(ev xproto.EnterNotifyEvent) { - err := xproto.ChangeWindowAttributesChecked(x.x.Conn(), ev.Event, xproto.CwCursor, - []uint32{uint32(x11.DefaultCursor)}).Check() - if err != nil { - fyne.LogError("Set Cursor Error", err) - } + xproto.ChangeWindowAttributes(x.x.Conn(), ev.Event, xproto.CwCursor, + []uint32{uint32(x11.DefaultCursor)}) if mouseNotify, ok := fynedesk.Instance().(notify.MouseNotify); ok { mouseNotify.MouseOutNotify() } @@ -241,8 +234,10 @@ func (x *x11WM) handleMouseEnter(ev xproto.EnterNotifyEvent) { func (x *x11WM) handleMouseLeave(ev xproto.LeaveNotifyEvent) { if ev.Event == x.menuID { // dismiss overlay menus on mouse out x.menuID = 0 - x.menuWin.Close() - x.menuWin = nil + if x.menuWin != nil { + x.menuWin.Close() + x.menuWin = nil + } } for _, c := range x.clients { diff --git a/modules/desktops/desktops.go b/modules/desktops/desktops.go index 4d518a6a..ca4fce6e 100644 --- a/modules/desktops/desktops.go +++ b/modules/desktops/desktops.go @@ -20,6 +20,11 @@ type desktops struct { gui *pager } +func (d *desktops) DesktopChangeNotify(id int) { + d.current = id + d.gui.refresh() +} + func (d *desktops) Destroy() { } @@ -37,13 +42,13 @@ func (d *desktops) Shortcuts() map[*fynedesk.Shortcut]func() { } } - mapping[&fynedesk.Shortcut{Name: "Switch to Previous Desktop", KeyName: fyne.KeyLeft, Modifier: fynedesk.UserModifier}] = func() { + mapping[&fynedesk.Shortcut{Name: "Switch to Previous Desktop", KeyName: fyne.KeyUp, Modifier: fynedesk.UserModifier}] = func() { if d.current == 0 { return } d.setDesktop(d.current - 1) } - mapping[&fynedesk.Shortcut{Name: "Switch to Next Desktop", KeyName: fyne.KeyRight, Modifier: fynedesk.UserModifier}] = func() { + mapping[&fynedesk.Shortcut{Name: "Switch to Next Desktop", KeyName: fyne.KeyDown, Modifier: fynedesk.UserModifier}] = func() { if d.current == deskCount-1 { return } diff --git a/modules/systray/generated/notifier/status_notifier_item.go b/modules/systray/generated/notifier/status_notifier_item.go index 6afbdb08..227025d9 100644 --- a/modules/systray/generated/notifier/status_notifier_item.go +++ b/modules/systray/generated/notifier/status_notifier_item.go @@ -317,7 +317,8 @@ func (o *StatusNotifierItem) GetIconName(ctx context.Context) (iconName string, // GetIconPixmap gets org.kde.StatusNotifierItem.IconPixmap property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector +// +// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector func (o *StatusNotifierItem) GetIconPixmap(ctx context.Context) (iconPixmap []struct { V0 int32 V1 int32 @@ -336,7 +337,8 @@ func (o *StatusNotifierItem) GetOverlayIconName(ctx context.Context) (overlayIco // GetOverlayIconPixmap gets org.kde.StatusNotifierItem.OverlayIconPixmap property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector +// +// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector func (o *StatusNotifierItem) GetOverlayIconPixmap(ctx context.Context) (overlayIconPixmap []struct { V0 int32 V1 int32 @@ -355,7 +357,8 @@ func (o *StatusNotifierItem) GetAttentionIconName(ctx context.Context) (attentio // GetAttentionIconPixmap gets org.kde.StatusNotifierItem.AttentionIconPixmap property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector +// +// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector func (o *StatusNotifierItem) GetAttentionIconPixmap(ctx context.Context) (attentionIconPixmap []struct { V0 int32 V1 int32 diff --git a/modules/systray/generated/watcher/status_notifier_watcher.go b/modules/systray/generated/watcher/status_notifier_watcher.go index 4e9832db..7a8dbd80 100644 --- a/modules/systray/generated/watcher/status_notifier_watcher.go +++ b/modules/systray/generated/watcher/status_notifier_watcher.go @@ -188,7 +188,8 @@ func (o *StatusNotifierWatcher) RegisterStatusNotifierHost(ctx context.Context, // GetRegisteredStatusNotifierItems gets org.kde.StatusNotifierWatcher.RegisteredStatusNotifierItems property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName.Out0 = QStringList +// +// @org.qtproject.QtDBus.QtTypeName.Out0 = QStringList func (o *StatusNotifierWatcher) GetRegisteredStatusNotifierItems(ctx context.Context) (registeredStatusNotifierItems []string, err error) { err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierWatcher, "RegisteredStatusNotifierItems").Store(®isteredStatusNotifierItems) return diff --git a/modules/systray/main.go b/modules/systray/main.go index 643b1058..08cf8f65 100644 --- a/modules/systray/main.go +++ b/modules/systray/main.go @@ -11,7 +11,6 @@ import ( "image" "image/color" "image/png" - "io/ioutil" "log" "os" "path/filepath" @@ -22,17 +21,18 @@ import ( "github.com/godbus/dbus/v5/introspect" "github.com/godbus/dbus/v5/prop" - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/container" - deskDriver "fyne.io/fyne/v2/driver/desktop" - "fyne.io/fyne/v2/theme" - "fyne.io/fyne/v2/widget" "fyshos.com/fynedesk" "fyshos.com/fynedesk/internal/icon" "fyshos.com/fynedesk/modules/systray/generated/menu" "fyshos.com/fynedesk/modules/systray/generated/notifier" "fyshos.com/fynedesk/modules/systray/generated/watcher" wmtheme "fyshos.com/fynedesk/theme" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + deskDriver "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const ( @@ -56,14 +56,19 @@ type tray struct { menu *menu.Dbusmenu box *fyne.Container - nodes map[dbus.Sender]*widget.Button + nodes map[dbus.Sender]*node +} + +type node struct { + ico *widget.Button + ni *notifier.StatusNotifierItem } // NewTray creates a new module that will show a system tray in the status area func NewTray() fynedesk.Module { iconSize := wmtheme.NarrowBarWidth grid := container.New(collapsingGridWrap(fyne.NewSize(iconSize, iconSize))) - t := &tray{box: grid, nodes: make(map[dbus.Sender]*widget.Button)} + t := &tray{box: grid, nodes: make(map[dbus.Sender]*node)} conn, _ := dbus.ConnectSessionBus() t.conn = conn @@ -116,6 +121,7 @@ func NewTray() fynedesk.Module { } watchErr := t.conn.AddMatchSignal(dbus.WithMatchInterface("org.freedesktop.DBus"), dbus.WithMatchObjectPath("/org/freedesktop/DBus")) + _ = t.conn.AddMatchSignal(dbus.WithMatchInterface("org.kde.StatusNotifierItem")) if watchErr != nil { fyne.LogError("Failed to monitor systray name loss", watchErr) return t @@ -125,19 +131,25 @@ func NewTray() fynedesk.Module { t.conn.Signal(c) go func() { for v := range c { - if v.Name != "org.freedesktop.DBus.NameOwnerChanged" { + switch v.Name { + case "org.freedesktop.DBus.NameOwnerChanged": + name := v.Body[0] + newOwner := v.Body[2] + if newOwner == "" { + if item, ok := t.nodes[dbus.Sender(name.(string))]; ok { + t.box.Remove(item.ico) + t.box.Refresh() + } + } + case "org.kde.StatusNotifierItem.NewIcon": + item, ok := t.nodes[dbus.Sender(v.Sender)] + if ok { + t.updateIcon(item) + } + default: log.Println("Also", v.Name) continue } - - name := v.Body[0] - newOwner := v.Body[2] - if newOwner == "" { - if item, ok := t.nodes[dbus.Sender(name.(string))]; ok { - t.box.Remove(item) - t.box.Refresh() - } - } } }() @@ -150,8 +162,9 @@ func (t *tray) Destroy() { func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (err *dbus.Error) { ni := notifier.NewStatusNotifierItem(t.conn.Object(string(sender), dbus.ObjectPath(service))) - ico, ok := t.nodes[sender] + item, ok := t.nodes[sender] if !ok { + var ico *widget.Button ico = widget.NewButton("", func() { if m, err := ni.GetMenu(t.conn.Context()); err == nil { t.showMenu(string(sender), m, ico) @@ -164,40 +177,13 @@ func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (e } }) ico.Importance = widget.LowImportance - t.nodes[sender] = ico + item = &node{ico, ni} + t.nodes[sender] = item t.box.Add(ico) } - ic, _ := ni.GetIconPixmap(t.conn.Context()) - if len(ic) > 0 { - img := pixelsToImage(ic[0]) - unique := strconv.Itoa(resourceID) + ".png" - resourceID++ - w := &bytes.Buffer{} - _ = png.Encode(w, img) - ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) - } else { - name, _ := ni.GetIconName(t.conn.Context()) - path, _ := ni.GetIconThemePath(t.conn.Context()) - fullPath := "" - if path != "" { - fullPath = filepath.Join(path, name+".png") - if _, err := os.Stat(fullPath); err != nil { // not found, search instead - fullPath = icon.FdoLookupIconPathInTheme("64", filepath.Join(path, "hicolor"), "", name) - } - } else { - fullPath = icon.FdoLookupIconPath("", 64, name) - } - img, err := ioutil.ReadFile(fullPath) - if err != nil { - fyne.LogError("Failed to load status icon", err) - ico.SetIcon(wmtheme.BrokenImageIcon) - } else { - ico.SetIcon(fyne.NewStaticResource(name, img)) - } - } - - ico.Refresh() + t.nodes[sender].ni = ni + t.updateIcon(item) t.box.Refresh() return nil @@ -316,6 +302,37 @@ func (t *tray) showMenu(sender string, name dbus.ObjectPath, from fyne.CanvasObj fynedesk.Instance().WindowManager().ShowOverlay(w, size, pos) } +func (t *tray) updateIcon(i *node) { + ic, _ := i.ni.GetIconPixmap(t.conn.Context()) + if len(ic) > 0 { + img := pixelsToImage(ic[0]) + unique := strconv.Itoa(resourceID) + ".png" + resourceID++ + w := &bytes.Buffer{} + _ = png.Encode(w, img) + i.ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) + } else { + name, _ := i.ni.GetIconName(t.conn.Context()) + path, _ := i.ni.GetIconThemePath(t.conn.Context()) + fullPath := "" + if path != "" { + fullPath = filepath.Join(path, name+".png") + if _, err := os.Stat(fullPath); err != nil { // not found, search instead + fullPath = icon.FdoLookupIconPathInTheme("64", filepath.Join(path, "hicolor"), "", name) + } + } else { + fullPath = icon.FdoLookupIconPath("", 64, name) + } + img, err := os.ReadFile(fullPath) + if err != nil { + fyne.LogError("Failed to load status icon", err) + i.ico.SetIcon(wmtheme.BrokenImageIcon) + } else { + i.ico.SetIcon(fyne.NewStaticResource(name, img)) + } + } +} + func createPropSpec() map[string]map[string]*prop.Prop { return map[string]map[string]*prop.Prop{ "org.kde.StatusNotifierWatcher": { diff --git a/test/desktop.go b/test/desktop.go index 7a10e3d1..af53ac11 100644 --- a/test/desktop.go +++ b/test/desktop.go @@ -45,7 +45,12 @@ func (*Desktop) Capture() image.Image { // ContentBoundsPixels returns a default value for how much space maximised apps should use func (*Desktop) ContentBoundsPixels(_ *fynedesk.Screen) (x, y, w, h uint32) { - return 0, 0, uint32(320), uint32(240) + return 0, 0, 320, 240 +} + +// RootSizePixels returns the total number of pixels required to fit all the screens +func (*Desktop) RootSizePixels() (w, h uint32) { + return 320, 240 } // Desktop returns the index of the current desktop (in test this is always 0) diff --git a/test/window.go b/test/window.go index f518d801..1842f6a3 100644 --- a/test/window.go +++ b/test/window.go @@ -3,8 +3,9 @@ package test import ( "image" - "fyne.io/fyne/v2" "fyshos.com/fynedesk" + + "fyne.io/fyne/v2" ) // Window is an in-memory virtual window for test purposes @@ -80,6 +81,9 @@ func (w *Window) Maximized() bool { return false } +// Move the window, does nothing in test windows +func (w *Window) Move(fyne.Position) {} + // Parent returns a window that this should be positioned within, if set. func (w *Window) Parent() fynedesk.Window { return w.parent diff --git a/window.go b/window.go index 1c5c6758..0761655a 100644 --- a/window.go +++ b/window.go @@ -30,6 +30,7 @@ type Window interface { Parent() Window Properties() WindowProperties // Request the properties set on this window Position() fyne.Position + Move(position fyne.Position) Desktop() int SetDesktop(int) diff --git a/wm.go b/wm.go index 9e8eee88..366f631a 100644 --- a/wm.go +++ b/wm.go @@ -17,6 +17,7 @@ type WindowManager interface { Run() ShowOverlay(fyne.Window, fyne.Size, fyne.Position) ShowMenuOverlay(*fyne.Menu, fyne.Size, fyne.Position) + ShowModal(fyne.Window, fyne.Size) } // Stack describes an ordered list of windows. diff --git a/wm/auth.go b/wm/auth.go new file mode 100644 index 00000000..ff8f01ce --- /dev/null +++ b/wm/auth.go @@ -0,0 +1,164 @@ +package wm + +import ( + "bytes" + "fmt" + "image/color" + "log" + "os" + "os/exec" + "os/user" + "sync" + + "fyshos.com/fynedesk" + wmTheme "fyshos.com/fynedesk/theme" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + deskDriver "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + + "github.com/godbus/dbus/v5" +) + +type subj struct { + Kind string + Details map[string]dbus.Variant +} + +type auth struct { + windows map[string]fyne.Window +} + +func (a *auth) register() { + conn2, _ := dbus.SystemBus() + err := conn2.ExportAll(a, "/AuthenticationAgent", "org.freedesktop.PolicyKit1.AuthenticationAgent") + if err != nil { + fyne.LogError("Could not start auth agent server", err) + } + + obj := conn2.Object("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority") + call := obj.Call("org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent", 0, + + &subj{"unix-session", map[string]dbus.Variant{ + "session-id": dbus.MakeVariant("c1"), + }}, "en_US", + "/AuthenticationAgent") + if call.Err != nil { + fyne.LogError("Failed to register auth agent", call.Err) + } +} + +type ident struct { + ID string + Details map[string]dbus.Variant +} + +func (a *auth) BeginAuthentication(actionID, message, iconName string, details map[string]string, cookie string, ids []ident, sender dbus.Sender) (err *dbus.Error) { + wg := &sync.WaitGroup{} + wg.Add(1) + pass := widget.NewPasswordEntry() + + username := "" + uid := "" + _, err2 := fmt.Sscanf(ids[0].Details["uid"].String(), "@u %s", &uid) + if err2 != nil { + currentUser, err2 := user.Current() + if err2 == nil { + username = currentUser.Username + } else { + fyne.LogError("Failed to look up fallback user", err2) + } + } else { + usr, err2 := user.LookupId(uid) + if err2 == nil { + username = usr.Username + } else { + fyne.LogError("Failed to look up user "+uid, err2) + } + } + f := widget.NewForm( + widget.NewFormItem("Ident", widget.NewLabel(username)), + widget.NewFormItem("Password", pass), + ) + w := fyne.CurrentApp().Driver().(deskDriver.Driver).CreateSplashWindow() + a.windows[cookie] = w + + var auth *widget.Button + auth = widget.NewButton("Authorize", func() { + auth.Disable() + cmd := exec.Command("/usr/lib/polkit-1/polkit-agent-helper-1", username) + + buffer := bytes.Buffer{} + buffer.Write([]byte(cookie + "\n")) + buffer.Write([]byte(pass.Text + "\n")) + cmd.Stdin = &buffer + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err3 := cmd.Run() + + if err3 != nil { + log.Println("Auth err", err3) + } else { + w.Close() + } + auth.Enable() + }) + auth.Importance = widget.HighImportance + cancel := widget.NewButton("Cancel", func() { + w.Close() + }) + pass.OnSubmitted = func(string) { + auth.OnTapped() + } + + header := widget.NewRichTextFromMarkdown(fmt.Sprintf("### Authorise\n\n_%s_", message)) + header.Truncation = fyne.TextTruncateEllipsis + bottomPad := canvas.NewRectangle(color.Transparent) + bottomPad.SetMinSize(fyne.NewSquareSize(10)) + content := container.NewBorder( + header, + container.NewVBox( + container.NewHBox(layout.NewSpacer(), + container.NewGridWithColumns(2, cancel, auth), + layout.NewSpacer()), bottomPad), + nil, nil, f) + + r, g, b, _ := theme.OverlayBackgroundColor().RGBA() + bgCol := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230} + + bg := canvas.NewRectangle(bgCol) + icon := canvas.NewImageFromResource(wmTheme.LockIcon) + iconBox := container.NewWithoutLayout(icon) + icon.Resize(fyne.NewSize(92, 92)) + icon.Move(fyne.NewPos(300-92-theme.Padding(), theme.Padding())) + w.SetContent(container.NewStack( + iconBox, bg, + container.NewPadded(content))) + + w.SetOnClosed(func() { + delete(a.windows, cookie) + wg.Done() + }) + fynedesk.Instance().WindowManager().ShowModal(w, fyne.NewSize(300, 210)) + + wg.Wait() + return nil +} + +func (a *auth) CancelAuthentication(cookie string, sender dbus.Sender) (err *dbus.Error) { + if w, ok := a.windows[cookie]; ok { + w.Close() // OnClose will tidy the session + } + return nil +} + +// StartAuthAgent asks our policy kit agent to start listening for auth requests. +func StartAuthAgent() { + a := &auth{windows: make(map[string]fyne.Window)} + go a.register() +} diff --git a/wm/border.go b/wm/border.go index 88f46e06..b9530dad 100644 --- a/wm/border.go +++ b/wm/border.go @@ -33,10 +33,6 @@ func NewBorder(win fynedesk.Window, icon fyne.Resource, canMaximize bool) *Borde if app != nil { icon = app.Icon(iconTheme, int(wmTheme.TitleHeight*2)) } - - if icon == nil { - icon = wmTheme.BrokenImageIcon - } } max := &widget.Button{Icon: wmTheme.MaximizeIcon, Importance: widget.LowImportance, OnTapped: func() { @@ -188,6 +184,7 @@ func (c *Border) CreateRenderer() fyne.WidgetRenderer { // SetIcon tells the border to change the icon that should be used func (c *Border) SetIcon(icon fyne.Resource) { if icon == nil { + c.appIcon.Icon = nil return }