Added MdHistoryMgr, moved input pipe to mooutils

This commit is contained in:
Yevgen Muntyan 2008-02-20 06:52:05 -06:00
parent 016ace4286
commit a9f6b8b1ac
17 changed files with 2251 additions and 504 deletions

View File

@ -101,8 +101,4 @@ AC_DEFUN_ONCE([MOO_AC_FLAGS],[
AC_SUBST(MOO_XML2H)
AC_SUBST(MOO_GLADE_SUBDIR_RULE)
AC_SUBST(MOO_GLADE_RULE)
if test "x$MOO_USE_PIPE_INPUT" = "xyes"; then
AC_DEFINE(MOO_USE_PIPE_INPUT, 1, [use fifo for input])
fi
])

View File

@ -56,7 +56,7 @@
<exe>medit/medit</exe>
<vars>
<var name="LANGUAGE">ru</var>
<var name="MOO_DEBUG">misc,input</var>
<var name="MOO_DEBUG">misc,input,ipc</var>
</vars>
</run>
</medit-project>

View File

@ -20,8 +20,6 @@ mooapp_sources = \
mooapp.c \
mooapp.h \
mooapp-private.h \
mooappinput.c \
mooappinput.h \
moohtml.h \
moohtml.c \
moolinklabel.h \

View File

@ -22,10 +22,53 @@
G_BEGIN_DECLS
void _moo_app_exec_cmd (MooApp *app,
char cmd,
const char *data,
guint len);
typedef enum
{
MOO_APP_CMD_ZERO = 0,
MOO_APP_CMD_PYTHON_STRING,
MOO_APP_CMD_PYTHON_FILE,
MOO_APP_CMD_SCRIPT,
MOO_APP_CMD_OPEN_FILE,
MOO_APP_CMD_OPEN_URIS,
MOO_APP_CMD_QUIT,
MOO_APP_CMD_DIE,
MOO_APP_CMD_PRESENT,
MOO_APP_CMD_LAST
} MooAppCmdCode;
#if defined(WANT_MOO_APP_CMD_STRINGS) || defined(WANT_MOO_APP_CMD_CHARS)
/* 'g' is taken by ggap */
#define CMD_ZERO "\0"
#define CMD_PYTHON_STRING "p"
#define CMD_PYTHON_FILE "P"
#define CMD_SCRIPT "s"
#define CMD_OPEN_FILE "f"
#define CMD_OPEN_URIS "u"
#define CMD_QUIT "q"
#define CMD_DIE "d"
#define CMD_PRESENT "r"
#endif
#ifdef WANT_MOO_APP_CMD_CHARS
static const char *moo_app_cmd_chars =
CMD_ZERO
CMD_PYTHON_STRING
CMD_PYTHON_FILE
CMD_SCRIPT
CMD_OPEN_FILE
CMD_OPEN_URIS
CMD_QUIT
CMD_DIE
CMD_PRESENT
;
#endif /* WANT_MOO_APP_CMD_CHARS */
GtkWidget *_moo_app_create_prefs_dialog (MooApp *app);

View File

