From dafc142bc6119fa5e34ecbd1ca2a18096aa397cb Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Fri, 25 Dec 2015 21:58:17 -0800 Subject: [PATCH] Split MooAppInput code into -unix and -win32 --- api/CMakeLists.txt | 2 +- api/sourcefiles.mak | 2 +- moo/mooutils/Makefile.incl | 19 +- moo/mooutils/mooappinput-common.c | 164 ++++++ moo/mooutils/mooappinput-priv.h | 45 ++ .../{mooappinput.c => mooappinput-unix.c} | 540 +----------------- moo/mooutils/mooappinput-win32.c | 331 +++++++++++ moo/mooutils/mooutils.cmake | 3 +- 8 files changed, 583 insertions(+), 523 deletions(-) create mode 100644 moo/mooutils/mooappinput-common.c create mode 100644 moo/mooutils/mooappinput-priv.h rename moo/mooutils/{mooappinput.c => mooappinput-unix.c} (54%) create mode 100644 moo/mooutils/mooappinput-win32.c diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 938a7402..94f4d416 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -177,7 +177,7 @@ SET(source_files ../moo/mooutils/mooactiongroup.h ../moo/mooutils/mooaction.h ../moo/mooutils/mooaction-private.h - ../moo/mooutils/mooappinput.c + ../moo/mooutils/mooappinput-common.c ../moo/mooutils/mooappinput.h ../moo/mooutils/mooapp-ipc.c ../moo/mooutils/mooapp-ipc.h diff --git a/api/sourcefiles.mak b/api/sourcefiles.mak index 5cceb40e..2bc28966 100644 --- a/api/sourcefiles.mak +++ b/api/sourcefiles.mak @@ -147,7 +147,7 @@ source_files = \ ../moo/mooutils/mooactiongroup.h\ ../moo/mooutils/mooaction.h\ ../moo/mooutils/mooaction-private.h\ - ../moo/mooutils/mooappinput.c\ + ../moo/mooutils/mooappinput-common.c\ ../moo/mooutils/mooappinput.h\ ../moo/mooutils/mooapp-ipc.c\ ../moo/mooutils/mooapp-ipc.h\ diff --git a/moo/mooutils/Makefile.incl b/moo/mooutils/Makefile.incl index a4b720dd..ceeb371d 100644 --- a/moo/mooutils/Makefile.incl +++ b/moo/mooutils/Makefile.incl @@ -32,8 +32,9 @@ moo_sources += \ mooutils/mooactiongroup.h \ mooutils/mooapp-ipc.c \ mooutils/mooapp-ipc.h \ - mooutils/mooappinput.c \ + mooutils/mooappinput-common.c \ mooutils/mooappinput.h \ + mooutils/mooappinput-priv.h \ mooutils/mooatom.h \ mooutils/moobigpaned.c \ mooutils/moobigpaned.h \ @@ -160,15 +161,27 @@ mooutils/mooutils-enums.c.stamp: $(moo_utils_enum_headers) Makefile mooutils/moo $(AM_V_at)echo stamp > mooutils/mooutils-enums.c.stamp endif -mooutils_win32_sources = mooutils/mooutils-win32.c +mooutils_win32_sources = \ + mooutils/mooutils-win32.c \ + mooutils/mooappinput-win32.c + +mooutils_unix_sources = \ + mooutils/mooappinput-unix.c + mooutils_unittest_sources = \ mooutils/moo-test-utils.c \ mooutils/moo-test-utils.h \ mooutils/moo-test-macros.h -EXTRA_DIST += $(mooutils_win32_sources) $(mooutils_unittest_sources) + +EXTRA_DIST += \ + $(mooutils_win32_sources) \ + $(mooutils_unix_sources) \ + $(mooutils_unittest_sources) if MOO_OS_WIN32 moo_sources += $(mooutils_win32_sources) +else +moo_sources += $(mooutils_unix_sources) endif moo_sources += $(mooutils_unittest_sources) diff --git a/moo/mooutils/mooappinput-common.c b/moo/mooutils/mooappinput-common.c new file mode 100644 index 00000000..929e1bfa --- /dev/null +++ b/moo/mooutils/mooappinput-common.c @@ -0,0 +1,164 @@ +/* + * mooutils/mooappinput-common.c + * + * Copyright (C) 2004-2015 by Yevgen Muntyan + * + * This file is part of medit. medit is free software; you can + * redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * You should have received a copy of the GNU Lesser General Public + * License along with medit. If not, see . + */ + +#include "config.h" +#include "mooutils/mooappinput-priv.h" + +#include +#include +#include +#include +#include "mooappinput.h" +#include "mooapp-ipc.h" +#include "mooutils-misc.h" +#include "mooutils-thread.h" +#include "mooutils-debug.h" + +MOO_DEBUG_INIT(input, FALSE) + +MooAppInput *_moo_app_input_instance; + +static void +exec_callback (char cmd, + const char *data, + gsize len) +{ + g_return_if_fail (_moo_app_input_instance && _moo_app_input_instance->callback); + if (cmd == MOO_APP_INPUT_IPC_MAGIC_CHAR) + _moo_ipc_dispatch (data, len); + else + _moo_app_input_instance->callback (cmd, data, len, _moo_app_input_instance->callback_data); +} + + +static MooAppInput * +moo_app_input_new (const char *name, + gboolean bind_default, + MooAppInputCallback callback, + gpointer callback_data) +{ + MooAppInput *ch; + InputChannel *ich; + + g_return_val_if_fail (callback != NULL, NULL); + + ch = g_slice_new0 (MooAppInput); + + ch->callback = callback; + ch->callback_data = callback_data; + ch->pipes = NULL; + ch->appname = g_strdup (MOO_PACKAGE_NAME); + + if ((ich = _moo_app_input_channel_new (ch->appname, _moo_get_pid_string (), FALSE))) + { + ch->pipes = g_slist_prepend (ch->pipes, ich); + ch->main_path = _moo_app_input_channel_get_path (ich); + } + + if (name && (ich = _moo_app_input_channel_new (ch->appname, name, FALSE))) + ch->pipes = g_slist_prepend (ch->pipes, ich); + + if (bind_default && (ich = _moo_app_input_channel_new (ch->appname, MOO_APP_INPUT_NAME_DEFAULT, TRUE))) + ch->pipes = g_slist_prepend (ch->pipes, ich); + + return ch; +} + +void +_moo_app_input_start (const char *name, + gboolean bind_default, + MooAppInputCallback callback, + gpointer callback_data) +{ + g_return_if_fail (_moo_app_input_instance == NULL); + _moo_app_input_instance = moo_app_input_new (name, bind_default, + callback, callback_data); +} + +static void +moo_app_input_free (MooAppInput *ch) +{ + g_return_if_fail (ch != NULL); + + g_slist_foreach (ch->pipes, (GFunc) _moo_app_input_channel_free, NULL); + g_slist_free (ch->pipes); + + g_free (ch->main_path); + g_free (ch->appname); + g_slice_free (MooAppInput, ch); +} + +void +_moo_app_input_shutdown (void) +{ + if (_moo_app_input_instance) + { + MooAppInput *tmp = _moo_app_input_instance; + _moo_app_input_instance = NULL; + moo_app_input_free (tmp); + } +} + + +const char * +_moo_app_input_get_path (void) +{ + return _moo_app_input_instance ? _moo_app_input_instance->main_path : NULL; +} + +gboolean +_moo_app_input_running (void) +{ + return _moo_app_input_instance != NULL; +} + + +void +_moo_app_input_channel_commit (GString **buffer) +{ + char buf[MOO_APP_INPUT_MAX_BUFFER_SIZE]; + GString *freeme = NULL; + char *ptr; + gsize len; + + if (!(*buffer)->len) + { + moo_dmsg ("got empty command"); + return; + } + + if ((*buffer)->len + 1 > MOO_APP_INPUT_MAX_BUFFER_SIZE) + { + freeme = *buffer; + *buffer = g_string_new_len (NULL, MOO_APP_INPUT_MAX_BUFFER_SIZE); + ptr = freeme->str; + len = freeme->len; + } + else + { + memcpy (buf, (*buffer)->str, (*buffer)->len + 1); + ptr = buf; + len = (*buffer)->len; + g_string_truncate (*buffer, 0); + } + + if (0) + g_print ("%s: commit %c\n%s\n-----\n", G_STRLOC, ptr[0], ptr + 1); + + exec_callback (ptr[0], ptr + 1, len - 1); + + if (freeme) + g_string_free (freeme, TRUE); +} diff --git a/moo/mooutils/mooappinput-priv.h b/moo/mooutils/mooappinput-priv.h new file mode 100644 index 00000000..495d468e --- /dev/null +++ b/moo/mooutils/mooappinput-priv.h @@ -0,0 +1,45 @@ +/* + * mooutils/mooappinput-priv.h + * + * Copyright (C) 2004-2015 by Yevgen Muntyan + * + * This file is part of medit. medit is free software; you can + * redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * You should have received a copy of the GNU Lesser General Public + * License along with medit. If not, see . + */ + +#pragma once + +#include "mooutils/mooappinput.h" + +typedef struct MooAppInput MooAppInput; +typedef struct InputChannel InputChannel; + +struct MooAppInput +{ + GSList *pipes; + char *appname; + char *main_path; + MooAppInputCallback callback; + gpointer callback_data; +}; + +#define MOO_APP_INPUT_NAME_DEFAULT "main" +#define MOO_APP_INPUT_IPC_MAGIC_CHAR 'I' +#define MOO_APP_INPUT_MAX_BUFFER_SIZE 4096 + +extern MooAppInput *_moo_app_input_instance; + +InputChannel *_moo_app_input_channel_new (const char *appname, + const char *name, + gboolean may_fail); +void _moo_app_input_channel_free (InputChannel *ch); +char *_moo_app_input_channel_get_path (InputChannel *ch); +const char *_moo_app_input_channel_get_name (InputChannel *ch); + +void _moo_app_input_channel_commit (GString **buffer); diff --git a/moo/mooutils/mooappinput.c b/moo/mooutils/mooappinput-unix.c similarity index 54% rename from moo/mooutils/mooappinput.c rename to moo/mooutils/mooappinput-unix.c index 3c24d385..8a63a069 100644 --- a/moo/mooutils/mooappinput.c +++ b/moo/mooutils/mooappinput-unix.c @@ -1,7 +1,7 @@ /* - * mooapp/mooappinput.c + * mooapp/mooappinput-unix.c * - * Copyright (C) 2004-2010 by Yevgen Muntyan + * Copyright (C) 2004-2015 by Yevgen Muntyan * * This file is part of medit. medit is free software; you can * redistribute it and/or modify it under the terms of the @@ -15,209 +15,30 @@ #include "config.h" -#ifdef __WIN32__ -#define MOO_APP_INPUT_WIN32 -#else -#define MOO_APP_INPUT_SOCKET -#endif - -#if defined(MOO_APP_INPUT_WIN32) -# include -# include -#else #define MOO_DO_NOT_MANGLE_GLIB_FUNCTIONS #include MGW_ERROR_IF_NOT_SHARED_LIBC + +#include "mooutils/mooappinput-priv.h" + # include # include -#endif -#ifndef __WIN32__ #include #include #include -#endif #include #include #include #include -#include "mooappinput.h" #include "mooapp-ipc.h" #include "mooutils-misc.h" #include "mooutils-thread.h" #include "mooutils-debug.h" -MOO_DEBUG_INIT(input, FALSE) - -#define MAX_BUFFER_SIZE 4096 -#define IPC_MAGIC_CHAR 'I' -#define MOO_APP_INPUT_NAME_DEFAULT "main" - -#ifdef MOO_APP_INPUT_SOCKET #define INPUT_PREFIX "in-" -#else -#define INPUT_PREFIX "input-" -#endif -typedef struct MooAppInput MooAppInput; -typedef struct InputChannel InputChannel; - -struct MooAppInput -{ - GSList *pipes; - char *appname; - char *main_path; - MooAppInputCallback callback; - gpointer callback_data; -}; - -static MooAppInput *inp_instance; - -static InputChannel *input_channel_new (const char *appname, - const char *name, - gboolean may_fail); -static void input_channel_free (InputChannel *ch); -static char *input_channel_get_path (InputChannel *ch); -G_GNUC_UNUSED -static const char *input_channel_get_name (InputChannel *ch); - - -static void -exec_callback (char cmd, - const char *data, - gsize len) -{ - g_return_if_fail (inp_instance && inp_instance->callback); - if (cmd == IPC_MAGIC_CHAR) - _moo_ipc_dispatch (data, len); - else - inp_instance->callback (cmd, data, len, inp_instance->callback_data); -} - - -static MooAppInput * -moo_app_input_new (const char *name, - gboolean bind_default, - MooAppInputCallback callback, - gpointer callback_data) -{ - MooAppInput *ch; - InputChannel *ich; - - g_return_val_if_fail (callback != NULL, NULL); - - ch = g_slice_new0 (MooAppInput); - - ch->callback = callback; - ch->callback_data = callback_data; - ch->pipes = NULL; - ch->appname = g_strdup (MOO_PACKAGE_NAME); - - if ((ich = input_channel_new (ch->appname, _moo_get_pid_string (), FALSE))) - { - ch->pipes = g_slist_prepend (ch->pipes, ich); - ch->main_path = input_channel_get_path (ich); - } - - if (name && (ich = input_channel_new (ch->appname, name, FALSE))) - ch->pipes = g_slist_prepend (ch->pipes, ich); - - if (bind_default && (ich = input_channel_new (ch->appname, MOO_APP_INPUT_NAME_DEFAULT, TRUE))) - ch->pipes = g_slist_prepend (ch->pipes, ich); - - return ch; -} - -void -_moo_app_input_start (const char *name, - gboolean bind_default, - MooAppInputCallback callback, - gpointer callback_data) -{ - g_return_if_fail (inp_instance == NULL); - inp_instance = moo_app_input_new (name, bind_default, - callback, callback_data); -} - -static void -moo_app_input_free (MooAppInput *ch) -{ - g_return_if_fail (ch != NULL); - - g_slist_foreach (ch->pipes, (GFunc) input_channel_free, NULL); - g_slist_free (ch->pipes); - - g_free (ch->main_path); - g_free (ch->appname); - g_slice_free (MooAppInput, ch); -} - -void -_moo_app_input_shutdown (void) -{ - if (inp_instance) - { - MooAppInput *tmp = inp_instance; - inp_instance = NULL; - moo_app_input_free (tmp); - } -} - - -const char * -_moo_app_input_get_path (void) -{ - return inp_instance ? inp_instance->main_path : NULL; -} - -gboolean -_moo_app_input_running (void) -{ - return inp_instance != NULL; -} - - -static void -commit (GString **buffer) -{ - char buf[MAX_BUFFER_SIZE]; - GString *freeme = NULL; - char *ptr; - gsize len; - - if (!(*buffer)->len) - { - moo_dmsg ("got empty command"); - return; - } - - if ((*buffer)->len + 1 > MAX_BUFFER_SIZE) - { - freeme = *buffer; - *buffer = g_string_new_len (NULL, MAX_BUFFER_SIZE); - ptr = freeme->str; - len = freeme->len; - } - else - { - memcpy (buf, (*buffer)->str, (*buffer)->len + 1); - ptr = buf; - len = (*buffer)->len; - g_string_truncate (*buffer, 0); - } - - if (0) - g_print ("%s: commit %c\n%s\n-----\n", G_STRLOC, ptr[0], ptr + 1); - - exec_callback (ptr[0], ptr + 1, len - 1); - - if (freeme) - g_string_free (freeme, TRUE); -} - - -#ifndef MOO_APP_INPUT_WIN32 static const char * get_display_name (void) @@ -444,10 +265,10 @@ _moo_app_input_broadcast (const char *header, moo_dmsg ("_moo_app_input_broadcast"); - if (!inp_instance) + if (!_moo_app_input_instance) return; - pipe_dir_name = get_pipe_dir (inp_instance->appname); + pipe_dir_name = get_pipe_dir (_moo_app_input_instance->appname); g_return_if_fail (pipe_dir_name != NULL); pipe_dir = g_dir_open (pipe_dir_name, 0, NULL); @@ -460,10 +281,10 @@ _moo_app_input_broadcast (const char *header, gboolean my_name = FALSE; const char *name = entry + strlen (INPUT_PREFIX); - for (l = inp_instance->pipes; !my_name && l != NULL; l = l->next) + for (l = _moo_app_input_instance->pipes; !my_name && l != NULL; l = l->next) { InputChannel *ch = l->data; - const char *ch_name = input_channel_get_name (ch); + const char *ch_name = _moo_app_input_channel_get_name (ch); if (ch_name && strcmp (ch_name, name) == 0) my_name = TRUE; } @@ -508,13 +329,6 @@ do_write (int fd, return TRUE; } -#endif - - -#ifdef MOO_APP_INPUT_SOCKET - -MGW_ERROR_IF_NOT_SHARED_LIBC - #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif @@ -539,15 +353,15 @@ struct InputChannel GSList *connections; }; -static char * -input_channel_get_path (InputChannel *ch) +char * +_moo_app_input_channel_get_path (InputChannel *ch) { g_return_val_if_fail (ch != NULL, NULL); return g_strdup (ch->path); } -static const char * -input_channel_get_name (InputChannel *ch) +const char * +_moo_app_input_channel_get_name (InputChannel *ch) { g_return_val_if_fail (ch != NULL, NULL); return ch->name; @@ -643,7 +457,7 @@ read_input (G_GNUC_UNUSED GIOChannel *source, } if (do_commit) - commit (&conn->buffer); + _moo_app_input_channel_commit (&conn->buffer); if (!do_commit && (condition & (G_IO_ERR | G_IO_HUP))) { @@ -676,7 +490,7 @@ accept_connection (G_GNUC_UNUSED GIOChannel *source, conn = g_slice_new0 (Connection); conn->ch = ch; - conn->buffer = g_string_new_len (NULL, MAX_BUFFER_SIZE); + conn->buffer = g_string_new_len (NULL, MOO_APP_INPUT_MAX_BUFFER_SIZE); conn->fd = accept (ch->fd, NULL, &dummy); @@ -798,10 +612,10 @@ input_channel_start (InputChannel *ch, return TRUE; } -static InputChannel * -input_channel_new (const char *appname, - const char *name, - gboolean may_fail) +InputChannel * +_moo_app_input_channel_new (const char *appname, + const char *name, + gboolean may_fail) { InputChannel *ch; @@ -819,15 +633,15 @@ input_channel_new (const char *appname, if (!input_channel_start (ch, may_fail)) { - input_channel_free (ch); + _moo_app_input_channel_free (ch); return NULL; } return ch; } -static void -input_channel_free (InputChannel *ch) +void +_moo_app_input_channel_free (InputChannel *ch) { input_channel_shutdown (ch); g_free (ch->name); @@ -863,7 +677,7 @@ do_send (const char *filename, if (iheader) { - char c = IPC_MAGIC_CHAR; + char c = MOO_APP_INPUT_IPC_MAGIC_CHAR; result = do_write (fd, &c, 1) && do_write (fd, iheader, strlen (iheader)); } @@ -880,311 +694,3 @@ do_send (const char *filename, close (fd); return result; } - -#endif /* MOO_APP_INPUT_SOCKET */ - - -/****************************************************************************/ -/* WIN32 - */ -#ifdef MOO_APP_INPUT_WIN32 - -typedef struct { - char *pipe_name; - guint event_id; -} ListenerInfo; - -struct InputChannel -{ - char *appname; - char *name; - char *pipe_name; - GString *buffer; - guint event_id; -}; - -static char * -input_channel_get_path (InputChannel *ch) -{ - g_return_val_if_fail (ch != NULL, NULL); - return g_strdup (ch->pipe_name); -} - -G_GNUC_UNUSED static const char * -input_channel_get_name (InputChannel *ch) -{ - g_return_val_if_fail (ch != NULL, NULL); - return ch->name; -} - -static ListenerInfo * -listener_info_new (const char *pipe_name, - guint event_id) -{ - ListenerInfo *info = g_new (ListenerInfo, 1); - info->pipe_name = g_strdup (pipe_name); - info->event_id = event_id; - return info; -} - -static void -listener_info_free (ListenerInfo *info) -{ - if (info) - { - g_free (info->pipe_name); - g_free (info); - } -} - - -static gpointer -listener_main (ListenerInfo *info) -{ - HANDLE input; - - _moo_message_async ("%s: hi there", G_STRLOC); - - /* XXX unicode */ - input = CreateNamedPipeA (info->pipe_name, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - 0, 0, 200, NULL); - - if (input == INVALID_HANDLE_VALUE) - { - _moo_message_async ("%s: could not create input pipe", G_STRLOC); - listener_info_free (info); - return NULL; - } - - _moo_message_async ("%s: opened pipe %s", G_STRLOC, info->pipe_name); - - while (TRUE) - { - DWORD bytes_read; - char c; - - DisconnectNamedPipe (input); - _moo_message_async ("%s: opening connection", G_STRLOC); - - if (!ConnectNamedPipe (input, NULL)) - { - DWORD err = GetLastError(); - - if (err != ERROR_PIPE_CONNECTED) - { - char *msg = g_win32_error_message (err); - _moo_message_async ("%s: error in ConnectNamedPipe(): %s", G_STRLOC, msg); - CloseHandle (input); - g_free (msg); - break; - } - } - - _moo_message_async ("%s: client connected", G_STRLOC); - - while (ReadFile (input, &c, 1, &bytes_read, NULL)) - { - if (bytes_read == 1) - { - _moo_event_queue_push (info->event_id, GINT_TO_POINTER ((int) c), NULL); - } - else - { - _moo_message_async ("%s: client disconnected", G_STRLOC); - break; - } - } - } - - _moo_message_async ("%s: goodbye", G_STRLOC); - - CloseHandle (input); - listener_info_free (info); - return NULL; -} - - -static char * -get_pipe_name (const char *appname, - const char *name) -{ - if (!name) - name = _moo_get_pid_string (); - return g_strdup_printf ("\\\\.\\pipe\\%s_in_%s", - appname, name); -} - - -static void -event_callback (GList *events, - InputChannel *ch) -{ - while (events) - { - char c = GPOINTER_TO_INT (events->data); - - if (c != 0) - g_string_append_c (ch->buffer, c); - else - commit (&ch->buffer); - - events = events->next; - } -} - - -static gboolean -input_channel_start (InputChannel *ch) -{ - ListenerInfo *info; - - g_free (ch->pipe_name); - ch->pipe_name = get_pipe_name (ch->appname, ch->name); - ch->event_id = _moo_event_queue_connect ((MooEventQueueCallback) event_callback, - ch, NULL); - - info = listener_info_new (ch->pipe_name, ch->event_id); - - if (!g_thread_create ((GThreadFunc) listener_main, info, FALSE, NULL)) - { - g_critical ("could not start listener thread"); - listener_info_free (info); - g_free (ch->pipe_name); - ch->pipe_name = NULL; - _moo_event_queue_disconnect (ch->event_id); - ch->event_id = 0; - return FALSE; - } - - return TRUE; -} - - -static InputChannel * -input_channel_new (const char *appname, - const char *name, - G_GNUC_UNUSED gboolean may_fail) -{ - InputChannel *ch; - - ch = g_slice_new0 (InputChannel); - ch->appname = g_strdup (appname); - ch->name = g_strdup (name); - ch->buffer = g_string_new_len (NULL, MAX_BUFFER_SIZE); - - if (!input_channel_start (ch)) - { - input_channel_free (ch); - return NULL; - } - - return ch; -} - -static void -input_channel_free (InputChannel *ch) -{ - if (ch->event_id) - _moo_event_queue_disconnect (ch->event_id); - if (ch->buffer) - g_string_free (ch->buffer, TRUE); - g_free (ch->pipe_name); - g_free (ch->appname); - g_free (ch->name); - g_slice_free (InputChannel, ch); -} - -static gboolean -write_data (HANDLE file, - const char *data, - gsize len, - const char *pipe_name) -{ - DWORD bytes_written; - - if (!WriteFile (file, data, (DWORD) len, &bytes_written, NULL)) - { - char *err_msg = g_win32_error_message (GetLastError ()); - g_warning ("could not write data to '%s': %s", pipe_name, err_msg); - g_free (err_msg); - return FALSE; - } - - if (bytes_written < (DWORD) len) - { - g_warning ("written less data than requested to '%s'", pipe_name); - return FALSE; - } - - return TRUE; -} - -gboolean -_moo_app_input_send_msg (const char *name, - const char *data, - gssize len) -{ - char *err_msg = NULL; - char *pipe_name; - HANDLE pipe_handle; - gboolean result = FALSE; - - g_return_val_if_fail (data != NULL, FALSE); - - if (len < 0) - len = strlen (data); - - if (!len) - return TRUE; - - if (!name) - name = "main"; - - pipe_name = get_pipe_name (MOO_PACKAGE_NAME, name); - /* XXX unicode */ - pipe_handle = CreateFileA (pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - - if (!pipe_handle) - { - err_msg = g_win32_error_message (GetLastError ()); - g_warning ("could not open pipe '%s': %s", pipe_name, err_msg); - goto out; - } - - result = write_data (pipe_handle, data, len, pipe_name); - - if (result) - { - char c = 0; - result = write_data (pipe_handle, &c, 1, pipe_name); - } - -out: - if (pipe_handle != INVALID_HANDLE_VALUE) - CloseHandle (pipe_handle); - - g_free (pipe_name); - g_free (err_msg); - return result; -} - -void -_moo_app_input_broadcast (const char *header, - const char *data, - gssize len) -{ - MOO_IMPLEMENT_ME - - g_return_if_fail (header != NULL); - g_return_if_fail (data != NULL); - - if (len < 0) - len = strlen (data); - - g_return_if_fail (len != 0); -} - -#endif /* MOO_APP_INPUT_WIN32 */ diff --git a/moo/mooutils/mooappinput-win32.c b/moo/mooutils/mooappinput-win32.c new file mode 100644 index 00000000..de2caa1f --- /dev/null +++ b/moo/mooutils/mooappinput-win32.c @@ -0,0 +1,331 @@ +/* + * mooapp/mooappinput-win32.c + * + * Copyright (C) 2004-2015 by Yevgen Muntyan + * + * This file is part of medit. medit is free software; you can + * redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * You should have received a copy of the GNU Lesser General Public + * License along with medit. If not, see . + */ + +#include "config.h" +#include "mooutils/mooappinput-priv.h" + +# include +# include + +#include +#include +#include +#include +#include "mooappinput.h" +#include "mooapp-ipc.h" +#include "mooutils-misc.h" +#include "mooutils-thread.h" +#include "mooutils-debug.h" + +#define INPUT_PREFIX "input-" + + +typedef struct { + char *pipe_name; + guint event_id; +} ListenerInfo; + +struct InputChannel +{ + char *appname; + char *name; + char *pipe_name; + GString *buffer; + guint event_id; +}; + +char * +_moo_app_input_channel_get_path (InputChannel *ch) +{ + g_return_val_if_fail (ch != NULL, NULL); + return g_strdup (ch->pipe_name); +} + +const char * +_moo_app_input_channel_get_name (InputChannel *ch) +{ + g_return_val_if_fail (ch != NULL, NULL); + return ch->name; +} + +static ListenerInfo * +listener_info_new (const char *pipe_name, + guint event_id) +{ + ListenerInfo *info = g_new (ListenerInfo, 1); + info->pipe_name = g_strdup (pipe_name); + info->event_id = event_id; + return info; +} + +static void +listener_info_free (ListenerInfo *info) +{ + if (info) + { + g_free (info->pipe_name); + g_free (info); + } +} + + +static gpointer +listener_main (ListenerInfo *info) +{ + HANDLE input; + + _moo_message_async ("%s: hi there", G_STRLOC); + + /* XXX unicode */ + input = CreateNamedPipeA (info->pipe_name, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + 0, 0, 200, NULL); + + if (input == INVALID_HANDLE_VALUE) + { + _moo_message_async ("%s: could not create input pipe", G_STRLOC); + listener_info_free (info); + return NULL; + } + + _moo_message_async ("%s: opened pipe %s", G_STRLOC, info->pipe_name); + + while (TRUE) + { + DWORD bytes_read; + char c; + + DisconnectNamedPipe (input); + _moo_message_async ("%s: opening connection", G_STRLOC); + + if (!ConnectNamedPipe (input, NULL)) + { + DWORD err = GetLastError(); + + if (err != ERROR_PIPE_CONNECTED) + { + char *msg = g_win32_error_message (err); + _moo_message_async ("%s: error in ConnectNamedPipe(): %s", G_STRLOC, msg); + CloseHandle (input); + g_free (msg); + break; + } + } + + _moo_message_async ("%s: client connected", G_STRLOC); + + while (ReadFile (input, &c, 1, &bytes_read, NULL)) + { + if (bytes_read == 1) + { + _moo_event_queue_push (info->event_id, GINT_TO_POINTER ((int) c), NULL); + } + else + { + _moo_message_async ("%s: client disconnected", G_STRLOC); + break; + } + } + } + + _moo_message_async ("%s: goodbye", G_STRLOC); + + CloseHandle (input); + listener_info_free (info); + return NULL; +} + + +static char * +get_pipe_name (const char *appname, + const char *name) +{ + if (!name) + name = _moo_get_pid_string (); + return g_strdup_printf ("\\\\.\\pipe\\%s_in_%s", + appname, name); +} + + +static void +event_callback (GList *events, + InputChannel *ch) +{ + while (events) + { + char c = GPOINTER_TO_INT (events->data); + + if (c != 0) + g_string_append_c (ch->buffer, c); + else + _moo_app_input_channel_commit (&ch->buffer); + + events = events->next; + } +} + + +static gboolean +input_channel_start (InputChannel *ch) +{ + ListenerInfo *info; + + g_free (ch->pipe_name); + ch->pipe_name = get_pipe_name (ch->appname, ch->name); + ch->event_id = _moo_event_queue_connect ((MooEventQueueCallback) event_callback, + ch, NULL); + + info = listener_info_new (ch->pipe_name, ch->event_id); + + if (!g_thread_create ((GThreadFunc) listener_main, info, FALSE, NULL)) + { + g_critical ("could not start listener thread"); + listener_info_free (info); + g_free (ch->pipe_name); + ch->pipe_name = NULL; + _moo_event_queue_disconnect (ch->event_id); + ch->event_id = 0; + return FALSE; + } + + return TRUE; +} + + +InputChannel * +_moo_app_input_channel_new (const char *appname, + const char *name, + G_GNUC_UNUSED gboolean may_fail) +{ + InputChannel *ch; + + ch = g_slice_new0 (InputChannel); + ch->appname = g_strdup (appname); + ch->name = g_strdup (name); + ch->buffer = g_string_new_len (NULL, MOO_APP_INPUT_MAX_BUFFER_SIZE); + + if (!input_channel_start (ch)) + { + _moo_app_input_channel_free (ch); + return NULL; + } + + return ch; +} + +void +_moo_app_input_channel_free (InputChannel *ch) +{ + if (ch->event_id) + _moo_event_queue_disconnect (ch->event_id); + if (ch->buffer) + g_string_free (ch->buffer, TRUE); + g_free (ch->pipe_name); + g_free (ch->appname); + g_free (ch->name); + g_slice_free (InputChannel, ch); +} + +static gboolean +write_data (HANDLE file, + const char *data, + gsize len, + const char *pipe_name) +{ + DWORD bytes_written; + + if (!WriteFile (file, data, (DWORD) len, &bytes_written, NULL)) + { + char *err_msg = g_win32_error_message (GetLastError ()); + g_warning ("could not write data to '%s': %s", pipe_name, err_msg); + g_free (err_msg); + return FALSE; + } + + if (bytes_written < (DWORD) len) + { + g_warning ("written less data than requested to '%s'", pipe_name); + return FALSE; + } + + return TRUE; +} + +gboolean +_moo_app_input_send_msg (const char *name, + const char *data, + gssize len) +{ + char *err_msg = NULL; + char *pipe_name; + HANDLE pipe_handle; + gboolean result = FALSE; + + g_return_val_if_fail (data != NULL, FALSE); + + if (len < 0) + len = strlen (data); + + if (!len) + return TRUE; + + if (!name) + name = "main"; + + pipe_name = get_pipe_name (MOO_PACKAGE_NAME, name); + /* XXX unicode */ + pipe_handle = CreateFileA (pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (!pipe_handle) + { + err_msg = g_win32_error_message (GetLastError ()); + g_warning ("could not open pipe '%s': %s", pipe_name, err_msg); + goto out; + } + + result = write_data (pipe_handle, data, len, pipe_name); + + if (result) + { + char c = 0; + result = write_data (pipe_handle, &c, 1, pipe_name); + } + +out: + if (pipe_handle != INVALID_HANDLE_VALUE) + CloseHandle (pipe_handle); + + g_free (pipe_name); + g_free (err_msg); + return result; +} + +void +_moo_app_input_broadcast (const char *header, + const char *data, + gssize len) +{ + MOO_IMPLEMENT_ME + + g_return_if_fail (header != NULL); + g_return_if_fail (data != NULL); + + if (len < 0) + len = strlen (data); + + g_return_if_fail (len != 0); +} diff --git a/moo/mooutils/mooutils.cmake b/moo/mooutils/mooutils.cmake index 7916e763..e0983466 100644 --- a/moo/mooutils/mooutils.cmake +++ b/moo/mooutils/mooutils.cmake @@ -34,7 +34,8 @@ SET(mooutils_sources mooutils/mooactiongroup.h mooutils/mooapp-ipc.c mooutils/mooapp-ipc.h - mooutils/mooappinput.c + mooutils/mooappinput-common.c + mooutils/mooappinput-priv.h mooutils/mooappinput.h mooutils/mooatom.h mooutils/moobigpaned.c