/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*- Copyright (C) 2021-2023 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include #include #include #include #include #include #include #include #include "haikuselect.h" /* The clipboard object representing the primary selection. */ static BClipboard *primary = NULL; /* The clipboard object representing the secondary selection. */ static BClipboard *secondary = NULL; /* The clipboard object used by other programs, representing the clipboard. */ static BClipboard *system_clipboard = NULL; /* The number of times the system clipboard has changed. */ static int64 count_clipboard = -1; /* The number of times the primary selection has changed. */ static int64 count_primary = -1; /* The number of times the secondary selection has changed. */ static int64 count_secondary = -1; /* Whether or not we currently think Emacs owns the primary selection. */ static bool owned_primary; /* Likewise for the secondary selection. */ static bool owned_secondary; /* And the clipboard. */ static bool owned_clipboard; static BClipboard * get_clipboard_object (enum haiku_clipboard clipboard) { switch (clipboard) { case CLIPBOARD_PRIMARY: return primary; case CLIPBOARD_SECONDARY: return secondary; case CLIPBOARD_CLIPBOARD: return system_clipboard; } abort (); } static char * be_find_clipboard_data_1 (BClipboard *cb, const char *type, ssize_t *len) { BMessage *data; const char *ptr; ssize_t nbytes; void *value; if (!cb->Lock ()) return NULL; data = cb->Data (); if (!data) { cb->Unlock (); return NULL; } data->FindData (type, B_MIME_TYPE, (const void **) &ptr, &nbytes); if (!ptr) { cb->Unlock (); return NULL; } if (len) *len = nbytes; value = malloc (nbytes); if (!data) { cb->Unlock (); return NULL; } memcpy (value, ptr, nbytes); cb->Unlock (); return (char *) value; } static void be_set_clipboard_data_1 (BClipboard *cb, const char *type, const char *data, ssize_t len, bool clear) { BMessage *message_data; if (!cb->Lock ()) return; if (clear) cb->Clear (); message_data = cb->Data (); if (!message_data) { cb->Unlock (); return; } if (data) { if (message_data->ReplaceData (type, B_MIME_TYPE, data, len) == B_NAME_NOT_FOUND) message_data->AddData (type, B_MIME_TYPE, data, len); } else message_data->RemoveName (type); cb->Commit (); cb->Unlock (); } void be_update_clipboard_count (enum haiku_clipboard id) { switch (id) { case CLIPBOARD_CLIPBOARD: count_clipboard = system_clipboard->SystemCount (); owned_clipboard = true; break; case CLIPBOARD_PRIMARY: count_primary = primary->SystemCount (); owned_primary = true; break; case CLIPBOARD_SECONDARY: count_secondary = secondary->SystemCount (); owned_secondary = true; break; } } char * be_find_clipboard_data (enum haiku_clipboard id, const char *type, ssize_t *len) { return be_find_clipboard_data_1 (get_clipboard_object (id), type, len); } void be_set_clipboard_data (enum haiku_clipboard id, const char *type, const char *data, ssize_t len, bool clear) { be_update_clipboard_count (id); be_set_clipboard_data_1 (get_clipboard_object (id), type, data, len, clear); } static bool clipboard_owner_p (void) { return (count_clipboard >= 0 && (count_clipboard + 1 == system_clipboard->SystemCount ())); } static bool primary_owner_p (void) { return (count_primary >= 0 && (count_primary + 1 == primary->SystemCount ())); } static bool secondary_owner_p (void) { return (count_secondary >= 0 && (count_secondary + 1 == secondary->SystemCount ())); } bool be_clipboard_owner_p (enum haiku_clipboard clipboard) { switch (clipboard) { case CLIPBOARD_PRIMARY: return primary_owner_p (); case CLIPBOARD_SECONDARY: return secondary_owner_p (); case CLIPBOARD_CLIPBOARD: return clipboard_owner_p (); } abort (); } void be_clipboard_init (void) { system_clipboard = new BClipboard ("system"); primary = new BClipboard ("primary"); secondary = new BClipboard ("secondary"); } int be_enum_message (void *message, int32 *tc, int32 index, int32 *count, const char **name_return) { BMessage *msg = (BMessage *) message; type_code type; char *name; status_t rc; rc = msg->GetInfo (B_ANY_TYPE, index, &name, &type, count); if (rc != B_OK) return 1; *tc = type; *name_return = name; return 0; } int be_get_refs_data (void *message, const char *name, int32 index, char **path_buffer) { status_t rc; BEntry entry; BPath path; entry_ref ref; BMessage *msg; msg = (BMessage *) message; rc = msg->FindRef (name, index, &ref); if (rc != B_OK) return 1; rc = entry.SetTo (&ref, 0); if (rc != B_OK) return 1; rc = entry.GetPath (&path); if (rc != B_OK) return 1; *path_buffer = strdup (path.Path ()); return 0; } int be_get_point_data (void *message, const char *name, int32 index, float *x, float *y) { status_t rc; BMessage *msg; BPoint point; msg = (BMessage *) message; rc = msg->FindPoint (name, index, &point); if (rc != B_OK) return 1; *x = point.x; *y = point.y; return 0; } int be_get_message_data (void *message, const char *name, int32 type_code, int32 index, const void **buf_return, ssize_t *size_return) { BMessage *msg = (BMessage *) message; return msg->FindData (name, type_code, index, buf_return, size_return) != B_OK; } uint32 be_get_message_type (void *message) { BMessage *msg = (BMessage *) message; return msg->what; } void be_set_message_type (void *message, uint32 what) { BMessage *msg = (BMessage *) message; msg->what = what; } void * be_get_message_message (void *message, const char *name, int32 index) { BMessage *msg = (BMessage *) message; BMessage *out = new (std::nothrow) BMessage; if (!out) return NULL; if (msg->FindMessage (name, index, out) != B_OK) { delete out; return NULL; } return out; } void * be_create_simple_message (void) { return new BMessage (B_SIMPLE_DATA); } int be_add_message_data (void *message, const char *name, int32 type_code, const void *buf, ssize_t buf_size) { BMessage *msg = (BMessage *) message; return msg->AddData (name, type_code, buf, buf_size) != B_OK; } int be_add_refs_data (void *message, const char *name, const char *filename) { BEntry entry (filename); entry_ref ref; BMessage *msg = (BMessage *) message; if (entry.InitCheck () != B_OK) return 1; if (entry.GetRef (&ref) != B_OK) return 1; return msg->AddRef (name, &ref) != B_OK; } int be_add_point_data (void *message, const char *name, float x, float y) { BMessage *msg = (BMessage *) message; return msg->AddPoint (name, BPoint (x, y)) != B_OK; } int be_add_message_message (void *message, const char *name, void *data) { BMessage *msg = (BMessage *) message; BMessage *data_message = (BMessage *) data; if (msg->AddMessage (name, data_message) != B_OK) return 1; return 0; } int be_lock_clipboard_message (enum haiku_clipboard clipboard, void **message_return, bool clear) { BClipboard *board; board = get_clipboard_object (clipboard); if (!board->Lock ()) return 1; if (clear) board->Clear (); *message_return = board->Data (); return 0; } void be_unlock_clipboard (enum haiku_clipboard clipboard, bool discard) { BClipboard *board; board = get_clipboard_object (clipboard); if (discard) board->Revert (); else board->Commit (); board->Unlock (); } void be_handle_clipboard_changed_message (void) { int64 n_clipboard, n_primary, n_secondary; n_clipboard = system_clipboard->SystemCount (); n_primary = primary->SystemCount (); n_secondary = secondary->SystemCount (); if (count_clipboard != -1 && (n_clipboard > count_clipboard + 1) && owned_clipboard) { owned_clipboard = false; haiku_selection_disowned (CLIPBOARD_CLIPBOARD, n_clipboard); } if (count_primary != -1 && (n_primary > count_primary + 1) && owned_primary) { owned_primary = false; haiku_selection_disowned (CLIPBOARD_PRIMARY, n_primary); } if (count_secondary != -1 && (n_secondary > count_secondary + 1) && owned_secondary) { owned_secondary = false; haiku_selection_disowned (CLIPBOARD_SECONDARY, n_secondary); } } void be_start_watching_selection (enum haiku_clipboard id) { BClipboard *clipboard; clipboard = get_clipboard_object (id); clipboard->StartWatching (be_app); } bool be_selection_outdated_p (enum haiku_clipboard id, int64 count) { if (id == CLIPBOARD_CLIPBOARD && count_clipboard > count) return true; if (id == CLIPBOARD_PRIMARY && count_primary > count) return true; if (id == CLIPBOARD_SECONDARY && count_secondary > count) return true; return false; } int64 be_get_clipboard_count (enum haiku_clipboard id) { BClipboard *clipboard; clipboard = get_clipboard_object (id); return clipboard->SystemCount (); }