Skip to content

Commit

Permalink
Add a new clip::has() function that allows to specify an error handling
Browse files Browse the repository at this point in the history
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
  • Loading branch information
martincapello committed Sep 8, 2023
1 parent f56e458 commit 28f5c61
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 63 deletions.
17 changes: 16 additions & 1 deletion clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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())
Expand Down
42 changes: 28 additions & 14 deletions clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
67 changes: 34 additions & 33 deletions clip_lock_impl.h
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion clip_none.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ typedef std::map<format, Buffer> 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() {
Expand Down
5 changes: 4 additions & 1 deletion clip_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
13 changes: 5 additions & 8 deletions clip_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
14 changes: 9 additions & 5 deletions clip_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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; i<tries && !res; ++i) {
res = m_lock.try_lock();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::this_thread::sleep_for(std::chrono::milliseconds(sleepms));
}
}
return res;
Expand Down Expand Up @@ -1045,8 +1045,12 @@ Manager* get_manager() {

} // anonymous namespace

lock::impl::impl(void*, int tries, int sleepms) : m_locked(false) {
m_locked = get_manager()->try_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() {
Expand Down

0 comments on commit 28f5c61

Please sign in to comment.