Added MdHistoryMgr, moved input pipe to mooutils
This commit is contained in:
parent
016ace4286
commit
a9f6b8b1ac
@ -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
|
||||
])
|
||||
|
2
moo.mprj
2
moo.mprj
@ -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>
|
||||
|
@ -20,8 +20,6 @@ mooapp_sources = \
|
||||
mooapp.c \
|
||||
mooapp.h \
|
||||
mooapp-private.h \
|
||||
mooappinput.c \
|
||||
mooappinput.h \
|
||||
moohtml.h \
|
||||
moohtml.c \
|
||||
moolinklabel.h \
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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,
|
||||
_moo_app_input_start (app->priv->info->short_name,
|
||||
app->priv->instance_name,
|
||||
TRUE);
|
||||
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,
|
||||
|
@ -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__ */
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
editor->priv->history = g_object_new (MD_TYPE_HISTORY_MGR,
|
||||
"name", "Editor",
|
||||
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->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)
|
||||
@ -1542,10 +1579,26 @@ static void
|
||||
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);
|
||||
|
@ -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
|
||||
|
@ -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
1281
moo/mooutils/mdhistorymgr.c
Normal file
File diff suppressed because it is too large
Load Diff
79
moo/mooutils/mdhistorymgr.h
Normal file
79
moo/mooutils/mdhistorymgr.h
Normal 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
397
moo/mooutils/mooapp-ipc.c
Normal 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
30
moo/mooutils/mooapp-ipc.h
Normal 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 */
|
@ -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,
|
||||
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)
|
||||
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);
|
46
moo/mooutils/mooappinput.h
Normal file
46
moo/mooutils/mooappinput.h
Normal 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__ */
|
Loading…
x
Reference in New Issue
Block a user