-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclipboard.c
148 lines (123 loc) · 4.69 KB
/
clipboard.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* Copyright (C) 2016 Richard Burke
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include "clipboard.h"
#include "external_command.h"
#define CLIPBOARD_CMD "wed-clipboard"
#define CLIPBOARD_CMD_USABLE CLIPBOARD_CMD " --usable"
#define CLIPBOARD_CMD_COPY CLIPBOARD_CMD " --copy"
#define CLIPBOARD_CMD_PASTE CLIPBOARD_CMD " --paste"
void cl_init(Clipboard *clipboard)
{
memset(clipboard, 0, sizeof(Clipboard));
int cmd_status;
Status status = ec_run_command(CLIPBOARD_CMD_USABLE, NULL, NULL, NULL,
&cmd_status);
if (STATUS_IS_SUCCESS(status) && ec_cmd_successfull(cmd_status)) {
clipboard->type = CT_EXTERNAL;
} else {
clipboard->type = CT_INTERNAL;
}
}
void cl_free(Clipboard *clipboard)
{
if (clipboard->type == CT_INTERNAL) {
bf_free_textselection(&clipboard->text_selection);
}
}
/* TODO use function pointers rather than if-else chain
* Also add support for multiple internal clipboards - can be unlimited if
* we allow arbitrary names */
Status cl_copy(Clipboard *clipboard, Buffer *buffer)
{
Status status = STATUS_SUCCESS;
Range range;
if (!bf_get_range(buffer, &range)) {
return status;
}
if (clipboard->type == CT_INTERNAL) {
status = bf_copy_selected_text(buffer, &clipboard->text_selection);
} else if (clipboard->type == CT_EXTERNAL) {
BufferInputStream bis;
RETURN_IF_FAIL(bf_get_buffer_input_stream(&bis, buffer, &range));
int cmd_status;
status = ec_run_command(CLIPBOARD_CMD_COPY, (InputStream *)&bis,
NULL, NULL, &cmd_status);
bis.is.close((InputStream *)&bis);
RETURN_IF_FAIL(status);
if (!ec_cmd_successfull(cmd_status)) {
status = st_get_error(ERR_CLIPBOARD_ERROR,
"Unable to copy to system clipboard");
}
}
return status;
}
Status cl_paste(Clipboard *clipboard, Buffer *buffer)
{
Status status = STATUS_SUCCESS;
if (clipboard->type == CT_INTERNAL) {
if (clipboard->text_selection.str != NULL) {
status = bf_insert_textselection(buffer,
&clipboard->text_selection, 1);
}
} else if (clipboard->type == CT_EXTERNAL) {
BufferOutputStream bos;
RETURN_IF_FAIL(
bf_get_buffer_output_stream(&bos, buffer, &buffer->pos, 0)
);
Status status = bc_start_grouped_changes(&buffer->changes);
int cmd_status;
if (STATUS_IS_SUCCESS(status)) {
status = ec_run_command(CLIPBOARD_CMD_PASTE, NULL,
(OutputStream *)&bos, NULL, &cmd_status);
}
bos.os.close((OutputStream *)&bos);
bc_end_grouped_changes(&buffer->changes);
RETURN_IF_FAIL(status);
if (!ec_cmd_successfull(cmd_status)) {
status = st_get_error(ERR_CLIPBOARD_ERROR,
"Unable to paste from system clipboard");
} else {
bp_advance_to_offset(&buffer->pos, bos.write_pos.offset);
}
}
return status;
}
/* Cut is not really a direct clipboard action, but exposing the functionality
* in this way is convenient and consistent with the functions above.
* Whether the clipboard entity should be tied so closely to the buffer entity
* is another question worth considering i.e. what if we don't want to
* copy/paste from/to a buffer? Should {Input,Output}Streams be passed
* instead? */
Status cl_cut(Clipboard *clipboard, Buffer *buffer)
{
Status status = STATUS_SUCCESS;
Range range;
if (!bf_get_range(buffer, &range)) {
return status;
}
if (clipboard->type == CT_INTERNAL) {
status = bf_cut_selected_text(buffer, &clipboard->text_selection);
} else if (clipboard->type == CT_EXTERNAL) {
status = cl_copy(clipboard, buffer);
if (STATUS_IS_SUCCESS(status)) {
status = bf_delete_range(buffer, &range);
}
}
return status;
}