summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actions.c23
-rw-r--r--src/actions.h3
-rw-r--r--src/data.h6
-rw-r--r--src/editor.c146
-rw-r--r--src/events.c81
-rw-r--r--src/globals.c146
-rw-r--r--src/globals.h9
-rw-r--r--src/main.c1
-rw-r--r--src/ratpoison.h2
-rw-r--r--src/sbuf.c11
-rw-r--r--src/sbuf.h1
11 files changed, 311 insertions, 118 deletions
diff --git a/src/actions.c b/src/actions.c
index 92e16c4..acda13e 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -125,14 +125,15 @@ static user_command user_commands[] =
{"cprev", cmd_cprev, arg_VOID},
{"dedicate", cmd_dedicate, arg_VOID},
{"describekey", cmd_describekey, arg_STRING},
- {"focusprev", cmd_prev_frame, arg_VOID},
{"inext", cmd_inext, arg_VOID},
{"iother", cmd_iother, arg_VOID},
{"iprev", cmd_iprev, arg_VOID},
- {"prompt", cmd_prompt, arg_STRING},
+ {"prompt", cmd_prompt, arg_STRING},
{"sdump", cmd_sdump, arg_VOID},
{"sfdump", cmd_sfdump, arg_VOID},
{"undo", cmd_undo, arg_STRING},
+ {"putsel", cmd_putsel, arg_STRING},
+ {"getsel", cmd_getsel, arg_STRING},
/*@end (tag required for genrpbindings) */
/* Commands to help debug ratpoison. */
@@ -4973,3 +4974,21 @@ cmd_dedicate (int interactive, char *data)
return NULL;
}
+char *
+cmd_putsel (int interactive, char *data)
+{
+ if (data == NULL)
+ {
+ message ("putsel: one argument required");
+ return NULL;
+ }
+
+ set_selection(data);
+ return NULL;
+}
+
+char *
+cmd_getsel (int interactive, char *data)
+{
+ return get_selection();
+}
diff --git a/src/actions.h b/src/actions.h
index 028edf1..e046aa9 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -141,9 +141,10 @@ char *cmd_prompt (int interactive, char *data);
char *cmd_sdump (int interactive, char *data);
char *cmd_sfdump (int interactively, char *data);
char *cmd_undo (int interactive, char *data);
+char *cmd_putsel (int interactive, char *data);
+char *cmd_getsel (int interactive, char *data);
void pop_frame_undo (rp_frame_undo *u);
-
rp_keymap *find_keymap (char *name);
void initialize_default_keybindings (void);
void keymap_free (rp_keymap *map);
diff --git a/src/data.h b/src/data.h
index 81a3edb..7ebb72b 100644
--- a/src/data.h
+++ b/src/data.h
@@ -340,5 +340,11 @@ struct rp_frame_undo
struct list_head node;
};
+typedef struct rp_xselection rp_xselection;
+struct rp_xselection
+{
+ unsigned char *text;
+ int len;
+};
#endif /* _RATPOISON_DATA_H */
diff --git a/src/editor.c b/src/editor.c
index 3a36291..6f312e0 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -257,6 +257,7 @@ static edit_status
editor_kill_word (rp_input_line *line)
{
int i, diff;
+
if (line->position < line->length)
{
@@ -265,6 +266,9 @@ editor_kill_word (rp_input_line *line)
diff = i - line->position;
+ /* Add the word to the X11 selection. */
+ set_nselection (&line->buffer[line->position], diff);
+
for (i = line->position; i <= line->length - diff; i++)
line->buffer[i] = line->buffer[i + diff];
@@ -288,6 +292,9 @@ editor_backward_kill_word (rp_input_line *line)
line->position = i;
+ /* Add the word to the X11 selection. */
+ set_nselection (&line->buffer[line->position], diff);
+
for (; i <= line->length - diff; i++)
line->buffer[i] = line->buffer[i + diff];
@@ -302,6 +309,9 @@ editor_kill_line (rp_input_line *line)
{
if (line->position < line->length)
{
+ /* Add the line to the X11 selection. */
+ set_selection (&line->buffer[line->position]);
+
line->length = line->position;
line->buffer[line->length] = 0;
}
@@ -309,19 +319,33 @@ editor_kill_line (rp_input_line *line)
return EDIT_DELETE;
}
-static edit_status
-editor_backward_kill_line (rp_input_line *line)
+/* Do the dirty work of killing a line backwards. */
+static void
+backward_kill_line (rp_input_line *line)
{
int i;
+ /* If we're at the beginning, we have nothing to do. */
if (line->position <= 0)
- return EDIT_NO_OP;
+ return;
for (i = line->position; i<= line->length; i++)
line->buffer[i - line->position] = line->buffer[i];
line->length -= line->position;
line->position = 0;
+}
+
+static edit_status
+editor_backward_kill_line (rp_input_line *line)
+{
+ if (line->position <= 0)
+ return EDIT_NO_OP;
+
+ /* Add the line to the X11 selection. */
+ set_nselection (line->buffer, line->position);
+
+ backward_kill_line (line);
return EDIT_DELETE;
}
@@ -469,118 +493,18 @@ editor_enter (rp_input_line *line)
}
static edit_status
-paste_cut_buffer (rp_input_line *line)
-{
- int nbytes;
- char *data;
- edit_status status;
-
- PRINT_DEBUG (("trying the cut buffer\n"));
-
- data = XFetchBytes (dpy, &nbytes);
-
- if (data)
- {
-/* status = editor_insert (line, data, nbytes); */
- status = editor_insert (line, data);
- XFree (data);
- }
- else
- {
- status = EDIT_NO_OP;
- }
-
- return status;
-}
-
-static edit_status
-paste_primary_selection (rp_input_line *line)
-{
- Atom actual_type;
- rp_screen *s = current_screen ();
- int actual_format;
- unsigned long nitems;
- unsigned long offset;
- unsigned long bytes_after;
- unsigned char *data;
-
- if (XGetWindowProperty (dpy, s->input_window, rp_selection, 0, 0, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &data) == Success)
- {
- if (data)
- {
- XFree (data);
- data = NULL;
- }
-
- PRINT_DEBUG (("actual_type = %ld, actual_format = %d, bytes_after = %ld\n", actual_type, actual_format, bytes_after));
-
- if (actual_type != XA_STRING || actual_format != 8)
- {
- PRINT_DEBUG (("selection data is invalid\n"));
- if (data)
- XFree (data);
- return EDIT_NO_OP;
- }
-
- offset = 0;
-
- while (bytes_after > 0)
- {
- if (XGetWindowProperty (dpy, s->input_window, rp_selection, offset / 4, bytes_after / 4 + 1, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &data) != Success)
- break;
-
- PRINT_DEBUG (("bytes_after = %ld, nitems = %ld, data = '%s'\n", bytes_after, nitems, data));
-
- nitems *= actual_format / 8;
- offset += nitems;
-
-/* editor_insert (line, data, nitems); */
- editor_insert (line, (char *)data);
-
- PRINT_DEBUG (("bytes_after = %ld, nitems = %ld, data = '%s'\n", bytes_after, nitems, data));
-
- XFree (data);
- }
- }
-
- /* notify the owner that the data has been transferred */
- XDeleteProperty(dpy, s->input_window, rp_selection);
-
- return EDIT_INSERT;
-}
-
-static edit_status
editor_paste_selection (rp_input_line *line)
{
- Atom property;
- XEvent ev;
- rp_screen *s = current_screen ();
- int loops = 1000;
-
- /* be a good icccm citizen */
- XDeleteProperty (dpy, s->input_window, rp_selection);
- /* TODO: we shouldn't use CurrentTime here, use the time of the XKeyEvent, should we fake it? */
- XConvertSelection (dpy, XA_PRIMARY, XA_STRING, rp_selection, s->input_window, CurrentTime);
-
- while (!XCheckTypedWindowEvent (dpy, s->input_window, SelectionNotify, &ev))
+ char *text;
+ text = get_selection();
+ if (text)
{
- if (loops == 0)
- {
- PRINT_ERROR (("selection request timed out\n"));
- return EDIT_NO_OP;
- }
- usleep (10000);
- loops--;
+ editor_insert(line, text);
+ free (text);
+ return EDIT_INSERT;
}
-
- PRINT_DEBUG (("SelectionNotify event\n"));
-
- property = ev.xselection.property;
-
- if (property != None)
- return paste_primary_selection (line);
else
- return paste_cut_buffer (line);
+ return EDIT_NO_OP;
}
static edit_status
@@ -604,7 +528,7 @@ editor_complete (rp_input_line *line, int direction)
return EDIT_NO_OP;
/* Insert the completion. */
- editor_backward_kill_line (line);
+ backward_kill_line (line);
editor_insert (line, s);
return EDIT_COMPLETE;
diff --git a/src/events.c b/src/events.c
index 00ebb0a..ce11485 100644
--- a/src/events.c
+++ b/src/events.c
@@ -24,6 +24,7 @@
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
+#include <X11/Xmd.h> /* for CARD32. */
#include <stdio.h>
#include <stdlib.h>
@@ -674,6 +675,76 @@ mapping_notify (XMappingEvent *ev)
}
}
+/* This is called whan an application has requested the
+ selection. Copied from rxvt. */
+static void
+selection_request (XSelectionRequestEvent *rq)
+{
+ XEvent ev;
+ CARD32 target_list[4];
+ Atom target;
+ static Atom xa_targets = None;
+ static Atom xa_compound_text = None;
+ static Atom xa_text = None;
+ XTextProperty ct;
+ XICCEncodingStyle style;
+ char *cl[4];
+
+ if (xa_text == None)
+ xa_text = XInternAtom(dpy, "TEXT", False);
+ if (xa_compound_text == None)
+ xa_compound_text = XInternAtom(dpy, "COMPOUND_TEXT", False);
+ if (xa_targets == None)
+ xa_targets = XInternAtom(dpy, "TARGETS", False);
+
+ ev.xselection.type = SelectionNotify;
+ ev.xselection.property = None;
+ ev.xselection.display = rq->display;
+ ev.xselection.requestor = rq->requestor;
+ ev.xselection.selection = rq->selection;
+ ev.xselection.target = rq->target;
+ ev.xselection.time = rq->time;
+
+ if (rq->target == xa_targets) {
+ target_list[0] = (CARD32) xa_targets;
+ target_list[1] = (CARD32) XA_STRING;
+ target_list[2] = (CARD32) xa_text;
+ target_list[3] = (CARD32) xa_compound_text;
+ XChangeProperty(dpy, rq->requestor, rq->property, rq->target,
+ (8 * sizeof(target_list[0])), PropModeReplace,
+ (unsigned char *)target_list,
+ (sizeof(target_list) / sizeof(target_list[0])));
+ ev.xselection.property = rq->property;
+ } else if (rq->target == XA_STRING
+ || rq->target == xa_compound_text
+ || rq->target == xa_text) {
+ if (rq->target == XA_STRING) {
+ style = XStringStyle;
+ target = XA_STRING;
+ } else {
+ target = xa_compound_text;
+ style = (rq->target == xa_compound_text) ? XCompoundTextStyle
+ : XStdICCTextStyle;
+ }
+ cl[0] = selection.text;
+ XmbTextListToTextProperty(dpy, cl, 1, style, &ct);
+ XChangeProperty(dpy, rq->requestor, rq->property,
+ target, 8, PropModeReplace,
+ ct.value, ct.nitems);
+ ev.xselection.property = rq->property;
+ }
+ XSendEvent(dpy, rq->requestor, False, 0, &ev);
+}
+
+static void
+selection_clear ()
+{
+ if (selection.text)
+ free (selection.text);
+ selection.text = NULL;
+ selection.len = 0;
+}
+
/* Given an event, call the correct function to handle it. */
static void
delegate_event (XEvent *ev)
@@ -740,6 +811,14 @@ delegate_event (XEvent *ev)
mapping_notify( &ev->xmapping );
break;
+ case SelectionRequest:
+ selection_request(&ev->xselectionrequest);
+ break;
+
+ case SelectionClear:
+ selection_clear();
+ break;
+
case ConfigureNotify:
case MapNotify:
case Expose:
@@ -747,9 +826,7 @@ delegate_event (XEvent *ev)
case KeyRelease:
case ReparentNotify:
case EnterNotify:
- case SelectionRequest:
case SelectionNotify:
- case SelectionClear:
case CirculateRequest:
/* Ignore these events. */
break;
diff --git a/src/globals.c b/src/globals.c
index bc369ae..a76f220 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -20,6 +20,8 @@
#include "ratpoison.h"
+#include <unistd.h> /* for usleep(). */
+
int alarm_signalled = 0;
int kill_signalled = 0;
int hup_signalled = 0;
@@ -70,6 +72,143 @@ char *rp_error_msg = NULL;
/* Global frame numset */
struct numset *rp_frame_numset;
+/* The X11 selection globals */
+rp_xselection selection;
+
+static void
+x_export_selection ()
+{
+ /* Hang the selections off screen 0's key window. */
+ XSetSelectionOwner(dpy, XA_PRIMARY, screens[0].key_window, CurrentTime);
+ if (XGetSelectionOwner(dpy, XA_PRIMARY) != screens[0].key_window)
+ PRINT_ERROR(("can't get primary selection"));
+ XChangeProperty(dpy, screens[0].root, XA_CUT_BUFFER0, XA_STRING, 8,
+ PropModeReplace, selection.text, selection.len);
+}
+
+void
+set_nselection (char *txt, int len)
+{
+ int i;
+
+ /* Update the selection structure */
+ if (selection.text != NULL)
+ free(selection.text);
+
+ /* Copy the string by hand. */
+ selection.text = malloc(len+1);
+ selection.len = len + 1;
+ for (i=0; i<len; i++)
+ selection.text[i] = txt[i];
+ selection.text[len] = 0;
+
+ x_export_selection();
+}
+
+void
+set_selection (char *txt)
+{
+ /* Update the selection structure */
+ if (selection.text != NULL)
+ free(selection.text);
+ selection.text = xstrdup (txt);
+ selection.len = strlen (txt);
+
+ x_export_selection();
+}
+
+static char *
+get_cut_buffer ()
+{
+ int nbytes;
+ char *data;
+
+ PRINT_DEBUG (("trying the cut buffer\n"));
+
+ data = XFetchBytes (dpy, &nbytes);
+
+ if (data)
+ {
+ struct sbuf *s = sbuf_new (0);
+ sbuf_nconcat (s, data, nbytes);
+ XFree (data);
+ return sbuf_free_struct (s);
+ }
+ else
+ return NULL;
+}
+
+/* Lifted the code from rxvt. */
+static char *
+get_primary_selection()
+{
+ long nread;
+ unsigned long bytes_after;
+ XTextProperty ct;
+ struct sbuf *s = sbuf_new(0);
+
+ for (nread = 0, bytes_after = 1; bytes_after > 0; nread += ct.nitems) {
+ if ((XGetWindowProperty(dpy, current_screen()->input_window, rp_selection, (nread / 4), 4096,
+ True, AnyPropertyType, &ct.encoding,
+ &ct.format, &ct.nitems, &bytes_after,
+ &ct.value) != Success)) {
+ XFree(ct.value);
+ sbuf_free(s);
+ return NULL;
+ }
+ if (ct.value == NULL)
+ continue;
+ /* Accumulate the data. FIXME: ct.value may not be NULL
+ terminated. */
+ sbuf_nconcat (s, ct.value, ct.nitems);
+ XFree(ct.value);
+ }
+ return sbuf_free_struct (s);
+}
+
+char *
+get_selection ()
+{
+ Atom property;
+ XEvent ev;
+ rp_screen *s = current_screen ();
+ int loops = 1000;
+
+ /* Just insert our text, if we own the selection. */
+ if (selection.text)
+ {
+ return xstrdup (selection.text);
+ }
+ else
+ {
+ /* be a good icccm citizen */
+ XDeleteProperty (dpy, s->input_window, rp_selection);
+ /* TODO: we shouldn't use CurrentTime here, use the time of the XKeyEvent, should we fake it? */
+ XConvertSelection (dpy, XA_PRIMARY, XA_STRING, rp_selection, s->input_window, CurrentTime);
+
+ /* This seems like a hack. */
+ while (!XCheckTypedWindowEvent (dpy, s->input_window, SelectionNotify, &ev))
+ {
+ if (loops == 0)
+ {
+ PRINT_ERROR (("selection request timed out\n"));
+ return NULL;
+ }
+ usleep (10000);
+ loops--;
+ }
+
+ PRINT_DEBUG (("SelectionNotify event\n"));
+
+ property = ev.xselection.property;
+
+ if (property != None)
+ return get_primary_selection ();
+ else
+ return get_cut_buffer ();
+ }
+}
+
/* The hook dictionary globals. */
LIST_HEAD (rp_key_hook);
@@ -106,3 +245,10 @@ set_window_focus (Window window)
LIST_HEAD (rp_frame_undos);
int rp_num_frame_undos = 0;
+
+void
+init_globals ()
+{
+ selection.text = NULL;
+ selection.len = 0;
+}
diff --git a/src/globals.h b/src/globals.h
index 45cb54c..8adb6ff 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -148,4 +148,13 @@ extern struct numset *rp_frame_numset;
extern struct list_head rp_frame_undos;
extern int rp_num_frame_undos;
+
+/* Selection handling globals */
+extern rp_xselection selection;
+void set_selection (char *txt);
+void set_nselection (char *txt, int len);
+char *get_selection ();
+
+void init_globals ();
+
#endif
diff --git a/src/main.c b/src/main.c
index e75d1d9..acae288 100644
--- a/src/main.c
+++ b/src/main.c
@@ -615,6 +615,7 @@ main (int argc, char *argv[])
set_sig_handler (SIGCHLD, chld_handler);
/* Setup ratpoison's internal structures */
+ init_globals ();
init_defaults ();
init_groups ();
init_window_stuff ();
diff --git a/src/ratpoison.h b/src/ratpoison.h
index 89a8059..1c84bb4 100644
--- a/src/ratpoison.h
+++ b/src/ratpoison.h
@@ -29,7 +29,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
+#include <string.h>
#include <X11/Xlib.h>
+#include <X11/Xatom.h>
#include <fcntl.h>
/* Some systems don't define the close-on-exec flag in fcntl.h */
diff --git a/src/sbuf.c b/src/sbuf.c
index 640b283..53c1490 100644
--- a/src/sbuf.c
+++ b/src/sbuf.c
@@ -69,9 +69,9 @@ sbuf_free_struct (struct sbuf *b)
}
char *
-sbuf_concat (struct sbuf *b, const char *str)
+sbuf_nconcat (struct sbuf *b, const char *str, int len)
{
- size_t minsz = b->len + strlen (str) + 1;
+ size_t minsz = b->len + len + 1;
if (b->maxsz < minsz)
{
@@ -86,6 +86,13 @@ sbuf_concat (struct sbuf *b, const char *str)
return b->data;
}
+
+char *
+sbuf_concat (struct sbuf *b, const char *str)
+{
+ return sbuf_nconcat (b, str, strlen (str));
+}
+
char *
sbuf_copy (struct sbuf *b, const char *str)
{
diff --git a/src/sbuf.h b/src/sbuf.h
index 66be1d1..071ab7d 100644
--- a/src/sbuf.h
+++ b/src/sbuf.h
@@ -39,6 +39,7 @@ struct sbuf *sbuf_new (size_t initsz);
void sbuf_free (struct sbuf *b);
char *sbuf_free_struct (struct sbuf *b);
char *sbuf_concat (struct sbuf *b, const char *str);
+char *sbuf_nconcat (struct sbuf *b, const char *str, int len);
char *sbuf_copy (struct sbuf *b, const char *str);
char *sbuf_clear (struct sbuf *b);
char *sbuf_get (struct sbuf *b);