summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clipfs.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/clipfs.c b/clipfs.c
index 10a7dcb..b602947 100644
--- a/clipfs.c
+++ b/clipfs.c
@@ -16,6 +16,13 @@ struct selection
xcb_atom_t atom;
};
+enum Status
+{
+ STATUS_TARGETS,
+ STATUS_SELECTION,
+ STATUS_DONE,
+};
+
int get_selection_index(const char *);
xcb_window_t find_owner(int);
void update_selection(int);
@@ -83,15 +90,20 @@ xcb_window_t find_owner(const int i)
void update_selection(const int i)
{
- xcb_atom_t TARGET_PROPERTY = get_atom(c, "_TARGET_SELECTION");
- xcb_atom_t UTF8_STRING = get_atom(c, "UTF8_STRING"); // TODO: Look into ways to support various TARGETS.
+ const xcb_atom_t PROPERTY = get_atom(c, "_RECEIVED_SELECTION"); // TODO: Get intern atoms beforehand.
+ const xcb_atom_t PNG = get_atom(c, "image/png");
+ const xcb_atom_t JPG = get_atom(c, "image/jpg");
+ const xcb_atom_t PIXMAP = get_atom(c, "PIXMAP"); // TODO: Format of this one depends on the application.
+ const xcb_atom_t UTF8_STRING = get_atom(c, "UTF8_STRING");
+ const xcb_atom_t TARGETS = get_atom(c, "TARGETS"); // TODO-multiple: MULTIPLE?
if (XCB_WINDOW_NONE == find_owner(i))
return;
- xcb_convert_selection(c, w, x[i].atom, UTF8_STRING, TARGET_PROPERTY, XCB_CURRENT_TIME);
+ xcb_convert_selection(c, w, x[i].atom, TARGETS, PROPERTY, XCB_CURRENT_TIME);
xcb_flush(c);
+ xcb_atom_t target = UTF8_STRING;
xcb_generic_event_t * e;
- int done = 0; // TODO: Look into continuous notifications.
- while (!done)
+ int status = STATUS_TARGETS; // TODO: Look into continuous notifications.
+ while (STATUS_DONE != status)
{
e = xcb_wait_for_event(c);
if (NULL == e) return;
@@ -104,17 +116,42 @@ void update_selection(const int i)
if (x[i].atom == n->selection && XCB_NONE != n->property)
{
xcb_get_property_cookie_t cookie = xcb_get_property(
- c, 1, w, TARGET_PROPERTY, XCB_ATOM_ANY, 0, UINT32_MAX);
+ c, 1, w, PROPERTY, XCB_ATOM_ANY, 0, UINT32_MAX);
xcb_get_property_reply_t * reply = xcb_get_property_reply(c, cookie, NULL);
if (reply)
{
- const int len = xcb_get_property_value_length(reply);
- x[i].data = realloc(x[i].data, len);
- if (NULL == x[i].data)
- x[i].len = 0;
- x[i].len = len;
- memcpy(x[i].data, xcb_get_property_value(reply), len);
- done = 1;
+ const unsigned len = xcb_get_property_value_length(reply);
+ xcb_atom_t * atoms;
+ switch (status)
+ {
+ case STATUS_TARGETS:
+ atoms = (xcb_atom_t *) xcb_get_property_value(reply);
+ for (unsigned j = 0; j < len / sizeof(xcb_atom_t); ++j)
+ { // TODO: Find a way to get original format?
+ if (JPG != target && PNG == atoms[j])
+ target = PNG;
+ if (JPG == atoms[j])
+ target = JPG;
+ if (PNG != target && JPG != target && PIXMAP == atoms[j])
+ target = PIXMAP;
+ }
+ xcb_convert_selection(c, w, x[i].atom, target, PROPERTY, XCB_CURRENT_TIME);
+ xcb_flush(c);
+ status = STATUS_SELECTION;
+ break;
+ case STATUS_SELECTION:
+ if (NULL == x[i].data && len != x[i].len)
+ x[i].data = realloc(x[i].data, len);
+ if (NULL == x[i].data)
+ x[i].len = 0;
+ x[i].len = len;
+ memcpy(x[i].data, xcb_get_property_value(reply), len);
+ status = STATUS_DONE;
+ break;
+ case STATUS_DONE:
+ default:
+ break; // Unreachable
+ }
free(reply);
}
}
@@ -175,10 +212,12 @@ int clip_readdir(
int clip_open(const char * path, struct fuse_file_info * fi)
{
- if (-ENOENT == get_selection_index(path))
+ const int i = get_selection_index(path);
+ if (-ENOENT == i)
return -ENOENT;
if (O_RDONLY != (fi->flags & O_ACCMODE))
return -EACCES;
+ update_selection(i); // TODO: The content is updated way too often.
return 0; // TODO: Maybe queue selection content retrieval here?
}
@@ -189,7 +228,6 @@ int clip_read(const char * path, char * buf, size_t size, off_t offset, struct f
const int i = get_selection_index(path);
if (-ENOENT == i)
return -ENOENT;
- update_selection(i); // TODO: The content is updated way too often.
if (offset < x[i].len)
{
if (offset + size > x[i].len)