Because of reasons like:
* answer button press doesn't generate an actual X keyboard event (but is visible through /dev/hidrawX) * linphone is running on local desktop, but I'm working on a fullscreen remote desktop and all keyboard events get sent there
I decided to use a simple Unix signal IPC to hook into the linphone gtk main loop, as described in:
http://askra.de/software/gtk-signals/a2955.html The implementation is basically: * create a "self-pipe" during initialization * create GIOChannel on "read" end of pipe, and add a watch to main loop * unix signal handler writes "message" into pipe* GIOChannel event reads "message" from pipe and calls linphone_gtk_answer_clicked(NULL), which already takes care of what to do if no call is currently ringing.
Last part is a perl script which reads bytes from /dev/hidrawX and looks for a specific byte-sequence and sends the "kill" to the pid of the running linphone. Perl script is currently hard-coded to hell, but I'll attach anyway for "documentation purposes". Note: requires "read" access to be granted on /dev/hidrawX device to current user before running. Note2: script also pauses playing rhythmbox on answer press.
-- Thanks, David Mansfield Cobite, INC.
--- linphone-3.5.2.orig/gtk/main.c 2012-12-26 10:29:12.521835222 -0500
+++ linphone-3.5.2/gtk/main.c 2012-12-26 11:38:40.804443105 -0500
@@ -1632,6 +1632,138 @@
}
#endif
+// unix signal handler
+
+static int signal_pipe[2];
+
+static void pipe_signals(int signal)
+{
+ if(write(signal_pipe[1], &signal, sizeof(int)) != sizeof(int))
+ {
+ fprintf(stderr, "unix signal %d lost\n", signal);
+ }
+}
+
+static gboolean deliver_signal(GIOChannel *source, GIOCondition cond, gpointer
d)
+{
+ GError *error = NULL; /* for error handling */
+
+ /*
+ * There is no g_io_channel_read or g_io_channel_read_int, so we read
+ * char's and use a union to recover the unix signal number.
+ */
+ union {
+ gchar chars[sizeof(int)];
+ int signal;
+ } buf;
+ GIOStatus status; /* save the reading status */
+ gsize bytes_read; /* save the number of chars read */
+
+ /*
+ * Read from the pipe as long as data is available. The reading end is
+ * also in non-blocking mode, so if we have consumed all unix signals,
+ * the read returns G_IO_STATUS_AGAIN.
+ */
+ while((status = g_io_channel_read_chars(source, buf.chars,
+ sizeof(int), &bytes_read, &error)) == G_IO_STATUS_NORMAL)
+ {
+ g_assert(error == NULL); /* no error if reading returns normal */
+
+ /*
+ * There might be some problem resulting in too few char's read.
+ * Check it.
+ */
+ if(bytes_read != sizeof(int)){
+ fprintf(stderr, "lost data in signal pipe (expected %d, received %d)\n",
+ (int)sizeof(int), (int)bytes_read);
+ continue; /* discard the garbage and keep fingers crossed */
+ }
+
+ /* Ok, we read a unix signal number, answer the call (if any) */
+ fprintf(stderr, "===== received signal %d\n", buf.signal);
+ linphone_gtk_answer_clicked(NULL);
+ }
+
+ /*
+ * Reading from the pipe has not returned with normal status. Check for
+ * potential errors and return from the callback.
+ */
+ if(error != NULL){
+ fprintf(stderr, "reading signal pipe failed: %s\n", error->message);
+ exit(1);
+ }
+ if(status == G_IO_STATUS_EOF){
+ fprintf(stderr, "signal pipe has been closed\n");
+ exit(1);
+ }
+
+ g_assert(status == G_IO_STATUS_AGAIN);
+
+ return (TRUE); /* keep the event source */
+}
+
+static void setup_answer_handler() {
+ int fd_flags;
+ GIOChannel *g_signal_in;
+ GError *error = NULL; /* handle errors */
+
+ /*
+ * Set the unix signal handling up.
+ * First create a pipe.
+ */
+ if(pipe(signal_pipe)) {
+ perror("pipe");
+ exit(1);
+ }
+
+ /*
+ * put the write end of the pipe into nonblocking mode,
+ * need to read the flags first, otherwise we would clear other flags too.
+ */
+ fd_flags = fcntl(signal_pipe[1], F_GETFL);
+ if(fd_flags == -1)
+ {
+ perror("read descriptor flags");
+ exit(1);
+ }
+ if(fcntl(signal_pipe[1], F_SETFL, fd_flags | O_NONBLOCK) == -1)
+ {
+ perror("write descriptor flags");
+ exit(1);
+ }
+
+ /* Install the unix signal handler pipe_signals for the signals of interest
*/
+ signal(SIGUSR1, pipe_signals);
+
+ /* convert the reading end of the pipe into a GIOChannel */
+ g_signal_in = g_io_channel_unix_new(signal_pipe[0]);
+ /*
+ * we only read raw binary data from the pipe,
+ * therefore clear any encoding on the channel
+ */
+ g_io_channel_set_encoding(g_signal_in, NULL, &error);
+ if(error != NULL){ /* handle potential errors */
+ fprintf(stderr, "g_io_channel_set_encoding failed %s\n",
+ error->message);
+ exit(1);
+ }
+
+ /* put the reading end also into non-blocking mode */
+ g_io_channel_set_flags(g_signal_in,
+ g_io_channel_get_flags(g_signal_in) |
G_IO_FLAG_NONBLOCK, &error);
+
+ if(error != NULL){ /* tread errors */
+ fprintf(stderr, "g_io_set_flags failed %s\n",
+ error->message);
+ exit(1);
+ }
+
+ /* register the reading end with the event loop */
+ g_io_add_watch(g_signal_in, G_IO_IN | G_IO_PRI, deliver_signal, NULL);
+
+}
+
+
int main(int argc, char *argv[]){
#ifdef ENABLE_NLS
void *p;
@@ -1764,6 +1896,8 @@
if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
linphone_gtk_check_for_new_version();
+ setup_answer_handler();
+
gtk_main();
linphone_gtk_quit();
#ifndef HAVE_GTK_OSX
answer_linphone.pl
Description: Perl program
_______________________________________________ Linphone-users mailing list [email protected] https://lists.nongnu.org/mailman/listinfo/linphone-users
