1 /**
2  * @file gntclipboard.c
3  *
4  * Copyright (C) 2007 Richard Nelson <wabz@whatsbeef.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
19  */
20 
21 
22 #include "internal.h"
23 #include <glib.h>
24 
25 #define PLUGIN_STATIC_NAME	GntClipboard
26 
27 #ifdef HAVE_X11
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/Xatom.h>
31 #endif
32 
33 #include <sys/types.h>
34 #include <signal.h>
35 
36 #include <glib.h>
37 
38 #include <plugin.h>
39 #include <version.h>
40 #include <debug.h>
41 #include <notify.h>
42 #include <gntwm.h>
43 
44 #include <gntplugin.h>
45 
46 #ifdef HAVE_X11
47 static pid_t child = 0;
48 
49 static gulong sig_handle;
50 
51 static void
set_clip(gchar * string)52 set_clip(gchar *string)
53 {
54 	Window w;
55 	XEvent e, respond;
56 	XSelectionRequestEvent *req;
57 	const char *ids;
58 	Display *dpy = XOpenDisplay(NULL);
59 
60 	if (!dpy)
61 		return;
62 	ids = getenv("WINDOWID");
63 	if (ids == NULL)
64 		return;
65 	w = atoi(ids);
66 	XSetSelectionOwner(dpy, XA_PRIMARY, w, CurrentTime);
67 	XFlush(dpy);
68 	XSelectInput(dpy, w, StructureNotifyMask);
69 	while (TRUE) {
70 		XNextEvent(dpy, &e); /* this blocks. */
71 		req = &e.xselectionrequest;
72 		if (e.type == SelectionRequest) {
73 			XChangeProperty(dpy,
74 				req->requestor,
75 				req->property,
76 				XA_STRING,
77 				8, PropModeReplace,
78 				(unsigned char *)string,
79 				strlen(string));
80 			respond.xselection.property = req->property;
81 			respond.xselection.type = SelectionNotify;
82 			respond.xselection.display = req->display;
83 			respond.xselection.requestor = req->requestor;
84 			respond.xselection.selection = req->selection;
85 			respond.xselection.target= req->target;
86 			respond.xselection.time = req->time;
87 			XSendEvent(dpy, req->requestor, 0, 0, &respond);
88 			XFlush (dpy);
89 		} else if (e.type == SelectionClear) {
90 			return;
91 		}
92 	}
93 	return;
94 }
95 
96 static void
clipboard_changed(GntWM * wm,gchar * string)97 clipboard_changed(GntWM *wm, gchar *string)
98 {
99 	if (child) {
100 		kill(child, SIGTERM);
101 	}
102 	if ((child = fork() == 0)) {
103 		set_clip(string);
104 		_exit(0);
105 	}
106 }
107 #endif
108 
109 static gboolean
plugin_load(PurplePlugin * plugin)110 plugin_load(PurplePlugin *plugin)
111 {
112 #ifdef HAVE_X11
113 	if (!XOpenDisplay(NULL)) {
114 		purple_debug_warning("gntclipboard", "Couldn't find X display\n");
115 		purple_notify_error(NULL, _("Error"), _("Error loading the plugin."),
116 				_("Couldn't find X display"));
117 		return FALSE;
118 	}
119 	if (!getenv("WINDOWID")) {
120 		purple_debug_warning("gntclipboard", "Couldn't find window\n");
121 		purple_notify_error(NULL, _("Error"), _("Error loading the plugin."),
122 				_("Couldn't find window"));
123 		return FALSE;
124 	}
125 	sig_handle = g_signal_connect(G_OBJECT(gnt_get_clipboard()), "clipboard_changed", G_CALLBACK(clipboard_changed), NULL);
126 	return TRUE;
127 #else
128 	purple_notify_error(NULL, _("Error"), _("Error loading the plugin."),
129 			_("This plugin cannot be loaded because it was not built with X11 support."));
130 	return FALSE;
131 #endif
132 }
133 
134 static gboolean
plugin_unload(PurplePlugin * plugin)135 plugin_unload(PurplePlugin *plugin)
136 {
137 #ifdef HAVE_X11
138 	if (child) {
139 		kill(child, SIGTERM);
140 		child = 0;
141 	}
142 	g_signal_handler_disconnect(G_OBJECT(gnt_get_clipboard()), sig_handle);
143 #endif
144 	return TRUE;
145 }
146 
147 static PurplePluginInfo info =
148 {
149 	PURPLE_PLUGIN_MAGIC,
150 	PURPLE_MAJOR_VERSION,
151 	PURPLE_MINOR_VERSION,
152 	PURPLE_PLUGIN_STANDARD,
153 	FINCH_PLUGIN_TYPE,
154 	0,
155 	NULL,
156 	PURPLE_PRIORITY_DEFAULT,
157 	"gntclipboard",
158 	N_("GntClipboard"),
159 	DISPLAY_VERSION,
160 	N_("Clipboard plugin"),
161 	N_("When the gnt clipboard contents change, "
162 		"the contents are made available to X, if possible."),
163 	"Richard Nelson <wabz@whatsbeef.net>",
164 	PURPLE_WEBSITE,
165 	plugin_load,
166 	plugin_unload,
167 	NULL,
168 	NULL,
169 	NULL,
170 	NULL,
171 	NULL,
172 
173 	/* padding */
174 	NULL,
175 	NULL,
176 	NULL,
177 	NULL
178 };
179 
180 static void
init_plugin(PurplePlugin * plugin)181 init_plugin(PurplePlugin *plugin)
182 {
183 }
184 
185 PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)
186