From 28f5c6154ec461b61c96d4bbfdc62a53414f9841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Capello?= Date: Fri, 8 Sep 2023 15:33:56 -0300 Subject: [PATCH] Add a new clip::has() function that allows to specify an error handling function avoiding the use of the default one This is introduced because sometimes the caller might want to handle the locking error that might arise in a different way than the current error handler does. Related to: aseprite/aseprite#4016 --- clip.cpp | 17 +++++++++++- clip.h | 42 ++++++++++++++++++++---------- clip_lock_impl.h | 67 ++++++++++++++++++++++++------------------------ clip_none.cpp | 5 +++- clip_osx.mm | 5 +++- clip_win.cpp | 13 ++++------ clip_x11.cpp | 14 ++++++---- 7 files changed, 100 insertions(+), 63 deletions(-) diff --git a/clip.cpp b/clip.cpp index bd221fc..06e0902 100644 --- a/clip.cpp +++ b/clip.cpp @@ -27,7 +27,14 @@ void default_error_handler(ErrorCode code) { error_handler g_error_handler = default_error_handler; lock::lock(void* native_window_handle) - : p(new impl(native_window_handle)) { + : lock(get_error_handler(), 5, 20, native_window_handle) { +} + +lock::lock(error_handler e, int tries, int sleepms, void* native_window_handle) + : p(new impl(native_window_handle, tries, sleepms)) { + if (!p->locked() && e) { + e(ErrorCode::CannotLock); + } } lock::~lock() = default; @@ -80,6 +87,14 @@ bool has(format f) { return false; } +bool has(format f, error_handler e, int tries, int sleepms) { + lock l(e, tries, sleepms); + if (l.locked()) + return l.is_convertible(f); + else + return false; +} + bool clear() { lock l; if (l.locked()) diff --git a/clip.h b/clip.h index bf3c9fd..7d448b0 100644 --- a/clip.h +++ b/clip.h @@ -24,6 +24,22 @@ namespace clip { class image; struct image_spec; + // ====================================================================== + // Error handling + // ====================================================================== + + enum class ErrorCode { + CannotLock, + ImageNotSupported, + }; + + typedef void (*error_handler)(ErrorCode code); + + void set_error_handler(error_handler f); + error_handler get_error_handler(); + + #define OMIT_LOCKING_ERROR nullptr + class lock { public: // You can give your current HWND as the "native_window_handle." @@ -33,6 +49,12 @@ namespace clip { // EmptyClipboard() call. Anyway it looks to work just fine if we // call OpenClipboard() with a null HWND. lock(void* native_window_handle = nullptr); + // Creates a lock where you can specify an error handler to use + // when the clipboad implementation requires locking it first and + // we couldn't get the lock. Also, we can specify the number of + // times we want to try to get the clipboard lock and how many + // milliseconds we want to wait between tries. + lock(error_handler e, int tries, int sleepms, void* native_window_handle = nullptr); ~lock(); // Returns true if we've locked the clipboard successfully in @@ -75,22 +97,14 @@ namespace clip { // Returns true if the clipboard has content of the given type. bool has(format f); - // Clears the clipboard content. - bool clear(); + // The same as has(format f) but you can specify an error handler when the + // clipboard cannot be locked, along with the number of locking tries and + // waiting period between tries. + bool has(format f, error_handler e, int tries, int sleepms); - // ====================================================================== - // Error handling - // ====================================================================== - enum class ErrorCode { - CannotLock, - ImageNotSupported, - }; - - typedef void (*error_handler)(ErrorCode code); - - void set_error_handler(error_handler f); - error_handler get_error_handler(); + // Clears the clipboard content. + bool clear(); // ====================================================================== // Text diff --git a/clip_lock_impl.h b/clip_lock_impl.h index 3f08af7..c2d5fa5 100644 --- a/clip_lock_impl.h +++ b/clip_lock_impl.h @@ -1,33 +1,34 @@ -// Clip Library -// Copyright (c) 2015-2018 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#ifndef CLIP_LOCK_IMPL_H_INCLUDED -#define CLIP_LOCK_IMPL_H_INCLUDED - -namespace clip { - -class lock::impl { -public: - impl(void* native_window_handle); - ~impl(); - - bool locked() const { return m_locked; } - bool clear(); - bool is_convertible(format f) const; - bool set_data(format f, const char* buf, size_t len); - bool get_data(format f, char* buf, size_t len) const; - size_t get_data_length(format f) const; - bool set_image(const image& image); - bool get_image(image& image) const; - bool get_image_spec(image_spec& spec) const; - -private: - bool m_locked; -}; - -} // namespace clip - -#endif +// Clip Library +// Copyright (c) 2015-2018 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef CLIP_LOCK_IMPL_H_INCLUDED +#define CLIP_LOCK_IMPL_H_INCLUDED + +namespace clip { + +class lock::impl { +public: + impl(void* native_window_handle); + impl(void* native_window_handle, int tries, int sleepms); + ~impl(); + + bool locked() const { return m_locked; } + bool clear(); + bool is_convertible(format f) const; + bool set_data(format f, const char* buf, size_t len); + bool get_data(format f, char* buf, size_t len) const; + size_t get_data_length(format f) const; + bool set_image(const image& image); + bool get_image(image& image) const; + bool get_image_spec(image_spec& spec) const; + +private: + bool m_locked; +}; + +} // namespace clip + +#endif diff --git a/clip_none.cpp b/clip_none.cpp index f4cc40c..74732e9 100644 --- a/clip_none.cpp +++ b/clip_none.cpp @@ -19,7 +19,10 @@ typedef std::map Map; static format g_last_format = 100; // TODO create an enum with common formats static Map g_data; -lock::impl::impl(void* native_handle) : m_locked(true) { +lock::impl::impl(void*, int tries, int sleepms) : m_locked(true) { +} + +lock::impl::impl(void* native_handle) : impl(native_handle, 0, 0) { } lock::impl::~impl() { diff --git a/clip_osx.mm b/clip_osx.mm index 52683b8..742000b 100644 --- a/clip_osx.mm +++ b/clip_osx.mm @@ -132,7 +132,10 @@ bool get_image_from_clipboard(image* output_img, } -lock::impl::impl(void*) : m_locked(true) { +lock::impl::impl(void*, int tries, int sleepms) : m_locked(true) { +} + +lock::impl::impl(void*) : impl(nullptr, 0, 0) { } lock::impl::~impl() { diff --git a/clip_win.cpp b/clip_win.cpp index d03a798..1145cfd 100644 --- a/clip_win.cpp +++ b/clip_win.cpp @@ -207,20 +207,17 @@ struct BitmapInfo { } -lock::impl::impl(void* hwnd) : m_locked(false) { - for (int i=0; i<5; ++i) { +lock::impl::impl(void* hwnd, int tries, int sleepms) : m_locked(false) { + for (int i = 0; i < tries; ++i) { if (OpenClipboard((HWND)hwnd)) { m_locked = true; break; } - Sleep(20); + Sleep(sleepms); } +} - if (!m_locked) { - error_handler e = get_error_handler(); - if (e) - e(ErrorCode::CannotLock); - } +lock::impl::impl(void* hwnd) : impl(hwnd, 5, 20) { } lock::impl::~impl() { diff --git a/clip_x11.cpp b/clip_x11.cpp index 842105b..ad4bc3a 100644 --- a/clip_x11.cpp +++ b/clip_x11.cpp @@ -123,7 +123,7 @@ class Manager { if (x11_clipboard_manager) { // We have to lock the m_lock mutex that will be used to wait // the m_cv condition in get_data_from_selection_owner(). - if (try_lock()) { + if (try_lock(5, 20)) { // Start the SAVE_TARGETS mechanism so the X11 // CLIPBOARD_MANAGER will save our clipboard data // from now on. @@ -148,13 +148,13 @@ class Manager { xcb_disconnect(m_connection); } - bool try_lock() { + bool try_lock(int tries, int sleepms) { bool res = m_lock.try_lock(); if (!res) { // TODO make this configurable (the same for Windows retries) - for (int i=0; i<5 && !res; ++i) { + for (int i=0; itry_lock(tries, sleepms); +} + lock::impl::impl(void*) : m_locked(false) { - m_locked = get_manager()->try_lock(); + m_locked = get_manager()->try_lock(5, 20); } lock::impl::~impl() {