Thu, 15 Jun 2017 11:35:00 -0500
eventloop: Replace eventloop input functions with Pidgin versions
Now that libpurple uses Gio, configuring the event loop to use
something other than the GLib event loop causes things to break.
This is because Gio adds sources to the GLib event loop in a way
which can't practically be overridden.
Fortunately, other event loops can still be used by driving the
GLib event loop manually. See the GLib Main Event Loop docs for
information on doing this.
This patch replaces purple_input_add() and purple_input_remove()
with what has been used in Pidgin. This should be a suitable,
generic, GLib solution until the rest of the codebase can be
ported off of these functions.
/* purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 02111-1301 USA */ #include "internal.h" #include "eventloop.h" #define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) #define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) static PurpleEventLoopUiOps *eventloop_ui_ops = NULL; typedef struct _PurpleIOClosure { PurpleInputFunction function; guint result; gpointer data; } PurpleIOClosure; guint purple_timeout_add(guint interval, GSourceFunc function, gpointer data) { return g_timeout_add(interval, function, data); } guint purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data) { return g_timeout_add_seconds(interval, function, data); } gboolean purple_timeout_remove(guint tag) { return g_source_remove(tag); } static gboolean purple_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) { PurpleIOClosure *closure = data; PurpleInputCondition purple_cond = 0; if (condition & PURPLE_GLIB_READ_COND) purple_cond |= PURPLE_INPUT_READ; if (condition & PURPLE_GLIB_WRITE_COND) purple_cond |= PURPLE_INPUT_WRITE; #ifdef _WIN32 if(!purple_cond) { return TRUE; } #endif /* _WIN32 */ closure->function(closure->data, g_io_channel_unix_get_fd(source), purple_cond); return TRUE; } guint purple_input_add(int source, PurpleInputCondition condition, PurpleInputFunction func, gpointer user_data) { PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); GIOChannel *channel; GIOCondition cond = 0; closure->function = func; closure->data = user_data; if (condition & PURPLE_INPUT_READ) cond |= PURPLE_GLIB_READ_COND; if (condition & PURPLE_INPUT_WRITE) cond |= PURPLE_GLIB_WRITE_COND; #ifdef _WIN32 channel = g_io_channel_win32_new_socket(source); #else channel = g_io_channel_unix_new(source); #endif closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, purple_io_invoke, closure, g_free); g_io_channel_unref(channel); return closure->result; } gboolean purple_input_remove(guint tag) { return g_source_remove(tag); } int purple_input_get_error(int fd, int *error) { PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops(); if (ops->input_get_error) { int ret = ops->input_get_error(fd, error); errno = *error; return ret; } else { socklen_t len; len = sizeof(*error); return getsockopt(fd, SOL_SOCKET, SO_ERROR, error, &len); } } int purple_input_pipe(int pipefd[2]) { #ifdef _WIN32 return wpurple_input_pipe(pipefd); #else return pipe(pipefd); #endif } void purple_eventloop_set_ui_ops(PurpleEventLoopUiOps *ops) { eventloop_ui_ops = ops; } PurpleEventLoopUiOps * purple_eventloop_get_ui_ops(void) { g_return_val_if_fail(eventloop_ui_ops != NULL, NULL); return eventloop_ui_ops; } /************************************************************************** * GBoxed code **************************************************************************/ static PurpleEventLoopUiOps * purple_eventloop_ui_ops_copy(PurpleEventLoopUiOps *ops) { PurpleEventLoopUiOps *ops_new; g_return_val_if_fail(ops != NULL, NULL); ops_new = g_new(PurpleEventLoopUiOps, 1); *ops_new = *ops; return ops_new; } GType purple_eventloop_ui_ops_get_type(void) { static GType type = 0; if (type == 0) { type = g_boxed_type_register_static("PurpleEventLoopUiOps", (GBoxedCopyFunc)purple_eventloop_ui_ops_copy, (GBoxedFreeFunc)g_free); } return type; }