2002-11-02 20:50:27

by Petr Baudis

[permalink] [raw]
Subject: [PATCH] Extended selection API

Hello,

this patch (against 2.5.45) extends the selection interface, so that userland
programs can directly save the data into the buffer and fetch them from it.
This way, it is possible for userland programs to handle cutting and pasting on
their own (not necessarily working with the screen content and getting the
content of the selection on stdin) or to implement shared selection buffer
between X11 and console etc.

This patch is roughly based on some very ancient diff I found lying on my
disk, however unfortunately I can't remember anymore who implemented this idea
originally; I made a lot of changes to the original patch anyway.

I wrote a trivial commandline-driven userland interface for this in order to
demonstrate the functionality. It is attached and it can be also found at
http://pasky.ji.cz/~pasky/dev/kernel/chsel.c.

Note that it's possibly totally flawed (I don't know anything about this
piece of code), but it looks to work ok. Please review, test and comment.

Kind regards,
Petr Baudis

--- linux-2.5.45/include/linux/selection.h Sat Nov 2 18:31:31 2002
+++ linux-2.5.45+pasky/include/linux/selection.h Sat Nov 2 19:18:40 2002
@@ -18,6 +18,9 @@
extern int mouse_reporting(void);
extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);

+extern int set_selection_user(const unsigned long arg);
+extern int get_selection_user(const unsigned long arg);
+
#define video_num_columns (vc_cons[currcons].d->vc_cols)
#define video_num_lines (vc_cons[currcons].d->vc_rows)
#define video_size_row (vc_cons[currcons].d->vc_size_row)
--- linux-2.5.45/drivers/char/vt.c Sat Nov 2 18:31:12 2002
+++ linux-2.5.45+pasky/drivers/char/vt.c Sat Nov 2 19:17:27 2002
@@ -2255,6 +2255,12 @@
case 12: /* get fg_console */
ret = fg_console;
break;
+ case 13: /* set selection to data provided by user */
+ ret = set_selection_user(arg);
+ break;
+ case 14: /* get selection */
+ ret = get_selection_user(arg);
+ break;
default:
ret = -EINVAL;
break;
--- linux-2.5.45/drivers/char/selection.c Sat Nov 2 18:31:22 2002
+++ linux-2.5.45+pasky/drivers/char/selection.c Sat Nov 2 20:20:30 2002
@@ -7,8 +7,13 @@
* 'void clear_selection(void)'
* 'int paste_selection(struct tty_struct *tty)'
* 'int sel_loadlut(const unsigned long arg)'
+ * 'int get_selection_user(const unsigned long arg)'
+ * 'int set_selection_user(const unsigned long arg)'
*
* Now that /dev/vcs exists, most of this can disappear again.
+ *
+ * Introduced usable userland selection interface
+ * 2002-11-02 Petr Baudis <[email protected]>
*/

#include <linux/module.h>
@@ -310,5 +315,75 @@
return 0;
}

+/* Fill the current selection buffer with the data provided in user buffer.
+ * The maximal size of the selection buffer is trimmed to 65535 here; could
+ * anyone possibly want more?
+ * Invoked by ioctl(). */
+int set_selection_user(const unsigned long arg)
+{
+ unsigned int buf_length;
+ char *new_sel_buffer = NULL;
+ char *args;
+
+ clear_selection();
+
+ args = (char *) (arg + 1);
+ get_user(buf_length, (unsigned int *) args);
+ args += sizeof(unsigned int);
+
+ if (buf_length > 0 && buf_length < 65536) {
+ new_sel_buffer = kmalloc(buf_length, GFP_KERNEL);
+ if (!new_sel_buffer) {
+ printk(KERN_WARNING "selection: kmalloc() failed\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(new_sel_buffer, (char *) args, buf_length)){
+ kfree(new_sel_buffer);
+ return -EFAULT;
+ }
+ } else if (buf_length) {
+ return -EINVAL;
+ }
+
+ if (sel_buffer)
+ kfree(sel_buffer);
+
+ sel_buffer = new_sel_buffer;
+ sel_buffer_lth = buf_length;
+
+ return 0;
+}
+
+/* Get (start of) content of the current selection buffer. Users should
+ * re-fetch if return_value > buf_length.
+ * Invoked by ioctl(). */
+int get_selection_user(const unsigned long arg)
+{
+ unsigned int buf_length;
+ char *args;
+
+ args = (char *) (arg + 1);
+ get_user(buf_length, (unsigned int *) args);
+ if (buf_length > sel_buffer_lth) {
+ buf_length = sel_buffer_lth;
+ if (copy_to_user((char *) args, &buf_length,
+ sizeof(unsigned int))) {
+ return -EFAULT;
+ }
+ }
+ args += sizeof(unsigned int);
+
+ if (!sel_buffer)
+ return 0;
+
+ if (copy_to_user((char *) args, sel_buffer, buf_length)) {
+ return -EFAULT;
+ }
+
+ return sel_buffer_lth;
+}
+
EXPORT_SYMBOL(set_selection);
EXPORT_SYMBOL(paste_selection);
+EXPORT_SYMBOL(set_selection_user);
+EXPORT_SYMBOL(get_selection_user);


Attachments:
(No filename) (4.37 kB)
chsel.c (2.28 kB)
Download all attachments