@ -16,7 +16,6 @@
#define MOO_APP_COMPILATION
#define WANT_MOO_APP_CMD_CHARS
#include "mooapp/mooappinput.h"
#include "mooapp/mooapp-private.h"
#include "mooapp/smclient/eggsmclient.h"
#include "mooedit/mooeditprefs.h"
@ -28,6 +27,7 @@
#include "mooutils/mooprefsdialog.h"
#include "mooutils/moopython.h"
#include "marshals.h"
#include "mooutils/mooappinput.h"
#include "mooutils/moodialogs.h"
#include "mooutils/moostock.h"
#include "mooutils/mooutils-fs.h"
@ -69,7 +69,6 @@
static struct {
MooApp *instance;
MooAppInput *input;
gboolean atexit_installed;
} moo_app_data;
@ -911,20 +910,33 @@ moo_app_init_real (MooApp *app)
}
static void
input_callback (char cmd,
const char *data,
guint len,
gpointer cb_data)
{
MooApp *app = cb_data;
g_return_if_fail (MOO_IS_APP (app));
g_return_if_fail (data != NULL);
g_signal_emit (app, signals[EXEC_CMD], 0, cmd, data, len);
}
static void
start_input (MooApp *app)
{
if (app->priv->run_input)
moo_app_data.input =
_moo_app_input_new (app->priv->info->short_name,
app->priv->instance_name,
TRUE);
_moo_app_input_start (app->priv->info->short_name,
app->priv->instance_name,
TRUE, input_callback, app);
}
const char *
moo_app_get_input_pipe_name (void)
{
return moo_app_data.input ? _moo_app_input_get_path (moo_app_data.input) : NULL;
return _moo_app_input_get_path ();
}
@ -996,7 +1008,7 @@ moo_app_send_files (MooApp *app,
g_free (uri);
}
result = moo_app_send_msg (app, pid, msg->str, msg->len + 1);
result = moo_app_send_msg (app, pid, msg->str, msg->len);
g_string_free (msg, TRUE);
return result;
@ -1125,14 +1137,8 @@ moo_app_install_cleanup (void)
static void
moo_app_cleanup (void)
{
if (moo_app_data.input)
{
_moo_app_input_free (moo_app_data.input);
moo_app_data.input = NULL;
}
_moo_app_input_shutdown ();
xdg_mime_shutdown ();
moo_cleanup ();
}
@ -1422,18 +1428,6 @@ moo_app_info_get_type (void)
}
void
_moo_app_exec_cmd (MooApp *app,
char cmd,
const char *data,
guint len)
{
g_return_if_fail (MOO_IS_APP (app));
g_return_if_fail (data != NULL);
g_signal_emit (app, signals[EXEC_CMD], 0, cmd, data, len);
}
static void
moo_app_new_file (MooApp *app,
const char *filename,

View File

@ -1,86 +0,0 @@
/*
* mooapp/mooappinput.h
*
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef __MOO_APP_INPUT__
#define __MOO_APP_INPUT__
#include <glib.h>
G_BEGIN_DECLS
typedef enum
{
MOO_APP_CMD_ZERO = 0,
MOO_APP_CMD_PYTHON_STRING,
MOO_APP_CMD_PYTHON_FILE,
MOO_APP_CMD_SCRIPT,
MOO_APP_CMD_OPEN_FILE,
MOO_APP_CMD_OPEN_URIS,
MOO_APP_CMD_QUIT,
MOO_APP_CMD_DIE,
MOO_APP_CMD_PRESENT,
MOO_APP_CMD_LAST
} MooAppCmdCode;
#if defined(WANT_MOO_APP_CMD_STRINGS) || defined(WANT_MOO_APP_CMD_CHARS)
/* 'g' is taken by ggap */
#define CMD_ZERO "\0"
#define CMD_PYTHON_STRING "p"
#define CMD_PYTHON_FILE "P"
#define CMD_SCRIPT "s"
#define CMD_OPEN_FILE "f"
#define CMD_OPEN_URIS "u"
#define CMD_QUIT "q"
#define CMD_DIE "d"
#define CMD_PRESENT "r"
#endif
#ifdef WANT_MOO_APP_CMD_CHARS
static const char *moo_app_cmd_chars =
CMD_ZERO
CMD_PYTHON_STRING
CMD_PYTHON_FILE
CMD_SCRIPT
CMD_OPEN_FILE
CMD_OPEN_URIS
CMD_QUIT
CMD_DIE
CMD_PRESENT
;
#endif /* WANT_MOO_APP_CMD_CHARS */
#define MOO_APP_INPUT_NAME_DEFAULT "main"
typedef struct _MooAppInput MooAppInput;
MooAppInput *_moo_app_input_new (const char *appname,
const char *name,
gboolean bind_default);
void _moo_app_input_free (MooAppInput *ch);
gboolean _moo_app_input_send_msg (const char *appname,
const char *name,
const char *data,
gssize len);
const char *_moo_app_input_get_path (MooAppInput *ch);
G_END_DECLS
#endif /* __MOO_APP_INPUT__ */

View File

@ -20,6 +20,7 @@
#include "mooedit/moolinemark.h"
#include "mooedit/mooeditor.h"
#include "mooedit/mootextview.h"
#include "mooutils/mdhistorymgr.h"
#include <sys/types.h>
G_BEGIN_DECLS
@ -59,6 +60,13 @@ gboolean _moo_edit_line_mark_clicked (MooTextView *view,
int line);
void _moo_edit_update_bookmarks_style(MooEdit *edit);
void _moo_edit_history_item_set_encoding (MdHistoryItem *item,
const char *encoding);
void _moo_edit_history_item_set_line (MdHistoryItem *item,
int line);
const char *_moo_edit_history_item_get_encoding (MdHistoryItem *item);
int _moo_edit_history_item_get_line (MdHistoryItem *item);
/***********************************************************************/
/* Preferences

View File

@ -28,6 +28,10 @@
#include <string.h>
#define KEY_ENCODING "encoding"
#define KEY_LINE "line"
GSList *_moo_edit_instances = NULL;
@ -714,6 +718,52 @@ moo_edit_get_editor (MooEdit *doc)
}
void
_moo_edit_history_item_set_encoding (MdHistoryItem *item,
const char *encoding)
{
g_return_if_fail (item != NULL);
md_history_item_set (item, KEY_ENCODING, encoding);
}
void
_moo_edit_history_item_set_line (MdHistoryItem *item,
int line)
{
char *value = NULL;
g_return_if_fail (item != NULL);
if (line >= 0)
value = g_strdup_printf ("%d", line + 1);
md_history_item_set (item, KEY_LINE, value);
g_free (value);
}
const char *
_moo_edit_history_item_get_encoding (MdHistoryItem *item)
{
g_return_val_if_fail (item != NULL, NULL);
return md_history_item_get (item, KEY_ENCODING);
}
int
_moo_edit_history_item_get_line (MdHistoryItem *item)
{
const char *strval;
g_return_val_if_fail (item != NULL, -1);
strval = md_history_item_get (item, KEY_LINE);
if (strval && strval[0])
return g_ascii_strtoll (strval, NULL, 10) - 1;
else
return -1;
}
typedef void (*SetVarFunc) (MooEdit *edit,
const char *name,
char *val);

View File

@ -23,7 +23,9 @@
#include "medit-ui.h"
#include "mooutils/moomenuaction.h"
#include "marshals.h"
#include "mooutils/mdhistorymgr.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooaction-private.h"
#include "mooutils/mooutils-gobject.h"
#include "mooutils/moofilewatch.h"
#include "mooutils/mooutils-fs.h"
@ -69,10 +71,8 @@ static WindowInfo *window_list_find_file (MooEditor *editor,
static void set_single_window (MooEditor *editor,
gboolean single);
static GtkAction *create_recent_action (MooEditWindow *window);
static void activate_history_item (MooEditor *editor,
MooHistoryItem *item,
MooEditWindow *window);
static GtkAction *create_open_recent_action (MooWindow *window,
gpointer user_data);
static MooEditWindow *create_window (MooEditor *editor);
static void moo_editor_add_doc (MooEditor *editor,
@ -110,7 +110,7 @@ struct _MooEditorPrivate {
MooUIXML *doc_ui_xml;
MooUIXML *ui_xml;
MooFilterMgr *filter_mgr;
MooHistoryList *history;
MdHistoryMgr *history;
MooLangMgr *lang_mgr;
MooFileWatch *file_watch;
gboolean open_single;
@ -272,7 +272,7 @@ moo_editor_class_init (MooEditorClass *klass)
edit_window_class = g_type_class_ref (MOO_TYPE_EDIT_WINDOW);
moo_window_class_new_action_custom (edit_window_class, RECENT_ACTION_ID, NULL,
(MooWindowActionFunc) create_recent_action,
create_open_recent_action,
NULL, NULL);
g_type_class_unref (edit_window_class);
@ -298,16 +298,9 @@ moo_editor_init (MooEditor *editor)
editor->priv->filter_mgr = moo_filter_mgr_new ();
editor->priv->history = moo_history_list_get ("Editor");
g_object_ref (editor->priv->history);
moo_history_list_set_display_func (editor->priv->history,
moo_history_list_display_basename,
NULL);
moo_history_list_set_tip_func (editor->priv->history,
moo_history_list_display_filename,
NULL);
g_signal_connect_swapped (editor->priv->history, "activate-item",
G_CALLBACK (activate_history_item), editor);
editor->priv->history = g_object_new (MD_TYPE_HISTORY_MGR,
"name", "Editor",
NULL);
editor->priv->windows = NULL;
editor->priv->windowless = window_info_new (NULL);
@ -951,48 +944,79 @@ static void
add_recent_file (MooEditor *editor,
const char *filename)
{
moo_history_list_add_filename (editor->priv->history, filename);
}
static GtkAction*
create_recent_action (MooEditWindow *window)
{
MooEditor *editor = moo_edit_window_get_editor (window);
GtkAction *action;
G_GNUC_UNUSED MooMenuMgr *mgr;
g_return_val_if_fail (editor != NULL, NULL);
action = moo_menu_action_new (RECENT_ACTION_ID, _("Open Recent"));
mgr = moo_history_list_get_menu_mgr (editor->priv->history);
moo_menu_mgr_set_show_tooltips (mgr, TRUE);
moo_menu_action_set_mgr (MOO_MENU_ACTION (action), mgr);
moo_menu_action_set_menu_data (MOO_MENU_ACTION (action), window, TRUE);
moo_bind_bool_property (action, "sensitive",
editor->priv->history, "empty", TRUE);
return action;
char *uri = g_filename_to_uri (filename, NULL, NULL);
if (uri)
md_history_mgr_add_uri (editor->priv->history, uri);
g_free (uri);
}
static void
activate_history_item (MooEditor *editor,
MooHistoryItem *item,
MooEditWindow *window)
recent_item_activated (MdHistoryItem *item,
gpointer data)
{
WindowInfo *win_info;
MooEditWindow *window = data;
MooEditor *editor = moo_editor_instance ();
const char *uri;
char *filename;
const char *encoding;
g_return_if_fail (MOO_IS_EDITOR (editor));
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
g_return_if_fail (item != NULL && item->data != NULL);
g_return_if_fail (MOO_IS_EDITOR (editor));
win_info = window_list_find (editor, window);
g_return_if_fail (win_info != NULL);
uri = md_history_item_get_uri (item);
filename = g_filename_from_uri (uri, NULL, NULL);
g_return_if_fail (filename != NULL);
if (!moo_editor_open_file (editor, window, GTK_WIDGET (window), item->data, NULL))
moo_history_list_remove (editor->priv->history, item->data);
encoding = _moo_edit_history_item_get_encoding (item);
if (!moo_editor_open_uri (editor, window, GTK_WIDGET (window), uri, encoding))
md_history_mgr_remove_uri (editor->priv->history, uri);
g_free (filename);
}
static GtkWidget *
create_recent_menu (GtkAction *action)
{
GtkWidget *menu, *item;
// GtkAction *action_more;
MooWindow *window;
MooEditor *editor;
window = _moo_action_get_window (action);
g_return_val_if_fail (MOO_IS_EDIT_WINDOW (window), NULL);
editor = moo_editor_instance ();
menu = md_history_mgr_create_menu (editor->priv->history,
recent_item_activated,
window, NULL);
moo_bind_bool_property (action,
"sensitive", editor->priv->history,
"empty", TRUE);
// item = gtk_separator_menu_item_new ();
// gtk_widget_show (item);
// gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
//
// action_more = md_app_window_get_action (app_window, "OpenRecentDialog");
// item = gtk_action_create_menu_item (action_more);
// gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = gtk_menu_item_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
return item;
}
static GtkAction *
create_open_recent_action (G_GNUC_UNUSED MooWindow *window,
G_GNUC_UNUSED gpointer user_data)
{
GtkAction *action;
action = moo_menu_action_new ("OpenRecent", _("Open Recent"));
moo_menu_action_set_func (MOO_MENU_ACTION (action), create_recent_menu);
return action;
}
@ -1233,6 +1257,19 @@ moo_editor_load_file (MooEditor *editor,
}
else
{
MdHistoryItem *hist_item;
char *uri;
uri = g_filename_to_uri (filename, NULL, NULL);
hist_item = md_history_mgr_find_uri (editor->priv->history, uri);
if (hist_item)
{
int line = _moo_edit_history_item_get_line (hist_item);
if (line >= 0)
moo_text_view_move_cursor (MOO_TEXT_VIEW (doc), line, 0, FALSE, TRUE);
}
g_free (uri);
if (!window)
window = moo_editor_get_active_window (editor);
if (!window)
@ -1539,13 +1576,29 @@ do_close_window (MooEditor *editor,
static void
do_close_doc (MooEditor *editor,
MooEdit *doc)
do_close_doc (MooEditor *editor,
MooEdit *doc)
{
WindowInfo *info = window_list_find_doc (editor, doc);
WindowInfo *info;
char *uri;
info = window_list_find_doc (editor, doc);
g_return_if_fail (info != NULL);
window_info_remove (info, doc);
if ((uri = moo_edit_get_uri (doc)))
{
MdHistoryItem *item;
item = md_history_item_new (uri, NULL);
_moo_edit_history_item_set_line (item,
moo_text_view_get_cursor_line (MOO_TEXT_VIEW (doc)));
_moo_edit_history_item_set_encoding (item, moo_edit_get_encoding (doc));
md_history_mgr_update_file (editor->priv->history, item);
md_history_item_free (item);
g_free (uri);
}
if (info->window)
_moo_edit_window_remove_doc (info->window, doc, TRUE);
else
@ -1815,12 +1868,6 @@ load_doc_session (MooEditor *editor,
moo_editor_load_file (editor, window, GTK_WIDGET (window), info, TRUE, FALSE, &doc);
if (doc)
{
int line = moo_markup_get_int_prop (elm, "line", 0);
moo_text_view_move_cursor (MOO_TEXT_VIEW (doc), line, 0, FALSE, TRUE);
}
moo_edit_file_info_free (info);
g_free (filename);
@ -1846,7 +1893,6 @@ save_doc_session (MooEdit *doc,
g_return_val_if_fail (utf8_filename != NULL, NULL);
node = moo_markup_create_text_element (elm, "document", utf8_filename);
moo_markup_set_int_prop (node, "line", moo_text_view_get_cursor_line (MOO_TEXT_VIEW (doc)));
if (encoding && encoding[0])
moo_markup_set_prop (node, "encoding", encoding);

View File

@ -16,7 +16,6 @@
#include <mooedit/mooeditwindow.h>
#include <mooedit/moolangmgr.h>
#include <mooutils/moouixml.h>
#include <mooutils/moohistorylist.h>
#include <mooutils/moofiltermgr.h>
G_BEGIN_DECLS

View File

@ -22,6 +22,7 @@ thread_sources = \
mooutils-thread.h
mooutils_include_headers = \
mdhistorymgr.h \
mooaction.h \
mooactionbase.h \
mooactioncollection.h \
@ -58,6 +59,11 @@ mooutils_include_headers = \
mooutils_sources = \
$(mooutils_include_headers) \
mdhistorymgr.c \
mooappinput.h \
mooappinput.c \
mooapp-ipc.h \
mooapp-ipc.c \
mooaccel.h \
mooaccel.c \
mooaccelbutton.c \

1281
moo/mooutils/mdhistorymgr.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/*
* mdhistorymgr.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef MD_HISTORY_MGR_H
#define MD_HISTORY_MGR_H
#include <gtk/gtk.h>
#define MD_TYPE_HISTORY_MGR (md_history_mgr_get_type ())
#define MD_HISTORY_MGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MD_TYPE_HISTORY_MGR, MdHistoryMgr))
#define MD_HISTORY_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MD_TYPE_HISTORY_MGR, MdHistoryMgrClass))
#define MD_IS_HISTORY_MGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MD_TYPE_HISTORY_MGR))
#define MD_IS_HISTORY_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MD_TYPE_HISTORY_MGR))
#define MD_HISTORY_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MD_TYPE_HISTORY_MGR, MdHistoryMgrClass))
typedef struct MdHistoryItem MdHistoryItem;
typedef struct MdHistoryMgr MdHistoryMgr;
typedef struct MdHistoryMgrClass MdHistoryMgrClass;
typedef struct MdHistoryMgrPrivate MdHistoryMgrPrivate;
struct MdHistoryMgr {
GObject base;
MdHistoryMgrPrivate *priv;
};
struct MdHistoryMgrClass {
GObjectClass base_class;
};
typedef void (*MdHistoryCallback) (MdHistoryItem *item,
gpointer data);
GType md_history_mgr_get_type (void) G_GNUC_CONST;
void md_history_mgr_add_file (MdHistoryMgr *mgr,
MdHistoryItem *item);
void md_history_mgr_update_file (MdHistoryMgr *mgr,
MdHistoryItem *item);
void md_history_mgr_add_uri (MdHistoryMgr *mgr,
const char *uri);
void md_history_mgr_remove_uri (MdHistoryMgr *mgr,
const char *uri);
MdHistoryItem *md_history_mgr_find_uri (MdHistoryMgr *mgr,
const char *uri);
guint md_history_mgr_get_n_items (MdHistoryMgr *mgr);
GtkWidget *md_history_mgr_create_menu (MdHistoryMgr *mgr,
MdHistoryCallback callback,
gpointer data,
GDestroyNotify notify);
MdHistoryItem *md_history_item_new (const char *uri,
const char *first_key,
...);
MdHistoryItem *md_history_item_copy (MdHistoryItem *item);
void md_history_item_free (MdHistoryItem *item);
void md_history_item_set (MdHistoryItem *item,
const char *key,
const char *value);
const char *md_history_item_get (MdHistoryItem *item,
const char *key);
const char *md_history_item_get_uri (MdHistoryItem *item);
void md_history_item_foreach (MdHistoryItem *item,
GDataForeachFunc func,
gpointer user_data);
#endif /* MD_HISTORY_MGR_H */

397
moo/mooutils/mooapp-ipc.c Normal file
View File

@ -0,0 +1,397 @@
#include "mooapp-ipc.h"
#include "mooappinput.h"
#include "mooutils-debug.h"
#include "mooutils-misc.h"
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#define VERSION_STRING "0001"
#define VERSION_LEN 4
#define STAMP_LEN 8
#define APP_ID_LEN 8
#define CLIENT_ID_LEN 4
#define MAX_ID_LEN 9999
MOO_DEBUG_INIT (ipc, TRUE)
static struct {
GHashTable *clients; /* id -> GSList* of ClientInfo */
GQuark ids_quark;
char *app_id;
guint stamp;
GHashTable *stamp_hash; /* app_id -> guint */
} ipc_data;
typedef struct {
GObject *object;
MooDataCallback callback;
guint ref_count : 31;
guint dead : 1;
} ClientInfo;
static ClientInfo *
client_info_new (GObject *obj,
MooDataCallback callback)
{
ClientInfo *ci = moo_new (ClientInfo);
ci->object = obj;
ci->callback = callback;
ci->ref_count = 1;
ci->dead = FALSE;
return ci;
}
static void
client_info_ref (ClientInfo *ci)
{
ci->ref_count++;
}
static void
client_info_unref (ClientInfo *ci)
{
g_return_if_fail (ci != NULL && ci->ref_count != 0);
if (!--ci->ref_count)
moo_free (ClientInfo, ci);
}
static char *
generate_id (void)
{
struct timeval tv;
int rand_int;
gettimeofday (&tv, NULL);
rand_int = g_random_int_range (1, 10000);
return g_strdup_printf ("%04d%04d", (int)(tv.tv_sec % 10000), rand_int);
}
static void
init_clients_table (void)
{
if (!ipc_data.clients)
{
ipc_data.clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
ipc_data.ids_quark = g_quark_from_static_string ("moo-ipc-client-id-list");
ipc_data.stamp_hash = g_hash_table_new (g_str_hash, g_str_equal);
ipc_data.app_id = generate_id ();
}
}
static void
unregister_client (const char *id,
GObject *obj)
{
ClientInfo *ci = NULL;
GSList *client_list, *l;
moo_dmsg ("%s: removing <%p, %s>", G_STRFUNC, (gpointer) obj, id);
client_list = g_hash_table_lookup (ipc_data.clients, id);
for (ci = NULL, l = client_list; !ci && l; l = l->next)
{
ci = l->data;
if (ci->object != obj)
ci = NULL;
}
if (!ci)
{
g_critical ("could not find <%p, %s>", (gpointer) obj, id);
}
else
{
client_list = g_slist_delete_link (client_list, l);
if (client_list)
g_hash_table_insert (ipc_data.clients, g_strdup (id), client_list);
else
g_hash_table_remove (ipc_data.clients, id);
ci->dead = TRUE;
client_info_unref (ci);
}
}
static void
client_died (GSList *ids,
GObject *dead_obj)
{
moo_dmsg ("%s: object %p died", G_STRFUNC, (gpointer) dead_obj);
while (ids)
{
char *id = ids->data;
unregister_client (id, dead_obj);
g_free (id);
ids = g_slist_delete_link (ids, ids);
}
}
void
moo_ipc_register_client (GObject *object,
const char *id,
MooDataCallback callback)
{
GSList *ids;
GSList *client_list;
ClientInfo *info;
g_return_if_fail (G_IS_OBJECT (object));
g_return_if_fail (id != NULL);
if (strlen (id) > MAX_ID_LEN)
{
g_critical ("%s: id '%s' is too long", G_STRFUNC, id);
return;
}
init_clients_table ();
ids = g_object_get_qdata (object, ipc_data.ids_quark);
if (g_slist_find_custom (ids, id, (GCompareFunc) strcmp))
{
g_critical ("%s: <%p, %s> already registered",
G_STRFUNC, (gpointer) object, id);
return;
}
if (ids)
g_object_weak_unref (object, (GWeakNotify) client_died, ids);
ids = g_slist_prepend (ids, g_strdup (id));
g_object_weak_ref (object, (GWeakNotify) client_died, ids);
g_object_set_qdata (object, ipc_data.ids_quark, ids);
info = client_info_new (object, callback);
client_list = g_hash_table_lookup (ipc_data.clients, id);
client_list = g_slist_prepend (client_list, info);
g_hash_table_insert (ipc_data.clients, g_strdup (id), client_list);
}
void
moo_ipc_unregister_client (GObject *object,
const char *id)
{
GSList *ids, *l;
g_return_if_fail (G_IS_OBJECT (object));
g_return_if_fail (id != NULL);
init_clients_table ();
ids = g_object_get_qdata (object, ipc_data.ids_quark);
if (!(l = g_slist_find_custom (ids, id, (GCompareFunc) strcmp)))
{
g_critical ("%s: <%p, %s> not registered",
G_STRFUNC, (gpointer) object, id);
return;
}
g_object_weak_unref (object, (GWeakNotify) client_died, ids);
ids = g_slist_delete_link (ids, l);
if (ids)
g_object_weak_ref (object, (GWeakNotify) client_died, ids);
g_object_set_qdata (object, ipc_data.ids_quark, ids);
unregister_client (id, object);
}
void
moo_ipc_send (GObject *sender,
const char *id,
const char *data,
gssize len)
{
GString *header;
guint id_len;
g_return_if_fail (!sender || G_IS_OBJECT (sender));
g_return_if_fail (id != NULL);
g_return_if_fail (data != NULL);
g_return_if_fail (ipc_data.app_id != NULL);
if (len < 0)
len = strlen (data);
id_len = strlen (id);
g_return_if_fail (id_len != 0 && id_len < MAX_ID_LEN);
header = g_string_new (VERSION_STRING);
g_string_append (header, ipc_data.app_id);
g_string_append_printf (header, "%08x", ++ipc_data.stamp);
g_string_append_printf (header, "%04x", id_len);
g_string_append (header, id);
_moo_app_input_broadcast (header->str, data, len);
g_string_free (header, TRUE);
}
static void
dispatch (const char *id,
const char *data,
gsize len)
{
GSList *clients;
moo_dmsg ("%s: got data for id '%s': %.*s",
G_STRFUNC, id, (int) len, data);
clients = g_hash_table_lookup (ipc_data.clients, id);
if (!clients)
{
moo_dmsg ("%s: no clients registered for id '%s'", G_STRFUNC, id);
return;
}
clients = g_slist_copy (clients);
g_slist_foreach (clients, (GFunc) client_info_ref, NULL);
while (clients)
{
ClientInfo *ci = clients->data;
if (!ci->dead)
{
moo_dmsg ("%s: feeding data to <%p>", G_STRFUNC, (gpointer) ci->object);
ci->callback (ci->object, data, len);
}
client_info_unref (ci);
clients = g_slist_delete_link (clients, clients);
}
}
static gboolean
get_uint (const char *data,
guint len,
guint *dest)
{
char *string, *end;
guint64 val;
gboolean result = FALSE;
string = g_strndup (data, len);
errno = 0;
val = g_ascii_strtoull (string, &end, 16);
if (!errno && !end[0] && val <= G_MAXUINT)
{
*dest = val;
result = TRUE;
}
g_free (string);
return result;
}
static gboolean
check_stamp (const char *app_id,
guint stamp)
{
gpointer old_val;
old_val = g_hash_table_lookup (ipc_data.stamp_hash, app_id);
if (old_val)
{
guint old_stamp = GPOINTER_TO_UINT (old_val);
moo_dmsg ("%s: new stamp %u, old stamp %u",
G_STRFUNC, stamp, old_stamp);
if (old_stamp >= stamp)
return FALSE;
g_hash_table_insert (ipc_data.stamp_hash, (char*) app_id,
GUINT_TO_POINTER (stamp));
}
else
{
g_hash_table_insert (ipc_data.stamp_hash, g_strdup (app_id),
GUINT_TO_POINTER (stamp));
}
return TRUE;
}
void
_moo_ipc_dispatch (const char *data,
gsize len)
{
guint stamp;
guint id_len;
char *id = NULL, *app_id = NULL;
g_return_if_fail (len >= VERSION_LEN + STAMP_LEN + APP_ID_LEN + CLIENT_ID_LEN);
if (!ipc_data.app_id)
{
moo_dmsg ("%s: no clients", G_STRFUNC);
goto out;
}
if (strncmp (data, VERSION_STRING, VERSION_LEN) != 0)
{
moo_dmsg ("%s: wrong version %.4s", G_STRFUNC, data);
goto out;
}
data += VERSION_LEN;
len -= VERSION_LEN;
if (strncmp (data, ipc_data.app_id, APP_ID_LEN) == 0)
{
moo_dmsg ("%s: got message from itself", G_STRFUNC);
goto out;
}
app_id = g_strndup (data, APP_ID_LEN);
data += APP_ID_LEN;
len -= APP_ID_LEN;
if (!get_uint (data, STAMP_LEN, &stamp))
{
moo_dmsg ("%s: invalid stamp '%.8s'", G_STRFUNC, data);
goto out;
}
if (!check_stamp (app_id, stamp))
goto out;
data += STAMP_LEN;
len -= STAMP_LEN;
if (!get_uint (data, CLIENT_ID_LEN, &id_len))
{
moo_dmsg ("%s: invalid id length '%.4s'", G_STRFUNC, data);
goto out;
}
data += CLIENT_ID_LEN;
len -= CLIENT_ID_LEN;
if (len < id_len)
{
moo_dmsg ("%s: id is too short: '%.*s' (expected %u)",
G_STRFUNC, (int) len, data, id_len);
goto out;
}
id = g_strndup (data, id_len);
data += id_len;
len -= id_len;
dispatch (id, data, len);
out:
g_free (id);
g_free (app_id);
}

30
moo/mooutils/mooapp-ipc.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef MOO_APP_IPC_H
#define MOO_APP_IPC_H
#include <glib-object.h>
G_BEGIN_DECLS
typedef void (*MooDataCallback) (GObject *object,
const char *data,
gsize len);
void moo_ipc_register_client (GObject *object,
const char *id,
MooDataCallback callback);
void moo_ipc_unregister_client (GObject *object,
const char *id);
void moo_ipc_send (GObject *sender,
const char *id,
const char *data,
gssize len);
void _moo_ipc_dispatch (const char *data,
gsize len);
G_END_DECLS
#endif /* MOO_APP_IPC_H */

View File

@ -10,14 +10,10 @@
* See COPYING file that comes with this distribution.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __WIN32__
#define MOO_APP_INPUT_WIN32
#elif defined(MOO_USE_PIPE_INPUT)
#define MOO_APP_INPUT_PIPE
#else
#define MOO_APP_INPUT_SOCKET
#endif
@ -25,9 +21,6 @@
#if defined(MOO_APP_INPUT_WIN32)
# include <windows.h>
# include <io.h>
#elif defined(MOO_APP_INPUT_PIPE)
# include <sys/poll.h>
# include <signal.h>
#else
# include <sys/socket.h>
# include <sys/un.h>
@ -44,16 +37,17 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "mooapp/mooappinput.h"
#define MOO_APP_COMPILATION
#include "mooapp/mooapp-private.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooutils-thread.h"
#include "mooutils/mooutils-debug.h"
#include "mooappinput.h"
#include "mooapp-ipc.h"
#include "mooutils-misc.h"
#include "mooutils-thread.h"
#include "mooutils-debug.h"
MOO_DEBUG_INIT(input, TRUE)
#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-"
@ -61,34 +55,58 @@ MOO_DEBUG_INIT(input, TRUE)
#define INPUT_PREFIX "input-"
#endif
typedef struct MooAppInput MooAppInput;
typedef struct InputChannel InputChannel;
struct _MooAppInput
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);
static const char *input_channel_get_name (InputChannel *ch);
MooAppInput *
_moo_app_input_new (const char *appname,
const char *name,
gboolean bind_default)
static void
exec_callback (char cmd,
const char *data,
guint 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 *appname,
const char *name,
gboolean bind_default,
MooAppInputCallback callback,
gpointer callback_data)
{
MooAppInput *ch;
InputChannel *ich;
g_return_val_if_fail (appname != NULL, NULL);
g_return_val_if_fail (callback != NULL, NULL);
ch = moo_new0 (MooAppInput);
ch->callback = callback;
ch->callback_data = callback_data;
ch->pipes = NULL;
ch->appname = g_strdup (appname);
@ -108,7 +126,19 @@ _moo_app_input_new (const char *appname,
}
void
_moo_app_input_free (MooAppInput *ch)
_moo_app_input_start (const char *appname,
const char *name,
gboolean bind_default,
MooAppInputCallback callback,
gpointer callback_data)
{
g_return_if_fail (inp_instance == NULL);
inp_instance = moo_app_input_new (appname, name, bind_default,
callback, callback_data);
}
static void
moo_app_input_free (MooAppInput *ch)
{
g_return_if_fail (ch != NULL);
@ -120,12 +150,28 @@ _moo_app_input_free (MooAppInput *ch)
moo_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 (MooAppInput *ch)
_moo_app_input_get_path (void)
{
g_return_val_if_fail (ch != NULL, NULL);
return ch->main_path;
return inp_instance ? inp_instance->main_path : NULL;
}
gboolean
_moo_app_input_running (void)
{
return inp_instance != NULL;
}
@ -161,7 +207,7 @@ commit (GString **buffer)
if (0)
g_print ("%s: commit %c\n%s\n-----\n", G_STRLOC, ptr[0], ptr + 1);
_moo_app_exec_cmd (moo_app_get_instance (), ptr[0], ptr + 1, len - 1);
exec_callback (ptr[0], ptr + 1, len - 1);
if (freeme)
g_string_free (freeme, TRUE);
@ -230,12 +276,14 @@ input_channel_start_io (int fd,
static gboolean do_send (const char *filename,
const char *iheader,
const char *data,
gssize data_len);
static gboolean
try_send (const char *pipe_dir_name,
const char *name,
const char *iheader,
const char *data,
gssize data_len)
{
@ -253,7 +301,7 @@ try_send (const char *pipe_dir_name,
goto out;
}
result = do_send (filename, data, data_len);
result = do_send (filename, iheader, data, data_len);
out:
g_free (filename);
@ -281,11 +329,11 @@ _moo_app_input_send_msg (const char *appname,
if (name)
{
success = try_send (pipe_dir_name, name, data, len);
success = try_send (pipe_dir_name, name, NULL, data, len);
goto out;
}
success = try_send (pipe_dir_name, MOO_APP_INPUT_NAME_DEFAULT, data, len);
success = try_send (pipe_dir_name, MOO_APP_INPUT_NAME_DEFAULT, NULL, data, len);
if (success)
goto out;
@ -300,7 +348,7 @@ _moo_app_input_send_msg (const char *appname,
{
name = entry + strlen (INPUT_PREFIX);
if (try_send (pipe_dir_name, name, data, len))
if (try_send (pipe_dir_name, name, NULL, data, len))
{
success = TRUE;
goto out;
@ -315,6 +363,53 @@ out:
return success;
}
void
_moo_app_input_broadcast (const char *header,
const char *data,
gssize len)
{
const char *entry;
GDir *pipe_dir = NULL;
char *pipe_dir_name;
g_return_if_fail (data != NULL);
moo_dmsg ("_moo_app_input_broadcast");
if (!inp_instance)
return;
pipe_dir_name = get_pipe_dir (inp_instance->appname);
g_return_if_fail (pipe_dir_name != NULL);
pipe_dir = g_dir_open (pipe_dir_name, 0, NULL);
while (pipe_dir && (entry = g_dir_read_name (pipe_dir)))
{
if (!strncmp (entry, INPUT_PREFIX, strlen (INPUT_PREFIX)))
{
GSList *l;
gboolean my_name = FALSE;
const char *name = entry + strlen (INPUT_PREFIX);
for (l = inp_instance->pipes; !my_name && l != NULL; l = l->next)
{
InputChannel *ch = l->data;
const char *ch_name = input_channel_get_name (ch);
if (ch_name && strcmp (ch_name, name) == 0)
my_name = TRUE;
}
if (!my_name)
try_send (pipe_dir_name, name, header, data, len);
}
}
if (pipe_dir)
g_dir_close (pipe_dir);
g_free (pipe_dir_name);
}
static gboolean
do_write (int fd,
const char *data,
@ -381,6 +476,13 @@ input_channel_get_path (InputChannel *ch)
return g_strdup (ch->path);
}
static const char *
input_channel_get_name (InputChannel *ch)
{
g_return_val_if_fail (ch != NULL, NULL);
return ch->name;
}
static void
connection_free (Connection *conn)
{
@ -674,6 +776,7 @@ input_channel_free (InputChannel *ch)
static gboolean
do_send (const char *filename,
const char *iheader,
const char *data,
gssize data_len)
{
@ -687,11 +790,24 @@ do_send (const char *filename,
return FALSE;
if (data_len < 0)
data_len = strlen (data) + 1;
data_len = strlen (data);
if (data_len)
if (iheader)
{
char c = IPC_MAGIC_CHAR;
result = do_write (fd, &c, 1) &&
do_write (fd, iheader, strlen (iheader));
}
if (result && data_len)
result = do_write (fd, data, data_len);
if (result)
{
char c = 0;
result = do_write (fd, &c, 1);
}
close (fd);
return result;
}
@ -699,284 +815,6 @@ do_send (const char *filename,
#endif /* MOO_APP_INPUT_SOCKET */
#ifdef MOO_APP_INPUT_PIPE
struct InputChannel
{
char *name;
char *path;
char *pipe_dir;
gboolean owns_file;
int fd;
GString *buffer;
GIOChannel *io;
guint io_watch;
GSList *connections;
};
static char *
input_channel_get_path (InputChannel *ch)
{
g_return_val_if_fail (ch != NULL, NULL);
return g_strdup (ch->path);
}
static void
input_channel_shutdown (InputChannel *ch)
{
if (ch->io_watch)
{
g_source_remove (ch->io_watch);
ch->io_watch = 0;
}
if (ch->io)
{
g_io_channel_shutdown (ch->io, FALSE, NULL);
g_io_channel_unref (ch->io);
ch->io = NULL;
}
if (ch->fd != -1)
{
close (ch->fd);
ch->fd = -1;
}
if (ch->path)
{
unlink (ch->path);
g_free (ch->path);
ch->path = NULL;
}
if (ch->buffer)
{
g_string_free (ch->buffer, TRUE);
ch->buffer = NULL;
}
}
static gboolean
read_input (GIOChannel *source,
GIOCondition condition,
InputChannel *ch)
{
gboolean error_occured = FALSE;
GError *err = NULL;
gboolean again = TRUE;
gboolean got_zero = FALSE;
g_return_val_if_fail (source == ch->io, FALSE);
/* XXX */
if (condition & (G_IO_ERR | G_IO_HUP))
error_occured = TRUE;
while (again && !error_occured && !err)
{
char c;
int bytes_read;
struct pollfd fd;
fd.fd = ch->fd;
fd.events = POLLIN | POLLPRI;
fd.revents = 0;
switch (poll (&fd, 1, 0))
{
case -1:
if (errno != EINTR && errno != EAGAIN)
error_occured = TRUE;
perror ("poll");
again = FALSE;
break;
case 0:
if (0)
g_print ("%s: got nothing\n", G_STRLOC);
again = FALSE;
break;
case 1:
if (fd.revents & (POLLERR))
{
if (errno != EINTR && errno != EAGAIN)
error_occured = TRUE;
perror ("poll");
}
else
{
bytes_read = read (ch->fd, &c, 1);
if (bytes_read == 1)
{
g_string_append_c (ch->buffer, c);
if (!c)
{
got_zero = TRUE;
again = FALSE;
}
}
else if (bytes_read == -1)
{
perror ("read");
if (errno != EINTR && errno != EAGAIN)
error_occured = TRUE;
again = FALSE;
}
else
{
again = FALSE;
}
}
break;
default:
g_assert_not_reached ();
}
}
if (error_occured || err)
{
g_critical ("%s: %s", G_STRLOC, err ? err->message : "error");
if (err)
g_error_free (err);
input_channel_shutdown (ch);
return FALSE;
}
if (got_zero)
commit (&ch->buffer);
return TRUE;
}
static gboolean
input_channel_start (InputChannel *ch,
G_GNUC_UNUSED gboolean may_fail)
{
mkdir (ch->pipe_dir, S_IRWXU);
unlink (ch->path);
if (mkfifo (ch->path, S_IRUSR | S_IWUSR) != 0)
{
int err = errno;
g_critical ("%s: error in mkfifo()", G_STRLOC);
g_critical ("%s: %s", G_STRLOC, g_strerror (err));
return FALSE;
}
/* XXX O_RDWR is not good (man 3p open), but it must be opened for
* writing by us, otherwise we get POLLHUP when a writer dies on the other end.
* So, open for writing separately. */
ch->fd = open (ch->path, O_RDWR | O_NONBLOCK);
if (ch->fd == -1)
{
int err = errno;
g_critical ("%s: error in open()", G_STRLOC);
g_critical ("%s: %s", G_STRLOC, g_strerror (err));
return FALSE;
}
moo_dmsg ("%s: opened input pipe %s with fd %d",
G_STRLOC, ch->path, ch->fd);
if (!input_channel_start_io (ch->fd, (GIOFunc) read_input, ch,
&ch->io, &ch->io_watch))
return FALSE;
return TRUE;
}
static InputChannel *
input_channel_new (const char *appname,
const char *name,
gboolean may_fail)
{
InputChannel *ch;
g_return_val_if_fail (appname != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
ch = moo_new0 (InputChannel);
ch->name = g_strdup (name);
ch->pipe_dir = get_pipe_dir (appname);
ch->path = get_pipe_path (ch->pipe_dir, name);
ch->fd = -1;
ch->io = NULL;
ch->io_watch = 0;
ch->buffer = g_string_new_len (NULL, MAX_BUFFER_SIZE);
if (!input_channel_start (ch, may_fail))
{
input_channel_free (ch);
return NULL;
}
return ch;
}
static void
input_channel_free (InputChannel *ch)
{
input_channel_shutdown (ch);
g_free (ch->name);
g_free (ch->path);
if (ch->pipe_dir)
{
remove (ch->pipe_dir);
g_free (ch->pipe_dir);
}
moo_free (InputChannel, ch);
}
static gboolean
do_send (const char *filename,
const char *data,
gssize data_len)
{
gboolean result = FALSE;
int fd;
moo_dmsg ("do_send: sending data to `%s'", filename);
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
{
moo_dmsg ("do_send: file `%s' doesn't exist", filename);
return FALSE;
}
fd = open (filename, O_WRONLY | O_NONBLOCK);
if (fd == -1)
{
moo_dmsg ("do_send: could not open `%s': %s", filename, g_strerror (errno));
return FALSE;
}
result = do_write (fd, data, data_len);
close (fd);
if (result)
moo_dmsg ("do_send: successfully sent stuff to `%s'", filename);
return result;
}
#endif /* MOO_APP_INPUT_PIPE */
/****************************************************************************/
/* WIN32
*/
@ -1003,6 +841,13 @@ input_channel_get_path (InputChannel *ch)
return g_strdup (ch->pipe_name);
}
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)
@ -1188,6 +1033,29 @@ input_channel_free (InputChannel *ch)
moo_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, 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;
}
}
gboolean
_moo_app_input_send_msg (const char *appname,
const char *name,
@ -1198,7 +1066,6 @@ _moo_app_input_send_msg (const char *appname,
char *pipe_name;
HANDLE pipe_handle;
gboolean result = FALSE;
DWORD bytes_written;
g_return_val_if_fail (appname != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
@ -1223,21 +1090,14 @@ _moo_app_input_send_msg (const char *appname,
goto out;
}
if (!WriteFile (pipe_handle, data, len, &bytes_written, NULL))
{
err_msg = g_win32_error_message (GetLastError ());
g_warning ("could not write data to '%s': %s", pipe_name, err_msg);
goto out;
}
result = write_data (pipe_handle, data, len, pipe_name);
if (bytes_written < (DWORD) len)
if (result)
{
g_warning ("written less data than requested to '%s'", pipe_name);
goto out;
char c = 0;
result = write_data (pipe_handle, &c, 1, pipe_name);
}
result = TRUE;
out:
if (pipe_handle != INVALID_HANDLE_VALUE)
CloseHandle (pipe_handle);

View File

@ -0,0 +1,46 @@
/*
* mooapp/mooappinput.h
*
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef __MOO_APP_INPUT__
#define __MOO_APP_INPUT__
#include <glib.h>
G_BEGIN_DECLS
typedef void (*MooAppInputCallback) (char cmd,
const char *data,
guint len,
gpointer cb_data);
void _moo_app_input_start (const char *appname,
const char *name,
gboolean bind_default,
MooAppInputCallback callback,
gpointer callback_data);
void _moo_app_input_shutdown (void);
gboolean _moo_app_input_running (void);
gboolean _moo_app_input_send_msg (const char *appname,
const char *name,
const char *data,
gssize len);
void _moo_app_input_broadcast (const char *header,
const char *data,
gssize len);
const char *_moo_app_input_get_path (void);
G_END_DECLS
#endif /* __MOO_APP_INPUT__ */