mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-07 04:10:27 -08:00
* lisp/term/haiku-win.el (haiku-selection-targets): Fix return values. (gui-backend-get-selection): Handle TIMESTAMP specially. * src/haiku_select.cc (be_get_clipboard_count): New function. * src/haikuselect.c (Fhaiku_selection_timestamp): New function. (syms_of_haikuselect): Add new defsubr. * src/haikuselect.h: Update prototypes.
519 lines
9.9 KiB
C++
519 lines
9.9 KiB
C++
/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*-
|
|
Copyright (C) 2021-2022 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 <https://www.gnu.org/licenses/>. */
|
|
|
|
#include <config.h>
|
|
|
|
#include <Application.h>
|
|
#include <Clipboard.h>
|
|
#include <Message.h>
|
|
#include <Path.h>
|
|
#include <Entry.h>
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#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 ();
|
|
}
|