diff --git a/core/.pre-commit-config.yaml b/core/.pre-commit-config.yaml index a5c48005..126e5f59 100644 --- a/core/.pre-commit-config.yaml +++ b/core/.pre-commit-config.yaml @@ -2,6 +2,15 @@ repos: - repo: https://github.com/golangci/golangci-lint rev: v2.6.2 hooks: - - id: golangci-lint-full - id: golangci-lint-fmt + require_serial: true + - id: golangci-lint-full - id: golangci-lint-config-verify + - repo: local + hooks: + - id: go-test + name: go test + entry: go test ./... + language: system + pass_filenames: false + types: [go] diff --git a/core/internal/server/clipboard/manager.go b/core/internal/server/clipboard/manager.go index a49f14e6..3d40851d 100644 --- a/core/internal/server/clipboard/manager.go +++ b/core/internal/server/clipboard/manager.go @@ -241,7 +241,30 @@ func (m *Manager) setupDataDeviceSync() { m.mimeTypes = mimes - go m.storeCurrentClipboard() + if len(mimes) == 0 { + return + } + + preferredMime := m.selectMimeType(mimes) + if preferredMime == "" { + return + } + + typedOffer := offer.(*ext_data_control.ExtDataControlOfferV1) + + r, w, err := os.Pipe() + if err != nil { + return + } + + if err := typedOffer.Receive(preferredMime, int(w.Fd())); err != nil { + r.Close() + w.Close() + return + } + w.Close() + + go m.readAndStore(r, preferredMime) }) if err := dataMgr.GetDataDeviceWithProxy(dataDevice, m.seat); err != nil { @@ -259,28 +282,24 @@ func (m *Manager) setupDataDeviceSync() { log.Info("Data device setup complete") } -func (m *Manager) storeCurrentClipboard() { - if m.currentOffer == nil { - return - } +func (m *Manager) readAndStore(r *os.File, mimeType string) { + defer r.Close() cfg := m.getConfig() - offer := m.currentOffer.(*ext_data_control.ExtDataControlOfferV1) + done := make(chan []byte, 1) + go func() { + data, _ := io.ReadAll(r) + done <- data + }() - if len(m.mimeTypes) == 0 { + var data []byte + select { + case data = <-done: + case <-time.After(500 * time.Millisecond): return } - preferredMime := m.selectMimeType(m.mimeTypes) - if preferredMime == "" { - preferredMime = m.mimeTypes[0] - } - - data, err := m.receiveData(offer, preferredMime) - if err != nil { - return - } if len(data) == 0 || int64(len(data)) > cfg.MaxEntrySize { return } @@ -289,7 +308,7 @@ func (m *Manager) storeCurrentClipboard() { } if !cfg.DisableHistory && m.db != nil { - m.storeClipboardEntry(data, preferredMime) + m.storeClipboardEntry(data, mimeType) } m.updateState() @@ -471,8 +490,9 @@ func (m *Manager) selectMimeType(mimes []string) string { "TEXT", "image/png", "image/jpeg", - "image/bmp", "image/gif", + "image/bmp", + "image/tiff", } for _, pref := range preferredTypes { @@ -483,6 +503,10 @@ func (m *Manager) selectMimeType(mimes []string) string { } } + if len(mimes) > 0 { + return mimes[0] + } + return "" } @@ -490,42 +514,6 @@ func (m *Manager) isImageMimeType(mime string) bool { return strings.HasPrefix(mime, "image/") } -func (m *Manager) receiveData(offer *ext_data_control.ExtDataControlOfferV1, mimeType string) ([]byte, error) { - r, w, err := os.Pipe() - if err != nil { - return nil, err - } - defer r.Close() - - receiveErr := make(chan error, 1) - m.post(func() { - err := offer.Receive(mimeType, int(w.Fd())) - w.Close() - receiveErr <- err - }) - - if err := <-receiveErr; err != nil { - return nil, err - } - - type result struct { - data []byte - err error - } - done := make(chan result, 1) - go func() { - data, err := io.ReadAll(r) - done <- result{data, err} - }() - - select { - case res := <-done: - return res.data, res.err - case <-time.After(500 * time.Millisecond): - return nil, fmt.Errorf("timeout reading clipboard data") - } -} - func (m *Manager) textPreview(data []byte) string { text := string(data) text = strings.TrimSpace(text) diff --git a/core/internal/server/clipboard/manager_test.go b/core/internal/server/clipboard/manager_test.go index 8c3aeb61..b6645bb9 100644 --- a/core/internal/server/clipboard/manager_test.go +++ b/core/internal/server/clipboard/manager_test.go @@ -334,8 +334,10 @@ func TestSelectMimeType(t *testing.T) { }{ {[]string{"text/plain;charset=utf-8", "text/html"}, "text/plain;charset=utf-8"}, {[]string{"text/html", "text/plain"}, "text/plain"}, - {[]string{"application/json", "image/png"}, "image/png"}, - {[]string{"application/json", "application/xml"}, ""}, + {[]string{"text/html", "image/png"}, "image/png"}, + {[]string{"image/png", "image/jpeg"}, "image/png"}, + {[]string{"image/png"}, "image/png"}, + {[]string{"application/octet-stream"}, "application/octet-stream"}, {[]string{}, ""}, }