Changed src/ to gnoemoe/
This commit is contained in:
parent
e52f7f05e2
commit
c0b3190df6
78 changed files with 0 additions and 16737 deletions
|
@ -1,46 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
SUBDIRS = test
|
||||
INCLUDES = \
|
||||
-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
|
||||
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
|
||||
@PACKAGE_CFLAGS@ \
|
||||
@RUBYINCLUDE@
|
||||
|
||||
bin_PROGRAMS = gnoemoe
|
||||
BUILT_SOURCES = gm-marshal.c gm-marshal.h
|
||||
|
||||
gnoemoe_SOURCES = $(BUILT_SOURCES) \
|
||||
gm-app.c gm-app.h \
|
||||
gm-options.c gm-options.h \
|
||||
gm-color-table.c gm-color-table.h \
|
||||
gm-net.c gm-net.h \
|
||||
gm-triggers.c gm-triggers.h \
|
||||
gm-world.c gm-world.h \
|
||||
gm-string.c gm-string.h \
|
||||
gm-support.c gm-support.h \
|
||||
gm-editor.c gm-editor.h \
|
||||
gm-pixbuf.c gm-pixbuf.h \
|
||||
gm-debug.c gm-debug.h
|
||||
|
||||
include $(srcdir)/widgets/Makefile.include
|
||||
include $(srcdir)/dialogs/Makefile.include
|
||||
include $(srcdir)/mcp/Makefile.include
|
||||
|
||||
if HAVE_SCRIPT
|
||||
gnoemoe_SOURCES += gm-scripts.c gm-scripts.h
|
||||
endif
|
||||
gm-marshal.h: gm-marshal.list $(GLIB_GENMARSHAL)
|
||||
$(GLIB_GENMARSHAL) $< --header --prefix=gm_marshal > $@
|
||||
|
||||
gm-marshal.c: gm-marshal.list $(GLIB_GENMARSHAL)
|
||||
echo "#include \"gm-marshal.h\"" > $@ && \
|
||||
$(GLIB_GENMARSHAL) $< --body --prefix=gm_marshal >> $@
|
||||
|
||||
gnoemoe_LDADD = @PACKAGE_LIBS@ $(INTLLIBS) @RUBYLINK@
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES)
|
||||
|
||||
dist-hook:
|
||||
cd $(distdir); rm -f $(BUILT_SOURCES)
|
||||
|
||||
AM_CFLAGS = -Werror -Wall -Wsign-compare
|
124
src/ansi.h
124
src/ansi.h
|
@ -1,124 +0,0 @@
|
|||
#ifndef ANSI_H
|
||||
#define ANSI_H
|
||||
|
||||
/** \defgroup ansi
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \brief enum indicating ansi code
|
||||
*
|
||||
* Enumeration which indicates the ansi code
|
||||
*/
|
||||
typedef enum _ansi_code {
|
||||
A_DEFAULT = 0, /**< default (reset all attributes) */
|
||||
A_BOLD = 1, /**< bold text */
|
||||
A_FAINT = 2, /**< faint text */
|
||||
A_ITALIC = 3, /**< italic text */
|
||||
A_UNDERLINE = 4, /**< underlined text */
|
||||
A_INVERSE = 7, /**< inverse foreground/background colors */
|
||||
A_INVISIBLE = 8, /**< invisible text */
|
||||
A_CROSSOUT = 9, /**< crossed out text */
|
||||
A_DOUBLE_UNDERLINE = 21, /**< double underlined text */
|
||||
|
||||
A_BOLD_OFF = 22, /**< text no longer bold */
|
||||
A_ITALIC_OFF = 23, /**< text no longer italic */
|
||||
A_UNDERLINE_OFF = 24, /**< text no longer underlined */
|
||||
A_INVERSE_OFF = 27, /**< text no longer inversed */
|
||||
A_INVISIBLE_OFF = 28, /**< text no longer invisible */
|
||||
A_CROSSOUT_OFF = 29, /**< text no longer crossed out */
|
||||
|
||||
A_FG_BLACK = 30, /**< foreground color black */
|
||||
A_FG_RED = 31, /**< foreground color red */
|
||||
A_FG_GREEN = 32, /**< foreground color green */
|
||||
A_FG_YELLOW = 33, /**< foreground color yellow */
|
||||
A_FG_BLUE = 34, /**< foreground color blue */
|
||||
A_FG_PURPLE = 35, /**< foreground color purple */
|
||||
A_FG_CYAN = 36, /**< foreground color cyan */
|
||||
A_FG_WHITE = 37, /**< foreground color white */
|
||||
A_FG_DEFAULT = 39, /**< foreground color default */
|
||||
|
||||
A_BG_BLACK = 40, /**< background color black */
|
||||
A_BG_RED = 41, /**< background color red */
|
||||
A_BG_GREEN = 42, /**< background color green */
|
||||
A_BG_YELLOW = 43, /**< background color yellow */
|
||||
A_BG_BLUE = 44, /**< background color blue */
|
||||
A_BG_PURPLE = 45, /**< background color purple */
|
||||
A_BG_CYAN = 46, /**< background color cyan */
|
||||
A_BG_WHITE = 47, /**< background color white */
|
||||
A_BG_DEFAULT = 49, /**< background color default */
|
||||
|
||||
A_NOWRAP = 50, /**< do not wrap this text */
|
||||
|
||||
A_FG_BLACK_H, /**< foreground color black high */
|
||||
A_FG_RED_H, /**< foreground color red high */
|
||||
A_FG_GREEN_H, /**< foreground color green high */
|
||||
A_FG_YELLOW_H, /**< foreground color yellow high */
|
||||
A_FG_BLUE_H, /**< foreground color blue high */
|
||||
A_FG_PURPLE_H, /**< foreground color purple high */
|
||||
A_FG_CYAN_H, /**< foreground color cyan high */
|
||||
A_FG_WHITE_H, /**< foreground color white high */
|
||||
A_FG_DEFAULT_H /**< foreground color default high */
|
||||
} ansi_code;
|
||||
|
||||
/** \brief struct for containing ansi-name pair
|
||||
*
|
||||
* Struct can be used to create a code to name to code mapping
|
||||
*/
|
||||
typedef struct _ansinamepair {
|
||||
const ansi_code code; /**< the ansi code */
|
||||
const char *name; /**< the ansi name */
|
||||
} ansinamepair;
|
||||
|
||||
/** \brief array containing color code/name mapping
|
||||
*
|
||||
* Array which can be used for color code/name mapping
|
||||
*/
|
||||
static const ansinamepair ansi_colors[] = {
|
||||
{A_FG_BLACK, "fg_black"},
|
||||
{A_FG_RED, "fg_red"},
|
||||
{A_FG_GREEN, "fg_green"},
|
||||
{A_FG_YELLOW, "fg_yellow"},
|
||||
{A_FG_BLUE, "fg_blue"},
|
||||
{A_FG_PURPLE, "fg_purple"},
|
||||
{A_FG_CYAN, "fg_cyan"},
|
||||
{A_FG_WHITE, "fg_white"},
|
||||
{A_FG_DEFAULT, "fg_default"},
|
||||
{A_FG_BLACK_H, "fg_black_h"},
|
||||
{A_FG_RED_H, "fg_red_h"},
|
||||
{A_FG_GREEN_H, "fg_green_h"},
|
||||
{A_FG_YELLOW_H, "fg_yellow_h"},
|
||||
{A_FG_BLUE_H, "fg_blue_h"},
|
||||
{A_FG_PURPLE_H, "fg_purple_h"},
|
||||
{A_FG_CYAN_H, "fg_cyan_h"},
|
||||
{A_FG_WHITE_H, "fg_white_h"},
|
||||
{A_FG_DEFAULT_H, "fg_default_h"},
|
||||
{A_BG_BLACK, "bg_black"},
|
||||
{A_BG_RED, "bg_red"},
|
||||
{A_BG_GREEN, "bg_green"},
|
||||
{A_BG_YELLOW, "bg_yellow"},
|
||||
{A_BG_BLUE, "bg_blue"},
|
||||
{A_BG_PURPLE, "bg_purple"},
|
||||
{A_BG_CYAN, "bg_cyan"},
|
||||
{A_BG_WHITE, "bg_white"},
|
||||
{A_BG_DEFAULT, "bg_default"}
|
||||
};
|
||||
|
||||
/** \brief array containing style code/name mapping
|
||||
*
|
||||
* Array which can be used for style code/name mapping
|
||||
*/
|
||||
static const ansinamepair ansi_styles[] = {
|
||||
{A_BOLD, "bold"},
|
||||
{A_FAINT, "faint"},
|
||||
{A_BOLD_OFF, "bold-off"},
|
||||
{A_UNDERLINE, "underline"},
|
||||
{A_DOUBLE_UNDERLINE, "dblunderline"},
|
||||
{A_UNDERLINE_OFF, "underline-off"},
|
||||
{A_CROSSOUT, "crossout"},
|
||||
{A_CROSSOUT_OFF, "crossout-off"},
|
||||
{A_ITALIC, "italic"},
|
||||
{A_ITALIC_OFF, "italic-off"}
|
||||
};
|
||||
|
||||
/** @} */
|
||||
#endif
|
|
@ -1,13 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
dialogsdir = dialogs
|
||||
|
||||
gnoemoe_SOURCES += \
|
||||
$(dialogsdir)/gm-world-info-dialog.c $(dialogsdir)/gm-world-info-dialog.h \
|
||||
$(dialogsdir)/gm-world-logs-dialog.c $(dialogsdir)/gm-world-logs-dialog.h \
|
||||
$(dialogsdir)/gm-world-properties-dialog.c \
|
||||
$(dialogsdir)/gm-world-properties-dialog.h \
|
||||
$(dialogsdir)/gm-worlds-list-dialog.c \
|
||||
$(dialogsdir)/gm-worlds-list-dialog.h \
|
||||
$(dialogsdir)/gm-scripts-dialog.c $(dialogsdir)/gm-scripts-dialog.h \
|
||||
$(dialogsdir)/gm-preferences-dialog.c $(dialogsdir)/gm-preferences-dialog.h \
|
||||
$(dialogsdir)/gm-triggers-dialog.c $(dialogsdir)/gm-triggers-dialog.h
|
|
@ -1,777 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glade/glade.h>
|
||||
#include <gtksourceview/gtksourceview.h>
|
||||
#include <gtksourceview/gtksourcelanguage.h>
|
||||
#include <gtksourceview/gtksourcelanguage.h>
|
||||
#include <gtksourceview/gtksourcelanguagesmanager.h>
|
||||
#include <gtksourceview/gtksourcetag.h>
|
||||
|
||||
#include "../gm-app.h"
|
||||
#include "gm-preferences-dialog.h"
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-options.h"
|
||||
#include "../gm-color-table.h"
|
||||
|
||||
void gm_preferences_dialog_run_dialog();
|
||||
|
||||
void on_gm_preferences_dialog_check_button_embed_editor_clicked(
|
||||
GtkButton *button, gpointer user_data);
|
||||
void on_gm_preferences_dialog_check_button_alt_editor_clicked(
|
||||
GtkButton *button, gpointer user_data);
|
||||
|
||||
void on_gm_preferences_dialog_combo_box_scheme_changed(GtkComboBox *box,
|
||||
gpointer user_data);
|
||||
void on_gm_preferences_dialog_check_button_fg_clicked(
|
||||
GtkButton *button, gpointer user_data);
|
||||
void on_gm_preferences_dialog_check_button_bg_clicked(
|
||||
GtkButton *button, gpointer user_data);
|
||||
void on_gm_preferences_dialog_toggle_button_style_clicked(
|
||||
GtkButton *button, gpointer user_data);
|
||||
|
||||
void on_gm_preferences_dialog_tree_view_editor_colors_row_changed(
|
||||
GtkTreeSelection *selection, gpointer data);
|
||||
void on_gm_preferences_dialog_color_button_fg_color_set(GtkColorButton *widget,
|
||||
gpointer data);
|
||||
void on_gm_preferences_dialog_color_button_bg_color_set(GtkColorButton *widget,
|
||||
gpointer data);
|
||||
void on_gm_preferences_dialog_response(GtkDialog *dialog, gint response,
|
||||
gpointer user_data);
|
||||
|
||||
void gm_preferences_dialog_load_colors();
|
||||
|
||||
typedef struct _GmPreferencesDialog {
|
||||
GladeXML *xml;
|
||||
GtkWidget *dialog;
|
||||
|
||||
} GmPreferencesDialog;
|
||||
|
||||
static const GmKeyValuePair color_mapping[] = {
|
||||
{"color_button_fg_default", "fg_default"},
|
||||
{"color_button_fg_default_h", "fg_default_h"},
|
||||
{"color_button_bg_default", "bg_default"},
|
||||
|
||||
{"color_button_fg_black", "fg_black"},
|
||||
{"color_button_fg_black_h", "fg_black_h"},
|
||||
{"color_button_fg_red", "fg_red"},
|
||||
{"color_button_fg_red_h", "fg_red_h"},
|
||||
{"color_button_fg_green", "fg_green"},
|
||||
{"color_button_fg_green_h", "fg_green_h"},
|
||||
{"color_button_fg_yellow", "fg_yellow"},
|
||||
{"color_button_fg_yellow_h", "fg_yellow_h"},
|
||||
{"color_button_fg_blue", "fg_blue"},
|
||||
{"color_button_fg_blue_h", "fg_blue_h"},
|
||||
{"color_button_fg_purple", "fg_purple"},
|
||||
{"color_button_fg_purple_h", "fg_purple_h"},
|
||||
{"color_button_fg_cyan", "fg_cyan"},
|
||||
{"color_button_fg_cyan_h", "fg_cyan_h"},
|
||||
{"color_button_fg_white", "fg_white"},
|
||||
{"color_button_fg_white_h", "fg_white_h"},
|
||||
|
||||
{"color_button_bg_black", "bg_black"},
|
||||
{"color_button_bg_red", "bg_red"},
|
||||
{"color_button_bg_green", "bg_green"},
|
||||
{"color_button_bg_yellow", "bg_yellow"},
|
||||
{"color_button_bg_blue", "bg_blue"},
|
||||
{"color_button_bg_purple", "bg_purple"},
|
||||
{"color_button_bg_cyan", "bg_cyan"},
|
||||
{"color_button_bg_white", "bg_white"}
|
||||
};
|
||||
|
||||
static const GmKeyValuePair color_schemes[] = {
|
||||
{N_("Default"), "default"},
|
||||
{N_("White on black"), "white_on_black"},
|
||||
{N_("User defined"), "user"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static GmPreferencesDialog *preferences = NULL;
|
||||
|
||||
enum {
|
||||
EDITOR_NAME,
|
||||
EDITOR_STYLE,
|
||||
EDITOR_ID,
|
||||
EDITOR_N_COLUMNS
|
||||
};
|
||||
|
||||
enum {
|
||||
SCHEME_NAME,
|
||||
SCHEME_OPTION,
|
||||
SCHEME_N_COLUMNS
|
||||
};
|
||||
|
||||
GtkWidget *
|
||||
gm_preferences_dialog_widget(gchar *name) {
|
||||
return glade_xml_get_widget(preferences->xml, name);
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_init_combo_box_scheme() {
|
||||
GtkComboBox *box = GTK_COMBO_BOX(gm_preferences_dialog_widget(
|
||||
"combo_box_scheme"));
|
||||
GtkListStore *store = gtk_list_store_new(SCHEME_N_COLUMNS, G_TYPE_STRING,
|
||||
G_TYPE_STRING);
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||
GtkTreeIter iter;
|
||||
int i, select = 0;
|
||||
const gchar *scheme = gm_options_get(gm_app_options(gm_app_instance()),
|
||||
"color_scheme");
|
||||
|
||||
gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box), renderer, TRUE);
|
||||
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(box), renderer, "text",
|
||||
SCHEME_NAME, NULL);
|
||||
|
||||
gtk_combo_box_set_model(box, GTK_TREE_MODEL(store));
|
||||
|
||||
i = 0;
|
||||
|
||||
while (color_schemes[i].key != NULL) {
|
||||
gtk_list_store_append(store, &iter);
|
||||
gtk_list_store_set(store, &iter, SCHEME_NAME, color_schemes[i].key,
|
||||
SCHEME_OPTION, color_schemes[i].value, -1);
|
||||
|
||||
if (scheme != NULL && strcasecmp(scheme, color_schemes[i].value) == 0) {
|
||||
select = i;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
gtk_combo_box_set_active(box, select);
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_init_editor_colors_tree() {
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeView *tv = GTK_TREE_VIEW(
|
||||
gm_preferences_dialog_widget("tree_view_editor_colors"));
|
||||
GtkListStore *store = gtk_list_store_new(EDITOR_N_COLUMNS, G_TYPE_STRING,
|
||||
GTK_TYPE_SOURCE_TAG_STYLE, G_TYPE_STRING);
|
||||
GtkTreeModel *model =
|
||||
gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(store));
|
||||
GtkTreeSelection *select;
|
||||
|
||||
gtk_tree_view_set_model(tv, model);
|
||||
select = gtk_tree_view_get_selection(tv);
|
||||
|
||||
g_signal_connect(select, "changed", G_CALLBACK(
|
||||
on_gm_preferences_dialog_tree_view_editor_colors_row_changed),
|
||||
NULL);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Tag"), renderer,
|
||||
"text", EDITOR_NAME, NULL);
|
||||
gtk_tree_view_append_column(tv, column);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Style"), renderer,
|
||||
NULL);
|
||||
gtk_tree_view_column_set_visible(column, FALSE);
|
||||
|
||||
gtk_tree_view_append_column(tv, column);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Id"), renderer, NULL);
|
||||
gtk_tree_view_column_set_visible(column, FALSE);
|
||||
|
||||
gtk_tree_view_append_column(tv, column);
|
||||
|
||||
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), EDITOR_NAME,
|
||||
GTK_SORT_ASCENDING);
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_init_editor_colors() {
|
||||
GtkSourceTag *st;
|
||||
GtkSourceTagStyle *sty;
|
||||
|
||||
GSList *tags, *tag;
|
||||
gchar *name, *id;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *store;
|
||||
GtkSourceLanguage *lang = NULL;
|
||||
|
||||
// TODO: Fix this!
|
||||
// lang = editor_get_language();
|
||||
|
||||
// Create column ed
|
||||
gm_preferences_dialog_init_editor_colors_tree();
|
||||
store = GTK_LIST_STORE(gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(
|
||||
gtk_tree_view_get_model(GTK_TREE_VIEW(
|
||||
gm_preferences_dialog_widget("tree_view_editor_colors"))))));
|
||||
|
||||
if (lang) {
|
||||
tags = gtk_source_language_get_tags(lang);
|
||||
|
||||
for (tag = tags; tag; tag = tag->next) {
|
||||
st = GTK_SOURCE_TAG(tag->data);
|
||||
sty = gtk_source_tag_get_style(st);
|
||||
|
||||
g_object_get(G_OBJECT(st), "name", &name, "id", &id, NULL);
|
||||
|
||||
gtk_list_store_prepend(store, &iter);
|
||||
gtk_list_store_set(store, &iter, EDITOR_NAME, name,
|
||||
EDITOR_STYLE, sty, EDITOR_ID, id, -1);
|
||||
|
||||
g_free(name);
|
||||
g_free(id);
|
||||
}
|
||||
|
||||
g_slist_free(tags);
|
||||
}
|
||||
}
|
||||
|
||||
#define GM_PREFERENCES_DIALOG_XML \
|
||||
PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-preferences.glade"
|
||||
|
||||
void
|
||||
gm_preferences_dialog_run() {
|
||||
const gchar *alt_editor;
|
||||
GmOptions *options = gm_app_options(gm_app_instance());
|
||||
|
||||
if (preferences != NULL) {
|
||||
gtk_window_present(GTK_WINDOW(preferences->dialog));
|
||||
return;
|
||||
} else {
|
||||
preferences = g_new0(GmPreferencesDialog, 1);
|
||||
}
|
||||
|
||||
preferences->xml = glade_xml_new(GM_PREFERENCES_DIALOG_XML,
|
||||
"gm_preferences_dialog", NULL);
|
||||
preferences->dialog =
|
||||
gm_preferences_dialog_widget("gm_preferences_dialog");
|
||||
gm_preferences_dialog_init_editor_colors();
|
||||
gm_preferences_dialog_load_colors();
|
||||
gm_preferences_dialog_init_combo_box_scheme();
|
||||
|
||||
gtk_font_button_set_font_name(GTK_FONT_BUTTON(
|
||||
gm_preferences_dialog_widget("font_button_font")),
|
||||
gm_options_get(options, "font-family"));
|
||||
|
||||
alt_editor = gm_options_get(options, "editor_alternative");
|
||||
|
||||
if (strcmp(alt_editor, "0") == 0) {
|
||||
alt_editor = NULL;
|
||||
} else {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_alt_editor")),
|
||||
TRUE);
|
||||
gtk_entry_set_text(GTK_ENTRY(
|
||||
gm_preferences_dialog_widget("entry_alt_editor")),
|
||||
alt_editor);
|
||||
}
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_embed_editor")),
|
||||
gm_options_get_int(options, "editor_embed"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_needs_terminal")),
|
||||
gm_options_get_int(options, "editor_needs_terminal"));
|
||||
|
||||
gtk_widget_set_sensitive(
|
||||
gm_preferences_dialog_widget("entry_alt_editor"),
|
||||
alt_editor != NULL);
|
||||
gtk_widget_set_sensitive(
|
||||
gm_preferences_dialog_widget("check_button_embed_editor"),
|
||||
alt_editor != NULL);
|
||||
gtk_widget_set_sensitive(
|
||||
gm_preferences_dialog_widget("check_button_needs_terminal"),
|
||||
alt_editor != NULL
|
||||
&& gm_options_get_int(options, "editor_embed") == 0);
|
||||
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_check_button_alt_editor_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_check_button_alt_editor_clicked));
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_check_button_embed_editor_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_check_button_embed_editor_clicked));
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_check_button_fg_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_check_button_fg_clicked));
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_check_button_bg_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_check_button_bg_clicked));
|
||||
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_combo_box_scheme_changed", G_CALLBACK(
|
||||
on_gm_preferences_dialog_combo_box_scheme_changed));
|
||||
|
||||
glade_xml_signal_connect_data(preferences->xml,
|
||||
"on_toggle_button_bold_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_toggle_button_style_clicked),
|
||||
GINT_TO_POINTER(1));
|
||||
glade_xml_signal_connect_data(preferences->xml,
|
||||
"on_toggle_button_style_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_toggle_button_style_clicked),
|
||||
GINT_TO_POINTER(2));
|
||||
glade_xml_signal_connect_data(preferences->xml,
|
||||
"on_toggle_button_underline_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_toggle_button_style_clicked),
|
||||
GINT_TO_POINTER(3));
|
||||
glade_xml_signal_connect_data(preferences->xml,
|
||||
"on_toggle_button_strike_trough_clicked", G_CALLBACK(
|
||||
on_gm_preferences_dialog_toggle_button_style_clicked),
|
||||
GINT_TO_POINTER(4));
|
||||
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_color_button_fg_color_set", G_CALLBACK(
|
||||
on_gm_preferences_dialog_color_button_fg_color_set));
|
||||
glade_xml_signal_connect(preferences->xml,
|
||||
"on_color_button_bg_color_set", G_CALLBACK(
|
||||
on_gm_preferences_dialog_color_button_bg_color_set));
|
||||
|
||||
gm_preferences_dialog_run_dialog();
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_load_colors() {
|
||||
int i;
|
||||
GtkColorButton *but;
|
||||
GdkColor col;
|
||||
GmColorTable *color_table = gm_app_color_table(gm_app_instance());
|
||||
|
||||
for (i = 0; i < (int)(sizeof(color_mapping) / sizeof(GmKeyValuePair)); i++) {
|
||||
but = GTK_COLOR_BUTTON(gm_preferences_dialog_widget(
|
||||
color_mapping[i].key));
|
||||
|
||||
gm_color_table_get(color_table, color_mapping[i].value, &col);
|
||||
gtk_color_button_set_color(but, &col);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_save_colors() {
|
||||
int i;
|
||||
GtkColorButton *but;
|
||||
GdkColor col;
|
||||
GmColorTable *color_table = gm_app_color_table(gm_app_instance());
|
||||
gchar *col_str;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(color_mapping) / sizeof(GmKeyValuePair)); i++) {
|
||||
but = GTK_COLOR_BUTTON(gm_preferences_dialog_widget(
|
||||
color_mapping[i].key));
|
||||
|
||||
gtk_color_button_get_color(but, &col);
|
||||
col_str = g_strdup_printf("#%04X%04X%04X", col.red, col.green,
|
||||
col.blue);
|
||||
|
||||
gm_color_table_set(color_table, color_mapping[i].value, col_str);
|
||||
g_free(col_str);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_save_editor_color(GtkTreeModel *model,
|
||||
GtkTreeIter *iter) {
|
||||
gchar *name, *id, *opt_key, *opt_value, *fg, *bg;
|
||||
GtkSourceTagStyle *style;
|
||||
GmOptions *options = gm_app_options(gm_app_instance());
|
||||
|
||||
gtk_tree_model_get(model, iter, EDITOR_NAME, &name, EDITOR_STYLE, &style,
|
||||
EDITOR_ID, &id, -1);
|
||||
|
||||
opt_key = g_strconcat("editor_", name, NULL);
|
||||
|
||||
if (!(style->mask & GTK_SOURCE_TAG_STYLE_USE_FOREGROUND)) {
|
||||
fg = g_strdup("0");
|
||||
} else {
|
||||
fg = g_strdup_printf("#%04X%04X%04X", style->foreground.red,
|
||||
style->foreground.green, style->foreground.blue);
|
||||
}
|
||||
|
||||
if (!(style->mask & GTK_SOURCE_TAG_STYLE_USE_BACKGROUND)) {
|
||||
bg = g_strdup("0");
|
||||
} else {
|
||||
bg = g_strdup_printf("#%04X%04X%04X", style->background.red,
|
||||
style->background.green, style->background.blue);
|
||||
}
|
||||
|
||||
opt_value = g_strdup_printf("%s,%s,%d,%d,%d,%d", fg, bg, style->bold,
|
||||
style->italic, style->underline,
|
||||
style->strikethrough);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmPreferencesDialog.SaveEditorColor %s to %s", opt_key,
|
||||
opt_value);
|
||||
|
||||
gm_options_set(options, opt_key, opt_value);
|
||||
|
||||
// TODO: do something about this
|
||||
//gtk_source_language_set_tag_style(editor_get_language(), id, style);
|
||||
|
||||
g_free(opt_key);
|
||||
g_free(opt_value);
|
||||
g_free(id);
|
||||
g_free(fg);
|
||||
g_free(bg);
|
||||
g_free(name);
|
||||
|
||||
// CHECK this:
|
||||
//gtk_source_tag_style_free(style);
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_save_editor_colors() {
|
||||
GtkTreeIter iter;
|
||||
GtkTreeView *vw = GTK_TREE_VIEW(
|
||||
gm_preferences_dialog_widget("tree_view_editor_colors"));
|
||||
GtkTreeModelSort *model = GTK_TREE_MODEL_SORT(gtk_tree_view_get_model(vw));
|
||||
GtkTreeModel *store = gtk_tree_model_sort_get_model(model);
|
||||
|
||||
if (gtk_tree_model_get_iter_first(store, &iter)) {
|
||||
do {
|
||||
gm_preferences_dialog_save_editor_color(store, &iter);
|
||||
} while (gtk_tree_model_iter_next(store, &iter));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_preferences_dialog_check_values() {
|
||||
const gchar *alt_editor = gtk_entry_get_text(GTK_ENTRY(
|
||||
gm_preferences_dialog_widget("entry_alt_editor")));
|
||||
const gchar *font_description = gtk_font_button_get_font_name(
|
||||
GTK_FONT_BUTTON(gm_preferences_dialog_widget("font_button_font")));
|
||||
gboolean use_alt_editor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_alt_editor")));
|
||||
GmOptions *options = gm_app_options(gm_app_instance());
|
||||
|
||||
if (use_alt_editor && alt_editor[0] != '\0') {
|
||||
gm_error_dialog(_("Editor can't be empty, enter a non empty command"),
|
||||
GTK_WINDOW(preferences->dialog));
|
||||
gm_notebook_focus_from_label(GTK_NOTEBOOK(gm_preferences_dialog_widget(
|
||||
"notebook_preferences")), _("Editor"));
|
||||
gtk_widget_grab_focus(gm_preferences_dialog_widget("entry_alt_editor"));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (use_alt_editor) {
|
||||
gm_options_set(options, "editor_alternative", alt_editor);
|
||||
} else {
|
||||
gm_options_set(options, "editor_alternative", "0");
|
||||
}
|
||||
|
||||
gm_options_set_int(options, "editor_embed", gtk_toggle_button_get_active(
|
||||
GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget
|
||||
("check_button_embed_editor"))));
|
||||
gm_options_set_int(options, "editor_needs_terminal",
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_needs_terminal"))));
|
||||
|
||||
gm_options_set(options, "font-family", font_description);
|
||||
gm_preferences_dialog_save_colors();
|
||||
gm_preferences_dialog_save_editor_colors();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_run_dialog() {
|
||||
g_signal_connect(preferences->dialog, "response",
|
||||
G_CALLBACK(on_gm_preferences_dialog_response), NULL);
|
||||
|
||||
gtk_widget_show(GTK_WIDGET(preferences->dialog));
|
||||
}
|
||||
|
||||
/* CALLBACKS */
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_response(GtkDialog *dialog, gint response,
|
||||
gpointer user_data) {
|
||||
gboolean is_okay = TRUE;
|
||||
|
||||
switch (response) {
|
||||
case GTK_RESPONSE_OK: case GTK_RESPONSE_APPLY:
|
||||
if (gm_preferences_dialog_check_values()) {
|
||||
gm_options_save(gm_app_options(gm_app_instance()));
|
||||
|
||||
if (response == GTK_RESPONSE_APPLY) {
|
||||
is_okay = FALSE;
|
||||
}
|
||||
} else {
|
||||
is_okay = FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_okay) {
|
||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||
g_object_unref(preferences->xml);
|
||||
g_free(preferences);
|
||||
preferences = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_check_button_embed_editor_clicked(
|
||||
GtkButton *button, gpointer user_data) {
|
||||
gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
|
||||
GmOptions *options = gm_app_options(gm_app_instance());
|
||||
|
||||
if (active) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_needs_terminal")),
|
||||
TRUE);
|
||||
} else {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_needs_terminal")),
|
||||
gm_options_get_int(options, "editor_needs_terminal"));
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"check_button_needs_terminal"), !active);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_check_button_alt_editor_clicked(
|
||||
GtkButton *button, gpointer user_data) {
|
||||
gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
|
||||
|
||||
if (!active) {
|
||||
gtk_entry_set_text(GTK_ENTRY(gm_preferences_dialog_widget(
|
||||
"entry_alt_editor")), "");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_embed_editor")),
|
||||
FALSE);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_preferences_dialog_widget("check_button_needs_terminal")),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"entry_alt_editor"), active);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"check_button_embed_editor"), active);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"check_button_needs_terminal"), active);
|
||||
}
|
||||
|
||||
void
|
||||
gm_preferences_dialog_editor_style_do_enable() {
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget("check_button_fg"),
|
||||
TRUE);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget("check_button_bg"),
|
||||
TRUE);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget("toggle_button_bold"),
|
||||
TRUE);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"toggle_button_style"), TRUE);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"toggle_button_underline"), TRUE);
|
||||
gtk_widget_set_sensitive(gm_preferences_dialog_widget(
|
||||
"toggle_button_strike_through"), TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_tree_view_editor_colors_row_changed(
|
||||
GtkTreeSelection *selection, gpointer data) {
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
GtkSourceTagStyle *style;
|
||||
GtkColorButton *fg, *bg;
|
||||
GtkToggleButton *fgt, *bgt;
|
||||
GdkColor empty_col;
|
||||
|
||||
gdk_color_parse("black", &empty_col);
|
||||
|
||||
gtk_tree_selection_get_selected(selection, &model, &iter);
|
||||
gtk_tree_model_get(model, &iter, EDITOR_STYLE, &style, -1);
|
||||
|
||||
fg = GTK_COLOR_BUTTON(gm_preferences_dialog_widget("color_button_fg"));
|
||||
bg = GTK_COLOR_BUTTON(gm_preferences_dialog_widget("color_button_bg"));
|
||||
fgt = GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget("check_button_fg"));
|
||||
bgt = GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget("check_button_bg"));
|
||||
|
||||
if (style->mask & GTK_SOURCE_TAG_STYLE_USE_FOREGROUND) {
|
||||
gtk_color_button_set_color(fg, &(style->foreground));
|
||||
gtk_widget_set_sensitive(GTK_WIDGET(fg), TRUE);
|
||||
gtk_toggle_button_set_active(fgt, TRUE);
|
||||
} else {
|
||||
gtk_color_button_set_color(fg, &empty_col);
|
||||
gtk_widget_set_sensitive(GTK_WIDGET(fg), FALSE);
|
||||
gtk_toggle_button_set_active(fgt, FALSE);
|
||||
}
|
||||
|
||||
if (style->mask & GTK_SOURCE_TAG_STYLE_USE_BACKGROUND) {
|
||||
gtk_color_button_set_color(bg, &(style->background));
|
||||
gtk_widget_set_sensitive(GTK_WIDGET(bg), TRUE);
|
||||
gtk_toggle_button_set_active(bgt, TRUE);
|
||||
} else {
|
||||
gtk_color_button_set_color(bg, &empty_col);
|
||||
gtk_widget_set_sensitive(GTK_WIDGET(bg), FALSE);
|
||||
gtk_toggle_button_set_active(bgt, FALSE);
|
||||
}
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget(
|
||||
"check_button_bold")), style->bold);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget(
|
||||
"check_button_style")), style->italic);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget(
|
||||
"check_button_underline")), style->underline);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gm_preferences_dialog_widget(
|
||||
"check_button_strike_through")), style->strikethrough);
|
||||
gm_preferences_dialog_editor_style_do_enable();
|
||||
}
|
||||
|
||||
typedef struct _GmSelectionInfo {
|
||||
GtkTreeIter siter;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *store;
|
||||
GtkTreeModel *model;
|
||||
GtkSourceTagStyle *style;
|
||||
} GmSelectionInfo;
|
||||
|
||||
GmSelectionInfo
|
||||
gm_preferences_dialog_get_selection_info() {
|
||||
GtkTreeSelection *selection;
|
||||
GmSelectionInfo info;
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
|
||||
gm_preferences_dialog_widget("tree_view_editor_colors")));
|
||||
|
||||
gtk_tree_selection_get_selected(selection, &(info.model), &(info.siter));
|
||||
gtk_tree_model_get(info.model, &(info.siter), EDITOR_STYLE, &(info.style),
|
||||
-1);
|
||||
gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(
|
||||
info.model), &(info.iter), &(info.siter));
|
||||
|
||||
info.store = GTK_LIST_STORE(gtk_tree_model_sort_get_model(
|
||||
GTK_TREE_MODEL_SORT(info.model)));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_check_button_fg_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
GmSelectionInfo info;
|
||||
gboolean tog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
|
||||
GtkWidget *clb = gm_preferences_dialog_widget("color_button_fg");
|
||||
GdkColor empty_col;
|
||||
|
||||
info = gm_preferences_dialog_get_selection_info();
|
||||
gdk_color_parse("black", &empty_col);
|
||||
|
||||
if (tog) {
|
||||
info.style->mask = info.style->mask |
|
||||
GTK_SOURCE_TAG_STYLE_USE_FOREGROUND;
|
||||
} else {
|
||||
info.style->mask = info.style->mask &
|
||||
~GTK_SOURCE_TAG_STYLE_USE_FOREGROUND;
|
||||
gtk_color_button_set_color(GTK_COLOR_BUTTON(clb), &empty_col);
|
||||
info.style->foreground = empty_col;
|
||||
}
|
||||
|
||||
gtk_list_store_set(info.store, &(info.iter), EDITOR_STYLE, info.style, -1);
|
||||
gtk_source_tag_style_free(info.style);
|
||||
|
||||
gtk_widget_set_sensitive(clb, tog);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_check_button_bg_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
GmSelectionInfo info;
|
||||
gboolean tog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
|
||||
GtkWidget *clb = gm_preferences_dialog_widget("color_button_bg");
|
||||
GdkColor empty_col;
|
||||
|
||||
info = gm_preferences_dialog_get_selection_info();
|
||||
gdk_color_parse("black", &empty_col);
|
||||
|
||||
if (tog) {
|
||||
info.style->mask = info.style->mask |
|
||||
GTK_SOURCE_TAG_STYLE_USE_BACKGROUND;
|
||||
} else {
|
||||
info.style->mask = info.style->mask &
|
||||
~GTK_SOURCE_TAG_STYLE_USE_BACKGROUND;
|
||||
gtk_color_button_set_color(GTK_COLOR_BUTTON(clb), &empty_col);
|
||||
info.style->background = empty_col;
|
||||
}
|
||||
|
||||
gtk_list_store_set(info.store, &(info.iter), EDITOR_STYLE, info.style, -1);
|
||||
gtk_source_tag_style_free(info.style);
|
||||
|
||||
gtk_widget_set_sensitive(clb, tog);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_toggle_button_style_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
GmSelectionInfo info;
|
||||
int type = GPOINTER_TO_INT(user_data);
|
||||
gboolean tog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
|
||||
|
||||
info = gm_preferences_dialog_get_selection_info();
|
||||
|
||||
switch (type) {
|
||||
case 1: /* bold */
|
||||
info.style->bold = tog;
|
||||
break;
|
||||
case 2: /* italic */
|
||||
info.style->italic = tog;
|
||||
break;
|
||||
case 3: /* underline */
|
||||
info.style->underline = tog;
|
||||
break;
|
||||
case 4:
|
||||
info.style->strikethrough = tog;
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_list_store_set(info.store, &(info.iter), EDITOR_STYLE, info.style, -1);
|
||||
gtk_source_tag_style_free(info.style);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_color_button_fg_color_set(GtkColorButton *widget,
|
||||
gpointer user_data) {
|
||||
GmSelectionInfo info;
|
||||
|
||||
info = gm_preferences_dialog_get_selection_info();
|
||||
gtk_color_button_get_color(widget, &(info.style->foreground));
|
||||
|
||||
gtk_list_store_set(info.store, &(info.iter), EDITOR_STYLE, info.style, -1);
|
||||
gtk_source_tag_style_free(info.style);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_color_button_bg_color_set(GtkColorButton *widget,
|
||||
gpointer user_data) {
|
||||
GmSelectionInfo info;
|
||||
|
||||
info = gm_preferences_dialog_get_selection_info();
|
||||
gtk_color_button_get_color(widget, &(info.style->background));
|
||||
|
||||
gtk_list_store_set(info.store, &(info.iter), EDITOR_STYLE, info.style, -1);
|
||||
gtk_source_tag_style_free(info.style);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_preferences_dialog_combo_box_scheme_changed(GtkComboBox *box,
|
||||
gpointer user_data) {
|
||||
GtkTreeIter iter;
|
||||
gchar *scheme;
|
||||
GtkTreeModel *model = gtk_combo_box_get_model(box);
|
||||
GmColorTable *color_table = gm_app_color_table(gm_app_instance());
|
||||
|
||||
gtk_combo_box_get_active_iter(box, &iter);
|
||||
gtk_tree_model_get(model, &iter, SCHEME_OPTION, &scheme, -1);
|
||||
gm_color_table_set_from_scheme_name(color_table, scheme);
|
||||
|
||||
g_free(scheme);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __GM_PREFERENCES_DIALOG_H__
|
||||
#define __GM_PREFERENCES_DIALOG_H__
|
||||
|
||||
void gm_preferences_dialog_run();
|
||||
|
||||
#endif /* __GM_PREFERENCES_DIALOG_H__ */
|
|
@ -1,920 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <gtksourceview/gtksourceview.h>
|
||||
#include <gtksourceview/gtksourcelanguage.h>
|
||||
#include <gtksourceview/gtksourcelanguagesmanager.h>
|
||||
#include <gtksourceview/gtksourcetag.h>
|
||||
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
#include <glade/glade.h>
|
||||
|
||||
#include "../gm-scripts.h"
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-app.h"
|
||||
#include "../gm-support.h"
|
||||
#include "../widgets/gm-app-view.h"
|
||||
#include "../widgets/gm-text-scroller.h"
|
||||
|
||||
#define SCRIPT_TEMPLATE \
|
||||
_("=begin\n" \
|
||||
"\t<title>\n" \
|
||||
"\t<copyright>\n" \
|
||||
"\n\tRegister functions in the register_functions method defined below.\n" \
|
||||
"\tRegister functions with " \
|
||||
"$scripts.register(<name>, <description>[, <alias>])\n=end" \
|
||||
"\n\ndef register_functions\n" \
|
||||
"\t$scripts.register(\"myscript\", \"use /myscript\")\nend\n\n" \
|
||||
"def myscript(argstr)\n\t# Insert code here\nend\n")
|
||||
|
||||
void on_gm_scripts_dialog_script_added(GmScripts *scripts, GmScript *script,
|
||||
gpointer user_data);
|
||||
void on_gm_scripts_dialog_script_changed(GmScripts *scripts, GmScript *script,
|
||||
gpointer user_data);
|
||||
void on_gm_scripts_dialog_script_removed(GmScripts *scripts, GmScript *script,
|
||||
gpointer user_data);
|
||||
void on_gm_scripts_dialog_message(GmScripts *scripts, gchar *message,
|
||||
gpointer user_data);
|
||||
void on_gm_scripts_dialog_error(GmScripts *scripts, gchar *message,
|
||||
gpointer user_data);
|
||||
void on_gm_scripts_dialog_run(GmScripts *scripts, gchar *message,
|
||||
gpointer user_data);
|
||||
|
||||
typedef enum _MessageType {
|
||||
SCRIPT_MESSAGE,
|
||||
SCRIPT_ERROR,
|
||||
SCRIPT_RUN
|
||||
} MessageType;
|
||||
|
||||
typedef enum _scripts_columns {
|
||||
SCRIPTS_NAME,
|
||||
SCRIPTS_OBJECT,
|
||||
SCRIPTS_N
|
||||
} scripts_columns;
|
||||
|
||||
typedef struct _SelectionInfo {
|
||||
GtkTreeView *view;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter seliter;
|
||||
GtkTreeIter parent;
|
||||
gboolean has_parent;
|
||||
gboolean can_save;
|
||||
gchar *filename;
|
||||
} SelectionInfo;
|
||||
|
||||
typedef struct _GmScriptsDialog {
|
||||
GtkTextTagTable *tag_table;
|
||||
GladeXML *xml;
|
||||
GtkTextBuffer *text_buffer_console;
|
||||
gchar *current_edit;
|
||||
GtkTextBuffer *text_buffer_editor;
|
||||
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *text_view_console;
|
||||
GtkWidget *statusbar_editor;
|
||||
GtkWidget *button_save;
|
||||
GtkWidget *tree_view_scripts;
|
||||
GtkWidget *tree_view_files;
|
||||
GtkWidget *button_delete;
|
||||
GmTextScroller *text_scroller;
|
||||
|
||||
SelectionInfo info;
|
||||
} GmScriptsDialog;
|
||||
|
||||
static GmScriptsDialog *scripts_dialog = NULL;
|
||||
|
||||
#define G_SCRIPTS_XML PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-scripts.glade"
|
||||
|
||||
gboolean on_gm_scripts_dialog_delete(GtkWidget *widget, GdkEvent *event,
|
||||
gpointer user_data);
|
||||
|
||||
void on_files_changed(GtkTreeSelection *treeselection, gpointer user_data);
|
||||
void on_tree_view_files_row_activated(GtkTreeView *treeview, GtkTreePath *arg1,
|
||||
GtkTreeViewColumn *arg2, gpointer user_data);
|
||||
void on_text_buffer_editor_modified_changed(GtkTextBuffer *buffer,
|
||||
gpointer user_data);
|
||||
|
||||
void on_tool_button_new_clicked(GtkToolButton *button, gpointer user_data);
|
||||
void on_tool_button_save_clicked(GtkToolButton *button, gpointer user_data);
|
||||
void on_tool_button_save_as_clicked(GtkToolButton *button, gpointer user_data);
|
||||
void on_tool_button_delete_clicked(GtkToolButton *button, gpointer user_data);
|
||||
|
||||
gboolean
|
||||
gm_scripts_dialog_can_write(gchar *filename) {
|
||||
return (access(filename, W_OK) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_set_status(gchar *msg) {
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(scripts_dialog->statusbar_editor),
|
||||
0);
|
||||
gtk_statusbar_push(GTK_STATUSBAR(scripts_dialog->statusbar_editor),
|
||||
0, msg);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_dialog_editor_save(gchar *filename) {
|
||||
FILE *f;
|
||||
gchar *msg, *text;
|
||||
GtkTextIter start, end;
|
||||
|
||||
if (!filename) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
f = fopen(filename, "w");
|
||||
|
||||
if (f) {
|
||||
gtk_text_buffer_get_start_iter(scripts_dialog->text_buffer_editor,
|
||||
&start);
|
||||
gtk_text_buffer_get_end_iter(scripts_dialog->text_buffer_editor, &end);
|
||||
text = gtk_text_buffer_get_text(scripts_dialog->text_buffer_editor,
|
||||
&start, &end, TRUE);
|
||||
|
||||
fputs(text, f);
|
||||
|
||||
msg = g_strconcat(_("Saved "), filename, NULL);
|
||||
gm_scripts_dialog_set_status(msg);
|
||||
g_free(msg);
|
||||
|
||||
if (scripts_dialog->current_edit != filename) {
|
||||
g_free(scripts_dialog->current_edit);
|
||||
scripts_dialog->current_edit = g_strdup(filename);
|
||||
}
|
||||
|
||||
gtk_text_buffer_set_modified(scripts_dialog->text_buffer_editor,
|
||||
FALSE);
|
||||
|
||||
fclose(f);
|
||||
return TRUE;
|
||||
} else {
|
||||
text = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
|
||||
msg = g_strconcat(_("Saving failed: "), strerror(errno), " (",
|
||||
text, ")", NULL);
|
||||
gm_error_dialog(msg, GTK_WINDOW(scripts_dialog->dialog));
|
||||
g_free(text);
|
||||
g_free(msg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_editor_load(SelectionInfo *info) {
|
||||
FILE *f;
|
||||
gchar line[1024];
|
||||
GtkTextIter end;
|
||||
gchar *lline, *msg;
|
||||
|
||||
if (info) {
|
||||
gtk_text_buffer_set_text(scripts_dialog->text_buffer_editor, "", 0);
|
||||
gtk_text_buffer_get_end_iter(scripts_dialog->text_buffer_editor, &end);
|
||||
|
||||
f = fopen(info->filename, "r");
|
||||
|
||||
if (f) {
|
||||
while (fgets((char *) &line, 1024 - 1, f) != NULL) {
|
||||
lline = g_locale_to_utf8((gchar *)&line, strlen((char *)&line),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (lline) {
|
||||
gtk_text_buffer_insert(scripts_dialog->text_buffer_editor,
|
||||
&end, lline, strlen(lline));
|
||||
g_free(lline);
|
||||
} else {
|
||||
gtk_text_buffer_insert(scripts_dialog->text_buffer_editor,
|
||||
&end, (gchar *)&line, strlen((char *)&line));
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
gtk_widget_set_sensitive(scripts_dialog->button_save,
|
||||
info->can_save);
|
||||
|
||||
g_free(scripts_dialog->current_edit);
|
||||
scripts_dialog->current_edit = g_strdup(info->filename);
|
||||
|
||||
g_free(scripts_dialog->current_edit);
|
||||
scripts_dialog->current_edit = g_strdup(info->filename);
|
||||
|
||||
msg = g_strconcat(_("Loaded "), info->filename, NULL);
|
||||
gm_scripts_dialog_set_status(msg);
|
||||
g_free(msg);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScript.EditorLoad: file (%s) could not be read: %s",
|
||||
scripts_dialog->current_edit, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
gtk_text_buffer_set_text(scripts_dialog->text_buffer_editor,
|
||||
SCRIPT_TEMPLATE, -1);
|
||||
g_free(scripts_dialog->current_edit);
|
||||
scripts_dialog->current_edit = NULL;
|
||||
|
||||
gm_scripts_dialog_set_status(_("New <untitled>"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_init_console() {
|
||||
GtkTextView *txt = GTK_TEXT_VIEW(scripts_dialog->text_view_console);
|
||||
PangoFontDescription *f;
|
||||
|
||||
gtk_text_view_set_buffer(txt, scripts_dialog->text_buffer_console);
|
||||
gtk_text_view_set_editable(txt, FALSE);
|
||||
|
||||
f =
|
||||
pango_font_description_from_string("monospace 8");
|
||||
|
||||
if (f) {
|
||||
gtk_widget_modify_font(GTK_WIDGET(txt), f);
|
||||
pango_font_description_free(f);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_tree_add_function(GtkTreeStore *model, GtkTreeIter *parent,
|
||||
GmScriptFunction *fi) {
|
||||
GtkTreeIter item;
|
||||
gchar *name, *description, *all, *markup;
|
||||
|
||||
gtk_tree_store_append(model, &item, parent);
|
||||
name = g_filename_to_utf8(fi->name, strlen(fi->name), NULL,
|
||||
NULL, NULL);
|
||||
description = g_locale_to_utf8(fi->description, strlen(fi->description),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
markup = g_markup_escape_text(description, g_utf8_strlen(description, -1));
|
||||
all = g_strconcat("<b>", name, "</b>\n", markup, NULL);
|
||||
gtk_tree_store_set(model, &item, SCRIPTS_NAME, all, -1);
|
||||
|
||||
g_free(all);
|
||||
g_free(markup);
|
||||
g_free(description);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_tree_update_script_item(GmScript *script, GtkTreeIter *iter) {
|
||||
GList *list;
|
||||
GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(
|
||||
GTK_TREE_VIEW(scripts_dialog->tree_view_scripts)));
|
||||
GtkTreeIter item;
|
||||
|
||||
if (gtk_tree_model_iter_children(GTK_TREE_MODEL(model), &item, iter)) {
|
||||
while (gtk_tree_store_remove(model, &item));
|
||||
}
|
||||
|
||||
for (list = script->functions; list; list = list->next) {
|
||||
gm_scripts_dialog_tree_add_function(model, iter,
|
||||
(GmScriptFunction *)(list->data));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_dialog_model_find_script(GtkTreeModel *model,
|
||||
GmScript *script, GtkTreeIter *item, GtkTreeIter *parent) {
|
||||
GmScript *obj;
|
||||
|
||||
if (gtk_tree_model_iter_children(model, item, parent)) {
|
||||
do {
|
||||
gtk_tree_model_get(model, item, SCRIPTS_OBJECT,
|
||||
&obj, -1);
|
||||
|
||||
if (obj == script) {
|
||||
return TRUE;
|
||||
}
|
||||
} while (gtk_tree_model_iter_next(model, item));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_tree_update_script(GmScript *script) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(
|
||||
GTK_TREE_VIEW(scripts_dialog->tree_view_scripts));
|
||||
GtkTreeIter item;
|
||||
|
||||
if (gm_scripts_dialog_model_find_script(model, script, &item, NULL)) {
|
||||
gm_scripts_dialog_tree_update_script_item(script, &item);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_tree_remove_script(GmScript *script) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(
|
||||
GTK_TREE_VIEW(scripts_dialog->tree_view_scripts));
|
||||
GtkTreeIter item;
|
||||
|
||||
if (gm_scripts_dialog_model_find_script(model, script, &item, NULL)) {
|
||||
gtk_tree_store_remove(GTK_TREE_STORE(model), &item);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_tree_add_script(GmScript *script) {
|
||||
GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(
|
||||
GTK_TREE_VIEW(scripts_dialog->tree_view_scripts)));
|
||||
GtkTreeIter item;
|
||||
gchar *name, *base;
|
||||
|
||||
gtk_tree_store_append(model, &item, NULL);
|
||||
name = g_filename_to_utf8(script->filename, strlen(script->filename), NULL,
|
||||
NULL, NULL);
|
||||
base = g_path_get_basename(name);
|
||||
g_free(name);
|
||||
|
||||
if (script->type == GM_SCRIPT_TYPE_USER) {
|
||||
name = g_strconcat(_("<b>User:</b> "), base, NULL);
|
||||
} else {
|
||||
name = g_strconcat(_("<b>Share:</b> "), base, NULL);
|
||||
}
|
||||
|
||||
g_free(base);
|
||||
gtk_tree_store_set(model, &item, SCRIPTS_NAME, name, SCRIPTS_OBJECT,
|
||||
script, -1);
|
||||
g_free(name);
|
||||
|
||||
gm_scripts_dialog_tree_update_script_item(script, &item);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_fill_tree() {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_scripts);
|
||||
GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(view));
|
||||
GList *scripts;
|
||||
|
||||
gtk_tree_store_clear(model);
|
||||
|
||||
for (scripts = gm_scripts_scripts(gm_app_scripts(gm_app_instance()));
|
||||
scripts; scripts = scripts->next) {
|
||||
gm_scripts_dialog_tree_add_script((GmScript *)(scripts->data));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_init_tree() {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_scripts);
|
||||
GtkTreeStore *model = gtk_tree_store_new(SCRIPTS_N, G_TYPE_STRING,
|
||||
G_TYPE_POINTER);
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Scripts"), renderer,
|
||||
"markup", SCRIPTS_NAME, NULL);
|
||||
|
||||
gtk_tree_view_append_column(view, column);
|
||||
gtk_tree_view_set_model(view, GTK_TREE_MODEL(model));
|
||||
|
||||
gm_scripts_dialog_fill_tree();
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_remove_file(GmScript *script) {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_files);
|
||||
GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(view));
|
||||
const gchar *sharedir = PACKAGE_DATA_DIR "/" PACKAGE "/scripts";
|
||||
GtkTreeIter parent;
|
||||
GtkTreeIter item;
|
||||
gchar *name = g_filename_to_utf8(script->filename,
|
||||
strlen(script->filename), NULL, NULL, NULL);
|
||||
|
||||
if (strncmp(sharedir, name, strlen(sharedir)) == 0) {
|
||||
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &parent, "0");
|
||||
} else {
|
||||
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &parent, "1");
|
||||
}
|
||||
|
||||
g_free(name);
|
||||
|
||||
if (gm_scripts_dialog_model_find_script(GTK_TREE_MODEL(model), script,
|
||||
&item, &parent)) {
|
||||
gtk_tree_store_remove(model, &item);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_dialog_add_file(GmScript *script) {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_files);
|
||||
GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(view));
|
||||
GtkTreeIter share, home, parent, item;
|
||||
gchar *sharedir = g_strdup(PACKAGE_DATA_DIR "/" PACKAGE "/scripts");
|
||||
gchar *homedir = g_strconcat(gm_app_path(gm_app_instance()), "/scripts",
|
||||
NULL);
|
||||
gchar *name;
|
||||
|
||||
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &share, "0");
|
||||
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &home, "1");
|
||||
|
||||
name = g_filename_to_utf8(script->filename, strlen(script->filename), NULL,
|
||||
NULL, NULL);
|
||||
|
||||
if (strncmp(sharedir, name, strlen(sharedir)) == 0) {
|
||||
parent = share;
|
||||
} else if (strncmp(homedir, name, strlen(homedir)) == 0) {
|
||||
parent = home;
|
||||
} else {
|
||||
g_free(sharedir);
|
||||
g_free(homedir);
|
||||
g_free(name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_tree_store_append(model, &item, &parent);
|
||||
gtk_tree_store_set(model, &item, SCRIPTS_NAME, g_strrstr(name, "/") + 1,
|
||||
SCRIPTS_OBJECT, script, -1);
|
||||
|
||||
g_free(name);
|
||||
g_free(sharedir);
|
||||
g_free(homedir);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_fill_files() {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_files);
|
||||
GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(view));
|
||||
GtkTreeIter share, home;
|
||||
GtkTreePath *path;
|
||||
GList *scripts;
|
||||
GmScript *script;
|
||||
|
||||
gtk_tree_store_clear(model);
|
||||
|
||||
gtk_tree_store_append(model, &share, NULL);
|
||||
gtk_tree_store_set(model, &share, SCRIPTS_NAME, _("Share"), -1);
|
||||
|
||||
gtk_tree_store_append(model, &home, NULL);
|
||||
gtk_tree_store_set(model, &home, SCRIPTS_NAME, _("User"), -1);
|
||||
|
||||
for (scripts = gm_scripts_scripts(gm_app_scripts(gm_app_instance()));
|
||||
scripts; scripts = scripts->next) {
|
||||
script = (GmScript *)(scripts->data);
|
||||
gm_scripts_dialog_add_file(script);
|
||||
}
|
||||
|
||||
path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &home);
|
||||
gtk_tree_view_expand_to_path(view, path);
|
||||
gtk_tree_path_free(path);
|
||||
|
||||
path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &share);
|
||||
gtk_tree_view_expand_to_path(view, path);
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_init_files() {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_files);
|
||||
GtkTreeStore *model = gtk_tree_store_new(SCRIPTS_N, G_TYPE_STRING,
|
||||
G_TYPE_POINTER);
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
|
||||
_("Filename"), renderer, "text", SCRIPTS_NAME, NULL);
|
||||
|
||||
gtk_tree_view_append_column(view, column);
|
||||
gtk_tree_view_set_model(view, GTK_TREE_MODEL(model));
|
||||
|
||||
selection = gtk_tree_view_get_selection(view);
|
||||
|
||||
g_signal_connect((gpointer)selection, "changed",
|
||||
G_CALLBACK(on_files_changed), NULL);
|
||||
gm_scripts_dialog_fill_files();
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_scripts_dialog_init_editor() {
|
||||
GtkSourceLanguagesManager *lm = gtk_source_languages_manager_new();
|
||||
GtkSourceLanguage *lang;
|
||||
GtkWidget *view;
|
||||
PangoFontDescription *f;
|
||||
|
||||
lang = gtk_source_languages_manager_get_language_from_mime_type(lm,
|
||||
"application/x-ruby");
|
||||
|
||||
view = gtk_source_view_new();
|
||||
scripts_dialog->text_buffer_editor = gtk_text_view_get_buffer(
|
||||
GTK_TEXT_VIEW(view));
|
||||
|
||||
g_signal_connect((gpointer)scripts_dialog->text_buffer_editor,
|
||||
"modified-changed",
|
||||
G_CALLBACK(on_text_buffer_editor_modified_changed), NULL);
|
||||
|
||||
if (lang) {
|
||||
gtk_source_buffer_set_language(
|
||||
GTK_SOURCE_BUFFER(scripts_dialog->text_buffer_editor), lang);
|
||||
}
|
||||
|
||||
f = pango_font_description_from_string(gm_options_get(gm_app_options(
|
||||
gm_app_instance()), "font-family"));
|
||||
gtk_widget_modify_font(view, f);
|
||||
|
||||
gtk_source_view_set_insert_spaces_instead_of_tabs(GTK_SOURCE_VIEW(view),
|
||||
FALSE);
|
||||
gtk_source_view_set_auto_indent(GTK_SOURCE_VIEW(view), TRUE);
|
||||
gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(view), TRUE);
|
||||
gtk_source_view_set_smart_home_end(GTK_SOURCE_VIEW(view), TRUE);
|
||||
gtk_source_view_set_tabs_width(GTK_SOURCE_VIEW(view), 4);
|
||||
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
|
||||
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 6);
|
||||
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(view), 6);
|
||||
|
||||
gtk_source_buffer_set_highlight(GTK_SOURCE_BUFFER(
|
||||
scripts_dialog->text_buffer_editor), TRUE);
|
||||
|
||||
// Load default template
|
||||
gtk_text_buffer_set_text(scripts_dialog->text_buffer_editor,
|
||||
SCRIPT_TEMPLATE, -1);
|
||||
|
||||
gtk_widget_show(view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
GtkTextTag *
|
||||
gm_scripts_dialog_create_tag(gchar *name, gchar *fg) {
|
||||
GtkTextTag *tag;
|
||||
GdkColor col;
|
||||
|
||||
gdk_color_parse(fg, &col);
|
||||
tag = gtk_text_tag_new(name);
|
||||
g_object_set(G_OBJECT(tag), "foreground-gdk", &col, NULL);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_init() {
|
||||
GmScripts *scripts = gm_app_scripts(gm_app_instance());
|
||||
|
||||
scripts_dialog = g_new0(GmScriptsDialog, 1);
|
||||
scripts_dialog->tag_table = g_object_ref(gtk_text_tag_table_new());
|
||||
scripts_dialog->dialog = NULL;
|
||||
|
||||
gtk_text_tag_table_add(scripts_dialog->tag_table,
|
||||
gm_scripts_dialog_create_tag("scripts-run", "#445632"));
|
||||
gtk_text_tag_table_add(scripts_dialog->tag_table,
|
||||
gm_scripts_dialog_create_tag("scripts-msg", "#314E6C"));
|
||||
gtk_text_tag_table_add(scripts_dialog->tag_table,
|
||||
gm_scripts_dialog_create_tag("scripts-error", "#663822"));
|
||||
|
||||
scripts_dialog->text_buffer_console =
|
||||
g_object_ref(gtk_text_buffer_new(scripts_dialog->tag_table));
|
||||
|
||||
// Attach signals to GmScripts object to know about changes
|
||||
g_signal_connect(scripts, "script_added",
|
||||
G_CALLBACK(on_gm_scripts_dialog_script_added), NULL);
|
||||
g_signal_connect(scripts, "script_changed",
|
||||
G_CALLBACK(on_gm_scripts_dialog_script_changed), NULL);
|
||||
g_signal_connect(scripts, "script_removed",
|
||||
G_CALLBACK(on_gm_scripts_dialog_script_removed), NULL);
|
||||
g_signal_connect(scripts, "message",
|
||||
G_CALLBACK(on_gm_scripts_dialog_message), NULL);
|
||||
g_signal_connect(scripts, "error",
|
||||
G_CALLBACK(on_gm_scripts_dialog_error), NULL);
|
||||
g_signal_connect(scripts, "run",
|
||||
G_CALLBACK(on_gm_scripts_dialog_run), NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_fini() {
|
||||
g_object_unref(scripts_dialog->tag_table);
|
||||
g_object_unref(scripts_dialog->text_buffer_console);
|
||||
g_free(scripts_dialog);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_scroll_end_idle(gpointer user_data) {
|
||||
//gm_text_scroller_scroll_end(scripts_dialog->text_scroller);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_dialog_run(GmAppView *view) {
|
||||
GtkWidget *editor;
|
||||
|
||||
if (scripts_dialog->dialog != NULL) {
|
||||
gtk_window_present(GTK_WINDOW(scripts_dialog->dialog));
|
||||
return;
|
||||
}
|
||||
|
||||
scripts_dialog->xml = glade_xml_new(G_SCRIPTS_XML, "gm_scripts_dialog", NULL);
|
||||
scripts_dialog->dialog = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"gm_scripts_dialog");
|
||||
scripts_dialog->text_view_console = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"text_view_console");
|
||||
scripts_dialog->statusbar_editor = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"statusbar_editor");
|
||||
scripts_dialog->button_save = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"tool_button_save");
|
||||
scripts_dialog->tree_view_scripts = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"tree_view_scripts");
|
||||
scripts_dialog->tree_view_files = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"tree_view_files");
|
||||
scripts_dialog->button_delete = glade_xml_get_widget(scripts_dialog->xml,
|
||||
"tool_button_delete");
|
||||
|
||||
// Create new text scroller, this object will take care of itself and will
|
||||
// destroy itself when the view dies, neat!
|
||||
scripts_dialog->text_scroller = gm_text_scroller_new(GTK_TEXT_VIEW(
|
||||
scripts_dialog->text_view_console));
|
||||
|
||||
gm_scripts_dialog_init_console();
|
||||
gm_scripts_dialog_init_tree();
|
||||
gm_scripts_dialog_init_files();
|
||||
|
||||
editor = gm_scripts_dialog_init_editor();
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(glade_xml_get_widget(scripts_dialog->xml,
|
||||
"scrolled_window_editor")), editor);
|
||||
|
||||
glade_xml_signal_connect(scripts_dialog->xml, "on_gm_scripts_dialog_delete",
|
||||
G_CALLBACK(on_gm_scripts_dialog_delete));
|
||||
glade_xml_signal_connect(scripts_dialog->xml,
|
||||
"on_tree_view_files_row_activated",
|
||||
G_CALLBACK(on_tree_view_files_row_activated));
|
||||
glade_xml_signal_connect(scripts_dialog->xml,
|
||||
"on_tool_button_new_clicked",
|
||||
G_CALLBACK(on_tool_button_new_clicked));
|
||||
glade_xml_signal_connect(scripts_dialog->xml,
|
||||
"on_tool_button_save_clicked",
|
||||
G_CALLBACK(on_tool_button_save_clicked));
|
||||
glade_xml_signal_connect(scripts_dialog->xml,
|
||||
"on_tool_button_save_as_clicked",
|
||||
G_CALLBACK(on_tool_button_save_as_clicked));
|
||||
glade_xml_signal_connect(scripts_dialog->xml,
|
||||
"on_tool_button_delete_clicked",
|
||||
G_CALLBACK(on_tool_button_delete_clicked));
|
||||
|
||||
gtk_window_set_transient_for(GTK_WINDOW(scripts_dialog->dialog),
|
||||
GTK_WINDOW(view));
|
||||
gm_scripts_dialog_set_status(_("New <untitled>"));
|
||||
|
||||
g_object_unref(scripts_dialog->xml);
|
||||
|
||||
g_idle_add((GSourceFunc)(gm_scripts_scroll_end_idle), NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gm_scripts_dialog_add(MessageType mtype, gchar *msg) {
|
||||
gchar *m, *tagName = NULL, *newLine;
|
||||
gchar p[3] = {' ', ' ', '\0'};
|
||||
GtkTextIter end;
|
||||
|
||||
switch (mtype) {
|
||||
case SCRIPT_RUN:
|
||||
p[0] = ':';
|
||||
tagName = g_strdup("scripts-run");
|
||||
break;
|
||||
case SCRIPT_MESSAGE:
|
||||
p[0] = '#';
|
||||
tagName = g_strdup("scripts-msg");
|
||||
break;
|
||||
case SCRIPT_ERROR:
|
||||
p[0] = '!';
|
||||
tagName = g_strdup("scripts-error");
|
||||
break;
|
||||
}
|
||||
|
||||
m = g_strconcat(p, msg, "\n", NULL);
|
||||
gtk_text_buffer_get_end_iter(scripts_dialog->text_buffer_console, &end);
|
||||
|
||||
// convert to UTF-8
|
||||
newLine = g_locale_to_utf8(m, strlen(m), NULL, NULL, NULL);
|
||||
|
||||
if (newLine == NULL) {
|
||||
gtk_text_buffer_insert_with_tags_by_name(
|
||||
scripts_dialog->text_buffer_console, &end, m, strlen(m),
|
||||
tagName, NULL);
|
||||
} else {
|
||||
gtk_text_buffer_insert_with_tags_by_name(
|
||||
scripts_dialog->text_buffer_console, &end, newLine,
|
||||
strlen(newLine), tagName, NULL);
|
||||
g_free(newLine);
|
||||
}
|
||||
|
||||
g_free(m);
|
||||
g_free(tagName);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_dialog_selection_info(SelectionInfo *info) {
|
||||
GtkTreeView *view = GTK_TREE_VIEW(scripts_dialog->tree_view_files);
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(view);
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(view);
|
||||
gchar *parentName, *name, *filename;
|
||||
|
||||
info->view = view;
|
||||
info->model = model;
|
||||
|
||||
if (gtk_tree_selection_get_selected(selection, &model, &(info->seliter))) {
|
||||
info->has_parent = gtk_tree_model_iter_parent(model,
|
||||
&(info->parent), &(info->seliter));
|
||||
|
||||
if (info->has_parent) {
|
||||
gtk_tree_model_get(model, &(info->parent), SCRIPTS_NAME,
|
||||
&parentName, -1);
|
||||
gtk_tree_model_get(model, &(info->seliter), SCRIPTS_NAME,
|
||||
&name, -1);
|
||||
|
||||
if (strcmp(parentName, _("Share")) == 0) {
|
||||
filename = g_strconcat(
|
||||
PACKAGE_DATA_DIR "/" PACKAGE "/scripts/", name, NULL);
|
||||
} else {
|
||||
filename = g_strconcat(gm_app_path(gm_app_instance()),
|
||||
"/scripts/", name, NULL);
|
||||
}
|
||||
|
||||
info->filename = g_filename_from_utf8(filename, -1,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
g_free(name);
|
||||
g_free(parentName);
|
||||
g_free(filename);
|
||||
info->can_save = gm_scripts_dialog_can_write(info->filename);
|
||||
} else {
|
||||
info->filename = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* CALLBACKS */
|
||||
|
||||
gboolean
|
||||
on_gm_scripts_dialog_delete(GtkWidget *widget, GdkEvent *event,
|
||||
gpointer user_data) {
|
||||
g_free(scripts_dialog->current_edit);
|
||||
scripts_dialog->current_edit = NULL;
|
||||
scripts_dialog->dialog = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
on_files_changed(GtkTreeSelection *treeselection, gpointer user_data) {
|
||||
SelectionInfo info;
|
||||
|
||||
if (gm_scripts_dialog_selection_info(&info)) {
|
||||
gtk_widget_set_sensitive(scripts_dialog->button_delete,
|
||||
info.has_parent && info.can_save);
|
||||
|
||||
if (info.filename) {
|
||||
g_free(info.filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_tree_view_files_row_activated(GtkTreeView *treeview, GtkTreePath *arg1,
|
||||
GtkTreeViewColumn *arg2, gpointer user_data) {
|
||||
SelectionInfo si;
|
||||
|
||||
if (gm_scripts_dialog_selection_info(&si) && si.filename) {
|
||||
gm_scripts_dialog_editor_load(&si);
|
||||
g_free(si.filename);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_text_buffer_editor_modified_changed(GtkTextBuffer *buffer,
|
||||
gpointer user_data) {
|
||||
gchar *msg;
|
||||
gboolean modified = gtk_text_buffer_get_modified(buffer);
|
||||
|
||||
if (modified) {
|
||||
if (scripts_dialog->current_edit) {
|
||||
msg = g_strconcat(_("Changed "), scripts_dialog->current_edit, NULL);
|
||||
} else {
|
||||
msg = g_strdup(_("Changed <untitled>"));
|
||||
}
|
||||
|
||||
gm_scripts_dialog_set_status(msg);
|
||||
g_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_tool_button_new_clicked(GtkToolButton *button, gpointer user_data) {
|
||||
gm_scripts_dialog_editor_load(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
on_tool_button_save_clicked(GtkToolButton *button, gpointer user_data) {
|
||||
if (scripts_dialog->current_edit) {
|
||||
gm_scripts_dialog_editor_save(scripts_dialog->current_edit);
|
||||
} else {
|
||||
on_tool_button_save_as_clicked(button, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_tool_button_save_as_clicked(GtkToolButton *button, gpointer user_data) {
|
||||
GtkWidget *dlg;
|
||||
gchar *filename, *di;
|
||||
|
||||
dlg = gtk_file_chooser_dialog_new(_("Save file"),
|
||||
GTK_WINDOW(scripts_dialog->dialog),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
if (scripts_dialog->current_edit) {
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dlg),
|
||||
scripts_dialog->current_edit);
|
||||
} else {
|
||||
di = g_strconcat(gm_app_path(gm_app_instance()),
|
||||
"/scripts/untitled.rb", NULL);
|
||||
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dlg), di);
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dlg), "untitled.rb");
|
||||
g_free(di);
|
||||
}
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) {
|
||||
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
|
||||
|
||||
gm_scripts_dialog_editor_save(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dlg);
|
||||
}
|
||||
|
||||
void
|
||||
on_tool_button_delete_clicked(GtkToolButton *button, gpointer user_data) {
|
||||
SelectionInfo info;
|
||||
|
||||
if (gm_scripts_dialog_selection_info(&info)) {
|
||||
if (info.has_parent && info.can_save) {
|
||||
remove(info.filename);
|
||||
}
|
||||
|
||||
g_free(info.filename);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_scripts_dialog_script_added(GmScripts *scripts, GmScript *script,
|
||||
gpointer user_data) {
|
||||
if (scripts_dialog->dialog != NULL) {
|
||||
gm_scripts_dialog_tree_add_script(script);
|
||||
gm_scripts_dialog_add_file(script);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_scripts_dialog_script_changed(GmScripts *scripts, GmScript *script,
|
||||
gpointer user_data) {
|
||||
if (scripts_dialog->dialog != NULL) {
|
||||
gm_scripts_dialog_tree_update_script(script);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_scripts_dialog_script_removed(GmScripts *scripts, GmScript *script,
|
||||
gpointer user_data) {
|
||||
if (scripts_dialog->dialog != NULL) {
|
||||
gm_scripts_dialog_tree_remove_script(script);
|
||||
gm_scripts_dialog_remove_file(script);
|
||||
|
||||
if (strcmp(script->filename, scripts_dialog->current_edit) == 0) {
|
||||
gm_scripts_dialog_editor_load(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_gm_scripts_dialog_message(GmScripts *scripts, gchar *message,
|
||||
gpointer user_data) {
|
||||
gm_scripts_dialog_add(SCRIPT_MESSAGE, message);
|
||||
}
|
||||
|
||||
void on_gm_scripts_dialog_error(GmScripts *scripts, gchar *message,
|
||||
gpointer user_data) {
|
||||
gm_scripts_dialog_add(SCRIPT_ERROR, message);
|
||||
}
|
||||
|
||||
void on_gm_scripts_dialog_run(GmScripts *scripts, gchar *message,
|
||||
gpointer user_data) {
|
||||
gm_scripts_dialog_add(SCRIPT_RUN, message);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef __GM_SCRIPTS_DIALOG_H__
|
||||
#define __GM_SCRIPTS_DIALOG_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
#include <gtk/gtk.h>
|
||||
#include "../gm-world.h"
|
||||
#include "../widgets/gm-app-view.h"
|
||||
|
||||
void gm_scripts_dialog_run(GmAppView *view);
|
||||
void gm_scripts_dialog_init();
|
||||
void gm_scripts_dialog_fini();
|
||||
|
||||
#endif
|
||||
#endif /* __GM_SCRIPTS_DIALOG_H__ */
|
|
@ -1,991 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgnomeui/libgnomeui.h>
|
||||
#include <glade/glade.h>
|
||||
|
||||
#include "../gm-support.h"
|
||||
|
||||
#include "../gm-debug.h"
|
||||
#include "gm-triggers-dialog.h"
|
||||
#include "../gm-app.h"
|
||||
#include "../gm-pixbuf.h"
|
||||
#include "../gm-scripts.h"
|
||||
|
||||
typedef struct _GmTriggersDialog {
|
||||
GtkWidget *dialog;
|
||||
GladeXML *xml;
|
||||
GmWorld *world;
|
||||
GmTrigger *trigger;
|
||||
gboolean is_new;
|
||||
|
||||
GtkWidget *entry_name;
|
||||
GtkWidget *button_ok;
|
||||
GtkWidget *button_next;
|
||||
GtkWidget *vbox_conditions;
|
||||
GtkWidget *vbox_actions;
|
||||
GtkWidget *notebook_triggers;
|
||||
GtkWidget *tree_view_event_types;
|
||||
GtkWidget *hbox_add_condition;
|
||||
GtkWidget *hbox_add_action;
|
||||
GtkTreeModel *action_model;
|
||||
GtkTreeModel *condition_model;
|
||||
GtkTreeModel *highlight_model;
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
GtkTreeModel *script_model;
|
||||
#endif
|
||||
} GmTriggersDialog;
|
||||
|
||||
enum {
|
||||
NO_ARGS,
|
||||
SINGLE_ARGS,
|
||||
CUSTOM_ARGS
|
||||
};
|
||||
|
||||
typedef enum _CustomArgType {
|
||||
CUSTOM_ARG_CREATE,
|
||||
CUSTOM_ARG_GET_DATA
|
||||
} CustomArgType;
|
||||
|
||||
gpointer gm_triggers_dialog_custom_arg_highlight(GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data);
|
||||
gpointer gm_triggers_dialog_custom_arg_browse(GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data);
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
gpointer gm_triggers_dialog_custom_arg_script(GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data);
|
||||
#endif
|
||||
|
||||
#define CUSTOM_ARG_FUNC(x) (CustomArgFunc *)(x)
|
||||
typedef gpointer (*CustomArgFunc) (GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data);
|
||||
|
||||
enum {
|
||||
COLUMN_NAME,
|
||||
COLUMN_DATA,
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
enum {
|
||||
COLUMN_HIGH_NAME,
|
||||
COLUMN_HIGH_TAG,
|
||||
N_COLUMNS_HIGH
|
||||
};
|
||||
|
||||
typedef struct _ModelData {
|
||||
gint type;
|
||||
gchar *title;
|
||||
gint args;
|
||||
CustomArgFunc func;
|
||||
} ModelData;
|
||||
|
||||
typedef struct _TagPair {
|
||||
const gchar *name;
|
||||
const gchar *tag;
|
||||
} TagPair;
|
||||
|
||||
typedef struct _ComboBoxTypeData {
|
||||
GmTriggersDialog *triggers;
|
||||
GmTriggerData *data;
|
||||
} ComboBoxTypeData;
|
||||
|
||||
static const TagPair highlightTags[] = {
|
||||
{N_("Black"), "bg_black"},
|
||||
{N_("Red"), "bg_red"},
|
||||
{N_("Green"), "bg_green"},
|
||||
{N_("Yellow"), "bg_yellow"},
|
||||
{N_("Blue"), "bg_blue"},
|
||||
{N_("Purple"), "bg_purple"},
|
||||
{N_("Cyan"), "bg_cyan"},
|
||||
{N_("White"), "bg_white"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const ModelData dataConditionOutput[] = {
|
||||
{TCT_CONTAINS, N_("Contains"), SINGLE_ARGS, NULL},
|
||||
{TCT_NOT_CONTAINS, N_("Not contains"), SINGLE_ARGS, NULL},
|
||||
{TCT_BEGINS, N_("Begins with"), SINGLE_ARGS, NULL},
|
||||
{TCT_NOT_BEGINS, N_("Not begins with"), SINGLE_ARGS, NULL},
|
||||
{TCT_ENDS, N_("Ends with"), SINGLE_ARGS, NULL},
|
||||
{TCT_NOT_ENDS, N_("Not ends with"), SINGLE_ARGS, NULL},
|
||||
{TCT_MATCHES, N_("Matches"), SINGLE_ARGS, NULL},
|
||||
{TCT_NOT_MATCHES, N_("Not matches"), SINGLE_ARGS, NULL},
|
||||
{-1, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static const ModelData dataConditionUsers[] = {
|
||||
{TCT_USER_ONLINE, N_("Online"), SINGLE_ARGS, NULL},
|
||||
{TCT_USER_OFFLINE, N_("Offline"), SINGLE_ARGS, NULL},
|
||||
{TCT_USER_IDLE, N_("Idle"), SINGLE_ARGS, NULL},
|
||||
{TCT_USER_IDLE_OFF, N_("No longer idle"), SINGLE_ARGS, NULL},
|
||||
{TCT_USER_AWAY, N_("Away"), SINGLE_ARGS, NULL},
|
||||
{TCT_USER_AWAY_OFF, N_("No longer away"), SINGLE_ARGS, NULL},
|
||||
{-1, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static const ModelData dataActionOutput[] = {
|
||||
{TAT_HIGHLIGHT_LINE, N_("Highlight line"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_highlight},
|
||||
{TAT_HIGHLIGHT_MATCH, N_("Highlight match"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_highlight},
|
||||
{TAT_BEEP, N_("Beep"), NO_ARGS, NULL},
|
||||
{TAT_PLAY_SOUND, N_("Play sound"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_browse},
|
||||
{TAT_NOTIFY, N_("Notify"), SINGLE_ARGS, NULL},
|
||||
#ifdef HAVE_RUBY
|
||||
{TAT_RUN_SCRIPT, N_("Run script"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_script},
|
||||
#endif
|
||||
{TAT_RUN, N_("Run"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_browse},
|
||||
{-1, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static const ModelData dataActionUsers[] = {
|
||||
{TAT_BEEP, N_("Beep"), NO_ARGS, NULL},
|
||||
{TAT_PLAY_SOUND, N_("Play sound"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_browse},
|
||||
{TAT_NOTIFY, N_("Notify"), SINGLE_ARGS, NULL},
|
||||
#ifdef HAVE_RUBY
|
||||
{TAT_RUN_SCRIPT, N_("Run script"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_script},
|
||||
#endif
|
||||
{TAT_RUN, N_("Run"), CUSTOM_ARGS,
|
||||
gm_triggers_dialog_custom_arg_browse},
|
||||
{-1, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
void on_button_next_clicked(GtkButton *button, GmTriggersDialog *triggers);
|
||||
void on_button_add_condition_clicked(GtkButton *button,
|
||||
GmTriggersDialog *triggers);
|
||||
void on_button_add_action_clicked(GtkButton *button,
|
||||
GmTriggersDialog *triggers);
|
||||
void on_notebook_triggers_switch_page(GtkNotebook *notebook, GtkNotebookPage
|
||||
*page, guint page_num, GmTriggersDialog *triggers);
|
||||
void on_combo_box_type_changed(GtkComboBox *widget, ComboBoxTypeData *tdata);
|
||||
void on_combo_box_type_destroy(GtkObject *object, ComboBoxTypeData *tdata);
|
||||
void on_button_remove_clicked(GtkButton *button, GmTriggersDialog *triggers);
|
||||
void on_tree_view_event_types_changed(GtkTreeSelection *treeselection,
|
||||
GmTriggersDialog *triggers);
|
||||
|
||||
#define G_TRIGGERS_XML PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-triggers.glade"
|
||||
|
||||
void
|
||||
gm_triggers_dialog_create_models(GmTriggersDialog *triggers,
|
||||
const ModelData *conditionData, const ModelData *actionData) {
|
||||
int i;
|
||||
GtkTreeIter iter;
|
||||
ModelData *data;
|
||||
GList *scripts, *item;
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
GmScript *script;
|
||||
GmScriptFunction *func;
|
||||
#endif
|
||||
|
||||
triggers->action_model = GTK_TREE_MODEL(gtk_list_store_new(
|
||||
N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER));
|
||||
triggers->condition_model = GTK_TREE_MODEL(gtk_list_store_new(
|
||||
N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER));
|
||||
triggers->highlight_model = GTK_TREE_MODEL(gtk_list_store_new(
|
||||
N_COLUMNS_HIGH, G_TYPE_STRING, G_TYPE_STRING));
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
triggers->script_model = GTK_TREE_MODEL(gtk_list_store_new(1,
|
||||
G_TYPE_STRING));
|
||||
#endif
|
||||
|
||||
for (i = 0; conditionData[i].type != -1; i++) {
|
||||
data = (ModelData *)(&(conditionData[i]));
|
||||
gtk_list_store_append(GTK_LIST_STORE(triggers->condition_model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(triggers->condition_model), &iter,
|
||||
COLUMN_NAME, _(data->title), COLUMN_DATA, data, -1);
|
||||
}
|
||||
|
||||
for (i = 0; actionData[i].type != -1; i++) {
|
||||
data = (ModelData *)(&(actionData[i]));
|
||||
gtk_list_store_append(GTK_LIST_STORE(triggers->action_model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(triggers->action_model), &iter,
|
||||
COLUMN_NAME, _(data->title), COLUMN_DATA, data, -1);
|
||||
}
|
||||
|
||||
for (i = 0; highlightTags[i].name != NULL; i++) {
|
||||
gtk_list_store_append(GTK_LIST_STORE(triggers->highlight_model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(triggers->highlight_model), &iter,
|
||||
COLUMN_HIGH_NAME, _(highlightTags[i].name), COLUMN_HIGH_TAG,
|
||||
highlightTags[i].tag, -1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
for (scripts = gm_scripts_scripts(gm_app_scripts(gm_app_instance()));
|
||||
scripts; scripts = scripts->next) {
|
||||
script = (GmScript *)(scripts->data);
|
||||
|
||||
for (item = script->functions; item; item = item->next) {
|
||||
func = (GmScriptFunction *)(item->data);
|
||||
gtk_list_store_append(GTK_LIST_STORE(triggers->script_model),
|
||||
&iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(triggers->script_model), &iter,
|
||||
0, func->name, -1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ModelData *
|
||||
gm_triggers_dialog_combo_get_selected_data(GmTriggersDialog *triggers,
|
||||
GtkComboBox *combo) {
|
||||
GtkTreeIter iter;
|
||||
ModelData *data;
|
||||
|
||||
gtk_combo_box_get_active_iter(combo, &iter);
|
||||
gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, COLUMN_DATA, &data,
|
||||
-1);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_triggers_dialog_collect_rules(GmTriggersDialog *triggers, GtkWidget *vbox) {
|
||||
gchar *text;
|
||||
GList *children, *child, *item, *result = NULL;
|
||||
GtkComboBox *combo;
|
||||
GtkEntry *entry;
|
||||
ModelData *data;
|
||||
GmTriggerData *d;
|
||||
|
||||
children = gtk_container_get_children(GTK_CONTAINER(vbox));
|
||||
|
||||
for (item = children; item; item = item->next) {
|
||||
if (item->data == triggers->hbox_add_condition ||
|
||||
item->data == triggers->hbox_add_action) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (GTK_IS_HBOX(item->data)) {
|
||||
child = gtk_container_get_children(GTK_CONTAINER(item->data));
|
||||
combo = GTK_COMBO_BOX(child->data);
|
||||
data = gm_triggers_dialog_combo_get_selected_data(triggers, combo);
|
||||
d = NULL;
|
||||
|
||||
switch (data->args) {
|
||||
case NO_ARGS:
|
||||
d = gm_trigger_data_new(data->type, NULL);
|
||||
break;
|
||||
case SINGLE_ARGS:
|
||||
if (child->next) {
|
||||
entry = GTK_ENTRY(child->next->data);
|
||||
text = (gchar *)gtk_entry_get_text(entry);
|
||||
|
||||
if (g_utf8_strlen(text, -1) > 0) {
|
||||
d = gm_trigger_data_new(data->type, g_strdup(text));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CUSTOM_ARGS:
|
||||
text = (gchar *)(data->func(triggers, CUSTOM_ARG_GET_DATA,
|
||||
child->next, NULL));
|
||||
|
||||
if (text != NULL && g_utf8_strlen(text, -1) > 0) {
|
||||
d = gm_trigger_data_new(data->type, text);
|
||||
} else {
|
||||
g_free(text);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (d) {
|
||||
result = g_list_append(result, d);
|
||||
}
|
||||
|
||||
g_list_free(child);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(children);
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_triggers_dialog_fill_trigger(GmTriggersDialog *triggers) {
|
||||
const gchar *name = gtk_entry_get_text(GTK_ENTRY(triggers->entry_name));
|
||||
GList *conditions = NULL;
|
||||
GList *actions = NULL;
|
||||
|
||||
if (g_utf8_strlen(name, -1) == 0) {
|
||||
gm_error_dialog(_("Please fill in a trigger name"),
|
||||
GTK_WINDOW(triggers->dialog));
|
||||
gtk_widget_grab_focus(triggers->entry_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
conditions = gm_triggers_dialog_collect_rules(triggers,
|
||||
triggers->vbox_conditions);
|
||||
|
||||
if (conditions == NULL) {
|
||||
gm_error_dialog(_("Please specify at least one condition"),
|
||||
GTK_WINDOW(triggers->dialog));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
actions = gm_triggers_dialog_collect_rules(triggers, triggers->vbox_actions);
|
||||
|
||||
if (actions == NULL) {
|
||||
gm_trigger_free_list(conditions);
|
||||
gm_error_dialog(_("Please specify at least one action"),
|
||||
GTK_WINDOW(triggers->dialog));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gm_trigger_set_name(triggers->trigger, name);
|
||||
gm_trigger_set_conditions(triggers->trigger, conditions);
|
||||
gm_trigger_set_actions(triggers->trigger, actions);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_dialog_initialize_event_types(GmTriggersDialog *triggers) {
|
||||
GtkListStore *store = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING,
|
||||
G_TYPE_INT);
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeIter iter;
|
||||
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(triggers->tree_view_event_types),
|
||||
GTK_TREE_MODEL(store));
|
||||
|
||||
renderer = gtk_cell_renderer_pixbuf_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "pixbuf",
|
||||
0, NULL);
|
||||
gtk_tree_view_column_set_min_width(column, 40);
|
||||
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(triggers->tree_view_event_types),
|
||||
column);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "markup",
|
||||
1, NULL);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(triggers->tree_view_event_types),
|
||||
column);
|
||||
|
||||
gtk_list_store_prepend(store, &iter);
|
||||
gtk_list_store_set(store, &iter, 0,
|
||||
gm_pixbuf_get_at_size("ice-userlist/programmer.svg", 32, 32), 1,
|
||||
_("<b>Player event</b>\nPlayer events are triggered on userlist "
|
||||
"activity"), 2, TT_USERS, -1);
|
||||
|
||||
gtk_list_store_prepend(store, &iter);
|
||||
gtk_list_store_set(store, &iter, 0,
|
||||
gm_pixbuf_get_at_size("world.svg", 32, 32), 1,
|
||||
_("<b>World event</b>\nWorld events are triggered on incoming "
|
||||
"lines of text"), 2, TT_OUTPUT, -1);
|
||||
|
||||
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(
|
||||
GTK_TREE_VIEW(triggers->tree_view_event_types)), &iter);
|
||||
g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(
|
||||
triggers->tree_view_event_types)), "changed",
|
||||
G_CALLBACK(on_tree_view_event_types_changed), triggers);
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_triggers_dialog_run_dialog(GmTriggersDialog *triggers) {
|
||||
gboolean done = FALSE;
|
||||
GmTrigger *result = NULL;
|
||||
|
||||
while (!done) {
|
||||
done = TRUE;
|
||||
|
||||
switch (gtk_dialog_run(GTK_DIALOG(triggers->dialog))) {
|
||||
case GTK_RESPONSE_OK:
|
||||
done = gm_triggers_dialog_fill_trigger(triggers);
|
||||
|
||||
if (done) {
|
||||
result = triggers->trigger;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (triggers->action_model != NULL)
|
||||
g_object_unref(triggers->action_model);
|
||||
if (triggers->condition_model != NULL)
|
||||
g_object_unref(triggers->condition_model);
|
||||
if (triggers->highlight_model != NULL)
|
||||
g_object_unref(triggers->highlight_model);
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
if (triggers->script_model != NULL)
|
||||
g_object_unref(triggers->script_model);
|
||||
#endif
|
||||
|
||||
if (!result && triggers->is_new) {
|
||||
gm_trigger_free(triggers->trigger);
|
||||
}
|
||||
|
||||
g_object_unref(triggers->xml);
|
||||
gtk_widget_destroy(triggers->dialog);
|
||||
|
||||
g_free(triggers);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_triggers_dialog_run_priv(GmWorld *world, GmTrigger *trigger,
|
||||
gboolean is_new) {
|
||||
GmTriggersDialog *triggers = g_new0(GmTriggersDialog, 1);
|
||||
|
||||
triggers->is_new = is_new;
|
||||
triggers->world = world;
|
||||
triggers->xml = glade_xml_new(G_TRIGGERS_XML, "gm_triggers_dialog", NULL);
|
||||
triggers->dialog = glade_xml_get_widget(triggers->xml,
|
||||
"gm_triggers_dialog");
|
||||
triggers->entry_name = glade_xml_get_widget(triggers->xml, "entry_name");
|
||||
triggers->vbox_conditions = glade_xml_get_widget(triggers->xml,
|
||||
"vbox_conditions");
|
||||
triggers->vbox_actions = glade_xml_get_widget(triggers->xml,
|
||||
"vbox_actions");
|
||||
triggers->notebook_triggers = glade_xml_get_widget(triggers->xml,
|
||||
"notebook_triggers");
|
||||
triggers->tree_view_event_types = glade_xml_get_widget(triggers->xml,
|
||||
"tree_view_event_types");
|
||||
triggers->button_ok = glade_xml_get_widget(triggers->xml, "button_ok");
|
||||
triggers->hbox_add_condition = glade_xml_get_widget(triggers->xml,
|
||||
"hbox_add_condition");
|
||||
triggers->hbox_add_action = glade_xml_get_widget(triggers->xml,
|
||||
"hbox_add_action");
|
||||
triggers->button_next = glade_xml_get_widget(triggers->xml, "button_next");
|
||||
|
||||
gm_triggers_dialog_initialize_event_types(triggers);
|
||||
|
||||
glade_xml_signal_connect_data(triggers->xml, "on_button_next_clicked",
|
||||
G_CALLBACK(on_button_next_clicked), triggers);
|
||||
glade_xml_signal_connect_data(triggers->xml,
|
||||
"on_button_add_condition_clicked",
|
||||
G_CALLBACK(on_button_add_condition_clicked), triggers);
|
||||
glade_xml_signal_connect_data(triggers->xml, "on_button_add_action_clicked",
|
||||
G_CALLBACK(on_button_add_action_clicked), triggers);
|
||||
glade_xml_signal_connect_data(triggers->xml,
|
||||
"on_notebook_triggers_switch_page",
|
||||
G_CALLBACK(on_notebook_triggers_switch_page), triggers);
|
||||
|
||||
triggers->trigger = trigger;
|
||||
|
||||
if (is_new) {
|
||||
gtk_notebook_set_current_page(
|
||||
GTK_NOTEBOOK(triggers->notebook_triggers), 0);
|
||||
} else {
|
||||
gtk_notebook_set_current_page(
|
||||
GTK_NOTEBOOK(triggers->notebook_triggers), 1);
|
||||
}
|
||||
|
||||
gtk_widget_show_all(triggers->dialog);
|
||||
return gm_triggers_dialog_run_dialog(triggers);
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_triggers_dialog_run(GmWorld *world, GmTrigger *trigger) {
|
||||
return gm_triggers_dialog_run_priv(world, trigger, FALSE);
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_triggers_dialog_run_new(GmWorld *world, GmTrigger *trigger) {
|
||||
if (!trigger) {
|
||||
trigger = gm_trigger_new();
|
||||
}
|
||||
|
||||
return gm_triggers_dialog_run_priv(world, trigger, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_dialog_select_combo_by_type(GmTriggersDialog *triggers,
|
||||
GtkComboBox *combo, gint type) {
|
||||
GtkTreeModel *model = gtk_combo_box_get_model(combo);
|
||||
GtkTreeIter iter;
|
||||
ModelData *data;
|
||||
|
||||
if (gtk_tree_model_get_iter_first(model, &iter)) {
|
||||
do {
|
||||
gtk_tree_model_get(model, &iter, COLUMN_DATA, &data, -1);
|
||||
|
||||
if (type == data->type) {
|
||||
gtk_combo_box_set_active_iter(combo, &iter);
|
||||
return;
|
||||
}
|
||||
} while (gtk_tree_model_iter_next(model, &iter));
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_triggers_dialog_create_item(GmTriggersDialog *triggers, GtkTreeModel *model,
|
||||
GmTriggerData *t) {
|
||||
GtkWidget *hbox, *combo, *button;
|
||||
ComboBoxTypeData *data;
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||
hbox = gtk_hbox_new(FALSE, 6);
|
||||
|
||||
combo = gtk_combo_box_new_with_model(model);
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
|
||||
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text",
|
||||
COLUMN_NAME, NULL);
|
||||
|
||||
|
||||
data = g_new0(ComboBoxTypeData, 1);
|
||||
data->triggers = triggers;
|
||||
data->data = t;
|
||||
|
||||
g_signal_connect(combo, "changed", G_CALLBACK(on_combo_box_type_changed),
|
||||
data);
|
||||
g_signal_connect(combo, "destroy", G_CALLBACK(on_combo_box_type_destroy),
|
||||
data);
|
||||
|
||||
button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
|
||||
g_signal_connect(button, "clicked", G_CALLBACK(on_button_remove_clicked),
|
||||
triggers);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
|
||||
gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, TRUE, 0);
|
||||
|
||||
gtk_widget_show_all(hbox);
|
||||
return hbox;
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_dialog_new_condition(GmTriggersDialog *triggers) {
|
||||
GtkWidget *hbox;
|
||||
GList *children;
|
||||
|
||||
hbox = gm_triggers_dialog_create_item(triggers, triggers->condition_model,
|
||||
NULL);
|
||||
children = gtk_container_get_children(GTK_CONTAINER(hbox));
|
||||
|
||||
if (triggers->trigger->event == TT_OUTPUT) {
|
||||
gm_triggers_dialog_select_combo_by_type(triggers,
|
||||
GTK_COMBO_BOX(children->data), dataConditionOutput[0].type);
|
||||
} else {
|
||||
gm_triggers_dialog_select_combo_by_type(triggers,
|
||||
GTK_COMBO_BOX(children->data), dataConditionUsers[0].type);
|
||||
}
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(triggers->vbox_conditions), hbox, FALSE, TRUE,
|
||||
0);
|
||||
g_list_free(children);
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_dialog_populate_conditions(GmTriggersDialog *triggers) {
|
||||
GList *item;
|
||||
GtkWidget *hbox;
|
||||
GmTriggerData *t;
|
||||
GList *children;
|
||||
|
||||
if (triggers->trigger->conditions) {
|
||||
for (item = triggers->trigger->conditions; item; item = item->next) {
|
||||
t = (GmTriggerData *)(item->data);
|
||||
|
||||
hbox = gm_triggers_dialog_create_item(triggers,
|
||||
triggers->condition_model, t);
|
||||
children = gtk_container_get_children(GTK_CONTAINER(hbox));
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(triggers->vbox_conditions), hbox,
|
||||
FALSE, TRUE, 0);
|
||||
gm_triggers_dialog_select_combo_by_type(triggers,
|
||||
GTK_COMBO_BOX(children->data), t->type);
|
||||
g_list_free(children);
|
||||
}
|
||||
} else {
|
||||
gm_triggers_dialog_new_condition(triggers);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_dialog_new_action(GmTriggersDialog *triggers) {
|
||||
GtkWidget *hbox;
|
||||
GList *children;
|
||||
|
||||
hbox = gm_triggers_dialog_create_item(triggers, triggers->action_model,
|
||||
NULL);
|
||||
children = gtk_container_get_children(GTK_CONTAINER(hbox));
|
||||
|
||||
if (triggers->trigger->event == TT_OUTPUT) {
|
||||
gm_triggers_dialog_select_combo_by_type(triggers,
|
||||
GTK_COMBO_BOX(children->data), dataActionOutput[0].type);
|
||||
} else {
|
||||
gm_triggers_dialog_select_combo_by_type(triggers,
|
||||
GTK_COMBO_BOX(children->data), dataActionUsers[0].type);
|
||||
}
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(triggers->vbox_actions), hbox, FALSE, TRUE, 0);
|
||||
g_list_free(children);
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_dialog_populate_actions(GmTriggersDialog *triggers) {
|
||||
GList *item;
|
||||
GtkWidget *hbox;
|
||||
GmTriggerData *t;
|
||||
GList *children;
|
||||
|
||||
if (triggers->trigger->actions) {
|
||||
for (item = triggers->trigger->actions; item; item = item->next) {
|
||||
t = (GmTriggerData *)(item->data);
|
||||
hbox = gm_triggers_dialog_create_item(triggers,
|
||||
triggers->action_model, t);
|
||||
children = gtk_container_get_children(GTK_CONTAINER(hbox));
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(triggers->vbox_actions), hbox, FALSE,
|
||||
TRUE, 0);
|
||||
gm_triggers_dialog_select_combo_by_type(triggers,
|
||||
GTK_COMBO_BOX(children->data), t->type);
|
||||
|
||||
g_list_free(children);
|
||||
}
|
||||
} else {
|
||||
gm_triggers_dialog_new_action(triggers);
|
||||
}
|
||||
}
|
||||
|
||||
/* CALLBACKS */
|
||||
void
|
||||
on_button_next_clicked(GtkButton *button, GmTriggersDialog *triggers) {
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
gint type;
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
|
||||
triggers->tree_view_event_types));
|
||||
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
|
||||
triggers->tree_view_event_types));
|
||||
|
||||
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
|
||||
gtk_tree_model_get(model, &iter, 2, &type, -1);
|
||||
|
||||
triggers->trigger->event = type;
|
||||
gtk_notebook_set_current_page(GTK_NOTEBOOK(
|
||||
triggers->notebook_triggers), 1);
|
||||
} else {
|
||||
gm_error_dialog(_("Select a event type first"),
|
||||
GTK_WINDOW(triggers->dialog));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_tree_view_event_types_changed(GtkTreeSelection *treeselection,
|
||||
GmTriggersDialog *triggers) {
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
gint type;
|
||||
|
||||
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
|
||||
triggers->tree_view_event_types));
|
||||
|
||||
if (!gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
|
||||
gtk_widget_set_sensitive(triggers->button_next, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive(triggers->button_next, TRUE);
|
||||
gtk_tree_model_get(model, &iter, 2, &type, -1);
|
||||
|
||||
switch (type) {
|
||||
case TT_OUTPUT:
|
||||
gtk_window_set_icon(GTK_WINDOW(triggers->dialog),
|
||||
gm_pixbuf_get_at_size("world.svg", 16, 16));
|
||||
break;
|
||||
case TT_USERS:
|
||||
gtk_window_set_icon(GTK_WINDOW(triggers->dialog),
|
||||
gm_pixbuf_get_at_size("ice-userlist/programmer.svg",
|
||||
16, 16));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_notebook_triggers_switch_page(GtkNotebook *notebook, GtkNotebookPage *page,
|
||||
guint page_num, GmTriggersDialog *triggers) {
|
||||
const ModelData *conditionData = NULL;
|
||||
const ModelData *actionData = NULL;
|
||||
|
||||
if (page_num != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive(triggers->button_ok, TRUE);
|
||||
|
||||
switch (triggers->trigger->event) {
|
||||
case TT_OUTPUT:
|
||||
gtk_window_set_icon(GTK_WINDOW(triggers->dialog),
|
||||
gm_pixbuf_get_at_size("world.svg", 16, 16));
|
||||
conditionData = dataConditionOutput;
|
||||
actionData = dataActionOutput;
|
||||
break;
|
||||
case TT_USERS:
|
||||
gtk_window_set_icon(GTK_WINDOW(triggers->dialog),
|
||||
gm_pixbuf_get_at_size("ice-userlist/programmer.svg",
|
||||
16, 16));
|
||||
conditionData = dataConditionUsers;
|
||||
actionData = dataActionUsers;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gm_triggers_dialog_create_models(triggers, conditionData, actionData);
|
||||
|
||||
if (triggers->trigger->name) {
|
||||
gtk_entry_set_text(GTK_ENTRY(triggers->entry_name),
|
||||
triggers->trigger->name);
|
||||
}
|
||||
|
||||
gm_triggers_dialog_populate_conditions(triggers);
|
||||
gm_triggers_dialog_populate_actions(triggers);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gm_triggers_dialog_custom_arg_highlight(GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data) {
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *combo;
|
||||
GtkCellRenderer *renderer;
|
||||
GList *item;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
gchar *tag;
|
||||
GmTriggerData *t = (GmTriggerData *)(user_data);
|
||||
|
||||
switch (type) {
|
||||
case CUSTOM_ARG_CREATE:
|
||||
hbox = GTK_WIDGET(data);
|
||||
combo = gtk_combo_box_new_with_model(triggers->highlight_model);
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
|
||||
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer,
|
||||
"text", COLUMN_HIGH_NAME, NULL);
|
||||
|
||||
if (!user_data) {
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
|
||||
} else {
|
||||
model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
|
||||
|
||||
if (gtk_tree_model_get_iter_first(model, &iter)) {
|
||||
do {
|
||||
gtk_tree_model_get(model, &iter, COLUMN_HIGH_TAG,
|
||||
&tag, -1);
|
||||
|
||||
if (strcmp(tag, t->data) == 0) {
|
||||
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),
|
||||
&iter);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(tag);
|
||||
} while (gtk_tree_model_iter_next(model, &iter));
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_show(combo);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
|
||||
break;
|
||||
case CUSTOM_ARG_GET_DATA:
|
||||
item = (GList *)(data);
|
||||
model = gtk_combo_box_get_model(GTK_COMBO_BOX(item->data));
|
||||
gtk_combo_box_get_active_iter(GTK_COMBO_BOX(item->data), &iter);
|
||||
gtk_tree_model_get(model, &iter, COLUMN_HIGH_TAG, &tag, -1);
|
||||
|
||||
return tag;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
on_button_browse_clicked(GtkButton *widget, GtkEntry *entry) {
|
||||
gchar *tmp;
|
||||
GtkWidget *d = gtk_file_chooser_dialog_new(_("Select file"),
|
||||
NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
|
||||
tmp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
|
||||
gtk_entry_set_text(entry, tmp);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(d);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gm_triggers_dialog_custom_arg_browse(GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data) {
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *browse, *tmp;
|
||||
GmTriggerData *t = (GmTriggerData *)(user_data);
|
||||
GList *item;
|
||||
|
||||
switch (type) {
|
||||
case CUSTOM_ARG_CREATE:
|
||||
hbox = GTK_WIDGET(data);
|
||||
entry = gtk_entry_new();
|
||||
|
||||
if (t) {
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), t->data);
|
||||
}
|
||||
|
||||
browse = gtk_button_new();
|
||||
tmp = gtk_hbox_new(FALSE, 3);
|
||||
gtk_container_add(GTK_CONTAINER(browse), tmp);
|
||||
gtk_box_pack_start(GTK_BOX(tmp), gtk_image_new_from_stock(
|
||||
GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON), FALSE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(tmp), gtk_label_new(_("Browse")),
|
||||
TRUE, TRUE, 0);
|
||||
|
||||
g_signal_connect(browse, "clicked",
|
||||
G_CALLBACK(on_button_browse_clicked), entry);
|
||||
|
||||
gtk_widget_show(entry);
|
||||
gtk_widget_show_all(browse);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), browse, FALSE, TRUE, 0);
|
||||
break;
|
||||
case CUSTOM_ARG_GET_DATA:
|
||||
item = (GList *)(data);
|
||||
return g_strdup(gtk_entry_get_text(GTK_ENTRY(item->data)));
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
on_combo_box_type_changed(GtkComboBox *widget, ComboBoxTypeData *tdata) {
|
||||
GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(widget));
|
||||
GList *item, *children = gtk_container_get_children(GTK_CONTAINER(parent));
|
||||
ModelData *data;
|
||||
GtkTreeIter iter;
|
||||
GtkWidget *tmp;
|
||||
|
||||
for (item = children->next; item && item->next; item = item->next) {
|
||||
gtk_widget_destroy(GTK_WIDGET(item->data));
|
||||
}
|
||||
|
||||
g_list_free(children);
|
||||
|
||||
if (gtk_combo_box_get_active_iter(widget, &iter)) {
|
||||
gtk_tree_model_get(gtk_combo_box_get_model(widget), &iter,
|
||||
COLUMN_DATA, &data, -1);
|
||||
|
||||
switch (data->args) {
|
||||
case SINGLE_ARGS:
|
||||
tmp = gtk_entry_new();
|
||||
|
||||
if (tdata->data) {
|
||||
gtk_entry_set_text(GTK_ENTRY(tmp), tdata->data->data);
|
||||
}
|
||||
|
||||
gtk_widget_show(tmp);
|
||||
gtk_box_pack_start(GTK_BOX(parent), tmp, TRUE, TRUE, 0);
|
||||
break;
|
||||
case CUSTOM_ARGS:
|
||||
data->func(tdata->triggers,
|
||||
CUSTOM_ARG_CREATE, (gpointer)parent,
|
||||
(gpointer)tdata->data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (tdata->data != NULL) {
|
||||
tdata->data = NULL;
|
||||
}
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_ALWAYS, "No active iter!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_combo_box_type_destroy(GtkObject *object, ComboBoxTypeData *tdata) {
|
||||
g_free(tdata);
|
||||
}
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
gpointer
|
||||
gm_triggers_dialog_custom_arg_script(GmTriggersDialog *triggers,
|
||||
CustomArgType type, gpointer data, gpointer user_data) {
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *entry;
|
||||
GtkEntryCompletion *entry_completion;
|
||||
GList *item;
|
||||
GmTriggerData *t = (GmTriggerData *)(user_data);
|
||||
|
||||
switch (type) {
|
||||
case CUSTOM_ARG_CREATE:
|
||||
hbox = GTK_WIDGET(data);
|
||||
entry = gtk_entry_new();
|
||||
entry_completion = gtk_entry_completion_new();
|
||||
gtk_entry_completion_set_model(entry_completion,
|
||||
triggers->script_model);
|
||||
gtk_entry_completion_set_text_column(entry_completion, 0);
|
||||
gtk_entry_set_completion(GTK_ENTRY(entry), entry_completion);
|
||||
|
||||
if (user_data) {
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), t->data);
|
||||
}
|
||||
|
||||
gtk_widget_show(entry);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
|
||||
break;
|
||||
case CUSTOM_ARG_GET_DATA:
|
||||
item = (GList *)(data);
|
||||
return g_strdup(gtk_entry_get_text(GTK_ENTRY(item->data)));
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
gm_triggers_dialog_idle_remove_item(GtkWidget *parent) {
|
||||
gtk_widget_destroy(parent);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
on_button_remove_clicked(GtkButton *button, GmTriggersDialog *triggers) {
|
||||
g_idle_add((GSourceFunc)(gm_triggers_dialog_idle_remove_item),
|
||||
gtk_widget_get_parent(GTK_WIDGET(button)));
|
||||
}
|
||||
|
||||
void
|
||||
on_button_add_condition_clicked(GtkButton *button, GmTriggersDialog *triggers) {
|
||||
gm_triggers_dialog_new_condition(triggers);
|
||||
}
|
||||
|
||||
void
|
||||
on_button_add_action_clicked(GtkButton *button, GmTriggersDialog *triggers) {
|
||||
gm_triggers_dialog_new_action(triggers);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef __GM_TRIGGERS_DIALOG__
|
||||
#define __GM_TRIGGERS_DIALOG__
|
||||
|
||||
#include "../gm-triggers.h"
|
||||
#include "../gm-world.h"
|
||||
|
||||
GmTrigger *gm_triggers_dialog_run(GmWorld *world, GmTrigger *trig);
|
||||
GmTrigger *gm_triggers_dialog_run_new(GmWorld *world, GmTrigger *trig);
|
||||
|
||||
#endif /* __GM_TRIGGERS_DIALOG__ */
|
|
@ -1,111 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glade/glade.h>
|
||||
#include <libgnome/libgnome.h>
|
||||
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-pixbuf.h"
|
||||
|
||||
#define G_WORLD_INFO_XML PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-world-info.glade"
|
||||
|
||||
gboolean on_gm_world_info_dialog_url_button_release(GtkWidget *button,
|
||||
GdkEventButton *event, gchar *link);
|
||||
|
||||
/* Private */
|
||||
void
|
||||
gm_world_info_dialog_set_label(GtkLabel *label, gchar *text) {
|
||||
if (text) {
|
||||
gtk_label_set_markup(label, text);
|
||||
} else {
|
||||
gtk_label_set_markup(label, _("<i>unspecified</i>"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Public */
|
||||
|
||||
GtkDialog *
|
||||
gm_world_info_dialog_new(GmWorldInfo world_info) {
|
||||
GladeXML *xml;
|
||||
GtkWidget *dlg, *widget;
|
||||
gchar *tmp;
|
||||
|
||||
xml = glade_xml_new(G_WORLD_INFO_XML, "dlgWorldInfo", NULL);
|
||||
dlg = glade_xml_get_widget(xml, "dlgWorldInfo");
|
||||
|
||||
gm_world_info_dialog_set_label(GTK_LABEL(glade_xml_get_widget(xml,
|
||||
"lblName")), world_info.admin);
|
||||
gm_world_info_dialog_set_label(GTK_LABEL(glade_xml_get_widget(xml,
|
||||
"lblLocation")), world_info.location);
|
||||
gm_world_info_dialog_set_label(GTK_LABEL(glade_xml_get_widget(xml,
|
||||
"lblSystem")), world_info.system);
|
||||
gm_world_info_dialog_set_label(GTK_LABEL(glade_xml_get_widget(xml,
|
||||
"lblCharset")), world_info.charset);
|
||||
gm_world_info_dialog_set_label(GTK_LABEL(glade_xml_get_widget(xml,
|
||||
"lblLanguage")), world_info.language);
|
||||
|
||||
if (world_info.homepage) {
|
||||
tmp = g_strconcat("<u><span color=\"#0000ff\">", world_info.homepage,
|
||||
"</span></u>", NULL);
|
||||
glade_xml_signal_connect_data(xml,
|
||||
"on_gm_world_info_dialog_url_button_release",
|
||||
G_CALLBACK(on_gm_world_info_dialog_url_button_release), NULL);
|
||||
widget = glade_xml_get_widget(xml, "lblHomepage");
|
||||
gtk_label_set_markup(GTK_LABEL(widget), tmp);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
if (world_info.contact) {
|
||||
tmp = g_strconcat("<u><span color=\"#0000ff\">", world_info.contact,
|
||||
"</span></u>", NULL);
|
||||
glade_xml_signal_connect_data(xml,
|
||||
"on_gm_world_info_dialog_url_button_release",
|
||||
G_CALLBACK(on_gm_world_info_dialog_url_button_release), "mailto:");
|
||||
widget = glade_xml_get_widget(xml, "lblEmail");
|
||||
gtk_label_set_markup(GTK_LABEL(widget), tmp);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
if (world_info.logo) {
|
||||
gtk_image_set_from_pixbuf(GTK_IMAGE(glade_xml_get_widget(xml,
|
||||
"imageLogo")), gm_pixbuf_get(world_info.logo));
|
||||
}
|
||||
|
||||
glade_xml_signal_connect(xml, "on_dlgWorldInfo_delete",
|
||||
G_CALLBACK(gtk_widget_destroy));
|
||||
glade_xml_signal_connect_data(xml, "on_buttonClose_clicked",
|
||||
G_CALLBACK(gm_widget_destroy_data), dlg);
|
||||
|
||||
gtk_widget_show_all(dlg);
|
||||
|
||||
g_object_unref(xml);
|
||||
return GTK_DIALOG(dlg);
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
gboolean
|
||||
on_gm_world_info_dialog_url_button_release(GtkWidget *label,
|
||||
GdkEventButton *event, gchar *prefix) {
|
||||
GError *err = NULL;
|
||||
gchar *tmp, *link;
|
||||
|
||||
if (prefix != NULL) {
|
||||
link = g_strconcat(prefix, gtk_label_get_text(GTK_LABEL(label)), NULL);
|
||||
} else {
|
||||
link = g_strdup(gtk_label_get_text(GTK_LABEL(label)));
|
||||
}
|
||||
|
||||
if (!gnome_url_show(link, &err)) {
|
||||
tmp = g_strdup_printf("Could not open link: %s", err->message);
|
||||
gm_error_dialog(tmp, NULL);
|
||||
g_free(tmp);
|
||||
g_error_free(err);
|
||||
}
|
||||
|
||||
g_free(link);
|
||||
return FALSE;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __GM_WORLD_INFO_DIALOG_H__
|
||||
#define __GM_WORLD_INFO_DIALOG_H__
|
||||
|
||||
GtkDialog *gm_world_info_dialog_new(GmWorldInfo world_info);
|
||||
|
||||
#endif /* __GM_WORLD_INFO_DIALOG_H__ */
|
|
@ -1,116 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glade/glade.h>
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-support.h"
|
||||
|
||||
#define G_WORLD_LOGS_XML PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-world-info.glade"
|
||||
|
||||
void
|
||||
on_gm_world_logs_dialog_row_activated(GtkTreeView *treeview, GtkTreePath *arg1,
|
||||
GtkTreeViewColumn *arg2, GtkDialog *dlg);
|
||||
|
||||
/* Public */
|
||||
|
||||
GtkDialog *
|
||||
gm_world_logs_dialog_new(GmWorld *world, GtkTreeView **view,
|
||||
GtkProgressBar **progress) {
|
||||
GladeXML *xml = glade_xml_new(G_WORLD_LOGS_XML, "dlgLogs", NULL);
|
||||
GtkDialog *dlg;
|
||||
GtkTreeModel *model, *smodel;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
gchar *path, *tmp, *tmp2;
|
||||
const gchar *fname;
|
||||
GDir *dir;
|
||||
GError *err;
|
||||
GtkTreeIter iter;
|
||||
FILE *f;
|
||||
long fsize;
|
||||
int res = 0;
|
||||
|
||||
dlg = GTK_DIALOG(glade_xml_get_widget(xml, "dlgLogs"));
|
||||
*view = GTK_TREE_VIEW(glade_xml_get_widget(xml, "tvwLogs"));
|
||||
|
||||
model = GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING));
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Logs"), renderer,
|
||||
"text", 1, NULL);
|
||||
gtk_tree_view_append_column(*view, column);
|
||||
|
||||
smodel = gtk_tree_model_sort_new_with_model(model);
|
||||
gtk_tree_view_column_set_sort_column_id(column, 0);
|
||||
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(smodel), 0,
|
||||
GTK_SORT_DESCENDING);
|
||||
|
||||
gtk_tree_view_set_model(*view, GTK_TREE_MODEL(smodel));
|
||||
|
||||
/* Fill it in */
|
||||
path = g_strdup_printf("%s/logs/", gm_world_path(world));
|
||||
dir = g_dir_open(path, 0, &err);
|
||||
|
||||
if (dir) {
|
||||
while ((fname = g_dir_read_name(dir)) != NULL) {
|
||||
res++;
|
||||
tmp = g_strconcat(path, fname, NULL);
|
||||
f = fopen(tmp, "r");
|
||||
|
||||
if (f) {
|
||||
fseek(f, 0, SEEK_END);
|
||||
fsize = ftell(f);
|
||||
fclose(f);
|
||||
g_free(tmp);
|
||||
|
||||
tmp = gnome_vfs_format_file_size_for_display(fsize);
|
||||
tmp2 = g_strconcat(fname, " (", tmp, ")", NULL);
|
||||
|
||||
gtk_list_store_prepend(GTK_LIST_STORE(model), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, fname, 1,
|
||||
tmp2, -1);
|
||||
g_free(tmp2);
|
||||
}
|
||||
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
g_dir_close(dir);
|
||||
|
||||
if (res != 0) {
|
||||
gtk_tree_model_get_iter_first(smodel, &iter);
|
||||
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(*view), &iter);
|
||||
glade_xml_signal_connect_data(xml, "on_tvwLogs_row_activated",
|
||||
G_CALLBACK(on_gm_world_logs_dialog_row_activated), dlg);
|
||||
|
||||
*progress = GTK_PROGRESS_BAR(glade_xml_get_widget(xml,
|
||||
"progressBarLoading"));
|
||||
} else {
|
||||
gm_info_dialog(_("There are no log files for this world"), NULL);
|
||||
gtk_widget_destroy(GTK_WIDGET(dlg));
|
||||
dlg = NULL;
|
||||
}
|
||||
} else {
|
||||
tmp = g_strdup_printf(_("Couldn't open the log directory: %s"), err->message);
|
||||
gm_error_dialog(tmp, NULL);
|
||||
g_error_free(err);
|
||||
g_free(tmp);
|
||||
gtk_widget_destroy(GTK_WIDGET(dlg));
|
||||
dlg = NULL;
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
g_object_unref(xml);
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
void
|
||||
on_gm_world_logs_dialog_row_activated(GtkTreeView *treeview, GtkTreePath *arg1,
|
||||
GtkTreeViewColumn *arg2, GtkDialog *dlg) {
|
||||
gtk_dialog_response(dlg, GTK_RESPONSE_OK);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef __GM_WORLD_LOGS_DIALOG_H__
|
||||
#define __GM_WORLD_LOGS_DIALOG_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "../gm-world.h"
|
||||
|
||||
GtkDialog *gm_world_logs_dialog_new(GmWorld *world, GtkTreeView **view,
|
||||
GtkProgressBar **progress);
|
||||
|
||||
#endif /* __GM_WORLD_LOGS_DIALOG_H__ */
|
|
@ -1,675 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gm-world-properties-dialog.h"
|
||||
#include "gm-triggers-dialog.h"
|
||||
#include "../gm-triggers.h"
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-app.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-options.h"
|
||||
#include "../gm-pixbuf.h"
|
||||
|
||||
typedef struct _GmWorldPropertiesDialog {
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *combo_box_charset;
|
||||
GtkWidget *tree_view_triggers;
|
||||
|
||||
GladeXML *xml;
|
||||
GmWorld *world;
|
||||
gboolean is_new;
|
||||
|
||||
gulong handler_id;
|
||||
} GmWorldPropertiesDialog;
|
||||
|
||||
static const encoding encodings[] = {
|
||||
{"ISO-8859-1", N_("Western")},
|
||||
{"ISO-8859-2", N_("Central European")},
|
||||
{"ISO-8859-3", N_("South European")},
|
||||
{"ISO-8859-4", N_("Baltic")},
|
||||
{"ISO-8859-5", N_("Cyrillic")},
|
||||
{"ISO-8859-6", N_("Arabic")},
|
||||
{"ISO-8859-7", N_("Greek")},
|
||||
{"ISO-8859-8", N_("Hebrew Visual")},
|
||||
{"ISO-8859-8-I", N_("Hebrew")},
|
||||
{"ISO-8859-9", N_("Turkish")},
|
||||
{"ISO-8859-10", N_("Nordic")},
|
||||
{"ISO-8859-13", N_("Baltic")},
|
||||
{"ISO-8859-14", N_("Celtic")},
|
||||
{"ISO-8859-15", N_("Western")},
|
||||
{"ISO-8859-16", N_("Romanian")},
|
||||
{"UTF-7", N_("Unicode")},
|
||||
{"UTF-8", N_("Unicode")},
|
||||
{"UTF-16", N_("Unicode")},
|
||||
{"UCS-2", N_("Unicode")},
|
||||
{"UCS-4", N_("Unicode")},
|
||||
{"ARMSCII-8", N_("Armenian")},
|
||||
{"BIG5", N_("Chinese Traditional")},
|
||||
{"BIG5-HKSCS", N_("Chinese Traditional")},
|
||||
{"CP866", N_("Cyrillic/Russian")},
|
||||
|
||||
{"EUC-JP", N_("Japanese")},
|
||||
{"EUC-KR", N_("Korean")},
|
||||
{"EUC-TW", N_("Chinese Traditional")},
|
||||
{"GB18030", N_("Chinese Simplified")},
|
||||
{"GB2312", N_("Chinese Simplified")},
|
||||
{"GBK", N_("Chinese Simplified")},
|
||||
{"GEORGIAN-ACADEMY", N_("Georgian")},
|
||||
{"HZ", N_("Chinese Simplified")},
|
||||
|
||||
{"IBM850", N_("Western")},
|
||||
{"IBM852", N_("Central European")},
|
||||
{"IBM855", N_("Cyrillic")},
|
||||
{"IBM857", N_("Turkish")},
|
||||
{"IBM862", N_("Hebrew")},
|
||||
{"IBM864", N_("Arabic")},
|
||||
|
||||
{"ISO-2022-JP", N_("Japanese")},
|
||||
{"ISO-2022-KR", N_("Korean")},
|
||||
{"ISO-IR-111", N_("Cyrillic")},
|
||||
{"JOHAB", N_("Korean")},
|
||||
{"KOI8R", N_("Cyrillic")},
|
||||
{"KOI8-R", N_("Cyrillic")},
|
||||
{"KOI8U", N_("Cyrillic/Ukrainian")},
|
||||
|
||||
{"SHIFT_JIS", N_("Japanese")},
|
||||
{"TCVN", N_("Vietnamese")},
|
||||
{"TIS-620", N_("Thai")},
|
||||
{"UHC", N_("Korean")},
|
||||
{"VISCII", N_("Vietnamese")},
|
||||
|
||||
{"WINDOWS-1250", N_("Central European")},
|
||||
{"WINDOWS-1251", N_("Cyrillic")},
|
||||
{"WINDOWS-1252", N_("Western")},
|
||||
{"WINDOWS-1253", N_("Greek")},
|
||||
{"WINDOWS-1254", N_("Turkish")},
|
||||
{"WINDOWS-1255", N_("Hebrew")},
|
||||
{"WINDOWS-1256", N_("Arabic")},
|
||||
{"WINDOWS-1257", N_("Baltic")},
|
||||
{"WINDOWS-1258", N_("Vietnamese")}
|
||||
};
|
||||
|
||||
static GList *gm_world_properties_dialog_open = NULL;
|
||||
|
||||
void gm_world_properties_dialog_run_dialog(GmWorldPropertiesDialog *properties);
|
||||
|
||||
void on_button_add_trigger_clicked(GtkButton *button,
|
||||
GmWorldPropertiesDialog *properties);
|
||||
void on_button_edit_trigger_clicked(GtkButton *button,
|
||||
GmWorldPropertiesDialog *properties);
|
||||
void on_button_delete_trigger_clicked(GtkButton *button,
|
||||
GmWorldPropertiesDialog *properties);
|
||||
void on_tree_view_triggers_row_activated(GtkTreeView *treeview,
|
||||
GtkTreePath *arg1, GtkTreeViewColumn *arg2,
|
||||
GmWorldPropertiesDialog *properties);
|
||||
void on_gm_world_properties_dialog_app_world_removed(GmApp *app, GmWorld *world,
|
||||
GmWorldPropertiesDialog *properties);
|
||||
|
||||
void on_gm_world_properties_dialog_response(GtkDialog *dialog, gint response,
|
||||
GmWorldPropertiesDialog *properties);
|
||||
|
||||
GtkWidget *
|
||||
gm_world_properties_dialog_widget(GmWorldPropertiesDialog *properties,
|
||||
gchar *name) {
|
||||
return glade_xml_get_widget(properties->xml, name);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_populate_charsets(
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
int i;
|
||||
const gchar *select = gm_options_get(gm_world_options(properties->world),
|
||||
"charset");
|
||||
gchar text[255];
|
||||
GtkListStore *store;
|
||||
GtkComboBoxEntry *combo = GTK_COMBO_BOX_ENTRY(properties->combo_box_charset);
|
||||
store = gtk_list_store_new(1, G_TYPE_STRING);
|
||||
gtk_combo_box_set_model(GTK_COMBO_BOX(combo), GTK_TREE_MODEL(store));
|
||||
gtk_combo_box_entry_set_text_column(combo, 0);
|
||||
|
||||
for (i = 0; i < (int)(sizeof(encodings) / sizeof(encoding)); i++) {
|
||||
sprintf(text, "%s - %s", encodings[i].charset, _(encodings[i].name));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), text);
|
||||
|
||||
if (strcasecmp(encodings[i].charset, select) == 0) {
|
||||
gtk_entry_set_text(GTK_ENTRY(GTK_BIN(combo)->child), text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_remove_trigger(GmWorldPropertiesDialog *properties,
|
||||
GtkTreeIter *iter) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(tree_view));
|
||||
|
||||
gtk_list_store_remove(store, iter);
|
||||
|
||||
if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL) == 0) {
|
||||
gtk_widget_set_sensitive(gm_world_properties_dialog_widget(properties,
|
||||
"button_edit_trigger"), FALSE);
|
||||
gtk_widget_set_sensitive(gm_world_properties_dialog_widget(properties,
|
||||
"button_delete_trigger"), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_update_trigger(GmWorldPropertiesDialog *properties,
|
||||
GtkTreeIter *iter, GmTrigger *t) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(tree_view));
|
||||
gchar *text;
|
||||
|
||||
text = g_strdup_printf(_("<b>%s</b>\nConditions: %d\nActions: %d"),
|
||||
t->name, g_list_length(t->conditions), g_list_length(t->actions));
|
||||
gtk_list_store_set(store, iter, 1, text, 2, t, -1);
|
||||
|
||||
switch (t->event) {
|
||||
case TT_OUTPUT:
|
||||
gtk_list_store_set(store, iter, 0,
|
||||
gm_pixbuf_get_at_size("world.svg", 32, 32), -1);
|
||||
break;
|
||||
case TT_USERS:
|
||||
gtk_list_store_set(store, iter, 0,
|
||||
gm_pixbuf_get_at_size("ice-userlist/programmer.svg", 32,
|
||||
32), -1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(text);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_add_trigger(GmWorldPropertiesDialog *properties,
|
||||
GmTrigger *t) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(tree_view));
|
||||
GtkTreeIter iter;
|
||||
|
||||
gtk_list_store_append(store, &iter);
|
||||
gm_world_properties_dialog_update_trigger(properties, &iter, t);
|
||||
|
||||
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(tree_view),
|
||||
&iter);
|
||||
|
||||
gtk_widget_set_sensitive(gm_world_properties_dialog_widget(properties,
|
||||
"button_edit_trigger"), TRUE);
|
||||
gtk_widget_set_sensitive(gm_world_properties_dialog_widget(properties,
|
||||
"button_delete_trigger"), TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_populate_tree_view_triggers(
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkListStore *store = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING,
|
||||
G_TYPE_POINTER);
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
const GList *item;
|
||||
GmTrigger *t;
|
||||
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(store));
|
||||
|
||||
renderer = gtk_cell_renderer_pixbuf_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "pixbuf",
|
||||
0, NULL);
|
||||
gtk_tree_view_column_set_min_width(column, 40);
|
||||
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "markup",
|
||||
1, NULL);
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
|
||||
for (item = gm_triggers_list(gm_world_triggers(properties->world)); item;
|
||||
item = item->next) {
|
||||
t = gm_trigger_dup((GmTrigger *)(item->data));
|
||||
gm_world_properties_dialog_add_trigger(properties, t);
|
||||
}
|
||||
|
||||
if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL) == 0) {
|
||||
gtk_widget_set_sensitive(gm_world_properties_dialog_widget(properties,
|
||||
"button_edit_trigger"), FALSE);
|
||||
gtk_widget_set_sensitive(gm_world_properties_dialog_widget(properties,
|
||||
"button_delete_trigger"), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
GmWorldPropertiesDialog *
|
||||
gm_world_properties_dialog_find(GmWorld *world) {
|
||||
GmWorldPropertiesDialog *result = NULL;
|
||||
GList *item;
|
||||
|
||||
for (item = gm_world_properties_dialog_open; item; item = item->next) {
|
||||
result = (GmWorldPropertiesDialog *)(item->data);
|
||||
|
||||
if (result->world == world) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_initialize(GmWorldPropertiesDialog *properties) {
|
||||
GmOptions *options = gm_world_options(properties->world);
|
||||
const gchar *logo;
|
||||
|
||||
gtk_entry_set_text(GTK_ENTRY(gm_world_properties_dialog_widget(properties,
|
||||
"entry_name")), gm_options_get(options, "name"));
|
||||
gtk_entry_set_text(GTK_ENTRY(gm_world_properties_dialog_widget(properties,
|
||||
"entry_host")), gm_options_get(options, "host"));
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(gm_world_properties_dialog_widget(
|
||||
properties, "spin_button_port")), (double)(gm_options_get_int(
|
||||
options, "port")));
|
||||
gtk_entry_set_text(GTK_ENTRY(gm_world_properties_dialog_widget(properties,
|
||||
"entry_player_name")), gm_options_get(options, "player_name"));
|
||||
gtk_entry_set_text(GTK_ENTRY(gm_world_properties_dialog_widget(properties,
|
||||
"entry_password")), gm_options_get(options, "password"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_world_properties_dialog_widget(properties,
|
||||
"check_button_auto_reconnect")),
|
||||
gm_options_get_int(options, "reconnect"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
||||
gm_world_properties_dialog_widget(properties,
|
||||
"check_button_auto_load")),
|
||||
gm_options_get_int(options, "autoload"));
|
||||
|
||||
gm_world_properties_dialog_populate_charsets(properties);
|
||||
gm_world_properties_dialog_populate_tree_view_triggers(properties);
|
||||
|
||||
glade_xml_signal_connect_data(properties->xml,
|
||||
"on_button_add_trigger_clicked",
|
||||
G_CALLBACK(on_button_add_trigger_clicked), properties);
|
||||
glade_xml_signal_connect_data(properties->xml,
|
||||
"on_button_edit_trigger_clicked",
|
||||
G_CALLBACK(on_button_edit_trigger_clicked), properties);
|
||||
glade_xml_signal_connect_data(properties->xml,
|
||||
"on_button_delete_trigger_clicked",
|
||||
G_CALLBACK(on_button_delete_trigger_clicked), properties);
|
||||
glade_xml_signal_connect_data(properties->xml,
|
||||
"on_tree_view_triggers_row_activated",
|
||||
G_CALLBACK(on_tree_view_triggers_row_activated), properties);
|
||||
|
||||
logo = gm_options_get(options, "logo");
|
||||
|
||||
if (logo != NULL) {
|
||||
gtk_window_set_icon(GTK_WINDOW(properties->dialog),
|
||||
gm_pixbuf_get(logo));
|
||||
} else {
|
||||
gtk_window_set_icon(GTK_WINDOW(properties->dialog),
|
||||
gm_pixbuf_get("world.svg"));
|
||||
}
|
||||
}
|
||||
|
||||
#define G_WORLD_PROPERTIES_DIALOG_XML PACKAGE_DATA_DIR "/" PACKAGE \
|
||||
"/ui/gm-world-properties.glade"
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_run_priv(GmWorld *world, gboolean is_new) {
|
||||
GmWorldPropertiesDialog *properties =
|
||||
gm_world_properties_dialog_find(world);
|
||||
gchar *title;
|
||||
|
||||
if (properties) {
|
||||
gtk_widget_show(properties->dialog);
|
||||
gtk_window_present(GTK_WINDOW(properties->dialog));
|
||||
return;
|
||||
}
|
||||
|
||||
properties = g_new0(GmWorldPropertiesDialog, 1);
|
||||
gm_world_properties_dialog_open = g_list_append(
|
||||
gm_world_properties_dialog_open, properties);
|
||||
|
||||
properties->is_new = is_new;
|
||||
properties->world = world;
|
||||
properties->xml = glade_xml_new(G_WORLD_PROPERTIES_DIALOG_XML,
|
||||
"gm_world_properties_dialog", NULL);
|
||||
|
||||
title = g_strconcat(_("World properties - "), gm_world_name(world), NULL);
|
||||
properties->dialog = gm_world_properties_dialog_widget(properties,
|
||||
"gm_world_properties_dialog");
|
||||
properties->tree_view_triggers = gm_world_properties_dialog_widget(
|
||||
properties, "tree_view_triggers");
|
||||
properties->combo_box_charset = gm_world_properties_dialog_widget(
|
||||
properties, "combo_box_charset");
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(properties->dialog), title);
|
||||
g_free(title);
|
||||
|
||||
gm_world_properties_dialog_initialize(properties);
|
||||
|
||||
if (!properties->is_new) {
|
||||
// Connect signal so we can close the dialog when a world gets removed
|
||||
properties->handler_id = g_signal_connect(gm_app_instance(),
|
||||
"world_removed",
|
||||
G_CALLBACK(on_gm_world_properties_dialog_app_world_removed),
|
||||
properties);
|
||||
} else {
|
||||
properties->handler_id = 0;
|
||||
}
|
||||
|
||||
gm_world_properties_dialog_run_dialog(properties);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_run(GmWorld *world) {
|
||||
gm_world_properties_dialog_run_priv(world, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_run_new(GmWorld *world) {
|
||||
if (!world) {
|
||||
world = gm_world_new(NULL);
|
||||
}
|
||||
|
||||
gm_world_properties_dialog_run_priv(world, TRUE);
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_world_properties_dialog_get_charset(gchar *charset) {
|
||||
gchar *ch;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(encodings) / sizeof(encoding)); i++) {
|
||||
ch = g_strconcat(encodings[i].charset, " - ", _(encodings[i].name),
|
||||
NULL);
|
||||
|
||||
if (g_strcasecmp(charset, ch) == 0) {
|
||||
g_free(ch);
|
||||
return g_strdup(encodings[i].charset);
|
||||
}
|
||||
|
||||
g_free(ch);
|
||||
}
|
||||
|
||||
return g_strdup(charset);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_free_triggers(GmWorldPropertiesDialog *properties) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkTreeModel *store = gtk_tree_view_get_model(tree_view);
|
||||
GtkTreeIter iter;
|
||||
GmTrigger *t;
|
||||
|
||||
if (gtk_tree_model_get_iter_first(store, &iter)) {
|
||||
do {
|
||||
gtk_tree_model_get(store, &iter, 2, &t, -1);
|
||||
gm_trigger_free(t);
|
||||
} while (gtk_tree_model_iter_next(store, &iter));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_set_triggers(GmWorldPropertiesDialog *properties) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkTreeModel *store = gtk_tree_view_get_model(tree_view);
|
||||
GtkTreeIter iter;
|
||||
GmTrigger *t;
|
||||
GmTriggers *triggers = gm_world_triggers(properties->world);
|
||||
|
||||
gm_triggers_clear(triggers);
|
||||
|
||||
if (gtk_tree_model_get_iter_first(store, &iter)) {
|
||||
do {
|
||||
gtk_tree_model_get(store, &iter, 2, &t, -1);
|
||||
gm_triggers_add(triggers, t);
|
||||
} while (gtk_tree_model_iter_next(store, &iter));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_properties_dialog_check_values(GmWorldPropertiesDialog *properties) {
|
||||
GmWorld *same_world;
|
||||
GmOptions *options = gm_world_options(properties->world);
|
||||
GtkWidget *dialog;
|
||||
GtkEntry *entry_name = GTK_ENTRY(gm_world_properties_dialog_widget(
|
||||
properties, "entry_name"));
|
||||
gchar *name = g_strdup(gtk_entry_get_text(entry_name));
|
||||
GtkEntry *entry_host = GTK_ENTRY(gm_world_properties_dialog_widget(
|
||||
properties, "entry_host"));
|
||||
gchar *host = g_strdup(gtk_entry_get_text(entry_host));
|
||||
|
||||
g_strstrip(name);
|
||||
g_strstrip(host);
|
||||
|
||||
same_world = gm_app_world_by_name(gm_app_instance(), name);
|
||||
|
||||
if (strlen(name) == 0) {
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(properties->dialog),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
"Name can not be empty, please fill in a name.");
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
gtk_notebook_set_current_page(GTK_NOTEBOOK(
|
||||
gm_world_properties_dialog_widget(properties,
|
||||
"notebook_main")), 0);
|
||||
gtk_widget_grab_focus(GTK_WIDGET(entry_name));
|
||||
g_free(name);
|
||||
g_free(host);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (same_world && same_world != properties->world) {
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(properties->dialog),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
_("Name can not be %s because a world with that name "
|
||||
"already exists."),
|
||||
name);
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
gtk_notebook_set_current_page(GTK_NOTEBOOK(
|
||||
gm_world_properties_dialog_widget(properties,
|
||||
"notebook_main")), 0);
|
||||
gtk_widget_grab_focus(GTK_WIDGET(entry_name));
|
||||
g_free(name);
|
||||
g_free(host);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (strlen(host) == 0) {
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(properties->dialog),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
_("Host can not be empty, please fill in a host."));
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
gtk_notebook_set_current_page(GTK_NOTEBOOK(
|
||||
gm_world_properties_dialog_widget(properties,
|
||||
"notebook_main")), 0);
|
||||
gtk_widget_grab_focus(GTK_WIDGET(entry_host));
|
||||
g_free(name);
|
||||
g_free(host);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gm_world_properties_dialog_set_triggers(properties);
|
||||
|
||||
gm_options_set(options, "host", host);
|
||||
gm_options_set_int(options, "port", gtk_spin_button_get_value_as_int(
|
||||
GTK_SPIN_BUTTON(gm_world_properties_dialog_widget(properties,
|
||||
"spin_button_port"))));
|
||||
|
||||
gm_options_set_int(options, "reconnect", gtk_toggle_button_get_active(
|
||||
GTK_TOGGLE_BUTTON(gm_world_properties_dialog_widget(properties,
|
||||
"check_button_auto_reconnect"))));
|
||||
gm_options_set_int(options, "autoload", gtk_toggle_button_get_active(
|
||||
GTK_TOGGLE_BUTTON(gm_world_properties_dialog_widget(properties,
|
||||
"check_button_auto_load"))));
|
||||
|
||||
gm_options_set(options, "player_name", (gchar *)gtk_entry_get_text(
|
||||
GTK_ENTRY(gm_world_properties_dialog_widget(properties,
|
||||
"entry_player_name"))));
|
||||
gm_options_set(options, "password", (gchar *)gtk_entry_get_text(
|
||||
GTK_ENTRY(gm_world_properties_dialog_widget(properties,
|
||||
"entry_password"))));
|
||||
gm_options_set(options, "charset", gm_world_properties_dialog_get_charset(
|
||||
(gchar *)gtk_entry_get_text(GTK_ENTRY(GTK_BIN(
|
||||
properties->combo_box_charset)->child))));
|
||||
|
||||
// Only change the name when it has actually changed, when the name
|
||||
// changes the options and triggers are automatically saved to the new
|
||||
// world location
|
||||
if (gm_options_get(options, "name") == NULL ||
|
||||
strcmp(name, gm_options_get(options, "name")) != 0) {
|
||||
gm_options_set(options, "name", name);
|
||||
} else {
|
||||
// Now we need to save the options and triggers ourselfs
|
||||
gm_options_save(options);
|
||||
gm_triggers_save(gm_world_triggers(properties->world));
|
||||
}
|
||||
|
||||
g_free(name);
|
||||
g_free(host);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_properties_dialog_run_dialog(GmWorldPropertiesDialog *properties) {
|
||||
g_signal_connect(properties->dialog, "response",
|
||||
G_CALLBACK(on_gm_world_properties_dialog_response), properties);
|
||||
|
||||
gtk_widget_show(GTK_WIDGET(properties->dialog));
|
||||
}
|
||||
|
||||
/* CALLBACKS */
|
||||
|
||||
void
|
||||
on_gm_world_properties_dialog_response(GtkDialog *dialog, gint response,
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
gboolean is_okay = TRUE;
|
||||
|
||||
switch (response) {
|
||||
case GTK_RESPONSE_OK:
|
||||
is_okay = gm_world_properties_dialog_check_values(properties);
|
||||
break;
|
||||
default:
|
||||
gm_world_properties_dialog_free_triggers(properties);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_okay) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (properties->is_new) {
|
||||
if (response == GTK_RESPONSE_OK) {
|
||||
gm_app_add_world(gm_app_instance(), properties->world);
|
||||
} else {
|
||||
g_object_unref(properties->world);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy(properties->dialog);
|
||||
|
||||
if (properties->handler_id > 0) {
|
||||
g_signal_handler_disconnect(gm_app_instance(), properties->handler_id);
|
||||
}
|
||||
|
||||
g_object_unref(properties->xml);
|
||||
gm_world_properties_dialog_open = g_list_remove(
|
||||
gm_world_properties_dialog_open, properties);
|
||||
|
||||
g_free(properties);
|
||||
}
|
||||
|
||||
void
|
||||
on_button_add_trigger_clicked(GtkButton *button,
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
GmTrigger *trigger = gm_triggers_dialog_run_new(properties->world, NULL);
|
||||
|
||||
if (trigger != NULL) {
|
||||
gm_world_properties_dialog_add_trigger(properties, trigger);
|
||||
}
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_world_properties_dialog_selected_trigger(GmWorldPropertiesDialog *properties,
|
||||
GtkTreeIter *iter) {
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW(properties->tree_view_triggers);
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
|
||||
GmTrigger *result = NULL;
|
||||
|
||||
if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree_view),
|
||||
&model, iter)) {
|
||||
gtk_tree_model_get(model, iter, 2, &result, -1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
on_button_edit_trigger_clicked(GtkButton *button,
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
GtkTreeIter iter;
|
||||
GmTrigger *trigger, *newt;
|
||||
|
||||
trigger = gm_world_properties_dialog_selected_trigger(properties, &iter);
|
||||
|
||||
if (trigger) {
|
||||
newt = gm_triggers_dialog_run(properties->world, trigger);
|
||||
|
||||
if (newt) {
|
||||
gm_world_properties_dialog_update_trigger(properties, &iter,
|
||||
trigger);
|
||||
}
|
||||
} else {
|
||||
gm_error_dialog(_("Select a trigger to edit first"),
|
||||
GTK_WINDOW(properties->dialog));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_button_delete_trigger_clicked(GtkButton *button,
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
GtkTreeIter iter;
|
||||
GmTrigger *trigger;
|
||||
|
||||
trigger = gm_world_properties_dialog_selected_trigger(properties, &iter);
|
||||
|
||||
if (trigger) {
|
||||
gm_world_properties_dialog_remove_trigger(properties, &iter);
|
||||
gm_trigger_free(trigger);
|
||||
} else {
|
||||
gm_error_dialog(_("First select a trigger to remove"),
|
||||
GTK_WINDOW(properties->dialog));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_tree_view_triggers_row_activated(GtkTreeView *treeview, GtkTreePath *arg1,
|
||||
GtkTreeViewColumn *arg2, GmWorldPropertiesDialog *properties) {
|
||||
on_button_edit_trigger_clicked(NULL, properties);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_properties_dialog_app_world_removed(GmApp *app, GmWorld *world,
|
||||
GmWorldPropertiesDialog *properties) {
|
||||
if (properties->world == world) {
|
||||
gtk_dialog_response(GTK_DIALOG(properties->dialog), GTK_RESPONSE_CLOSE);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef __GM_WORLD_PROPERTIES_DIALOG__
|
||||
#define __GM_WORLD_PROPERTIES_DIALOG__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glade/glade.h>
|
||||
|
||||
#include "../gm-world.h"
|
||||
|
||||
typedef struct _encoding {
|
||||
const gchar *charset;
|
||||
const gchar *name;
|
||||
} encoding;
|
||||
|
||||
void gm_world_properties_dialog_run(GmWorld *world);
|
||||
void gm_world_properties_dialog_run_new(GmWorld *world);
|
||||
|
||||
#endif /* __GM_WORLD_PROPERTIES_DIALOG__ */
|
|
@ -1,466 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgnomeui/libgnomeui.h>
|
||||
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-app.h"
|
||||
#include "gm-worlds-list-dialog.h"
|
||||
#include "gm-world-properties-dialog.h"
|
||||
#include "../gm-pixbuf.h"
|
||||
|
||||
typedef struct _GmWorldsListDialog {
|
||||
GladeXML *xml;
|
||||
GtkWidget *dialog;
|
||||
GtkTreeView *tree_view_worlds;
|
||||
GtkTreeModel *model_worlds;
|
||||
} GmWorldsListDialog;
|
||||
|
||||
void on_gm_worlds_list_dialog_button_delete_clicked(GtkButton * utton,
|
||||
gpointer user_data);
|
||||
void on_gm_worlds_list_dialog_button_new_clicked(GtkButton *button,
|
||||
gpointer user_data);
|
||||
void on_gm_worlds_list_dialog_button_modify_clicked(GtkButton *button,
|
||||
gpointer user_data);
|
||||
void on_gm_worlds_list_dialog_button_duplicate_clicked(GtkButton *button,
|
||||
gpointer user_data);
|
||||
void on_gm_worlds_list_dialog_button_connect_clicked(GtkButton *button,
|
||||
gpointer user_data);
|
||||
|
||||
void on_gm_worlds_list_dialog_tree_view_worlds_key_press(GtkWidget *widget,
|
||||
GdkEventKey *event, gpointer user_data);
|
||||
|
||||
void on_gm_worlds_list_dialog_app_world_added(GmApp *app, GmWorld *world,
|
||||
gpointer user_data);
|
||||
void on_gm_worlds_list_dialog_app_world_removed(GmApp *app, GmWorld *world,
|
||||
gpointer user_data);
|
||||
void on_gm_worlds_list_dialog_world_option_changed(GmOptions *options,
|
||||
const gchar *key, GmWorld *world);
|
||||
void on_gm_worlds_list_dialog_response(GtkDialog *dialog, gint response,
|
||||
gpointer user_data);
|
||||
|
||||
static GmWorldsListDialog *gm_worlds_list_dialog_instance;
|
||||
|
||||
enum {
|
||||
LOGO_COLUMN,
|
||||
NAME_COLUMN,
|
||||
WORLD_COLUMN,
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
GtkWidget *
|
||||
gm_worlds_list_dialog_widget(gchar *name) {
|
||||
return glade_xml_get_widget(gm_worlds_list_dialog_instance->xml, name);
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_worlds_list_dialog_world_text(GmWorld *world) {
|
||||
gchar *text;
|
||||
const gchar *player, *server;
|
||||
GmOptions *options = gm_world_options(world);
|
||||
|
||||
player = gm_options_get(options, "player_name");
|
||||
server = gm_options_get(options, "host");
|
||||
|
||||
text = g_strconcat("<b>", gm_options_get(options, "name"),
|
||||
_("</b>\nServer: "),
|
||||
((server && server[0] != '\0') ? server : _("<i>unspecified</i>")),
|
||||
_("\nPlayer: "),
|
||||
((player && player[0] != '\0') ? player : _("<i>unspecified</i>")),
|
||||
NULL);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static void
|
||||
gm_worlds_list_dialog_add_world(GmWorld *world) {
|
||||
GtkTreeIter iter;
|
||||
GdkPixbuf *pix_logo = NULL;
|
||||
gchar *name = gm_worlds_list_dialog_world_text(world);
|
||||
const gchar *logo = gm_options_get(gm_world_options(world), "logo");
|
||||
GtkListStore *store = GTK_LIST_STORE(
|
||||
gm_worlds_list_dialog_instance->model_worlds);
|
||||
|
||||
if (logo) {
|
||||
pix_logo = gm_pixbuf_get_at_size(logo, 32, 32);
|
||||
} else {
|
||||
pix_logo = gm_pixbuf_get_at_size("world.svg", 32, 32);
|
||||
}
|
||||
|
||||
gtk_list_store_append(store, &iter);
|
||||
gtk_list_store_set(store, &iter, LOGO_COLUMN, pix_logo, NAME_COLUMN,
|
||||
name, WORLD_COLUMN, world, -1);
|
||||
|
||||
g_signal_connect(gm_world_options(world), "option_changed",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_world_option_changed), world);
|
||||
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
#define G_WORLDS_LISTS_DIALOG_XML PACKAGE_DATA_DIR "/" PACKAGE \
|
||||
"/ui/gm-worlds-list.glade"
|
||||
|
||||
static void
|
||||
gm_worlds_list_dialog_populate_worlds() {
|
||||
GmApp *app = gm_app_instance();
|
||||
GList *worlds = gm_app_worlds(app);
|
||||
GList *item;
|
||||
GmWorld *world;
|
||||
|
||||
for (item = worlds; item; item = item->next) {
|
||||
world = (GmWorld *)(item->data);
|
||||
gm_worlds_list_dialog_add_world(world);
|
||||
}
|
||||
|
||||
g_list_free(worlds);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_worlds_list_dialog_create_tree_view_worlds() {
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreeModel *model;
|
||||
|
||||
model = GTK_TREE_MODEL(gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF,
|
||||
G_TYPE_STRING, G_TYPE_POINTER));
|
||||
tree_view = GTK_TREE_VIEW(gm_worlds_list_dialog_widget("tree_view_worlds"));
|
||||
gtk_tree_view_set_model(tree_view, model);
|
||||
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(tree_view),
|
||||
GTK_SELECTION_MULTIPLE);
|
||||
|
||||
renderer = gtk_cell_renderer_pixbuf_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Logo"), renderer,
|
||||
"pixbuf", LOGO_COLUMN, NULL);
|
||||
gtk_tree_view_column_set_min_width(column, 40);
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
|
||||
"markup", NAME_COLUMN, NULL);
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
|
||||
gm_worlds_list_dialog_instance->tree_view_worlds = tree_view;
|
||||
gm_worlds_list_dialog_instance->model_worlds = model;
|
||||
|
||||
gm_worlds_list_dialog_populate_worlds();
|
||||
}
|
||||
|
||||
void
|
||||
gm_worlds_list_dialog_run() {
|
||||
GladeXML *xml;
|
||||
|
||||
if (gm_worlds_list_dialog_instance) {
|
||||
gtk_widget_show(gm_worlds_list_dialog_instance->dialog);
|
||||
gtk_window_present(GTK_WINDOW(gm_worlds_list_dialog_instance->dialog));
|
||||
return;
|
||||
}
|
||||
|
||||
gm_worlds_list_dialog_instance = g_new0(GmWorldsListDialog, 1);
|
||||
xml = glade_xml_new(G_WORLDS_LISTS_DIALOG_XML, "gm_worlds_list_dialog",
|
||||
NULL);
|
||||
gm_worlds_list_dialog_instance->xml = xml;
|
||||
|
||||
gm_worlds_list_dialog_create_tree_view_worlds();
|
||||
|
||||
glade_xml_signal_connect(xml, "on_button_delete_clicked",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_button_delete_clicked));
|
||||
glade_xml_signal_connect(xml, "on_button_new_clicked",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_button_new_clicked));
|
||||
glade_xml_signal_connect(xml, "on_button_modify_clicked",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_button_modify_clicked));
|
||||
glade_xml_signal_connect(xml, "on_button_duplicate_clicked",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_button_connect_clicked));
|
||||
glade_xml_signal_connect(xml, "on_button_connect_clicked",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_button_connect_clicked));
|
||||
|
||||
glade_xml_signal_connect(xml, "on_tree_view_worlds_key_press",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_tree_view_worlds_key_press));
|
||||
|
||||
gm_worlds_list_dialog_instance->dialog =
|
||||
gm_worlds_list_dialog_widget("gm_worlds_list_dialog");
|
||||
|
||||
g_signal_connect(gm_app_instance(), "world_added",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_app_world_added), NULL);
|
||||
g_signal_connect(gm_app_instance(), "world_removed",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_app_world_removed), NULL);
|
||||
|
||||
gtk_window_set_icon(GTK_WINDOW(gm_worlds_list_dialog_instance->dialog),
|
||||
gm_pixbuf_get("world.svg"));
|
||||
gtk_widget_show(gm_worlds_list_dialog_instance->dialog);
|
||||
|
||||
g_signal_connect(gm_worlds_list_dialog_instance->dialog, "response",
|
||||
G_CALLBACK(on_gm_worlds_list_dialog_response), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_worlds_list_dialog_delete_selected_worlds() {
|
||||
GtkTreeView *tree_view = gm_worlds_list_dialog_instance->tree_view_worlds;
|
||||
GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds;
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
|
||||
GtkTreeIter iter;
|
||||
GList *paths = gtk_tree_selection_get_selected_rows(selection, &model);
|
||||
GList *refs = NULL;
|
||||
GList *node = NULL;
|
||||
gchar *message;
|
||||
gpointer proxy = g_object_newv(G_TYPE_OBJECT, 0, NULL);
|
||||
GmWorld *world;
|
||||
|
||||
for (node = paths; node; node = node->next) {
|
||||
refs = g_list_append(refs,
|
||||
gtk_tree_row_reference_new_proxy(proxy, model, node->data));
|
||||
gtk_tree_path_free(node->data);
|
||||
}
|
||||
|
||||
g_list_free(paths);
|
||||
|
||||
if (refs) {
|
||||
for (node = refs; node; node = node->next) {
|
||||
GtkTreePath *path = gtk_tree_row_reference_get_path(node->data);
|
||||
|
||||
gtk_tree_model_get_iter(model, &iter, path);
|
||||
gtk_tree_model_get(model, &iter, WORLD_COLUMN, &world, -1);
|
||||
|
||||
if (!(world && gm_world_loaded(world))) {
|
||||
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
|
||||
gm_app_remove_world(gm_app_instance(), world);
|
||||
} else {
|
||||
message = g_strdup_printf(_
|
||||
("Can't remove the world %s because it is loaded. "
|
||||
"First close the world and then try again."),
|
||||
gm_world_name(world));
|
||||
gm_error_dialog(message,
|
||||
GTK_WINDOW(gm_worlds_list_dialog_instance->dialog));
|
||||
g_free(message);
|
||||
}
|
||||
|
||||
gtk_tree_row_reference_deleted(proxy, path);
|
||||
gtk_tree_path_free(path);
|
||||
gtk_tree_row_reference_free(node->data);
|
||||
}
|
||||
} else {
|
||||
gm_error_dialog(_("You first need to select a world to delete."),
|
||||
GTK_WINDOW(gm_worlds_list_dialog_instance->dialog));
|
||||
}
|
||||
|
||||
g_list_free(refs);
|
||||
g_object_unref(proxy);
|
||||
}
|
||||
|
||||
void
|
||||
gm_worlds_list_dialog_modify_world() {
|
||||
GtkTreeView *tree_view = gm_worlds_list_dialog_instance->tree_view_worlds;
|
||||
GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds;
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
|
||||
GtkTreeIter iter;
|
||||
GList *first_path = gtk_tree_selection_get_selected_rows(selection, &model);
|
||||
GmWorld *world;
|
||||
|
||||
if (first_path) {
|
||||
gtk_tree_model_get_iter(model, &iter, first_path->data);
|
||||
gtk_tree_model_get(model, &iter, WORLD_COLUMN, &world, -1);
|
||||
|
||||
gm_world_properties_dialog_run(world);
|
||||
} else {
|
||||
gm_error_dialog(_("You first need to select a world to modify."),
|
||||
GTK_WINDOW(gm_worlds_list_dialog_instance->dialog));
|
||||
}
|
||||
|
||||
g_list_free(first_path);
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_worlds_list_dialog_selected_path() {
|
||||
GtkTreeView *tree_view = gm_worlds_list_dialog_instance->tree_view_worlds;
|
||||
GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds;
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
|
||||
|
||||
return gtk_tree_selection_get_selected_rows(selection, &model);
|
||||
}
|
||||
|
||||
GmWorld *
|
||||
gm_worlds_list_dialog_selected_world() {
|
||||
GtkTreeIter iter;
|
||||
GList *first_path = gm_worlds_list_dialog_selected_path();
|
||||
GmWorld *world = NULL;
|
||||
|
||||
if (first_path) {
|
||||
gtk_tree_model_get_iter(gm_worlds_list_dialog_instance->model_worlds,
|
||||
&iter, first_path->data);
|
||||
gtk_tree_model_get(gm_worlds_list_dialog_instance->model_worlds, &iter,
|
||||
WORLD_COLUMN, &world, -1);
|
||||
}
|
||||
|
||||
g_list_free(first_path);
|
||||
return world;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_worlds_list_dialog_find(GmWorld *world, GtkTreeIter *iter) {
|
||||
GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds;
|
||||
GmWorld *list_world;
|
||||
|
||||
if (gtk_tree_model_get_iter_first(model, iter)) {
|
||||
do {
|
||||
gtk_tree_model_get(model, iter, WORLD_COLUMN, &list_world, -1);
|
||||
|
||||
if (world == list_world) {
|
||||
return TRUE;
|
||||
}
|
||||
} while (gtk_tree_model_iter_next(model, iter));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_response(GtkDialog *dialog, gint response,
|
||||
gpointer user_data) {
|
||||
g_object_unref(gm_worlds_list_dialog_instance->xml);
|
||||
gtk_widget_destroy(gm_worlds_list_dialog_instance->dialog);
|
||||
g_free(gm_worlds_list_dialog_instance);
|
||||
gm_worlds_list_dialog_instance = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_button_delete_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
gm_worlds_list_dialog_delete_selected_worlds();
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_tree_view_worlds_key_press(GtkWidget *widget,
|
||||
GdkEventKey *event, gpointer user_data) {
|
||||
switch (event->keyval) {
|
||||
case GDK_D: case GDK_d:
|
||||
gm_worlds_list_dialog_delete_selected_worlds();
|
||||
break;
|
||||
case GDK_O: case GDK_o:
|
||||
break;
|
||||
case GDK_N: case GDK_n:
|
||||
gm_world_properties_dialog_run_new(NULL);
|
||||
break;
|
||||
case GDK_M: case GDK_m:
|
||||
gm_worlds_list_dialog_modify_world();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_button_new_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
gm_world_properties_dialog_run_new(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_button_modify_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
gm_worlds_list_dialog_modify_world();
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_button_duplicate_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
GmWorld *world = gm_worlds_list_dialog_selected_world();
|
||||
GmWorld *new_world;
|
||||
|
||||
if (world) {
|
||||
// now duplicate the world
|
||||
new_world = gm_world_dup(world);
|
||||
|
||||
// Yeah we got some world, now show the props!
|
||||
gm_world_properties_dialog_run_new(new_world);
|
||||
} else {
|
||||
gm_error_dialog(
|
||||
_("You first need to select a world to duplicate."),
|
||||
GTK_WINDOW(gm_worlds_list_dialog_instance->dialog));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_button_connect_clicked(GtkButton *button,
|
||||
gpointer user_data) {
|
||||
GList *first_path = gm_worlds_list_dialog_selected_path();
|
||||
GList *path;
|
||||
GmWorld *world;
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (first_path) {
|
||||
for (path = first_path; path; path = path->next) {
|
||||
gtk_tree_model_get_iter(
|
||||
gm_worlds_list_dialog_instance->model_worlds, &iter,
|
||||
first_path->data);
|
||||
gtk_tree_model_get(gm_worlds_list_dialog_instance->model_worlds,
|
||||
&iter, WORLD_COLUMN, &world, -1);
|
||||
gm_world_load(world);
|
||||
}
|
||||
} else {
|
||||
gm_error_dialog(
|
||||
_("You first need to select a world to connect to."),
|
||||
GTK_WINDOW(gm_worlds_list_dialog_instance->dialog));
|
||||
}
|
||||
|
||||
g_list_free(first_path);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_app_world_added(GmApp *app, GmWorld *world,
|
||||
gpointer user_data) {
|
||||
gm_worlds_list_dialog_add_world(world);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_app_world_removed(GmApp *app, GmWorld *world,
|
||||
gpointer user_data) {
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gm_worlds_list_dialog_find(world, &iter)) {
|
||||
gtk_list_store_remove(GTK_LIST_STORE(
|
||||
gm_worlds_list_dialog_instance->model_worlds), &iter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_worlds_list_dialog_world_option_changed(GmOptions *options,
|
||||
const gchar *key, GmWorld *world) {
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *store =
|
||||
GTK_LIST_STORE(gm_worlds_list_dialog_instance->model_worlds);
|
||||
gchar *text;
|
||||
const gchar *logo;
|
||||
GdkPixbuf *pix_logo;
|
||||
|
||||
if (!gm_worlds_list_dialog_find(world, &iter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(key, "name") == 0 ||
|
||||
strcmp(key, "player_name") == 0 ||
|
||||
strcmp(key, "host") == 0) {
|
||||
text = gm_worlds_list_dialog_world_text(world);
|
||||
gtk_list_store_set(store, &iter, NAME_COLUMN, text, -1);
|
||||
g_free(text);
|
||||
} else if (strcmp(key, "logo")) {
|
||||
logo = gm_options_get(options, "logo");
|
||||
|
||||
if (logo) {
|
||||
pix_logo = gm_pixbuf_get_at_size(logo, 32, 32);
|
||||
} else {
|
||||
pix_logo = gm_pixbuf_get_at_size("world.svg", 32, 32);
|
||||
}
|
||||
|
||||
gtk_list_store_set(store, &iter, LOGO_COLUMN, pix_logo, -1);
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __GM_WORLDS_LIST_DIALOG__
|
||||
#define __GM_WORLDS_LIST_DIALOG__
|
||||
|
||||
void gm_worlds_list_dialog_run();
|
||||
|
||||
#endif /* __GM_WORLDS_LIST_DIALOG */
|
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
def replaceAll(line, subst)
|
||||
subst.each do |sub,rep|
|
||||
line = line.gsub('{' + sub + '}', rep)
|
||||
end
|
||||
|
||||
return line
|
||||
end
|
||||
|
||||
def degenerateCaps(text)
|
||||
text = text.gsub(/[A-Z]+[a-z]+/) do |s|
|
||||
s.downcase + '_'
|
||||
end
|
||||
|
||||
return text[0..-2]
|
||||
end
|
||||
|
||||
subst = {}
|
||||
name = ARGV[0]
|
||||
|
||||
if (name == nil) then
|
||||
print "Class name (capitalized): "
|
||||
name = gets[0..-2]
|
||||
end
|
||||
|
||||
subst['template_'] = degenerateCaps(name)
|
||||
subst['template-'] = subst['template_'].sub('_', '-')
|
||||
subst['TEMPLATE'] = subst['template_'].upcase
|
||||
subst['Template'] = name
|
||||
|
||||
tc = IO.readlines("template.c")
|
||||
th = IO.readlines("template.h")
|
||||
|
||||
f = File.open('gm-' + subst['template-'] + '.c', 'w')
|
||||
tc.each do |line|
|
||||
f.write(replaceAll(line, subst))
|
||||
end
|
||||
f.close
|
||||
|
||||
f = File.open('gm-' + subst['template-'] + '.h', 'w')
|
||||
th.each do |line|
|
||||
f.write(replaceAll(line, subst))
|
||||
end
|
||||
f.close
|
||||
|
||||
print "Done ...\n"
|
|
@ -1,58 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
def replaceAll(line, subst)
|
||||
subst.each do |sub,rep|
|
||||
line = line.gsub('{' + sub + '}', rep)
|
||||
end
|
||||
|
||||
return line
|
||||
end
|
||||
|
||||
def degenerateCaps(text)
|
||||
text = text.gsub(/[A-Z]+[a-z]+/) do |s|
|
||||
s.downcase + '_'
|
||||
end
|
||||
|
||||
return text[0..-2]
|
||||
end
|
||||
|
||||
subst = {}
|
||||
name = ARGV[0]
|
||||
parent = ARGV[1]
|
||||
|
||||
if (name == nil) then
|
||||
print "Class name (capitalized): "
|
||||
name = gets[0..-2]
|
||||
end
|
||||
|
||||
subst['template_'] = degenerateCaps(name)
|
||||
subst['template-'] = subst['template_'].sub('_', '-')
|
||||
subst['TEMPLATE'] = subst['template_'].upcase
|
||||
subst['Template'] = name
|
||||
|
||||
if (parent == nil) then
|
||||
print "Parent name (capitalized): "
|
||||
parent = gets[0..-2]
|
||||
end
|
||||
|
||||
subst['parent_'] = degenerateCaps(parent)
|
||||
subst['parent-'] = subst['parent_'].sub('_', '-')
|
||||
subst['PARENT'] = subst['parent_'].upcase
|
||||
subst['Parent'] = parent
|
||||
|
||||
tc = IO.readlines("gtktemplate.c")
|
||||
th = IO.readlines("gtktemplate.h")
|
||||
|
||||
f = File.open('gm-' + subst['template-'] + '.c', 'w')
|
||||
tc.each do |line|
|
||||
f.write(replaceAll(line, subst))
|
||||
end
|
||||
f.close
|
||||
|
||||
f = File.open('gm-' + subst['template-'] + '.h', 'w')
|
||||
th.each do |line|
|
||||
f.write(replaceAll(line, subst))
|
||||
end
|
||||
f.close
|
||||
|
||||
print "Done ...\n"
|
559
src/gm-app.c
559
src/gm-app.c
|
@ -1,559 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgnome/libgnome.h>
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
#include <libgnomeui/libgnomeui.h>
|
||||
|
||||
#include "widgets/gm-app-view.h"
|
||||
#include "gm-world.h"
|
||||
#include "gm-color-table.h"
|
||||
|
||||
#include "gm-app.h"
|
||||
//#include "editor.h"
|
||||
#include "gm-debug.h"
|
||||
#include "gm-pixbuf.h"
|
||||
#include "gm-support.h"
|
||||
#include "gm-scripts.h"
|
||||
|
||||
static gchar *debug_level = NULL;
|
||||
static gboolean show_version = FALSE;
|
||||
static gboolean recover = FALSE;
|
||||
static gchar *load_worlds = NULL;
|
||||
static GmApp *application;
|
||||
|
||||
//static void gm_app_tray_create(tray_info *t);
|
||||
//gboolean on_gm_app_tray_button_press(GtkWidget *widget, GdkEventButton *event,
|
||||
// gpointer user_data);
|
||||
//gboolean on_gm_app_tray_destroy(GtkWidget *widget, gpointer user_data);
|
||||
void on_gm_app_view_size_allocate(GmAppView *view, GtkAllocation *allocation,
|
||||
GmApp *app);
|
||||
|
||||
struct poptOption poptions[] = {
|
||||
{"debug", 'd', POPT_ARG_STRING, &debug_level, 0, N_("Enable debugging. "
|
||||
"Specify multiple debug levels with a comma seperated list. "
|
||||
"Available levels: default, mcp, all"), N_("DBGGLEVEL")},
|
||||
{"version", 'v', POPT_ARG_NONE, &show_version, 0, N_("Show application "
|
||||
"version"), NULL},
|
||||
{"load", 'l', POPT_ARG_STRING, &load_worlds, 0, N_("Load specified worlds. "
|
||||
"Specify multiple worlds with a comma separated list"),
|
||||
N_("WORLDS")},
|
||||
{"recover", 'r', POPT_ARG_NONE, &recover, 0, N_("Recover from previous "
|
||||
"session (used with gnome session)"), NULL},
|
||||
{NULL, '\0', 0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
#define GM_APP_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_APP, GmAppPrivate))
|
||||
void gm_app_destroy_worlds(GmApp *app);
|
||||
|
||||
struct _GmAppPrivate {
|
||||
gchar *path;
|
||||
gchar *worlds_path;
|
||||
gchar *options_path;
|
||||
|
||||
GmAppView *view;
|
||||
GmOptions *options;
|
||||
GmColorTable *color_table;
|
||||
GnomeClient *client;
|
||||
GList *worlds;
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
GmScripts *scripts;
|
||||
#endif
|
||||
|
||||
//tray_info tray;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
WORLD_ADDED,
|
||||
WORLD_REMOVED,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint app_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmApp, gm_app, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_app_finalize(GObject *object) {
|
||||
GmApp *app = GM_APP(object);
|
||||
|
||||
gnome_vfs_shutdown();
|
||||
//mcp_fini();
|
||||
//editor_fini();
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
g_object_unref(app->priv->scripts);
|
||||
#endif
|
||||
|
||||
//mcpconsole_fini();
|
||||
gm_app_destroy_worlds(app);
|
||||
gm_pixbuf_fini();
|
||||
|
||||
gm_options_save(app->priv->options);
|
||||
g_object_unref(app->priv->options);
|
||||
|
||||
gm_color_table_save(app->priv->color_table);
|
||||
g_object_unref(app->priv->color_table);
|
||||
|
||||
g_free(app->priv->path);
|
||||
g_free(app->priv->worlds_path);
|
||||
g_free(app->priv->options_path);
|
||||
|
||||
G_OBJECT_CLASS(gm_app_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_app_class_init(GmAppClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_app_finalize;
|
||||
|
||||
app_signals[WORLD_ADDED] =
|
||||
g_signal_new("world_added",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmAppClass, world_added),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
|
||||
app_signals[WORLD_REMOVED] =
|
||||
g_signal_new("world_removed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmAppClass, world_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmAppPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_app_init(GmApp *app) {
|
||||
app->priv = GM_APP_GET_PRIVATE(app);
|
||||
|
||||
app->priv->path = NULL;
|
||||
app->priv->worlds_path = NULL;
|
||||
app->priv->options_path = NULL;
|
||||
app->priv->options = NULL;
|
||||
app->priv->client = NULL;
|
||||
app->priv->worlds = NULL;
|
||||
|
||||
//gm_app_tray_create(&(app->priv->tray));
|
||||
}
|
||||
|
||||
/* Private functions */
|
||||
void
|
||||
gm_app_destroy_worlds(GmApp *app) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
on_gm_app_session_die(GnomeClient * client, gpointer client_data) {
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
/*static void
|
||||
gm_app_tray_create(tray_info *t) {
|
||||
t->flash_timeout = 0;
|
||||
t->icon = egg_tray_icon_new(_("GnoeMoe Gnome MOO Client"));
|
||||
t->event_box = gtk_event_box_new();
|
||||
|
||||
t->iconnr = TRAY_ICON_DEFAULT;
|
||||
t->image = gtk_image_new_from_pixbuf(
|
||||
gnoe_pixbuf_get("tray/default.svg"));
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(t->event_box), t->image);
|
||||
t->tooltips = gtk_tooltips_new();
|
||||
|
||||
gtk_widget_show(t->event_box);
|
||||
gtk_widget_show(t->image);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(t->icon), t->event_box);
|
||||
gtk_widget_show(GTK_WIDGET(t->icon));
|
||||
|
||||
gtk_widget_add_events(GTK_WIDGET(t->icon), GDK_BUTTON_PRESS_MASK);
|
||||
|
||||
g_signal_connect(t->icon, "button_press_event",
|
||||
G_CALLBACK(on_gm_app_tray_button_press), NULL);
|
||||
|
||||
// Handles when the area is removed from the panel.
|
||||
g_signal_connect(t->icon, "destroy", G_CALLBACK(on_gm_app_tray_destroy),
|
||||
t->event_box);
|
||||
}*/
|
||||
|
||||
static gboolean
|
||||
on_gm_app_save_session(GnomeClient * client, gint phase,
|
||||
GnomeSaveStyle save_style, gint is_shutdown,
|
||||
GnomeInteractStyle interact_style, gint is_fast, gchar ** client_data) {
|
||||
gchar **argv;
|
||||
gint argc = sizeof(client_data) / sizeof(gchar *) + 1;
|
||||
int i;
|
||||
GString *ws = g_string_new("");
|
||||
GList *elem, *list;
|
||||
GmWorld *world;
|
||||
|
||||
argv = g_new(gchar *, argc);
|
||||
argv[0] = client_data[0];
|
||||
argv[1] = "--recover";
|
||||
|
||||
for (i = 1; i < argc - 1; i++) {
|
||||
argv[i + 1] = client_data[i];
|
||||
}
|
||||
|
||||
gnome_client_set_clone_command(client, argc, argv);
|
||||
gnome_client_set_restart_command(client, argc, argv);
|
||||
|
||||
// Saving worlds state
|
||||
list = gm_app_worlds(application);
|
||||
|
||||
for (elem = list; elem; elem = elem->next) {
|
||||
world = (GmWorld *) (elem->data);
|
||||
|
||||
if (gm_world_loaded(world)) {
|
||||
if (strlen(ws->str) != 0) {
|
||||
ws = g_string_append_c(ws, ';');
|
||||
}
|
||||
|
||||
ws = g_string_append(ws, gm_world_name(world));
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(list);
|
||||
gm_options_set(gm_app_options(application), "worlds_saved_state", ws->str);
|
||||
gm_options_save(gm_app_options(application));
|
||||
g_string_free(ws, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_app_create_settings(GmApp *app) {
|
||||
app->priv->options = gm_options_new();
|
||||
|
||||
gm_options_set(app->priv->options, "editor_alternative", "0");
|
||||
gm_options_set(app->priv->options, "editor_embed", "0");
|
||||
gm_options_set(app->priv->options, "editor_needs_terminal", "0");
|
||||
gm_options_set(app->priv->options, "worlds_saved_state", "");
|
||||
gm_options_set(app->priv->options, "search_direction", "1");
|
||||
}
|
||||
|
||||
void
|
||||
gm_app_load_worlds(GmApp *app, gboolean autoload) {
|
||||
GDir *handle = g_dir_open(app->priv->worlds_path, 0, NULL);
|
||||
char *name, *path;
|
||||
GmWorld *new_world;
|
||||
|
||||
if (handle != NULL) {
|
||||
while ((name = (char *) g_dir_read_name(handle)) != NULL) {
|
||||
path = g_strconcat(app->priv->worlds_path, G_DIR_SEPARATOR_S,
|
||||
name, NULL);
|
||||
|
||||
if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
|
||||
new_world = gm_world_new(path);
|
||||
|
||||
if (new_world != NULL) {
|
||||
gm_app_add_world(app, new_world);
|
||||
|
||||
if (autoload && gm_options_get_int(
|
||||
gm_world_options(new_world), "autoload")) {
|
||||
gm_world_load(new_world);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_ALWAYS, "Nee: %s", path);
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
g_dir_close(handle);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmApp.load_worlds: failed to open worlds path %s",
|
||||
app->priv->path);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_app_initialize(GmApp *app) {
|
||||
gchar *colors_path;
|
||||
|
||||
gm_debug_set_level(debug_level);
|
||||
|
||||
app->priv->worlds_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S,
|
||||
"worlds", NULL);
|
||||
app->priv->options_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S,
|
||||
"settings", NULL);
|
||||
|
||||
if (!g_file_test(app->priv->path, G_FILE_TEST_EXISTS)) {
|
||||
mkdir(app->priv->path, 0755);
|
||||
mkdir(app->priv->worlds_path, 0755);
|
||||
}
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
app->priv->scripts = gm_scripts_new();
|
||||
#endif
|
||||
|
||||
gm_app_create_settings(app);
|
||||
gm_options_load(app->priv->options, app->priv->options_path);
|
||||
|
||||
// Load color table
|
||||
colors_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S, "colors",
|
||||
NULL);
|
||||
app->priv->color_table = gm_color_table_new_from_options(colors_path);
|
||||
g_free(colors_path);
|
||||
}
|
||||
|
||||
void
|
||||
gm_app_run(GmApp *app) {
|
||||
gchar **wrlds;
|
||||
const gchar *savedState;
|
||||
int i = 0;
|
||||
GmWorld *world;
|
||||
int width, height;
|
||||
|
||||
app->priv->view = gm_app_view_new(app);
|
||||
|
||||
width = gm_options_get_int(app->priv->options, "width");
|
||||
height = gm_options_get_int(app->priv->options, "height");
|
||||
|
||||
if (height > 10 && width > 10) {
|
||||
gtk_window_set_default_size(GTK_WINDOW(app->priv->view), width, height);
|
||||
}
|
||||
|
||||
gtk_widget_show(GTK_WIDGET(app->priv->view));
|
||||
|
||||
//mcpconsole_init();
|
||||
|
||||
g_signal_connect(app->priv->view, "size_allocate",
|
||||
G_CALLBACK(on_gm_app_view_size_allocate), app);
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
gm_scripts_load(app->priv->scripts);
|
||||
#endif
|
||||
|
||||
gm_app_load_worlds(app, !(recover || load_worlds));
|
||||
|
||||
if (recover) {
|
||||
savedState = gm_options_get(app->priv->options, "worlds_saved_state");
|
||||
|
||||
if (strlen(savedState) != 0) {
|
||||
wrlds = g_strsplit(savedState, ";", -1);
|
||||
|
||||
for (i = 0; wrlds[i]; i++) {
|
||||
if (strlen(wrlds[i]) != 0) {
|
||||
world = gm_app_world_by_name(app, wrlds[i]);
|
||||
|
||||
if (world) {
|
||||
gm_world_load(world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(wrlds);
|
||||
}
|
||||
} else if (load_worlds) {
|
||||
wrlds = g_strsplit(load_worlds, ",", -1);
|
||||
|
||||
for (i = 0; wrlds[i]; i++) {
|
||||
world = gm_app_world_by_name(app, wrlds[i]);
|
||||
|
||||
if (world) {
|
||||
gm_world_load(world);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(wrlds);
|
||||
}
|
||||
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
GmApp *
|
||||
gm_app_new(int argc, char *argv[]) {
|
||||
GmApp *app = GM_APP(g_object_new(GM_TYPE_APP, NULL));
|
||||
|
||||
app->priv->path = gnome_util_home_file("gnoemoe");
|
||||
|
||||
if (!app->priv->path) {
|
||||
printf(_("GnoeMoe Application: there is no application directory, "
|
||||
"this is very bad!!!\n"));
|
||||
return app;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
|
||||
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain(GETTEXT_PACKAGE);
|
||||
#endif
|
||||
|
||||
gtk_set_locale();
|
||||
gtk_init(&argc, &argv);
|
||||
gnome_program_init(PACKAGE, VERSION, LIBGNOMEUI_MODULE,
|
||||
argc, argv, GNOME_PARAM_POPT_TABLE, poptions,
|
||||
GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR, NULL);
|
||||
|
||||
if (show_version) {
|
||||
printf(_("Current version of GnoeMoe is %s\n"), VERSION);
|
||||
return app;
|
||||
}
|
||||
|
||||
app->priv->client = gnome_master_client();
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(app->priv->client), "save_yourself",
|
||||
GTK_SIGNAL_FUNC(on_gm_app_save_session), argv);
|
||||
gtk_signal_connect(GTK_OBJECT(app->priv->client), "die",
|
||||
GTK_SIGNAL_FUNC(on_gm_app_session_die), NULL);
|
||||
|
||||
/* Initialize everything */
|
||||
gnome_vfs_init();
|
||||
glade_init();
|
||||
//mcp_init();
|
||||
gm_pixbuf_init();
|
||||
gm_app_initialize(app);
|
||||
//editor_init();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void
|
||||
gm_app_add_world(GmApp *app, GmWorld *world) {
|
||||
app->priv->worlds = g_list_append(app->priv->worlds, g_object_ref(world));
|
||||
g_signal_emit(app, app_signals[WORLD_ADDED], 0, world);
|
||||
}
|
||||
|
||||
void
|
||||
gm_app_remove_world(GmApp *app, GmWorld *world) {
|
||||
// Only remove when not loaded
|
||||
const gchar *path = gm_world_path(world);
|
||||
|
||||
if (!gm_world_loaded(world)) {
|
||||
app->priv->worlds = g_list_remove(app->priv->worlds, world);
|
||||
g_signal_emit(app, app_signals[WORLD_REMOVED], 0, world);
|
||||
|
||||
g_object_unref(world);
|
||||
gm_directory_remove_all(path, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
GmWorld *
|
||||
gm_app_world_by_name(GmApp *app, gchar *name) {
|
||||
GList *elem;
|
||||
const gchar *world_name;
|
||||
|
||||
for (elem = app->priv->worlds; elem; elem = elem->next) {
|
||||
world_name = gm_world_name(GM_WORLD(elem->data));
|
||||
|
||||
if (!g_strcasecmp(name, world_name)) {
|
||||
return GM_WORLD(elem->data);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GmOptions *
|
||||
gm_app_options(GmApp *app) {
|
||||
return app->priv->options;
|
||||
}
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
GmScripts *
|
||||
gm_app_scripts(GmApp *app) {
|
||||
return app->priv->scripts;
|
||||
}
|
||||
#endif
|
||||
|
||||
const gchar *
|
||||
gm_app_worlds_path(GmApp *app) {
|
||||
return app->priv->worlds_path;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_app_path(GmApp *app) {
|
||||
return app->priv->path;
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_app_worlds(GmApp *app) {
|
||||
return g_list_copy(app->priv->worlds);
|
||||
}
|
||||
|
||||
GmColorTable *
|
||||
gm_app_color_table(GmApp *app) {
|
||||
return app->priv->color_table;
|
||||
}
|
||||
|
||||
GmApp *
|
||||
gm_app_instance() {
|
||||
return application;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
g_type_init();
|
||||
application = gm_app_new(argc, argv);
|
||||
gm_app_run(application);
|
||||
g_object_unref(application);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
void
|
||||
on_gm_app_view_size_allocate(GmAppView *view, GtkAllocation *allocation,
|
||||
GmApp *app) {
|
||||
gm_options_set_int(app->priv->options, "width", allocation->width);
|
||||
gm_options_set_int(app->priv->options, "height", allocation->height);
|
||||
}
|
||||
|
||||
/*gboolean
|
||||
on_gm_app_tray_button_press(GtkWidget *widget, GdkEventButton *event,
|
||||
gpointer user_data) {
|
||||
if (event->type == GDK_2BUTTON_PRESS ||
|
||||
event->type == GDK_3BUTTON_PRESS) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (event->button) {
|
||||
case 1:
|
||||
if_main_show_hide(!GTK_WIDGET_VISIBLE(wndMain));
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_gm_app_tray_destroy(GtkWidget *widget, gpointer user_data) {
|
||||
gtk_widget_destroy(GTK_WIDGET(app_tray_info.icon));
|
||||
app_tray_info.icon = NULL;
|
||||
app_tray_info.event_box = NULL;
|
||||
app_tray_info.image = NULL;
|
||||
app_tray_info.tooltips = NULL;
|
||||
|
||||
if (app_tray_info.flash_timeout != 0) {
|
||||
g_source_remove(app_tray_info.flash_timeout);
|
||||
}
|
||||
|
||||
tray_create(&app_tray_info);
|
||||
|
||||
if (!have_tray()) {
|
||||
gtk_widget_show(if_main_get_widget("wndMain"));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}*/
|
79
src/gm-app.h
79
src/gm-app.h
|
@ -1,79 +0,0 @@
|
|||
#ifndef __GM_APP_H__
|
||||
#define __GM_APP_H__
|
||||
|
||||
//#define G_XML PACKAGE_DATA_DIR "/" PACKAGE "/ui/gm-main.glade"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gm-world.h"
|
||||
#include "gm-options.h"
|
||||
#include "gm-color-table.h"
|
||||
#include "gm-scripts.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_APP (gm_app_get_type())
|
||||
#define GM_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_APP, GmApp))
|
||||
#define GM_APP_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_APP, GmApp const))
|
||||
#define GM_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_APP, GmAppClass))
|
||||
#define GM_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_APP))
|
||||
#define GM_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_APP))
|
||||
#define GM_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_APP, GmAppClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmAppPrivate GmAppPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmApp GmApp;
|
||||
|
||||
struct _GmApp {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmAppPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmAppClass GmAppClass;
|
||||
|
||||
struct _GmAppClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* world_added) (GmApp *app, GmWorld *world);
|
||||
void (* world_removed) (GmApp *app, GmWorld *world);
|
||||
};
|
||||
|
||||
GmApp *gm_app_instance();
|
||||
GType gm_app_get_type(void) G_GNUC_CONST;
|
||||
GmApp *gm_app_new(int argc, char *argv[]);
|
||||
|
||||
void gm_app_add_world(GmApp *app, GmWorld *world);
|
||||
void gm_app_remove_world(GmApp *app, GmWorld *world);
|
||||
|
||||
const gchar *gm_app_worlds_path(GmApp *app);
|
||||
const gchar *gm_app_path(GmApp *app);
|
||||
GmOptions *gm_app_options(GmApp *app);
|
||||
GList *gm_app_worlds(GmApp *app);
|
||||
GmColorTable *gm_app_color_table(GmApp *app);
|
||||
GmWorld *gm_app_world_by_name(GmApp *app, gchar *name);
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
GmScripts *gm_app_scripts(GmApp *app);
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GM_APP_H__ */
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef __GM_BOGUS_H__
|
||||
#define __GM_BOGUS_H__
|
||||
|
||||
#endif /* __GM_BOGUS_H__ */
|
|
@ -1,359 +0,0 @@
|
|||
#include <glib.h>
|
||||
#include "gm-color-table.h"
|
||||
#include "string.h"
|
||||
#include "ansi.h"
|
||||
#include "gm-debug.h"
|
||||
|
||||
#define GM_COLOR_TABLE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_COLOR_TABLE, GmColorTablePrivate))
|
||||
|
||||
void gm_color_table_item_free(gpointer item);
|
||||
|
||||
typedef struct _GmColorTableItem GmColorTableItem;
|
||||
|
||||
struct _GmColorTableItem {
|
||||
gchar *hex;
|
||||
GdkColor color;
|
||||
};
|
||||
|
||||
typedef struct _GmColorTableSchemeItem {
|
||||
const gchar *name;
|
||||
const gchar *hex;
|
||||
} GmColorTableSchemeItem;
|
||||
|
||||
static const GmColorTableSchemeItem scheme_default[] = {
|
||||
{"fg_default", "#000000"},
|
||||
{"fg_black", "#000000"},
|
||||
{"fg_red", "#663822"},
|
||||
{"fg_green", "#445632"},
|
||||
{"fg_yellow", "#D1940C"},
|
||||
{"fg_blue", "#314E6C"},
|
||||
{"fg_purple", "#494066"},
|
||||
{"fg_cyan", "#0000FFFFFFFF"},
|
||||
{"fg_white", "#BAB5AB"},
|
||||
|
||||
{"fg_default_h", "#565248"},
|
||||
{"fg_black_h", "#565248"},
|
||||
{"fg_red_h", "#990000"},
|
||||
{"fg_green_h", "#267726"},
|
||||
{"fg_yellow_h", "#EED680"},
|
||||
{"fg_blue_h", "#9DB8D2"},
|
||||
{"fg_purple_h", "#ADA7C8"},
|
||||
{"fg_cyan_h", "#86EEFFFFFFFF"},
|
||||
{"fg_white_h", "#807D74"},
|
||||
|
||||
//{"bg_default", "#EAE8E3"},
|
||||
{"bg_default", "#FFFFFF"},
|
||||
{"bg_black", "#000000"},
|
||||
{"bg_red", "#663822"},
|
||||
{"bg_green", "#445632"},
|
||||
{"bg_yellow", "#D1940C"},
|
||||
{"bg_blue", "#314E6C"},
|
||||
{"bg_purple", "#494066"},
|
||||
{"bg_cyan", "#0000FFFFFFFF"},
|
||||
{"bg_white", "#FFFFFFFFFFFF"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const GmColorTableSchemeItem scheme_white_on_black[] = {
|
||||
{"fg_default", "#D6B5D6B5D6B5"},
|
||||
{"fg_black", "#2D6B2D6B2D6B"},
|
||||
{"fg_red", "#FFFF00000000"},
|
||||
{"fg_green", "#0000FFFF0000"},
|
||||
{"fg_yellow", "#FFFFD0450000"},
|
||||
{"fg_blue", "#3EF73EF7BFFF"},
|
||||
{"fg_purple", "#A0A02020F0F0"},
|
||||
{"fg_cyan", "#0000FFFFFFFF"},
|
||||
{"fg_white", "#D8C5D8C5D8C5"},
|
||||
|
||||
{"fg_default_h", "#FFFFFFFFFFFF"},
|
||||
{"fg_black_h", "#529452945294"},
|
||||
{"fg_red_h", "#FFFF785F785F"},
|
||||
{"fg_green_h", "#66ADFFFF66AD"},
|
||||
{"fg_yellow_h", "#FFFFFFFF58C6"},
|
||||
{"fg_blue_h", "#86318631FFFF"},
|
||||
{"fg_purple_h", "#C6576A18FFFF"},
|
||||
{"fg_cyan_h", "#86EEFFFFFFFF"},
|
||||
{"fg_white_h", "#FFFFFFFFFFFF"},
|
||||
|
||||
{"bg_default", "#000000000000"},
|
||||
{"bg_black", "#2B5B2B5B2B5B"},
|
||||
{"bg_red", "#FFFF00000000"},
|
||||
{"bg_green", "#000080000000"},
|
||||
{"bg_yellow", "#C047C0470000"},
|
||||
{"bg_blue", "#00000000FFFF"},
|
||||
{"bg_purple", "#A0A02020F0F0"},
|
||||
{"bg_cyan", "#0000B74CB74C"},
|
||||
{"bg_white", "#FFFFFFFFFFFF"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
typedef struct _GmColorScheme {
|
||||
GmColorTableScheme scheme;
|
||||
const gchar *name;
|
||||
const GmColorTableSchemeItem *values;
|
||||
} GmColorScheme;
|
||||
|
||||
static const GmColorScheme scheme_names[] = {
|
||||
{SCHEME_NONE, "none", NULL},
|
||||
{SCHEME_DEFAULT, "default", scheme_default},
|
||||
{SCHEME_WHITE_ON_BLACK, "white_on_black", scheme_white_on_black},
|
||||
{SCHEME_USER, "user", NULL},
|
||||
{SCHEME_NONE, NULL, NULL}
|
||||
};
|
||||
|
||||
struct _GmColorTablePrivate {
|
||||
GHashTable *colors;
|
||||
gchar *font_description;
|
||||
GmOptions *options;
|
||||
|
||||
GmColorTableScheme scheme;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
COLOR_CHANGED,
|
||||
FONT_CHANGED,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint color_table_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmColorTable, gm_color_table, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_color_table_finalize(GObject *object) {
|
||||
//GmColorTable *table = GM_COLOR_TABLE(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_color_table_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_color_table_class_init(GmColorTableClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_color_table_finalize;
|
||||
|
||||
color_table_signals[COLOR_CHANGED] =
|
||||
g_signal_new("color_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmColorTableClass, color_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
color_table_signals[FONT_CHANGED] =
|
||||
g_signal_new("font_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmColorTableClass, font_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmColorTablePrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_color_table_init(GmColorTable *table) {
|
||||
table->priv = GM_COLOR_TABLE_GET_PRIVATE(table);
|
||||
table->priv->colors = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, gm_color_table_item_free);
|
||||
table->priv->scheme = SCHEME_NONE;
|
||||
}
|
||||
|
||||
/* Private functions */
|
||||
void
|
||||
gm_color_table_item_free(gpointer item) {
|
||||
GmColorTableItem *i = (GmColorTableItem *)(item);
|
||||
|
||||
g_free(i->hex);
|
||||
g_free(i);
|
||||
}
|
||||
|
||||
void
|
||||
gm_color_table_load_scheme(GmColorTable *table,
|
||||
GmColorTableScheme scheme) {
|
||||
int i = 0;
|
||||
const GmColorTableSchemeItem *values = scheme_names[scheme].values;
|
||||
|
||||
while (values[i].name != NULL) {
|
||||
gm_color_table_set(table, values[i].name, values[i].hex);
|
||||
++i;
|
||||
}
|
||||
|
||||
table->priv->scheme = scheme;
|
||||
}
|
||||
|
||||
void
|
||||
gm_color_table_initialize(GmColorTable *table) {
|
||||
gm_color_table_set_font_description(table, "Monospace 10");
|
||||
gm_color_table_load_scheme(table, SCHEME_DEFAULT);
|
||||
}
|
||||
|
||||
void
|
||||
gm_color_table_fill_from_options(GmColorTable *table) {
|
||||
unsigned int i;
|
||||
const gchar *value;
|
||||
GmOptions *options = table->priv->options;
|
||||
|
||||
// New, color schemes
|
||||
value = gm_options_get(options, "color_scheme");
|
||||
|
||||
if (value == NULL || strcmp(value, "user") == 0) {
|
||||
for (i = 0; i < sizeof(ansi_colors) / sizeof(ansinamepair); i++) {
|
||||
value = gm_options_get(options, ansi_colors[i].name);
|
||||
|
||||
if (value != NULL) {
|
||||
gm_color_table_set(table, ansi_colors[i].name, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gm_color_table_set_from_scheme_name(table, value);
|
||||
}
|
||||
|
||||
value = gm_options_get(options, "font_family");
|
||||
|
||||
if (value && *value != '\0') {
|
||||
gm_color_table_set_font_description(table, value);
|
||||
} else {
|
||||
gm_options_set(options, "font_family", "Monospace 10");
|
||||
}
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
|
||||
GmColorTable *
|
||||
gm_color_table_new(void) {
|
||||
GmColorTable *table = GM_COLOR_TABLE(g_object_new(GM_TYPE_COLOR_TABLE, NULL));
|
||||
|
||||
gm_color_table_load_scheme(table, SCHEME_DEFAULT);
|
||||
return table;
|
||||
}
|
||||
|
||||
GmColorTable *
|
||||
gm_color_table_new_from_options(gchar *filename) {
|
||||
GmColorTable *table = GM_COLOR_TABLE(g_object_new(GM_TYPE_COLOR_TABLE, NULL));
|
||||
|
||||
table->priv->options = gm_options_new();
|
||||
gm_options_set(table->priv->options, "color_scheme", "default");
|
||||
gm_options_load(table->priv->options, filename);
|
||||
gm_color_table_fill_from_options(table);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void gm_color_table_save(GmColorTable *table) {
|
||||
if (table->priv->options) {
|
||||
gm_options_save(table->priv->options);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_color_table_set(GmColorTable *table, const gchar *name, const gchar *hex) {
|
||||
GmColorTableItem *item;
|
||||
|
||||
item = g_hash_table_lookup(table->priv->colors, name);
|
||||
|
||||
if (table->priv->scheme == SCHEME_USER) {
|
||||
gm_options_set(table->priv->options, name, hex);
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
item = g_new0(GmColorTableItem, 1);
|
||||
g_hash_table_insert(table->priv->colors, g_strdup(name), item);
|
||||
}
|
||||
|
||||
if (item->hex == NULL || strcmp(hex, item->hex) != 0) {
|
||||
g_free(item->hex);
|
||||
item->hex = g_strdup(hex);
|
||||
gdk_color_parse(item->hex, &(item->color));
|
||||
|
||||
g_signal_emit(table, color_table_signals[COLOR_CHANGED], 0, name);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_color_table_get(GmColorTable *table, const gchar *name, GdkColor *color) {
|
||||
GmColorTableItem *item;
|
||||
|
||||
item = g_hash_table_lookup(table->priv->colors, name);
|
||||
|
||||
if (item != NULL) {
|
||||
*color = item->color;
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_color_table_get_hex(GmColorTable *table, const gchar *name) {
|
||||
GmColorTableItem *item;
|
||||
|
||||
item = g_hash_table_lookup(table->priv->colors, name);
|
||||
|
||||
if (item != NULL) {
|
||||
return item->hex;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_color_table_set_font_description(GmColorTable *table,
|
||||
const gchar *font_description) {
|
||||
const gchar *fd;
|
||||
|
||||
if (font_description == NULL) {
|
||||
fd = "Monospace 10";
|
||||
} else {
|
||||
fd = font_description;
|
||||
}
|
||||
|
||||
gm_options_set(table->priv->options, "font_family",
|
||||
fd);
|
||||
|
||||
if (table->priv->font_description == NULL ||
|
||||
strcmp(table->priv->font_description, fd) != 0) {
|
||||
g_free(table->priv->font_description);
|
||||
table->priv->font_description = g_strdup(fd);
|
||||
|
||||
g_signal_emit(table, color_table_signals[FONT_CHANGED], 0,
|
||||
table->priv->font_description);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_color_table_font_description(GmColorTable *table) {
|
||||
return table->priv->font_description;
|
||||
}
|
||||
|
||||
void
|
||||
gm_color_table_set_from_scheme_name(GmColorTable *table, const gchar *scheme) {
|
||||
int i = 0;
|
||||
|
||||
while (scheme_names[i].name != NULL) {
|
||||
if (strcasecmp(scheme_names[i].name, scheme) == 0 &&
|
||||
scheme_names[i].values != NULL) {
|
||||
gm_color_table_load_scheme(table, scheme_names[i].scheme);
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if (scheme_names[i].name == NULL) {
|
||||
gm_color_table_load_scheme(table, SCHEME_DEFAULT);
|
||||
|
||||
gm_options_set(table->priv->options, "color_scheme",
|
||||
"default");
|
||||
} else {
|
||||
gm_options_set(table->priv->options, "color_scheme",
|
||||
scheme_names[i].name);
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
#ifndef __GM_COLOR_TABLE_H__
|
||||
#define __GM_COLOR_TABLE_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gm-options.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_COLOR_TABLE (gm_color_table_get_type())
|
||||
#define GM_COLOR_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_COLOR_TABLE, GmColorTable))
|
||||
#define GM_COLOR_TABLE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_COLOR_TABLE, GmColorTable const))
|
||||
#define GM_COLOR_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_COLOR_TABLE, GmColorTableClass))
|
||||
#define GM_IS_COLOR_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_COLOR_TABLE))
|
||||
#define GM_IS_COLOR_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_COLOR_TABLE))
|
||||
#define GM_COLOR_TABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_COLOR_TABLE, GmColorTableClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmColorTablePrivate GmColorTablePrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmColorTable GmColorTable;
|
||||
|
||||
struct _GmColorTable {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmColorTablePrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmColorTableClass GmColorTableClass;
|
||||
|
||||
struct _GmColorTableClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* color_changed) (GmColorTable *table, const gchar *color);
|
||||
void (* font_changed) (GmColorTable *table, const gchar *font_description);
|
||||
};
|
||||
|
||||
typedef enum _GmColorTableScheme {
|
||||
SCHEME_NONE = 0,
|
||||
SCHEME_DEFAULT = 1,
|
||||
SCHEME_WHITE_ON_BLACK = 2,
|
||||
SCHEME_USER = 3
|
||||
} GmColorTableScheme;
|
||||
|
||||
GType gm_color_table_get_type(void) G_GNUC_CONST;
|
||||
|
||||
GmColorTable *gm_color_table_new(void);
|
||||
GmColorTable *gm_color_table_new_from_options(gchar *filename);
|
||||
void gm_color_table_save(GmColorTable *table);
|
||||
|
||||
void gm_color_table_set(GmColorTable *table, const gchar *name,
|
||||
const gchar *hex);
|
||||
gboolean gm_color_table_get(GmColorTable *table, const gchar *name,
|
||||
GdkColor *color);
|
||||
const gchar *gm_color_table_get_hex(GmColorTable *table, const gchar *name);
|
||||
|
||||
void gm_color_table_set_font_description(GmColorTable *table,
|
||||
const gchar *font_description);
|
||||
const gchar *gm_color_table_font_description(GmColorTable *table);
|
||||
|
||||
void gm_color_table_load_scheme(GmColorTable *table,
|
||||
GmColorTableScheme scheme);
|
||||
void gm_color_table_set_from_scheme_name(GmColorTable *table,
|
||||
const gchar *name);
|
||||
void gm_color_table_set_from_options(GmColorTable *table, GmOptions *options);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_COLOR_TABLE_H__ */
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "gm-debug.h"
|
||||
|
||||
typedef struct _LevelMap {
|
||||
gchar const *name;
|
||||
GmDebugLevel level;
|
||||
} LevelMap;
|
||||
|
||||
static LevelMap level_mapping[] = {
|
||||
{"default", DEBUG_DEFAULT},
|
||||
{"mcp", DEBUG_MCP},
|
||||
{"all", DEBUG_ALL},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static gint debug_level = DEBUG_ALWAYS;
|
||||
|
||||
static void
|
||||
gm_debug_msg_real(FILE *f, struct tm *timet, gchar *line, va_list args) {
|
||||
fprintf(f, "[%02d:%02d:%02d] # ", timet->tm_hour, timet->tm_min,
|
||||
timet->tm_sec);
|
||||
vfprintf(f, line, args);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
gm_debug_msg(gint level, gchar *line, ...) {
|
||||
struct tm *timet;
|
||||
time_t timer;
|
||||
va_list args;
|
||||
|
||||
if ((debug_level | level) == debug_level) {
|
||||
va_start(args, line);
|
||||
timer = time(0);
|
||||
timet = localtime(&timer);
|
||||
|
||||
if (level & DEBUG_ALWAYS) {
|
||||
gm_debug_msg_real(stdout, timet, line, args);
|
||||
}
|
||||
|
||||
if ((level & DEBUG_ALWAYS) != level) {
|
||||
gm_debug_msg_real(stderr, timet, line, args);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_debug_set_level(gchar *level) {
|
||||
gchar **levels, **iter;
|
||||
debug_level = DEBUG_ALWAYS;
|
||||
LevelMap *map;
|
||||
|
||||
if (level == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
levels = g_strsplit(level, ",", -1);
|
||||
|
||||
for (iter = levels; *iter; ++iter) {
|
||||
for (map = level_mapping; map->name; ++map) {
|
||||
if (strcasecmp(map->name, *iter) == 0) {
|
||||
debug_level = debug_level | map->level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(levels);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef __GM_DEBUG_H__
|
||||
#define __GM_DEBUG_H__ 1
|
||||
|
||||
typedef enum _GmDebugLevel {
|
||||
DEBUG_ALWAYS = 1 << 1,
|
||||
DEBUG_DEFAULT = 1 << 2,
|
||||
DEBUG_MCP = 1 << 3,
|
||||
DEBUG_ALL = 0xFFFF
|
||||
} GmDebugLevel;
|
||||
|
||||
void gm_debug_msg(gint level, char *line, ...);
|
||||
void gm_debug_set_level(gchar *level);
|
||||
|
||||
#endif /* __GM_DEBUG_H__ */
|
128
src/gm-editor.c
128
src/gm-editor.c
|
@ -1,128 +0,0 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "gm-editor.h"
|
||||
#include "gm-world.h"
|
||||
#include "gm-support.h"
|
||||
|
||||
#define GM_EDITOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_EDITOR, GmEditorPrivate))
|
||||
|
||||
struct _GmEditorPrivate {
|
||||
gchar *name;
|
||||
gchar *upload_cmd;
|
||||
gchar *mcp_type;
|
||||
|
||||
GmEditType type;
|
||||
gboolean is_code;
|
||||
|
||||
GList *lines;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
SAVE,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint editor_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmEditor, gm_editor, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_editor_finalize(GObject *object) {
|
||||
GmEditor *editor = GM_EDITOR(object);
|
||||
|
||||
g_free(editor->priv->name);
|
||||
g_free(editor->priv->upload_cmd);
|
||||
g_free(editor->priv->mcp_type);
|
||||
g_list_free_simple(editor->priv->lines);
|
||||
|
||||
G_OBJECT_CLASS(gm_editor_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_editor_class_init(GmEditorClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_editor_finalize;
|
||||
|
||||
editor_signals[SAVE] =
|
||||
g_signal_new("save",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmEditorClass, save),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmEditorPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_editor_init(GmEditor *view) {
|
||||
view->priv = GM_EDITOR_GET_PRIVATE(view);
|
||||
}
|
||||
|
||||
GmEditor *
|
||||
gm_editor_new(gchar *name, gchar *uploadcmd, GList *text) {
|
||||
GmEditor *editor = GM_EDITOR(g_object_new(GM_TYPE_EDITOR, NULL));
|
||||
|
||||
editor->priv->name = g_strdup(name);
|
||||
editor->priv->upload_cmd = g_strdup(uploadcmd);
|
||||
editor->priv->mcp_type = NULL;
|
||||
editor->priv->lines = g_list_copy(text);
|
||||
editor->priv->type = E_LEGACY;
|
||||
editor->priv->is_code = (strncmp(uploadcmd, "@program", 7) == 0);
|
||||
return editor;
|
||||
}
|
||||
|
||||
GmEditor *
|
||||
gm_editor_new_mcp(gchar *name, gchar *reference, gchar *type,
|
||||
GList *text) {
|
||||
GmEditor *editor = GM_EDITOR(g_object_new(GM_TYPE_EDITOR, NULL));
|
||||
|
||||
editor->priv->name = g_strdup(name);
|
||||
editor->priv->upload_cmd = g_strdup(reference);
|
||||
editor->priv->mcp_type = g_strdup(type);
|
||||
editor->priv->lines = g_list_copy(text);
|
||||
editor->priv->type = E_LEGACY;
|
||||
editor->priv->is_code = (strcmp(type, "moo-code") == 0);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_editor_is_code(GmEditor *editor) {
|
||||
return editor->priv->is_code;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_editor_name(GmEditor *editor) {
|
||||
return editor->priv->name;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_editor_upload_cmd(GmEditor *editor) {
|
||||
return editor->priv->upload_cmd;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_editor_mcp_type(GmEditor *editor) {
|
||||
return editor->priv->mcp_type;
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_editor_lines(GmEditor *editor) {
|
||||
return editor->priv->lines;
|
||||
}
|
||||
|
||||
GmEditType
|
||||
gm_editor_type(GmEditor *editor) {
|
||||
return editor->priv->type;
|
||||
}
|
||||
|
||||
void
|
||||
gm_editor_save(GmEditor *editor) {
|
||||
g_signal_emit(editor, editor_signals[SAVE], 0);
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
#ifndef __GM_EDITOR_H__
|
||||
#define __GM_EDITOR_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_EDITOR (gm_editor_get_type())
|
||||
#define GM_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_EDITOR, GmEditor))
|
||||
#define GM_EDITOR_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_EDITOR, GmEditor const))
|
||||
#define GM_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_EDITOR, GmEditorClass))
|
||||
#define GM_IS_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_EDITOR))
|
||||
#define GM_IS_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_EDITOR))
|
||||
#define GM_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_EDITOR, GmEditorClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmEditorPrivate GmEditorPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmEditor GmEditor;
|
||||
|
||||
struct _GmEditor {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmEditorPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmEditorClass GmEditorClass;
|
||||
|
||||
struct _GmEditorClass {
|
||||
GObject parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* save) (GmEditor *editor);
|
||||
};
|
||||
|
||||
typedef enum _GmEditType GmEditType;
|
||||
enum _GmEditType {
|
||||
E_LEGACY,
|
||||
E_MCP
|
||||
};
|
||||
|
||||
GType gm_editor_get_type(void) G_GNUC_CONST;
|
||||
GmEditor *gm_editor_new(gchar *name, gchar *uploadcmd, GList *text);
|
||||
GmEditor *gm_editor_new_mcp(gchar *name, gchar *reference, gchar *type,
|
||||
GList *text);
|
||||
|
||||
void gm_editor_save(GmEditor *editor);
|
||||
|
||||
gboolean gm_editor_is_code(GmEditor *editor);
|
||||
gchar *gm_editor_name(GmEditor *editor);
|
||||
gchar *gm_editor_upload_cmd(GmEditor *editor);
|
||||
gchar *gm_editor_mcp_type(GmEditor *editor);
|
||||
GList *gm_editor_lines(GmEditor *editor);
|
||||
GmEditType gm_editor_type(GmEditor *editor);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_EDITOR_H__ */
|
|
@ -1,4 +0,0 @@
|
|||
VOID:STRING,UINT
|
||||
VOID:STRING,INT
|
||||
VOID:INT,INT
|
||||
VOID:INT,STRING
|
537
src/gm-net.c
537
src/gm-net.c
|
@ -1,537 +0,0 @@
|
|||
|
||||
#include <glib.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "gm-net.h"
|
||||
#include "gm-marshal.h"
|
||||
#include "gm-debug.h"
|
||||
#include "gm-support.h"
|
||||
|
||||
#define GM_NET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_NET, GmNetPrivate))
|
||||
|
||||
struct _GmNetPrivate {
|
||||
int socket; /**< the connection socket, is -1 if not connected */
|
||||
GIOChannel *channel; /**< the channel which is used to 'listen' on the socket via the glib main loop */
|
||||
guint source; /**< the id of the socket watch */
|
||||
guint connect_timeout_id; /**< the connect timeout id */
|
||||
guint connect_check_id; /**< the connect timeout id */
|
||||
struct timeval last_connected; /**< contains when the last connect happened */
|
||||
int tn_last; /**< used for telnet */
|
||||
int tn_subneg; /**< used for telnet */
|
||||
|
||||
struct addrinfo *addr;
|
||||
struct addrinfo *current;
|
||||
|
||||
GmNetState state; /**< state of the connection */
|
||||
gchar *current_host;
|
||||
gchar *current_port;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
STATE_CHANGING,
|
||||
NET_ERROR,
|
||||
BYTES_RECV,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint net_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmNet, gm_net, G_TYPE_OBJECT)
|
||||
|
||||
/* These values taken from RFC 854 and RFC 857. */
|
||||
#define TN_WILL 251
|
||||
#define TN_WONT 252
|
||||
#define TN_DO 253
|
||||
#define TN_DONT 254
|
||||
#define TN_IAC 255 /* Interpret As Command */
|
||||
#define TN_SB 250 /* start of subnegotiation */
|
||||
#define TN_SE 240 /* end of subnegotiaton */
|
||||
|
||||
void gm_net_connect_next(GmNet *net);
|
||||
|
||||
gboolean on_gm_net_input_recv(GIOChannel * source, GIOCondition condition,
|
||||
GmNet *net);
|
||||
gboolean on_gm_net_connect_check(GIOChannel * source, GIOCondition condition,
|
||||
GmNet *net);
|
||||
gboolean on_gm_net_connect_timeout(GmNet *net);
|
||||
|
||||
static void
|
||||
gm_net_finalize(GObject *object) {
|
||||
//GmNet *net = GM_NET(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_net_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_net_class_init(GmNetClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_net_finalize;
|
||||
|
||||
net_signals[STATE_CHANGING] =
|
||||
g_signal_new("state_changing",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmNetClass, state_changing),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_UINT);
|
||||
|
||||
net_signals[NET_ERROR] =
|
||||
g_signal_new("net_error",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmNetClass, net_error),
|
||||
NULL, NULL,
|
||||
gm_marshal_VOID__STRING_INT,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_INT);
|
||||
|
||||
net_signals[BYTES_RECV] =
|
||||
g_signal_new("bytes_recv",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmNetClass, bytes_recv),
|
||||
NULL, NULL,
|
||||
gm_marshal_VOID__STRING_UINT,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_UINT);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmNetPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_net_init(GmNet *net) {
|
||||
net->priv = GM_NET_GET_PRIVATE(net);
|
||||
net->priv->state = GM_NET_STATE_DISCONNECTED;
|
||||
net->priv->addr = NULL;
|
||||
net->priv->current = NULL;
|
||||
net->priv->channel = NULL;
|
||||
|
||||
net->priv->source = 0;
|
||||
net->priv->connect_timeout_id = 0;
|
||||
net->priv->connect_check_id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_set_state(GmNet *net, GmNetState state) {
|
||||
g_signal_emit(net, net_signals[STATE_CHANGING], 0, state);
|
||||
net->priv->state = state;
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_clean_disconnection(GmNet *net) {
|
||||
GError *err = NULL;
|
||||
|
||||
if (!net->priv->channel) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.CleanDisconnection: NOT clean for %d",
|
||||
net->priv->socket);
|
||||
return;
|
||||
}
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.CleanDisconnection: clean disconnect for %d",
|
||||
net->priv->socket);
|
||||
|
||||
// Shutdown the channel
|
||||
g_io_channel_shutdown(net->priv->channel, TRUE, &err);
|
||||
|
||||
if (err) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.CleanDisconnection: error on channel shutdown: "
|
||||
"%s", err->message);
|
||||
g_error_free(err);
|
||||
err = NULL;
|
||||
}
|
||||
|
||||
g_io_channel_unref(net->priv->channel);
|
||||
|
||||
net->priv->channel = NULL;
|
||||
net->priv->socket = -1;
|
||||
|
||||
net->priv->tn_last = 0;
|
||||
net->priv->tn_subneg = 0;
|
||||
|
||||
gm_net_set_state(net, GM_NET_STATE_DISCONNECTED);
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_dirty_disconnection(GmNet *net, int err) {
|
||||
gchar *msg;
|
||||
|
||||
// Pff, stupid, we print a message and pass it on to clean_disconnection
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.DirtyDisconnection: dirty disconnect %d",
|
||||
net->priv->socket);
|
||||
|
||||
msg = g_strdup_printf(_("Connection lost... (%s)"), strerror(err));
|
||||
g_signal_emit(net, net_signals[NET_ERROR], 0, msg,
|
||||
GM_NET_ERROR_DISCONNECTED);
|
||||
g_free(msg);
|
||||
|
||||
gm_net_clean_disconnection(net);
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_connect_succeed(GmNet *net) {
|
||||
freeaddrinfo(net->priv->addr);
|
||||
net->priv->addr = NULL;
|
||||
net->priv->current = NULL;
|
||||
|
||||
net->priv->source = g_io_add_watch(net->priv->channel,
|
||||
G_IO_IN | G_IO_HUP, (GIOFunc)on_gm_net_input_recv, net);
|
||||
|
||||
if (net->priv->connect_timeout_id != 0) {
|
||||
g_source_remove(net->priv->connect_timeout_id);
|
||||
net->priv->connect_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (net->priv->connect_check_id != 0) {
|
||||
g_source_remove(net->priv->connect_check_id);
|
||||
net->priv->connect_check_id = 0;
|
||||
}
|
||||
|
||||
gettimeofday(&(net->priv->last_connected), NULL);
|
||||
gm_net_set_state(net, GM_NET_STATE_CONNECTED);
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_connect_failed(GmNet *net, gchar *err, gint code) {
|
||||
if (net->priv->channel) {
|
||||
g_io_channel_shutdown(net->priv->channel, TRUE, NULL);
|
||||
g_io_channel_unref(net->priv->channel);
|
||||
net->priv->channel = NULL;
|
||||
}
|
||||
|
||||
g_signal_emit(net, net_signals[NET_ERROR], 0, err, GM_NET_ERROR_CONNECTING);
|
||||
|
||||
if (net->priv->addr && net->priv->current->ai_next) {
|
||||
net->priv->current = net->priv->current->ai_next;
|
||||
gm_net_connect_next(net);
|
||||
} else {
|
||||
net->priv->socket = -1;
|
||||
|
||||
if (net->priv->addr) {
|
||||
freeaddrinfo(net->priv->addr);
|
||||
net->priv->addr = NULL;
|
||||
net->priv->current = NULL;
|
||||
}
|
||||
|
||||
// Don't use set_state here because we weren't really connected before
|
||||
gm_net_set_state(net, GM_NET_STATE_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_connect_next(GmNet *net) {
|
||||
char host[NI_MAXHOST], port[NI_MAXSERV];
|
||||
int ret, result;
|
||||
struct addrinfo *tmp = net->priv->current;
|
||||
|
||||
if (tmp == NULL) {
|
||||
return;
|
||||
} else {
|
||||
if ((ret = getnameinfo(tmp->ai_addr, tmp->ai_addrlen, host, NI_MAXHOST,
|
||||
port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.ConnectNext: getnameinfo error: %s",
|
||||
gai_strerror(ret));
|
||||
gm_net_connect_failed(net, (gchar *)gai_strerror(ret), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
net->priv->current_host = host;
|
||||
net->priv->current_port = port;
|
||||
gm_net_set_state(net, GM_NET_STATE_TRY_ADDRESS);
|
||||
|
||||
net->priv->socket = socket(tmp->ai_family, tmp->ai_socktype,
|
||||
tmp->ai_protocol);
|
||||
|
||||
if (net->priv->socket < 0) {
|
||||
gm_net_connect_failed(net, strerror(errno), errno);
|
||||
} else {
|
||||
fcntl(net->priv->socket, F_SETFL,
|
||||
fcntl(net->priv->socket, F_GETFL) | O_NONBLOCK);
|
||||
|
||||
if ((result = connect(net->priv->socket, tmp->ai_addr,
|
||||
net->priv->addr->ai_addrlen)) == -1 && errno != EINPROGRESS) {
|
||||
gm_net_connect_failed(net, strerror(errno), errno);
|
||||
} else {
|
||||
net->priv->channel = g_io_channel_unix_new(net->priv->socket);
|
||||
g_io_channel_set_close_on_unref(net->priv->channel, TRUE);
|
||||
|
||||
if (result == 0) {
|
||||
gm_net_connect_succeed(net);
|
||||
} else {
|
||||
net->priv->connect_check_id = g_io_add_watch(net->priv->channel,
|
||||
G_IO_OUT|G_IO_ERR, (GIOFunc)on_gm_net_connect_check, net);
|
||||
net->priv->connect_timeout_id = g_timeout_add(5000,
|
||||
(GSourceFunc)on_gm_net_connect_timeout, net);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_handle_telnet(GmNet *net, unsigned char *buf, int *len) {
|
||||
int i, j;
|
||||
unsigned char c;
|
||||
|
||||
j = 0;
|
||||
|
||||
for (i = 0; i < *len; ++i) {
|
||||
c = buf[i];
|
||||
|
||||
if (net->priv->tn_last) {
|
||||
switch (net->priv->tn_last) {
|
||||
case TN_WILL: case TN_WONT: case TN_DO: case TN_DONT:
|
||||
net->priv->tn_last = 0;
|
||||
break;
|
||||
case TN_IAC:
|
||||
switch (c) {
|
||||
case TN_WILL: case TN_WONT: case TN_DO: case TN_DONT:
|
||||
net->priv->tn_last = c;
|
||||
break;
|
||||
case TN_SB:
|
||||
net->priv->tn_subneg = 1;
|
||||
net->priv->tn_last = 0;
|
||||
break;
|
||||
case TN_SE:
|
||||
net->priv->tn_subneg = 0;
|
||||
net->priv->tn_last = 0;
|
||||
break;
|
||||
case TN_IAC:
|
||||
if (!net->priv->tn_subneg) {
|
||||
buf[j] = c;
|
||||
++j;
|
||||
}
|
||||
net->priv->tn_last = 0;
|
||||
break;
|
||||
default:
|
||||
net->priv->tn_last = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (c == TN_IAC) {
|
||||
net->priv->tn_last = TN_IAC;
|
||||
} else if (net->priv->tn_subneg) {
|
||||
continue;
|
||||
} else {
|
||||
buf[j] = c;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
*len = j; //Since j-- is the last written char
|
||||
}
|
||||
|
||||
/* Public */
|
||||
GmNet *
|
||||
gm_net_new() {
|
||||
GmNet *net = GM_NET(g_object_new(GM_TYPE_NET, NULL));
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
GmNetState
|
||||
gm_net_state(GmNet *net) {
|
||||
return net->priv->state;
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_connect(GmNet *net, const gchar *host, const gchar *port) {
|
||||
struct addrinfo hint;
|
||||
int ret;
|
||||
char shost[NI_MAXHOST], sport[NI_MAXSERV];
|
||||
|
||||
if (net->priv->state != GM_NET_STATE_DISCONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(shost, NI_MAXHOST - 1, "%s", host);
|
||||
snprintf(sport, NI_MAXSERV - 1, "%s", port);
|
||||
|
||||
net->priv->current_host = shost;
|
||||
net->priv->current_port = sport;
|
||||
|
||||
gm_net_set_state(net, GM_NET_STATE_CONNECTING);
|
||||
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
hint.ai_flags = 0;
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.Connect: getaddrinfo: %s : %s", shost, sport);
|
||||
|
||||
if ((ret = getaddrinfo(shost, sport, &hint, &(net->priv->addr))) != 0) {
|
||||
net->priv->addr = NULL;
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.Connect: getaddrinfo failed: %s", gai_strerror(ret));
|
||||
gm_net_connect_failed(net, (gchar *)gai_strerror(ret), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (net->priv->addr != NULL) {
|
||||
net->priv->current = net->priv->addr;
|
||||
gm_net_connect_next(net);
|
||||
} else {
|
||||
gm_net_connect_failed(net, _("No addresses available"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_disconnect(GmNet *net) {
|
||||
if (net->priv->state == GM_NET_STATE_CONNECTED) {
|
||||
gm_net_set_state(net, GM_NET_STATE_DISCONNECTING);
|
||||
|
||||
// Remove the watch
|
||||
g_source_remove(net->priv->source);
|
||||
gm_net_clean_disconnection(net);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_send_line(GmNet *net, gchar *line) {
|
||||
gchar *send_line;
|
||||
|
||||
send_line = (gchar *)(g_strconcat(line, "\r\n", NULL));
|
||||
gm_net_send(net, send_line);
|
||||
g_free(send_line);
|
||||
}
|
||||
|
||||
void
|
||||
gm_net_send(GmNet *net, gchar *text) {
|
||||
int result;
|
||||
fd_set connect_set;
|
||||
|
||||
if (net->priv->state == GM_NET_STATE_CONNECTED) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.Send: %s", text);
|
||||
|
||||
if ((result = send(net->priv->socket, text, strlen(text), 0)) == -1
|
||||
&& (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
FD_ZERO(&connect_set);
|
||||
FD_SET(net->priv->socket, &connect_set);
|
||||
|
||||
// Wait for sending to be done
|
||||
select(net->priv->socket + 1, NULL, &connect_set, NULL, NULL);
|
||||
} else if (result == -1) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.Send: error on sending line: %s", strerror(errno));
|
||||
gm_net_dirty_disconnection(net, errno);
|
||||
}
|
||||
} else {
|
||||
g_signal_emit(net, net_signals[NET_ERROR], 0, _("Not connected"),
|
||||
GM_NET_ERROR);
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.Send: not connected!");
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_net_current_host(GmNet *net) {
|
||||
return net->priv->current_host;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_net_current_port(GmNet *net) {
|
||||
return net->priv->current_port;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
#define MAX_RECV_BUF 1024
|
||||
|
||||
gboolean
|
||||
on_gm_net_input_recv(GIOChannel * source, GIOCondition condition, GmNet *net) {
|
||||
unsigned char lbuf[MAX_RECV_BUF];
|
||||
int len;
|
||||
|
||||
if (condition == G_IO_HUP) {
|
||||
gm_net_set_state(net, GM_NET_STATE_DISCONNECTING);
|
||||
gm_net_clean_disconnection(net);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (net->priv->state != GM_NET_STATE_CONNECTED) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.OnInputRecv: not connected!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Break the received line by newline (skip \r)
|
||||
len = recv(net->priv->socket, lbuf, MAX_RECV_BUF - 2, 0);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmNet.OnInputRecv: received %d bytes", len);
|
||||
|
||||
if (len < 1) {
|
||||
// Disconnected, either clean or dirty
|
||||
// (shouldn't this be caught by G_IO_HUP?)
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gm_net_set_state(net, GM_NET_STATE_DISCONNECTING);
|
||||
gm_net_dirty_disconnection(net, errno);
|
||||
} else {
|
||||
gm_net_set_state(net, GM_NET_STATE_DISCONNECTING);
|
||||
gm_net_clean_disconnection(net);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
} else {
|
||||
// It's fine, we have text!
|
||||
gm_net_handle_telnet(net, lbuf, &len);
|
||||
g_signal_emit(net, net_signals[BYTES_RECV], 0, lbuf, len);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_gm_net_connect_check(GIOChannel * source, GIOCondition condition,
|
||||
GmNet *net) {
|
||||
int option = 0;
|
||||
socklen_t optionsize = sizeof(option);
|
||||
|
||||
if (net->priv->connect_timeout_id != 0) {
|
||||
g_source_remove(net->priv->connect_timeout_id);
|
||||
net->priv->connect_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (condition == G_IO_ERR) {
|
||||
getsockopt(net->priv->socket, SOL_SOCKET, SO_ERROR, &option, &optionsize);
|
||||
gm_net_connect_failed(net, strerror(option), option);
|
||||
} else {
|
||||
gm_net_connect_succeed(net);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_gm_net_connect_timeout(GmNet *net) {
|
||||
net->priv->connect_timeout_id = 0;
|
||||
|
||||
if (net->priv->connect_check_id != 0) {
|
||||
g_source_remove(net->priv->connect_check_id);
|
||||
net->priv->connect_check_id = 0;
|
||||
}
|
||||
|
||||
gm_net_connect_failed(net, _("Connect timeout (5)"), 0);
|
||||
return FALSE;
|
||||
}
|
81
src/gm-net.h
81
src/gm-net.h
|
@ -1,81 +0,0 @@
|
|||
#ifndef __GM_NET_H__
|
||||
#define __GM_NET_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_NET (gm_net_get_type())
|
||||
#define GM_NET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_NET, GmNet))
|
||||
#define GM_NET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_NET, GmNet const))
|
||||
#define GM_NET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_NET, GmNetClass))
|
||||
#define GM_IS_NET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_NET))
|
||||
#define GM_IS_NET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_NET))
|
||||
#define GM_NET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_NET, GmNetClass))
|
||||
|
||||
typedef enum _GmNetState {
|
||||
GM_NET_STATE_CONNECTED, /**< socket connected */
|
||||
GM_NET_STATE_DISCONNECTED, /**< socket disconnected */
|
||||
GM_NET_STATE_CONNECTING, /**< socket still connecting */
|
||||
GM_NET_STATE_TRY_ADDRESS, /**< connecting to address */
|
||||
GM_NET_STATE_DISCONNECTING /**< socket still disconnecting */
|
||||
} GmNetState;
|
||||
|
||||
typedef enum _GmNetError {
|
||||
GM_NET_ERROR_CONNECTING, /**< error while connecting */
|
||||
GM_NET_ERROR_DISCONNECTED, /**< error while connecting */
|
||||
GM_NET_ERROR /**< general error */
|
||||
} GmNetError;
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmNetPrivate GmNetPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmNet GmNet;
|
||||
|
||||
struct _GmNet {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmNetPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmNetClass GmNetClass;
|
||||
|
||||
struct _GmNetClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* state_changing) (GmNet *net, guint state);
|
||||
void (* net_error) (GmNet *net, gchar *error, gint code);
|
||||
void (* bytes_recv) (GmNet *net, gchar *text);
|
||||
};
|
||||
|
||||
GType gm_net_get_type(void) G_GNUC_CONST;
|
||||
GmNet *gm_net_new(void);
|
||||
|
||||
GmNetState gm_net_state(GmNet *net);
|
||||
void gm_net_connect(GmNet *net, const gchar *host, const gchar *port);
|
||||
void gm_net_disconnect(GmNet *net);
|
||||
void gm_net_send_line(GmNet *net, gchar *line);
|
||||
void gm_net_send(GmNet *net, gchar *text);
|
||||
const gchar *gm_net_current_host(GmNet *net);
|
||||
const gchar *gm_net_current_port(GmNet *net);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_NET_H__ */
|
212
src/gm-options.c
212
src/gm-options.c
|
@ -1,212 +0,0 @@
|
|||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "gm-options.h"
|
||||
#include "gm-string.h"
|
||||
#include "gm-debug.h"
|
||||
|
||||
extern int errno;
|
||||
|
||||
#define GM_OPTIONS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_OPTIONS, GmOptionsPrivate))
|
||||
|
||||
struct _GmOptionsPrivate {
|
||||
GHashTable *options;
|
||||
gchar *filepath;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
OPTION_CHANGED,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint options_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmOptions, gm_options, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_options_finalize(GObject *object) {
|
||||
GmOptions *options = GM_OPTIONS(object);
|
||||
|
||||
g_hash_table_destroy(options->priv->options);
|
||||
g_free(options->priv->filepath);
|
||||
|
||||
G_OBJECT_CLASS(gm_options_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_options_class_init(GmOptionsClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_options_finalize;
|
||||
|
||||
options_signals[OPTION_CHANGED] =
|
||||
g_signal_new("option_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmOptionsClass, option_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmOptionsPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_options_init(GmOptions *options) {
|
||||
options->priv = GM_OPTIONS_GET_PRIVATE(options);
|
||||
options->priv->options = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
options->priv->filepath = NULL;
|
||||
}
|
||||
|
||||
GmOptions *
|
||||
gm_options_new(void) {
|
||||
GmOptions *options = GM_OPTIONS(g_object_new(GM_TYPE_OPTIONS, NULL));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
void
|
||||
gm_options_dup_option(gchar *key, gchar *value, GmOptions *copy) {
|
||||
gm_options_set(copy, key, value);
|
||||
}
|
||||
|
||||
GmOptions *
|
||||
gm_options_dup(GmOptions *source) {
|
||||
GmOptions *copy = gm_options_new();
|
||||
|
||||
g_hash_table_foreach(source->priv->options, (GHFunc)gm_options_dup_option,
|
||||
copy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Adds an option to opt, even if key already exists
|
||||
void
|
||||
gm_options_set(GmOptions * options, const gchar *key, const gchar *value) {
|
||||
gchar *trimmed = gm_string_trim(key);
|
||||
gchar *lookup = g_hash_table_lookup(options->priv->options, trimmed);
|
||||
gboolean changed = lookup != NULL && lookup != value;
|
||||
|
||||
if (lookup != value) {
|
||||
g_hash_table_insert(options->priv->options, g_strdup(trimmed),
|
||||
g_strdup(value));
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
g_signal_emit(options, options_signals[OPTION_CHANGED], 0, trimmed);
|
||||
}
|
||||
|
||||
g_free(trimmed);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_options_get(GmOptions *options, const gchar *key) {
|
||||
return g_hash_table_lookup(options->priv->options, key);
|
||||
}
|
||||
|
||||
void
|
||||
gm_options_set_int(GmOptions *options, const gchar *key, int value) {
|
||||
gchar val[15];
|
||||
|
||||
g_snprintf((gchar *) &val, 15, "%d", value);
|
||||
gm_options_set(options, key, (const gchar *)val);
|
||||
}
|
||||
|
||||
int
|
||||
gm_options_get_int(GmOptions *options, const gchar *key) {
|
||||
const gchar *val = gm_options_get(options, key);
|
||||
int ret;
|
||||
|
||||
if (val && gm_string_to_int(val, &ret)) {
|
||||
return ret;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_options_save_value(gchar *key, gchar *value, FILE *f) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.SaveValue: saving %s, %s", key, value);
|
||||
fprintf(f, "%s=%s\n", key, value);
|
||||
}
|
||||
|
||||
void
|
||||
gm_options_save(GmOptions *options) {
|
||||
FILE *f;
|
||||
|
||||
if (options->priv->filepath == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen(options->priv->filepath, "w");
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.save: saving options (%s)!", options->priv->filepath);
|
||||
|
||||
if (f) {
|
||||
g_hash_table_foreach(options->priv->options,
|
||||
(GHFunc)gm_options_save_value, f);
|
||||
|
||||
fclose(f);
|
||||
chmod(options->priv->filepath, 0660);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.save: couldn't open option file for saving: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_options_save_as(GmOptions *options, const gchar *filename) {
|
||||
g_free(options->priv->filepath);
|
||||
options->priv->filepath = g_strdup(filename);
|
||||
|
||||
gm_options_save(options);
|
||||
}
|
||||
|
||||
void
|
||||
gm_options_load(GmOptions *options, const char *filename) {
|
||||
FILE *f;
|
||||
gchar **keyvalue, line[1024];
|
||||
int i;
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: loading options (%s)!", filename);
|
||||
|
||||
if ((f = fopen(filename, "r")) != NULL) {
|
||||
i = 0;
|
||||
while (fgets((char *) &line, 1024 - 1, f) != NULL) {
|
||||
line[strlen((char *) &line) - 1] = '\0';
|
||||
i++;
|
||||
|
||||
if (strlen(line) != 0) { // Empty lines, we don't need to process those
|
||||
keyvalue = g_strsplit(line, "=", 2);
|
||||
// This will return at least 1 element, at most 2, we need 2
|
||||
if (strncmp(keyvalue[0], "#", 1) != 0) { // Commented lines, well ignore them too
|
||||
if (keyvalue[1] != NULL) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: adding %s, %s", keyvalue[0], keyvalue[1]);
|
||||
gm_options_set(options, keyvalue[0], keyvalue[1]);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: wrong syntax of options "
|
||||
"line in %s line %d", filename, i);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(keyvalue);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: could not retrieve contents of file "
|
||||
"%s (%s)", filename, strerror(errno));
|
||||
}
|
||||
|
||||
g_free(options->priv->filepath);
|
||||
options->priv->filepath = g_strdup(filename);
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
#ifndef __GM_OPTIONS_H__
|
||||
#define __GM_OPTIONS_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_OPTIONS (gm_options_get_type())
|
||||
#define GM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_OPTIONS, GmOptions))
|
||||
#define GM_OPTIONS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_OPTIONS, GmOptions const))
|
||||
#define GM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_OPTIONS, GmOptionsClass))
|
||||
#define GM_IS_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_OPTIONS))
|
||||
#define GM_IS_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_OPTIONS))
|
||||
#define GM_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_OPTIONS, GmOptionsClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmOptionsPrivate GmOptionsPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmOptions GmOptions;
|
||||
|
||||
struct _GmOptions {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmOptionsPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmOptionsClass GmOptionsClass;
|
||||
|
||||
struct _GmOptionsClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* option_changed) (GmOptions *options, const gchar *key);
|
||||
};
|
||||
|
||||
GType gm_options_get_type(void) G_GNUC_CONST;
|
||||
GmOptions *gm_options_new(void);
|
||||
|
||||
GmOptions *gm_options_dup(GmOptions *source);
|
||||
void gm_options_add(GmOptions *options, const gchar *key, const gchar *value);
|
||||
void gm_options_set(GmOptions *options, const gchar *key, const gchar *value);
|
||||
const gchar *gm_options_get(GmOptions *options, const gchar *key);
|
||||
void gm_options_set_int(GmOptions *options, const gchar *key, int value);
|
||||
int gm_options_get_int(GmOptions *options, const gchar *key);
|
||||
|
||||
void gm_options_save(GmOptions *options);
|
||||
void gm_options_save_as(GmOptions *options, const gchar *filename);
|
||||
void gm_options_load(GmOptions *options, const gchar *filename);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GM_OPTIONS_H__ */
|
182
src/gm-pixbuf.c
182
src/gm-pixbuf.c
|
@ -1,182 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "gm-debug.h"
|
||||
#include "gm-pixbuf.h"
|
||||
|
||||
static GList *gm_pixbuf_directories = NULL;
|
||||
static GList *gm_pixbufs = NULL;
|
||||
|
||||
GdkPixbuf *gm_pixbuf_create(const gchar * filename, int width, int height);
|
||||
|
||||
void
|
||||
gm_pixbuf_add_directory(const gchar *directory) {
|
||||
gm_pixbuf_directories =
|
||||
g_list_prepend(gm_pixbuf_directories, g_strdup(directory));
|
||||
}
|
||||
|
||||
void
|
||||
gm_pixbuf_init() {
|
||||
gm_pixbuf_add_directory(PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
|
||||
}
|
||||
|
||||
void
|
||||
gm_pixbuf_fini() {
|
||||
GList *l;
|
||||
GmPixbufInfo *i;
|
||||
|
||||
for (l = gm_pixbuf_directories; l; l = l->next) {
|
||||
g_free(l->data);
|
||||
}
|
||||
|
||||
g_list_free(gm_pixbuf_directories);
|
||||
|
||||
for (l = gm_pixbufs; l; l = l->next) {
|
||||
i = (GmPixbufInfo *)(l->data);
|
||||
g_free(i->name);
|
||||
g_object_unref(i->pixbuf);
|
||||
g_free(i);
|
||||
}
|
||||
|
||||
g_list_free(gm_pixbufs);
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_pixbuf_find(const gchar *filename) {
|
||||
GList *elem;
|
||||
|
||||
if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
|
||||
return g_strdup(filename);
|
||||
}
|
||||
|
||||
for (elem = gm_pixbuf_directories; elem; elem = elem->next) {
|
||||
gchar *pathname =
|
||||
g_strdup_printf("%s%s%s", (gchar *) elem->data,
|
||||
G_DIR_SEPARATOR_S, filename);
|
||||
|
||||
if (g_file_test(pathname, G_FILE_TEST_EXISTS)) {
|
||||
return pathname;
|
||||
}
|
||||
|
||||
g_free(pathname);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
gm_pixbuf_create(const gchar * filename, int width, int height) {
|
||||
gchar *pathname = NULL, *ext;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!filename || strlen(filename) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pathname = gm_pixbuf_find(filename);
|
||||
|
||||
if (!pathname) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "gm_pixbuf_create: couldn't find pixbuf file: %s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ext = rindex(pathname, '.');
|
||||
|
||||
if (width < 1 || height < 1) {
|
||||
pixbuf = gdk_pixbuf_new_from_file(pathname, &error);
|
||||
} else {
|
||||
pixbuf = gdk_pixbuf_new_from_file_at_size(pathname, width, height, &error);
|
||||
}
|
||||
|
||||
if (!pixbuf) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "gm_pixbuf_create: failed to load pixbuf from file: %s: %s\n",
|
||||
pathname, error->message);
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
|
||||
g_free(pathname);
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
gm_pixbuf_get_at_size(const gchar *filename, int width, int height) {
|
||||
GdkPixbuf *pix;
|
||||
GList *elem;
|
||||
GmPixbufInfo *i;
|
||||
|
||||
for (elem = gm_pixbufs; elem; elem = elem->next) {
|
||||
i = (GmPixbufInfo *) (elem->data);
|
||||
|
||||
if (strcmp(i->name, filename) == 0 &&
|
||||
i->width == width && i->height == height) {
|
||||
return i->pixbuf;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, so create it
|
||||
pix = gm_pixbuf_create(filename, width, height);
|
||||
|
||||
if (pix) {
|
||||
i = g_new(GmPixbufInfo, 1);
|
||||
i->name = g_strdup(filename);
|
||||
i->width = width;
|
||||
i->height = height;
|
||||
i->pixbuf = pix;
|
||||
gm_pixbufs = g_list_append(gm_pixbufs, i);
|
||||
return pix;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns pixbuf if it is already loaded in pixmaps
|
||||
GdkPixbuf *
|
||||
gm_pixbuf_get(const gchar *filename) {
|
||||
return gm_pixbuf_get_at_size(filename, -1, -1);
|
||||
}
|
||||
|
||||
void gm_pixbuf_set_alpha(GdkPixbuf **pixs, guchar alpha) {
|
||||
int width, height, n_channels, rowstride, y, x;
|
||||
GdkPixbuf *pix;
|
||||
guchar *pixels, *p;
|
||||
|
||||
if (!gdk_pixbuf_get_has_alpha(*pixs)) {
|
||||
pix = gdk_pixbuf_add_alpha(*pixs, FALSE, 0, 0, 0);
|
||||
gdk_pixbuf_unref(*pixs);
|
||||
} else {
|
||||
pix = *pixs;
|
||||
}
|
||||
|
||||
n_channels = gdk_pixbuf_get_n_channels(pix);
|
||||
|
||||
if (gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB ||
|
||||
gdk_pixbuf_get_bits_per_sample(pix) != 8 ||
|
||||
!gdk_pixbuf_get_has_alpha(pix) ||
|
||||
n_channels != 4) {
|
||||
*pixs = pix;
|
||||
return;
|
||||
}
|
||||
|
||||
width = gdk_pixbuf_get_width(pix);
|
||||
height = gdk_pixbuf_get_height(pix);
|
||||
rowstride = gdk_pixbuf_get_rowstride(pix);
|
||||
pixels = gdk_pixbuf_get_pixels(pix);
|
||||
p = pixels;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
p[3] = alpha;
|
||||
p = p + n_channels;
|
||||
}
|
||||
}
|
||||
|
||||
*pixs = pix;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef gm_pixbuf_H
|
||||
#define gm_pixbuf_H 1
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct _GmPixbufInfo {
|
||||
gchar *name;
|
||||
int width;
|
||||
int height;
|
||||
GdkPixbuf *pixbuf;
|
||||
} GmPixbufInfo;
|
||||
|
||||
void gm_pixbuf_init();
|
||||
void gm_pixbuf_fini();
|
||||
|
||||
void gm_pixbuf_add_directory(const gchar *directory);
|
||||
|
||||
GdkPixbuf *gm_pixbuf_get(const gchar *filename);
|
||||
GdkPixbuf *gm_pixbuf_get_at_size(const gchar *filename, int width, int height);
|
||||
|
||||
void gm_pixbuf_set_alpha(GdkPixbuf **pixs, guchar alpha);
|
||||
|
||||
#endif
|
870
src/gm-scripts.c
870
src/gm-scripts.c
|
@ -1,870 +0,0 @@
|
|||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <ruby.h>
|
||||
#include <libgnomevfs/gnome-vfs-mime-utils.h>
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "gm-debug.h"
|
||||
#include "gm-world.h"
|
||||
#include "gm-app.h"
|
||||
#include "gm-scripts.h"
|
||||
#include "gm-support.h"
|
||||
#include "gm-world.h"
|
||||
|
||||
#define GM_SCRIPTS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_SCRIPTS, GmScriptsPrivate))
|
||||
#define RB_CALLBACK(x) (VALUE (*)())(x)
|
||||
#define GM_SCRIPTS_GLOBAL PACKAGE_DATA_DIR "/" PACKAGE "/scripts"
|
||||
|
||||
static VALUE rb_world_class, rb_client_class, rb_scripts_class;
|
||||
|
||||
VALUE script_world_name(VALUE self);
|
||||
VALUE gm_scripts_rb_world_new(GmWorld *world);
|
||||
VALUE gm_scripts_rb_scripts_new(GmScripts *scripts);
|
||||
|
||||
void gm_scripts_rb_world_class_init();
|
||||
void gm_scripts_rb_client_class_init();
|
||||
void gm_scripts_rb_scripts_class_init();
|
||||
|
||||
void gm_scripts_unload(GmScripts *scripts);
|
||||
void gm_scripts_rb_init();
|
||||
|
||||
struct _GmScriptsPrivate {
|
||||
GList *files;
|
||||
GmScript *loading;
|
||||
GList *monitors;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
SCRIPT_ADDED,
|
||||
SCRIPT_CHANGED,
|
||||
SCRIPT_REMOVED,
|
||||
RELOAD,
|
||||
MESSAGE,
|
||||
ERROR,
|
||||
RUN,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_scripts_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmScripts, gm_scripts, G_TYPE_OBJECT)
|
||||
|
||||
|
||||
static void
|
||||
gm_scripts_finalize(GObject *object) {
|
||||
GmScripts *scripts = GM_SCRIPTS(object);
|
||||
GList *monitors;
|
||||
|
||||
gm_scripts_unload(scripts);
|
||||
|
||||
for (monitors = scripts->priv->monitors; monitors;
|
||||
monitors = monitors->next) {
|
||||
gnome_vfs_monitor_cancel((GnomeVFSMonitorHandle *)(monitors->data));
|
||||
}
|
||||
|
||||
g_list_free(scripts->priv->monitors);
|
||||
scripts->priv->monitors = NULL;
|
||||
|
||||
G_OBJECT_CLASS(gm_scripts_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_scripts_class_init(GmScriptsClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_scripts_finalize;
|
||||
|
||||
gm_scripts_signals[SCRIPT_ADDED] =
|
||||
g_signal_new("script_added",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, script_added),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
gm_scripts_signals[SCRIPT_CHANGED] =
|
||||
g_signal_new("script_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, script_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
gm_scripts_signals[SCRIPT_REMOVED] =
|
||||
g_signal_new("script_removed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, script_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
gm_scripts_signals[RELOAD] =
|
||||
g_signal_new("reload",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, reload),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
gm_scripts_signals[MESSAGE] =
|
||||
g_signal_new("message",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, message),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
gm_scripts_signals[ERROR] =
|
||||
g_signal_new("error",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, error),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
gm_scripts_signals[RUN] =
|
||||
g_signal_new("run",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmScriptsClass, run),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmScriptsPrivate));
|
||||
|
||||
gm_scripts_rb_init();
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_rb_init(GmScriptsClass *klass) {
|
||||
ruby_init();
|
||||
|
||||
gm_scripts_rb_world_class_init();
|
||||
gm_scripts_rb_client_class_init();
|
||||
gm_scripts_rb_scripts_class_init();
|
||||
}
|
||||
|
||||
static void
|
||||
gm_scripts_init(GmScripts *scripts) {
|
||||
scripts->priv = GM_SCRIPTS_GET_PRIVATE(scripts);
|
||||
|
||||
scripts->priv->monitors = NULL;
|
||||
scripts->priv->files = NULL;
|
||||
}
|
||||
|
||||
GmScripts *
|
||||
gm_scripts_new() {
|
||||
GmScripts *scripts = GM_SCRIPTS(g_object_new(GM_TYPE_SCRIPTS, NULL));
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
void gm_scripts_monitor_cb (GnomeVFSMonitorHandle *handle,
|
||||
const gchar *monitor_uri, const gchar *info_uri,
|
||||
GnomeVFSMonitorEventType event_type,
|
||||
GmScripts *scripts) {
|
||||
gchar *filename = gnome_vfs_get_local_path_from_uri(info_uri);
|
||||
|
||||
switch (event_type) {
|
||||
case GNOME_VFS_MONITOR_EVENT_CHANGED:
|
||||
gm_scripts_reload_file(scripts, filename);
|
||||
break;
|
||||
case GNOME_VFS_MONITOR_EVENT_DELETED:
|
||||
gm_scripts_remove_file(scripts, filename);
|
||||
break;
|
||||
case GNOME_VFS_MONITOR_EVENT_CREATED:
|
||||
gm_scripts_add_file(scripts, filename);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
void
|
||||
gm_script_function_destroy(GmScriptFunction *fi) {
|
||||
g_free(fi->name);
|
||||
g_free(fi->fname);
|
||||
g_free(fi->description);
|
||||
g_free(fi);
|
||||
}
|
||||
|
||||
void
|
||||
gm_script_destroy_functions(GmScript *script) {
|
||||
GList *functions;
|
||||
|
||||
for (functions = script->functions; functions;
|
||||
functions = functions->next) {
|
||||
gm_script_function_destroy((GmScriptFunction *)(functions->data));
|
||||
}
|
||||
|
||||
g_list_free(script->functions);
|
||||
script->functions = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_script_destroy(GmScript *script) {
|
||||
gm_script_destroy_functions(script);
|
||||
g_free(script->filename);
|
||||
g_free(script);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_unload(GmScripts *scripts) {
|
||||
GList *files;
|
||||
|
||||
for (files = scripts->priv->files; files; files = files->next) {
|
||||
gm_script_destroy((GmScript *)(files->data));
|
||||
}
|
||||
|
||||
g_list_free(scripts->priv->files);
|
||||
scripts->priv->files = NULL;
|
||||
}
|
||||
|
||||
GmScriptFunction *
|
||||
gm_scripts_find(GmScripts *scripts, gchar *name) {
|
||||
GList *files;
|
||||
GList *functions;
|
||||
GmScriptFunction *func;
|
||||
GmScript *script;
|
||||
|
||||
for (files = scripts->priv->files; files; files = files->next) {
|
||||
script = (GmScript *)(files->data);
|
||||
for (functions = script->functions; functions;
|
||||
functions = functions->next) {
|
||||
func = (GmScriptFunction *)(functions->data);
|
||||
|
||||
if (strcasecmp(func->name, name) == 0) {
|
||||
return func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_add(GmScripts *scripts, gchar *name, gchar *fname,
|
||||
gchar *description) {
|
||||
GmScriptFunction *func;
|
||||
|
||||
if (gm_scripts_find(scripts, name) == NULL) {
|
||||
func = g_new(GmScriptFunction, 1);
|
||||
func->script = scripts->priv->loading;
|
||||
func->name = g_strdup(name);
|
||||
func->fname = g_strdup(fname);;
|
||||
func->description = g_strdup(description);
|
||||
|
||||
scripts->priv->loading->functions =
|
||||
g_list_append(scripts->priv->loading->functions, func);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
gm_scripts_rb_register_functions_wrap(VALUE arg) {
|
||||
return rb_eval_string("register_functions");
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_rb_script_define_world(VALUE *world) {
|
||||
rb_define_variable("$world", world);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_rb_error(GmScripts *scripts) {
|
||||
int c;
|
||||
VALUE lasterr;
|
||||
char *err;
|
||||
gchar *msg;
|
||||
VALUE ary;
|
||||
|
||||
if(!NIL_P(ruby_errinfo)) {
|
||||
lasterr = rb_gv_get("$!");
|
||||
err = RSTRING(rb_obj_as_string(lasterr))->ptr;
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.Error: Error while executing Ruby code: %s",
|
||||
err);
|
||||
|
||||
msg = g_strdup_printf(_("Error in execution: %s"), err);
|
||||
g_signal_emit(scripts, gm_scripts_signals[MESSAGE], 0, msg);
|
||||
g_free(msg);
|
||||
|
||||
ary = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.Error: Ruby backtrace:");
|
||||
g_signal_emit(scripts, gm_scripts_signals[ERROR], 0,
|
||||
_("Ruby backtrace:"));
|
||||
|
||||
for (c = 0; c < RARRAY(ary)->len; c++) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.Error: \tfrom %s",
|
||||
RSTRING(RARRAY(ary)->ptr[c])->ptr);
|
||||
|
||||
msg = g_strdup_printf(_("\tfrom %s"),
|
||||
RSTRING(RARRAY(ary)->ptr[c])->ptr);
|
||||
g_signal_emit(scripts, gm_scripts_signals[ERROR], 0, msg);
|
||||
g_free(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gm_scripts_rb_do(GmScripts *scripts, VALUE (*body)(), VALUE arg) {
|
||||
int status;
|
||||
|
||||
rb_protect(body, arg, &status);
|
||||
|
||||
if (status != 0) {
|
||||
gm_scripts_rb_error(scripts);
|
||||
ruby_cleanup(status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
VALUE
|
||||
gm_scripts_run_function(GmScriptInfo *arg) {
|
||||
VALUE ret;
|
||||
gchar *argstr;
|
||||
gchar *funcAll;
|
||||
|
||||
if (arg->argstr) {
|
||||
argstr = gm_str_escape(arg->argstr);
|
||||
funcAll = g_strconcat(arg->name, "(\"", argstr, "\")", NULL);
|
||||
g_free(argstr);
|
||||
} else {
|
||||
funcAll = g_strconcat(arg->name, "()", NULL);
|
||||
}
|
||||
|
||||
ret = rb_eval_string(funcAll);
|
||||
g_free(funcAll);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_run(GmScripts *scripts, GmWorld *world, gchar *name, gchar *argstr) {
|
||||
VALUE rbWorld, rbClient;
|
||||
gchar *msg;
|
||||
GmScriptInfo *info;
|
||||
GmScriptFunction *f = gm_scripts_find(scripts, name);
|
||||
|
||||
if (!f) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info = g_new0(GmScriptInfo, 1);
|
||||
info->name = g_strdup(f->fname);
|
||||
|
||||
if (argstr) {
|
||||
info->argstr = g_strdup(argstr);
|
||||
msg = g_strdup_printf(_("Run script '%s' from '%s' (%s)"), f->fname,
|
||||
f->script->filename, argstr);
|
||||
} else {
|
||||
info->argstr = NULL;
|
||||
msg = g_strdup_printf(_("Run script '%s' from '%s' ()"), f->fname,
|
||||
f->script->filename);
|
||||
}
|
||||
|
||||
g_signal_emit(scripts, gm_scripts_signals[RUN], 0, msg);
|
||||
g_free(msg);
|
||||
|
||||
gm_scripts_rb_do(scripts, RB_CALLBACK(rb_load_file),
|
||||
(VALUE)(f->script->filename));
|
||||
ruby_exec();
|
||||
|
||||
rbWorld = gm_scripts_rb_world_new(world);
|
||||
rb_define_variable("$world", &rbWorld);
|
||||
|
||||
rbClient = rb_class_new_instance(0, NULL, rb_client_class);
|
||||
rb_define_variable("$client", &rbClient);
|
||||
|
||||
gm_scripts_rb_do(scripts, RB_CALLBACK(gm_scripts_run_function),
|
||||
(VALUE)info);
|
||||
|
||||
g_free(info->name);
|
||||
g_free(info->argstr);
|
||||
g_free(info);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VALUE
|
||||
gm_scripts_rb_register_func_old(int argc, VALUE *argv) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.RegisterFunc: This is the deprecated way to "
|
||||
"register functions is does no longer work. Use $scripts.register "
|
||||
"instead.");
|
||||
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_register_functions(GmScripts *scripts) {
|
||||
gchar *msg;
|
||||
VALUE rbScripts;
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.RegisterFunctions: registering functions in %s",
|
||||
scripts->priv->loading->filename);
|
||||
|
||||
msg = g_strdup_printf(_("Registering functions from '%s'"),
|
||||
scripts->priv->loading->filename);
|
||||
g_signal_emit(scripts, gm_scripts_signals[MESSAGE], 0, msg);
|
||||
g_free(msg);
|
||||
|
||||
// Okay, I'm desperate... define an empty register_functions method so
|
||||
// that the previous when gets cleared ... :(
|
||||
rb_eval_string("def register_functions() end");
|
||||
|
||||
if (!gm_scripts_rb_do(scripts, RB_CALLBACK(rb_load_file),
|
||||
(VALUE) scripts->priv->loading->filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ruby_exec();
|
||||
|
||||
rbScripts = gm_scripts_rb_scripts_new(scripts);
|
||||
rb_define_variable("$scripts", &rbScripts);
|
||||
rb_define_global_function("register_func", &gm_scripts_rb_register_func_old,
|
||||
-1);
|
||||
|
||||
gm_scripts_rb_do(scripts,
|
||||
RB_CALLBACK(gm_scripts_rb_register_functions_wrap), 0);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_remove_file(GmScripts *scripts, const gchar *uri) {
|
||||
GList *f, *l;
|
||||
GmScript *script;
|
||||
|
||||
l = g_list_copy(scripts->priv->files);
|
||||
|
||||
for (f = l; f; f = f->next) {
|
||||
script = (GmScript *)(f->data);
|
||||
|
||||
if (strcmp(script->filename, uri) == 0) {
|
||||
scripts->priv->files = g_list_remove(scripts->priv->files, script);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.RemoveFile: Removing scripts from `%s'",
|
||||
script->filename);
|
||||
g_signal_emit(scripts, gm_scripts_signals[SCRIPT_REMOVED], 0,
|
||||
script);
|
||||
|
||||
gm_script_destroy(script);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(l);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_scripts_add_file(GmScripts *scripts, const gchar *uri) {
|
||||
GList *f;
|
||||
GmScript *script;
|
||||
gchar *msg;
|
||||
|
||||
for (f = scripts->priv->files; f; f = f->next) {
|
||||
script = (GmScript *)(f->data);
|
||||
|
||||
if (strcmp(script->filename, uri) == 0) {
|
||||
msg = g_strdup_printf(_("File `%s' already loaded"), uri);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.AddFile: %s", msg);
|
||||
g_signal_emit(scripts, gm_scripts_signals[ERROR], 0, msg);
|
||||
|
||||
g_free(msg);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
msg = g_strdup_printf(_("File `%s' added"), uri);
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.AddFile: %s", msg);
|
||||
g_free(msg);
|
||||
|
||||
script = g_new0(GmScript, 1);
|
||||
script->filename = g_strdup(uri);
|
||||
|
||||
if (strncmp(uri, GM_SCRIPTS_GLOBAL,
|
||||
strlen(GM_SCRIPTS_GLOBAL)) == 0) {
|
||||
script->type = GM_SCRIPT_TYPE_SHARE;
|
||||
} else {
|
||||
script->type = GM_SCRIPT_TYPE_USER;
|
||||
}
|
||||
|
||||
scripts->priv->files = g_list_append(scripts->priv->files, script);
|
||||
scripts->priv->loading = script;
|
||||
|
||||
gm_scripts_register_functions(scripts);
|
||||
g_signal_emit(scripts, gm_scripts_signals[SCRIPT_ADDED], 0, script);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_reload_file(GmScripts *scripts, const gchar *uri) {
|
||||
GList *files;
|
||||
GmScript *script;
|
||||
|
||||
for (files = scripts->priv->files; files; files = files->next) {
|
||||
script = (GmScript *)(files->data);
|
||||
|
||||
if (strcmp(script->filename, uri) == 0) {
|
||||
// Remove all functions and reregister the file
|
||||
scripts->priv->loading = script;
|
||||
|
||||
gm_script_destroy_functions(script);
|
||||
gm_scripts_register_functions(scripts);
|
||||
|
||||
g_signal_emit(scripts, gm_scripts_signals[SCRIPT_CHANGED], 0,
|
||||
script);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the script does not yet exist, add it
|
||||
gm_scripts_add_file(scripts, uri);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_load_dir(GmScripts *scripts, gchar *dirname) {
|
||||
gchar *filename;
|
||||
gchar *file;
|
||||
GDir *d;
|
||||
GnomeVFSMonitorHandle *handle;
|
||||
|
||||
if (g_file_test(dirname, G_FILE_TEST_EXISTS) &&
|
||||
g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
|
||||
|
||||
if ((d = g_dir_open(dirname, 0, NULL))) {
|
||||
while ((file = (gchar *)g_dir_read_name(d))) {
|
||||
filename = g_strconcat(dirname, "/", file, NULL);
|
||||
gm_scripts_add_file(scripts, filename);
|
||||
g_free(filename);
|
||||
}
|
||||
}
|
||||
|
||||
gnome_vfs_monitor_add(&handle, dirname, GNOME_VFS_MONITOR_DIRECTORY,
|
||||
(GnomeVFSMonitorCallback)gm_scripts_monitor_cb, scripts);
|
||||
scripts->priv->monitors = g_list_append(scripts->priv->monitors,
|
||||
handle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_load(GmScripts *scripts) {
|
||||
gchar *path;
|
||||
|
||||
if (scripts->priv->files) {
|
||||
g_signal_emit(scripts, gm_scripts_signals[RELOAD], 0);
|
||||
gm_scripts_unload(scripts);
|
||||
}
|
||||
|
||||
path = g_strconcat(gm_app_path(gm_app_instance()), "/scripts", NULL);
|
||||
|
||||
gm_scripts_load_dir(scripts, path);
|
||||
gm_scripts_load_dir(scripts, GM_SCRIPTS_GLOBAL);
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_scripts_scripts(GmScripts *scripts) {
|
||||
return scripts->priv->files;
|
||||
}
|
||||
// Ruby class functions
|
||||
|
||||
VALUE
|
||||
gm_scripts_rb_world_new(GmWorld *world) {
|
||||
VALUE tdata = Data_Wrap_Struct(rb_world_class, 0, 0, world);
|
||||
|
||||
return tdata;
|
||||
}
|
||||
|
||||
VALUE
|
||||
gm_scripts_rb_scripts_new(GmScripts *scripts) {
|
||||
VALUE tdata = Data_Wrap_Struct(rb_scripts_class, 0, 0, scripts);
|
||||
|
||||
return tdata;
|
||||
}
|
||||
|
||||
// Ruby world class functions
|
||||
static VALUE
|
||||
gm_scripts_rb_world_name(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
return rb_str_new2(gm_options_get(gm_world_options(world), "name"));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_host(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
return rb_str_new2(gm_options_get(gm_world_options(world), "host"));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_port(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
return rb_str_new2(gm_options_get(gm_world_options(world), "port"));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_writeln(VALUE self, VALUE str) {
|
||||
GmWorld *world;
|
||||
gchar *strVal;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
strVal = rb_string_value_cstr(&str);
|
||||
|
||||
gm_world_writeln(world, strVal);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_sendln(VALUE self, VALUE str) {
|
||||
GmWorld *world;
|
||||
gchar *strVal;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
strVal = rb_string_value_cstr(&str);
|
||||
|
||||
gm_world_sendln(world, strVal);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_input(VALUE self, VALUE str) {
|
||||
GmWorld *world;
|
||||
gchar *strVal;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
strVal = rb_string_value_cstr(&str);
|
||||
|
||||
gm_world_process_input(world, strVal);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_loaded(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
if (gm_world_loaded(world)) {
|
||||
return Qtrue;
|
||||
} else {
|
||||
return Qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_connected(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
if (gm_world_state(world) == GM_NET_STATE_CONNECTED) {
|
||||
return Qtrue;
|
||||
} else {
|
||||
return Qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_quit(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
gm_world_unload(world);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_connect(int argc, VALUE *argv, VALUE self) {
|
||||
GmWorld *world;
|
||||
const gchar *strHost, *strPort;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
if (argc == 0) {
|
||||
strHost = gm_options_get(gm_world_options(world), "host");
|
||||
} else {
|
||||
strHost = rb_string_value_cstr(&(argv[0]));
|
||||
}
|
||||
|
||||
if (argc == 0 || argc == 1) {
|
||||
strPort = gm_options_get(gm_world_options(world), "port");
|
||||
} else {
|
||||
strPort = rb_string_value_cstr(&(argv[1]));
|
||||
}
|
||||
|
||||
gm_world_connect_to(world, (gchar *)strHost, (gchar *)strPort);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_world_disconnect(VALUE self) {
|
||||
GmWorld *world;
|
||||
|
||||
Data_Get_Struct(self, GmWorld, world);
|
||||
|
||||
gm_world_disconnect(world);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
// Ruby client class functions
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_client_version(VALUE self) {
|
||||
return rb_str_new2(VERSION);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_client_worlds(VALUE self) {
|
||||
GList *world;
|
||||
VALUE rb_array = rb_ary_new();
|
||||
VALUE rb_world;
|
||||
|
||||
for (world = gm_app_worlds(gm_app_instance()); world; world = world->next) {
|
||||
rb_world = gm_scripts_rb_world_new((GmWorld *)(world->data));
|
||||
rb_ary_push(rb_array, rb_world);
|
||||
}
|
||||
|
||||
return rb_array;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
gm_scripts_rb_client_open(VALUE self, VALUE str) {
|
||||
GmWorld *world;
|
||||
gchar *strVal;
|
||||
|
||||
strVal = rb_string_value_cstr(&str);
|
||||
|
||||
world = gm_app_world_by_name(gm_app_instance(), strVal);
|
||||
|
||||
if (world == NULL) {
|
||||
return Qfalse;
|
||||
} else {
|
||||
gm_world_load(world);
|
||||
return Qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
// Ruby scripts class functions
|
||||
VALUE
|
||||
gm_scripts_rb_scripts_register(int argc, VALUE *argv, VALUE self) {
|
||||
char *name, *fname = NULL, *description = NULL;
|
||||
gchar *msg;
|
||||
GmScripts *scripts;
|
||||
|
||||
Data_Get_Struct(self, GmScripts, scripts);
|
||||
|
||||
if (argc > 1) {
|
||||
name = rb_string_value_cstr(&argv[0]);
|
||||
description = rb_string_value_cstr(&argv[1]);
|
||||
|
||||
if (argc == 2) {
|
||||
fname = name;
|
||||
} else {
|
||||
fname = rb_string_value_cstr(&argv[2]);
|
||||
}
|
||||
|
||||
if (gm_scripts_add(scripts, name, fname, description)) {
|
||||
msg = g_strdup_printf(_("Register function '%s' from '%s'"), name,
|
||||
scripts->priv->loading->filename);
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.RbScriptsRegister: Adding script function "
|
||||
"%s from %s", name, scripts->priv->loading->filename);
|
||||
g_signal_emit(scripts, gm_scripts_signals[MESSAGE], 0, msg);
|
||||
g_free(msg);
|
||||
return Qtrue;
|
||||
} else {
|
||||
msg = g_strdup_printf(_("Script '%s' is already defined"), name);
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmScripts.RbScriptsRegister: Script function %s "
|
||||
"already defined!", name);
|
||||
g_signal_emit(scripts, gm_scripts_signals[ERROR], 0, msg);
|
||||
g_free(msg);
|
||||
return Qfalse;
|
||||
}
|
||||
} else {
|
||||
return Qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
// Ruby class initializations
|
||||
|
||||
void
|
||||
gm_scripts_rb_world_class_init() {
|
||||
rb_world_class = rb_define_class("World", rb_cObject);
|
||||
|
||||
rb_define_method(rb_world_class, "name", gm_scripts_rb_world_name, 0);
|
||||
rb_define_method(rb_world_class, "host", gm_scripts_rb_world_host, 0);
|
||||
rb_define_method(rb_world_class, "port", gm_scripts_rb_world_port, 0);
|
||||
|
||||
rb_define_method(rb_world_class, "writeln", gm_scripts_rb_world_writeln, 1);
|
||||
rb_define_method(rb_world_class, "println", gm_scripts_rb_world_writeln, 1);
|
||||
rb_define_method(rb_world_class, "sendln", gm_scripts_rb_world_sendln, 1);
|
||||
rb_define_method(rb_world_class, "input", gm_scripts_rb_world_input, 1);
|
||||
rb_define_method(rb_world_class, "quit", gm_scripts_rb_world_quit, 0);
|
||||
rb_define_method(rb_world_class, "connect",
|
||||
gm_scripts_rb_world_connect, -1);
|
||||
rb_define_method(rb_world_class, "disconnect",
|
||||
gm_scripts_rb_world_disconnect, 0);
|
||||
rb_define_method(rb_world_class, "loaded?", gm_scripts_rb_world_loaded, 0);
|
||||
rb_define_method(rb_world_class, "connected?",
|
||||
gm_scripts_rb_world_connected, 0);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_rb_client_class_init() {
|
||||
rb_client_class = rb_define_class("Client", rb_cObject);
|
||||
|
||||
rb_define_method(rb_client_class, "version",
|
||||
gm_scripts_rb_client_version, 0);
|
||||
rb_define_method(rb_client_class, "worlds",
|
||||
gm_scripts_rb_client_worlds, 0);
|
||||
rb_define_method(rb_client_class, "open", gm_scripts_rb_client_open, 1);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scripts_rb_scripts_class_init() {
|
||||
rb_scripts_class = rb_define_class("Scripts", rb_cObject);
|
||||
|
||||
rb_define_method(rb_scripts_class, "register",
|
||||
gm_scripts_rb_scripts_register, -1);
|
||||
}
|
109
src/gm-scripts.h
109
src/gm-scripts.h
|
@ -1,109 +0,0 @@
|
|||
#ifndef __GM_SCRIPTS_H__
|
||||
#define __GM_SCRIPTS_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RUBY
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gm-world.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_SCRIPTS (gm_scripts_get_type())
|
||||
#define GM_SCRIPTS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_SCRIPTS, GmScripts))
|
||||
#define GM_SCRIPTS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_SCRIPTS, GmScripts const))
|
||||
#define GM_SCRIPTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_SCRIPTS, GmScriptsClass))
|
||||
#define GM_IS_SCRIPTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_SCRIPTS))
|
||||
#define GM_IS_SCRIPTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_SCRIPTS))
|
||||
#define GM_SCRIPTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_SCRIPTS, GmScriptsClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmScriptsPrivate GmScriptsPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmScripts GmScripts;
|
||||
|
||||
struct _GmScripts {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmScriptsPrivate *priv;
|
||||
};
|
||||
|
||||
typedef enum _GmScriptType {
|
||||
GM_SCRIPT_TYPE_USER,
|
||||
GM_SCRIPT_TYPE_SHARE
|
||||
} GmScriptType;
|
||||
|
||||
typedef struct _GmScript {
|
||||
gchar *filename;
|
||||
GmScriptType type;
|
||||
GList *functions;
|
||||
} GmScript;
|
||||
|
||||
typedef struct _GmScriptFunction {
|
||||
GmScript *script;
|
||||
gchar *name;
|
||||
gchar *fname;
|
||||
gchar *description;
|
||||
} GmScriptFunction;
|
||||
|
||||
typedef struct _GmScriptInfo {
|
||||
gchar *name;
|
||||
gchar *argstr;
|
||||
} GmScriptInfo;
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmScriptsClass GmScriptsClass;
|
||||
|
||||
struct _GmScriptsClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* script_added) (GmScripts *scripts, GmScript *script);
|
||||
void (* script_changed) (GmScripts *scripts, GmScript *script);
|
||||
void (* script_removed) (GmScripts *scripts, GmScript *script);
|
||||
void (* reload) (GmScripts *scripts);
|
||||
void (* message) (GmScripts *scripts, gchar *message);
|
||||
void (* error) (GmScripts *scripts, gchar *message);
|
||||
void (* run) (GmScripts *scripts, gchar *message);
|
||||
};
|
||||
|
||||
GType gm_scripts_get_type(void) G_GNUC_CONST;
|
||||
GmScripts *gm_scripts_new();
|
||||
|
||||
//void gm_script_init();
|
||||
//void gm_script_fini();
|
||||
|
||||
void gm_scripts_reload_file(GmScripts *scripts, const gchar *uri);
|
||||
gboolean gm_scripts_add_file(GmScripts *scripts, const gchar *uri);
|
||||
void gm_scripts_remove_file(GmScripts *scripts, const gchar *uri);
|
||||
|
||||
GmScriptFunction *gm_scripts_find(GmScripts *scripts, gchar *name);
|
||||
GList *gm_scripts_scripts(GmScripts *scripts);
|
||||
|
||||
gboolean gm_scripts_run(GmScripts *scripts, GmWorld *world, gchar *name,
|
||||
gchar *argstr);
|
||||
void gm_scripts_load(GmScripts *scripts);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* HAVE_RUBY */
|
||||
#endif /* __GM_SCRIPTS_H__ */
|
203
src/gm-string.c
203
src/gm-string.c
|
@ -1,203 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "gm-string.h"
|
||||
#include "gm-debug.h"
|
||||
|
||||
/*
|
||||
void
|
||||
stringlist_add(stringlist * strl, char *data) {
|
||||
stringlist_item *newStringlistItem =
|
||||
(stringlist_item *) malloc(sizeof(stringlist_item));
|
||||
newStringlistItem->data = strdup(data);
|
||||
|
||||
if (strl->firstItem == NULL) {
|
||||
strl->firstItem = newStringlistItem;
|
||||
} else {
|
||||
newStringlistItem->prev = strl->lastItem;
|
||||
|
||||
if (strl->lastItem != NULL)
|
||||
strl->lastItem->next = newStringlistItem;
|
||||
}
|
||||
|
||||
strl->lastItem = newStringlistItem;
|
||||
newStringlistItem->next = NULL;
|
||||
|
||||
strl->count++;
|
||||
}
|
||||
|
||||
void
|
||||
stringlist_remove(stringlist * strl, stringlist_item * removed) {
|
||||
if (removed == strl->firstItem) {
|
||||
strl->firstItem = removed->next;
|
||||
} else {
|
||||
removed->prev->next = removed->next;
|
||||
}
|
||||
|
||||
if (removed == strl->lastItem) {
|
||||
strl->lastItem = removed->prev;
|
||||
} else {
|
||||
removed->next->prev = removed->next;
|
||||
}
|
||||
|
||||
free(removed->data);
|
||||
free(removed);
|
||||
strl->count--;
|
||||
}
|
||||
|
||||
stringlist *
|
||||
stringlist_create(char *argstr, char *delim) {
|
||||
stringlist *newStringlist = (stringlist *) malloc(sizeof(stringlist));
|
||||
char *data, *work, *working, *strPos;
|
||||
|
||||
newStringlist->firstItem = NULL;
|
||||
newStringlist->lastItem = NULL;
|
||||
newStringlist->count = 0;
|
||||
|
||||
if (delim == NULL) {
|
||||
stringlist_add(newStringlist, argstr);
|
||||
return newStringlist;
|
||||
}
|
||||
|
||||
working = strdup(argstr);
|
||||
working = mystring_cat(working, delim);
|
||||
work = working;
|
||||
|
||||
while (strlen(work) != 0) {
|
||||
|
||||
if ((strPos = strstr(work, delim)) != NULL && strPos > work) {
|
||||
data = NULL;
|
||||
data = mystring_catn(data, work, (strPos - work));
|
||||
stringlist_add(newStringlist, data);
|
||||
free(data);
|
||||
}
|
||||
work = strPos + strlen(delim);
|
||||
|
||||
}
|
||||
|
||||
free(working);
|
||||
return newStringlist;
|
||||
}
|
||||
|
||||
void
|
||||
stringlist_destroy(stringlist * strl) {
|
||||
stringlist_item *curItem = strl->firstItem;
|
||||
|
||||
while (curItem != NULL) {
|
||||
stringlist_remove(strl, curItem);
|
||||
curItem = strl->firstItem;
|
||||
}
|
||||
|
||||
free(strl);
|
||||
}
|
||||
|
||||
char *
|
||||
stringlist_glue_it(stringlist * strl, char *glue) {
|
||||
char *result = NULL;
|
||||
stringlist_item *curItem = strl->firstItem;
|
||||
|
||||
while (curItem != NULL) {
|
||||
if (curItem != strl->firstItem) {
|
||||
result = mystring_cat(result, glue);
|
||||
result = mystring_cat(result, curItem->data);
|
||||
} else {
|
||||
result = strdup(curItem->data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
gboolean
|
||||
gm_string_to_int(const gchar *str, int *result) {
|
||||
*result = 0;
|
||||
|
||||
if (str == NULL || *str == '\0') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*result = atoi(str);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_string_catn(gchar *str, gchar *add, guint n) {
|
||||
guint relen;
|
||||
gchar *newstr;
|
||||
|
||||
if (str == NULL) {
|
||||
relen = 0;
|
||||
} else {
|
||||
relen = strlen(str);
|
||||
}
|
||||
|
||||
if ((newstr = (gchar *) realloc(str, (relen + n + 1) * sizeof(gchar))) == NULL) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "mystring_catn: REALLOC FAILED!");
|
||||
return str;
|
||||
} else {
|
||||
if (relen == 0) {
|
||||
newstr[0] = '\0';
|
||||
}
|
||||
|
||||
strncat(newstr, add, n);
|
||||
return newstr;
|
||||
}
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_string_cat(gchar *str, gchar *add) {
|
||||
return gm_string_catn(str, add, strlen(add));
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_string_trim(const gchar *str) {
|
||||
gchar *newstr = NULL;
|
||||
const gchar *r, *l;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = str + strlen(str);
|
||||
l = str;
|
||||
|
||||
while (*l == ' ' || *r == ' ') {
|
||||
if (l == r) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*l == ' ') {
|
||||
l++;
|
||||
}
|
||||
|
||||
if (l == r) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*r == ' ') {
|
||||
r--;
|
||||
}
|
||||
}
|
||||
|
||||
if (l == r) {
|
||||
return g_strdup("");
|
||||
} else {
|
||||
newstr = g_strndup(l, r - l);
|
||||
return newstr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_string_remove_char(char *str, char rem) {
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; str[i] != '\0'; i++) {
|
||||
if (str[i] != rem) {
|
||||
str[j] = str[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
str[j] = '\0';
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef MY_STRING_H
|
||||
#define MY_STRING_H 1
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*typedef struct _stringlist_item stringlist_item;
|
||||
struct _stringlist_item {
|
||||
char *data;
|
||||
|
||||
stringlist_item *next;
|
||||
stringlist_item *prev;
|
||||
};
|
||||
|
||||
typedef struct _stringlist stringlist;
|
||||
struct _stringlist {
|
||||
stringlist_item *firstItem;
|
||||
stringlist_item *lastItem;
|
||||
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
void stringlist_add(stringlist * strl, char *data);
|
||||
void stringlist_remove(stringlist * strl, stringlist_item * removed);
|
||||
stringlist *stringlist_create(char *argstr, char *delim);
|
||||
void stringlist_destroy(stringlist * strl);
|
||||
char *stringlist_glue_it(stringlist * strl, char *glue);
|
||||
*/
|
||||
|
||||
int gm_string_to_int(const gchar *str, int *result);
|
||||
char *gm_string_catn(char *str, char *add, unsigned int n);
|
||||
char *gm_string_cat(char *str, char *add);
|
||||
char *gm_string_trim(const gchar *str);
|
||||
void gm_string_remove_char(char *str, char rem);
|
||||
|
||||
#endif
|
647
src/gm-support.c
647
src/gm-support.c
|
@ -1,647 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <regex.h>
|
||||
#include <libgnome/gnome-url.h>
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "gm-support.h"
|
||||
#include "gm-debug.h"
|
||||
#include "gm-pixbuf.h"
|
||||
//#include "if_main.h"
|
||||
|
||||
#define URL_REGEXP "(((mailto|news|telnet|nttp|file|http|sftp|ftp|https|dav|callto)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.@:]+[^]''\\.}>\\) ,\\/\\\"\\!]+(:[0-9]*)?(/|/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"\\!])?"
|
||||
static regex_t url_regexp;
|
||||
|
||||
gchar *
|
||||
gm_fix_decimal_point(gchar *line, int len) {
|
||||
int i;
|
||||
struct lconv *l = localeconv();
|
||||
|
||||
if (l->decimal_point[0] == '.') {
|
||||
return line;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (line[i] == '.') {
|
||||
line[i] = l->decimal_point[0];
|
||||
}
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_fix_decimal_point_rev(gchar *line, int len) {
|
||||
int i;
|
||||
struct lconv *l = localeconv();
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (line[i] == l->decimal_point[0]) {
|
||||
line[i] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_ansi_strip(gchar * s) {
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; s[i] != '\0'; i++) {
|
||||
// Escape sequence, advance to character after 'm'
|
||||
if (s[i] == '\x1B') {
|
||||
while (s[i] != '\0' && s[i] != 'm') {
|
||||
i++;
|
||||
}
|
||||
} else if (s[i] != '\x07') {
|
||||
s[j] = s[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
s[j] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
garray_length(gchar **s) {
|
||||
int i = 0;
|
||||
|
||||
while (s[i] != NULL) {
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void g_list_free_simple(GList *s) {
|
||||
GList *tmp;
|
||||
|
||||
for (tmp = s; tmp; tmp = tmp->next) {
|
||||
g_free(tmp->data);
|
||||
}
|
||||
|
||||
g_list_free(s);
|
||||
}
|
||||
|
||||
gchar *
|
||||
g_list_find_simple(GList *s, gchar *f) {
|
||||
GList *tmp;
|
||||
|
||||
for (tmp = s; tmp; tmp = tmp->next) {
|
||||
if (strcmp(tmp->data, f) == 0) {
|
||||
return tmp->data;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_dialog(gchar * message, GtkMessageType messagebox_type,
|
||||
GtkWindow * parent) {
|
||||
GtkWidget *dlg;
|
||||
|
||||
if (parent == NULL) {
|
||||
//parent = GTK_WINDOW(if_main_get_widget("wndMain"));
|
||||
}
|
||||
|
||||
dlg =
|
||||
gtk_message_dialog_new(parent,
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
messagebox_type, GTK_BUTTONS_OK, message, NULL);
|
||||
gtk_dialog_run(GTK_DIALOG(dlg));
|
||||
gtk_widget_destroy(dlg);
|
||||
}
|
||||
|
||||
void
|
||||
gm_error_dialog(gchar * message, GtkWindow * parent) {
|
||||
gm_dialog(message, GTK_MESSAGE_ERROR, parent);
|
||||
}
|
||||
|
||||
void
|
||||
gm_warning_dialog(gchar * message, GtkWindow * parent) {
|
||||
gm_dialog(message, GTK_MESSAGE_WARNING, parent);
|
||||
}
|
||||
|
||||
void
|
||||
gm_info_dialog(gchar * message, GtkWindow * parent) {
|
||||
gm_dialog(message, GTK_MESSAGE_INFO, parent);
|
||||
}
|
||||
|
||||
void
|
||||
gm_question_dialog(gchar * message, GtkWindow * parent) {
|
||||
gm_dialog(message, GTK_MESSAGE_QUESTION, parent);
|
||||
}
|
||||
|
||||
void
|
||||
gm_do_events() {
|
||||
while (gtk_events_pending()) {
|
||||
gtk_main_iteration();
|
||||
}
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_str_escape(gchar * line) {
|
||||
gchar *newLine;
|
||||
int i, j = 0;
|
||||
|
||||
if (strlen(line) == 0) {
|
||||
return g_strdup("");
|
||||
}
|
||||
|
||||
if (strstr(line, "\"") || strstr(line, "\\")) {
|
||||
newLine = g_new(gchar, (strlen(line) * 2) + 1);
|
||||
|
||||
for (i = 0; i < (int)strlen(line); i++) {
|
||||
if (line[i] == '"' || line[i] == '\\') {
|
||||
newLine[j] = '\\';
|
||||
j++;
|
||||
}
|
||||
newLine[j] = line[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
newLine[j] = '\0';
|
||||
return newLine;
|
||||
} else {
|
||||
return g_strdup(line);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_directory_remove_all(const gchar * path, gboolean remove_self) {
|
||||
GDir *cDir;
|
||||
gchar *name;
|
||||
gchar *newPath;
|
||||
|
||||
if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
|
||||
// Iterate through the files and do the right thingie
|
||||
if ((cDir = g_dir_open(path, 0, NULL))) {
|
||||
while ((name = (gchar *) (g_dir_read_name(cDir))) != NULL) {
|
||||
newPath = g_strconcat(path, "/", name, NULL);
|
||||
gm_directory_remove_all(newPath, TRUE);
|
||||
g_free(newPath);
|
||||
}
|
||||
g_dir_close(cDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (remove_self) {
|
||||
// Its a file, or just empty! MUST...BE...REMOVEEEED!
|
||||
remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
gm_url_regex_match(const gchar *msg, int len, GArray *start, GArray *end) {
|
||||
static gboolean inited = FALSE;
|
||||
regmatch_t matches[1];
|
||||
gint ret = 0, num_matches = 0, offset = 0;
|
||||
gchar *tmp;
|
||||
gint s;
|
||||
|
||||
if (!inited) {
|
||||
memset(&url_regexp, 0, sizeof (regex_t));
|
||||
regcomp(&url_regexp, URL_REGEXP, REG_EXTENDED);
|
||||
inited = TRUE;
|
||||
}
|
||||
|
||||
tmp = g_strndup(msg, len);
|
||||
|
||||
while (!ret) {
|
||||
ret = regexec(&url_regexp, (char *)(tmp + offset), 1, matches, 0);
|
||||
|
||||
if (ret == 0) {
|
||||
if (matches[0].rm_so > matches[0].rm_eo) {
|
||||
break;
|
||||
}
|
||||
|
||||
num_matches++;
|
||||
|
||||
s = matches[0].rm_so + offset;
|
||||
offset = matches[0].rm_eo + offset;
|
||||
|
||||
g_array_append_val(start, s);
|
||||
g_array_append_val(end, offset);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(tmp);
|
||||
|
||||
return num_matches;
|
||||
}
|
||||
|
||||
void
|
||||
gm_open_url (const gchar *url) {
|
||||
if (!url || strlen (url) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* gnome_url_show doesn't work when there's no protocol, so we might
|
||||
* need to add one.
|
||||
*/
|
||||
if (strstr (url, "://") == NULL) {
|
||||
gchar *tmp;
|
||||
|
||||
tmp = g_strconcat ("http://", url, NULL);
|
||||
gnome_url_show(tmp, NULL);
|
||||
g_free (tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
gnome_url_show (url, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gm_fetch_handle_free(GmFetchHandle *g) {
|
||||
GList *tmp;
|
||||
|
||||
g_free(g->cur_file_name);
|
||||
|
||||
for (tmp = g->source_uri; tmp; tmp = tmp->next) {
|
||||
gnome_vfs_uri_unref((GnomeVFSURI*)(tmp->data));
|
||||
}
|
||||
g_list_free(g->source_uri);
|
||||
|
||||
|
||||
for (tmp = g->dest_uri; tmp; tmp = tmp->next) {
|
||||
gnome_vfs_uri_unref((GnomeVFSURI*)(tmp->data));
|
||||
}
|
||||
g_list_free(g->dest_uri);
|
||||
|
||||
g_free(g);
|
||||
}
|
||||
|
||||
GmFetchHandle *
|
||||
gm_fetch_handle_create(GFunc cb, gpointer user_data) {
|
||||
GmFetchHandle *g = g_new0(GmFetchHandle, 1);
|
||||
|
||||
g->cb = cb;
|
||||
g->user_data = user_data;
|
||||
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_OK;
|
||||
g->cur_phase = -1;
|
||||
g->prev_phase = -1;
|
||||
g->cur_file = -1;
|
||||
g->prev_file = -1;
|
||||
g->source_uri = NULL;
|
||||
g->dest_uri = NULL;
|
||||
g->cur_file_name = NULL;
|
||||
g->files_total = 0;
|
||||
g->done = FALSE;
|
||||
g->aborted = FALSE;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
gint
|
||||
gm_fetch_progress(GnomeVFSAsyncHandle *handle,
|
||||
GnomeVFSXferProgressInfo *info,
|
||||
GmFetchHandle *g) {
|
||||
gchar *name;
|
||||
const gchar *err;
|
||||
|
||||
g->cur_phase = info->phase;
|
||||
g->cur_file = info->file_index;
|
||||
g->files_total = info->files_total;
|
||||
g->bytes_total = info->bytes_total;
|
||||
g->file_size = info->file_size;
|
||||
g->bytes_copied = info->bytes_copied;
|
||||
g->total_bytes_copied = info->total_bytes_copied;
|
||||
g->status = info->status;
|
||||
|
||||
if (g->aborted) {
|
||||
g->cb(g, g->user_data);
|
||||
gm_fetch_handle_free(g);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (info->target_name != NULL) {
|
||||
if (g->cur_file_name && strcmp(g->cur_file_name, info->target_name) != 0) {
|
||||
g->cur_phase = GNOME_VFS_XFER_PHASE_FILECOMPLETED;
|
||||
g->cb(g, g->user_data);
|
||||
g->cur_phase = info->phase;
|
||||
|
||||
g_free(g->cur_file_name);
|
||||
g->cur_file_name = NULL;
|
||||
}
|
||||
|
||||
if (!g->cur_file_name) {
|
||||
g->cur_file_name = g_strdup(info->target_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE) {
|
||||
name = gnome_vfs_get_local_path_from_uri(info->target_name);
|
||||
gm_debug_msg(DEBUG_DEFAULT, "gnoemoe_fetch_progress: asking for overwriting %s: yes", name);
|
||||
|
||||
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE;
|
||||
return GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE;
|
||||
} else if (info->status == GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR) {
|
||||
name = gnome_vfs_get_local_path_from_uri(info->target_name);
|
||||
err = gnome_vfs_result_to_string(info->vfs_status);
|
||||
|
||||
gdk_threads_enter();
|
||||
gm_debug_msg(DEBUG_DEFAULT, "gnoemoe_fetch_progress: error for %s: %s", name, err);
|
||||
g->cb(g, g->user_data);
|
||||
gdk_threads_leave();
|
||||
|
||||
g_free(g->cur_file_name);
|
||||
g->cur_file_name = NULL;
|
||||
|
||||
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR;
|
||||
g_free(name);
|
||||
|
||||
return GNOME_VFS_XFER_ERROR_ACTION_SKIP;
|
||||
}
|
||||
|
||||
if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) {
|
||||
if (g->cur_file_name != NULL) {
|
||||
g->cur_phase = GNOME_VFS_XFER_PHASE_FILECOMPLETED;
|
||||
g->cb(g, g->user_data);
|
||||
g->cur_phase = info->phase;
|
||||
}
|
||||
|
||||
g->done = TRUE;
|
||||
g->cb(g, g->user_data);
|
||||
gm_fetch_handle_free(g);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g->prev_status = info->status;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint
|
||||
gm_fetch_interact(GnomeVFSXferProgressInfo *info, gpointer user_data) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
GmFetchHandle *
|
||||
gm_fetch(const GList *source, const GList *dest,
|
||||
GFunc cb, gpointer user_data) {
|
||||
GmFetchHandle *g = gm_fetch_handle_create(cb, user_data);
|
||||
gchar *uri;
|
||||
|
||||
for (; source; source = source->next) {
|
||||
uri = (gchar *)(source->data);
|
||||
g->source_uri = g_list_append(g->source_uri, gnome_vfs_uri_new(uri));
|
||||
}
|
||||
|
||||
for (; dest; dest = dest->next) {
|
||||
uri = (gchar *)(dest->data);
|
||||
g->dest_uri = g_list_append(g->dest_uri, gnome_vfs_uri_new(uri));
|
||||
}
|
||||
|
||||
gnome_vfs_async_xfer(&(g->handle), g->source_uri, g->dest_uri,
|
||||
GNOME_VFS_XFER_DEFAULT|GNOME_VFS_XFER_RECURSIVE,
|
||||
GNOME_VFS_XFER_ERROR_MODE_QUERY,
|
||||
GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
|
||||
GNOME_VFS_PRIORITY_DEFAULT,
|
||||
(GnomeVFSAsyncXferProgressCallback)gm_fetch_progress,
|
||||
g, gm_fetch_interact, g);
|
||||
return g;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_is_end_scrolled(GtkScrolledWindow *wnd, guint charHeight) {
|
||||
GtkAdjustment *ad = gtk_scrolled_window_get_vadjustment(wnd);
|
||||
|
||||
return ((ad->page_size + ad->value) >= ad->upper - (double)charHeight);
|
||||
}
|
||||
|
||||
void
|
||||
gm_scroll_end(GtkTextView *view, gboolean needs) {
|
||||
GtkTextBuffer *buf;
|
||||
GtkTextMark *mark;
|
||||
GtkTextIter iter;
|
||||
|
||||
if (!needs) {
|
||||
return;
|
||||
}
|
||||
|
||||
buf = gtk_text_view_get_buffer(view);
|
||||
mark = gtk_text_buffer_get_mark(buf, "end-of-buffer");
|
||||
|
||||
if (mark == NULL) {
|
||||
gtk_text_buffer_get_end_iter(buf, &iter);
|
||||
mark = gtk_text_buffer_create_mark(buf, "end-of-buffer", &iter, FALSE);
|
||||
}
|
||||
|
||||
gtk_text_view_scroll_to_mark(view, mark, 0.0, TRUE, 1.0, 1.0);
|
||||
}
|
||||
|
||||
#define MAX_BUF 1024
|
||||
|
||||
GString *
|
||||
gm_read_file(const gchar *fname, gboolean readall, OpenLogProgress func, gpointer user_data) {
|
||||
FILE *f;
|
||||
gchar line[MAX_BUF], *tmp;
|
||||
GString *str = NULL;
|
||||
long bytes_read = 0, bytes_total = 0;
|
||||
|
||||
if (!fname) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = fopen(fname, "r");
|
||||
|
||||
if (f) {
|
||||
fseek(f, 0, SEEK_END);
|
||||
bytes_total = ftell(f);
|
||||
rewind(f);
|
||||
|
||||
str = g_string_new("");
|
||||
|
||||
while (fgets((char *) &line, MAX_BUF, f) != NULL) {
|
||||
bytes_read += strlen((char *)&line);
|
||||
tmp = NULL;
|
||||
if (g_utf8_validate(line, -1, NULL)) {
|
||||
if (readall) {
|
||||
str = g_string_append(str, line);
|
||||
}
|
||||
tmp = g_strdup(line);
|
||||
} else {
|
||||
tmp = g_locale_to_utf8(line, -1, NULL, NULL, NULL);
|
||||
|
||||
if (!tmp) {
|
||||
tmp = g_convert(line, -1, "UTF-8", "ISO-8859-15", NULL, NULL, NULL);
|
||||
}
|
||||
if (!tmp) {
|
||||
tmp = g_convert(line, -1, "UTF-8", "ISO-8859-15", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (readall) {
|
||||
str = g_string_append(str, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (func != NULL) {
|
||||
func(bytes_read, bytes_total, tmp, user_data);
|
||||
} else {
|
||||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return str;
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "support_read_file: file (%s) could not be read: %s",
|
||||
fname, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_create_tab_label(const gchar *icon, const gchar *caption, gboolean has_exit,
|
||||
GmLabelInfo *info) {
|
||||
/* First create the gbox (size 3) which will contain an icon, a label and a
|
||||
exit button if has_exit is true */
|
||||
GtkWidget *hboxTabLabel;
|
||||
gint h, w;
|
||||
|
||||
hboxTabLabel = gtk_hbox_new(FALSE, 3);
|
||||
|
||||
gtk_widget_show(hboxTabLabel);
|
||||
|
||||
info->image_icon = gtk_image_new_from_pixbuf(
|
||||
gm_pixbuf_get_at_size(icon, 16, 16));
|
||||
gtk_widget_set_size_request(info->image_icon, 16, 16);
|
||||
gtk_widget_show(info->image_icon);
|
||||
gtk_box_pack_start(GTK_BOX(hboxTabLabel), info->image_icon, TRUE, TRUE, 0);
|
||||
|
||||
info->label_name = gtk_label_new(caption);
|
||||
gtk_widget_show(info->label_name);
|
||||
gtk_box_pack_start(GTK_BOX(hboxTabLabel), info->label_name, FALSE, FALSE, 0);
|
||||
|
||||
if (has_exit) {
|
||||
info->button_exit = gtk_button_new();
|
||||
gtk_widget_show(info->button_exit);
|
||||
|
||||
gtk_box_pack_end(GTK_BOX(hboxTabLabel), info->button_exit , FALSE,
|
||||
FALSE, 0);
|
||||
|
||||
gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);
|
||||
gtk_widget_set_size_request(info->button_exit , w + 2, h + 2);
|
||||
gtk_button_set_relief(GTK_BUTTON(info->button_exit ), GTK_RELIEF_NONE);
|
||||
gtk_button_set_focus_on_click(GTK_BUTTON(info->button_exit), FALSE);
|
||||
|
||||
info->image_exit = gtk_image_new_from_stock("gtk-close",
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_show(info->image_exit);
|
||||
gtk_container_add(GTK_CONTAINER(info->button_exit), info->image_exit);
|
||||
}
|
||||
|
||||
return hboxTabLabel;
|
||||
}
|
||||
|
||||
void
|
||||
gm_widget_destroy_data(GtkWidget *caller, GtkWidget *destroyer) {
|
||||
if (GTK_IS_WIDGET(destroyer)) {
|
||||
gtk_widget_destroy(destroyer);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_default_charset() {
|
||||
const gchar *loc = NULL;
|
||||
g_get_charset(&loc);
|
||||
|
||||
if (loc == NULL || strlen(loc) == 0) {
|
||||
loc = "ISO-8859-15";
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
void
|
||||
gm_notebook_focus_from_label(GtkNotebook *note, gchar *caption) {
|
||||
int p = gtk_notebook_get_n_pages(note);
|
||||
int i;
|
||||
GtkWidget *child;
|
||||
|
||||
for (i = 0; i < p; i++) {
|
||||
child = gtk_notebook_get_nth_page(note, i);
|
||||
if (!g_strcasecmp(gtk_notebook_get_tab_label_text(note, child),
|
||||
caption)) {
|
||||
gtk_notebook_set_current_page(note, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_string_skip_space(gchar **ptr) {
|
||||
while (**ptr != '\0' && g_unichar_isspace(g_utf8_get_char(*ptr))) {
|
||||
*ptr = g_utf8_next_char(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_string_skip_nonspace(gchar **ptr) {
|
||||
while (**ptr != '\0' && !g_unichar_isspace(g_utf8_get_char(*ptr))) {
|
||||
*ptr = g_utf8_next_char(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_string_skip_till(gchar **ptr, gchar const *find) {
|
||||
gchar const *fptr;
|
||||
gunichar check;
|
||||
|
||||
while (**ptr != '\0') {
|
||||
check = g_utf8_get_char(*ptr);
|
||||
|
||||
for (fptr = find; *fptr; ++fptr) {
|
||||
// CHECK: find should also be treated as utf8!
|
||||
if (check == (gunichar)(*fptr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*ptr = g_utf8_next_char(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_to_utf8_with_fallback(gchar const *text, gssize len, gchar const *from,
|
||||
gchar const *fallback) {
|
||||
gchar *res;
|
||||
gsize read, written;
|
||||
GString *str = g_string_new("");
|
||||
|
||||
// TODO: use g_iconv instead of g_convert
|
||||
|
||||
while ((res = g_convert(text, len, "UTF-8", from, &read, &written, NULL))
|
||||
== NULL) {
|
||||
res = g_convert(text, read, "UTF-8", from, NULL, NULL, NULL);
|
||||
str = g_string_append(str, res);
|
||||
|
||||
str = g_string_append(str, fallback);
|
||||
text = text + read + 1;
|
||||
|
||||
if (len != -1)
|
||||
len = len - read - 1;
|
||||
}
|
||||
|
||||
str = g_string_append(str, res);
|
||||
g_free(res);
|
||||
|
||||
res = str->str;
|
||||
g_string_free(str, FALSE);
|
||||
return res;
|
||||
}
|
156
src/gm-support.h
156
src/gm-support.h
|
@ -1,156 +0,0 @@
|
|||
#ifndef __GM_SUPPORT_H__
|
||||
#define __GM_SUPPORT_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
|
||||
/*
|
||||
* Standard gettext macros.
|
||||
*/
|
||||
#ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# undef _
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
# ifdef gettext_noop
|
||||
# define N_(String) gettext_noop (String)
|
||||
# else
|
||||
# define N_(String) (String)
|
||||
# endif
|
||||
#else
|
||||
# define textdomain(String) (String)
|
||||
# define gettext(String) (String)
|
||||
# define dgettext(Domain,Message) (Message)
|
||||
# define dcgettext(Domain,Message,Type) (Message)
|
||||
# define bindtextdomain(Domain,Directory) (Domain)
|
||||
#ifndef _
|
||||
# define _(String) (String)
|
||||
#endif
|
||||
# define N_(String) (String)
|
||||
#endif
|
||||
|
||||
#define CALC_COLOR_RANGE(x) (int)((-(1/((x * 0.5)+1))+1)*255)
|
||||
|
||||
/** \defgroup support */
|
||||
|
||||
/** \ingroup support
|
||||
* \brief Widget container for tabs
|
||||
*
|
||||
* Contains all widgets that could be useful to be modified.
|
||||
* Stored here because it makes it easier to look them up.
|
||||
*
|
||||
*/
|
||||
typedef struct _GmLabelInfo GmLabelInfo;
|
||||
struct _GmLabelInfo {
|
||||
/** \brief GtkButton widget
|
||||
*
|
||||
* GtkButton widget, reference to the tabs exit button
|
||||
*/
|
||||
GtkWidget *button_exit;
|
||||
|
||||
/** \brief GtkImage widget
|
||||
*
|
||||
* GtkImage widget, reference to the tabs exit button image
|
||||
*/
|
||||
GtkWidget *image_exit;
|
||||
|
||||
/** \brief GtkLabel widget
|
||||
*
|
||||
* GtkLabel widget, reference to the tabs label
|
||||
*/
|
||||
GtkWidget *label_name;
|
||||
|
||||
/** \brief GtkImage widget
|
||||
*
|
||||
* GtkImage widget, reference to the tabs icon
|
||||
*/
|
||||
GtkWidget *image_icon;
|
||||
};
|
||||
|
||||
/** \ingroup support
|
||||
* \brief Key/value pair struct
|
||||
*
|
||||
* Contains two fields. Used to create hash tables
|
||||
*
|
||||
*/
|
||||
typedef struct _GmKeyValuePair {
|
||||
gchar *key; /**< the key */
|
||||
gchar *value; /**< the value */
|
||||
} GmKeyValuePair;
|
||||
|
||||
typedef struct _GmFetchHandle GmFetchHandle;
|
||||
struct _GmFetchHandle {
|
||||
GnomeVFSAsyncHandle *handle;
|
||||
|
||||
GFunc cb;
|
||||
gpointer user_data;
|
||||
|
||||
GList *source_uri;
|
||||
GList *dest_uri;
|
||||
|
||||
GnomeVFSXferPhase cur_phase;
|
||||
GnomeVFSXferPhase prev_phase;
|
||||
GnomeVFSXferProgressStatus prev_status;
|
||||
GnomeVFSXferProgressStatus status;
|
||||
|
||||
GnomeVFSFileSize bytes_total;
|
||||
GnomeVFSFileSize file_size;
|
||||
GnomeVFSFileSize bytes_copied;
|
||||
GnomeVFSFileSize total_bytes_copied;
|
||||
|
||||
gulong files_total;
|
||||
gulong cur_file;
|
||||
gulong prev_file;
|
||||
gchar *cur_file_name;
|
||||
|
||||
gboolean aborted;
|
||||
gboolean done;
|
||||
};
|
||||
|
||||
gchar *gm_fix_decimal_point(gchar *line, int len);
|
||||
gchar *gm_fix_decimal_point_rev(gchar *line, int len);
|
||||
gchar *gm_ansi_strip(gchar * s);
|
||||
int garray_length(gchar **s);
|
||||
void g_list_free_simple(GList *s);
|
||||
gchar *g_list_find_simple(GList *s, gchar *f);
|
||||
|
||||
void gm_error_dialog(gchar * message, GtkWindow * parent);
|
||||
void gm_warning_dialog(gchar * message, GtkWindow * parent);
|
||||
void gm_info_dialog(gchar * message, GtkWindow * parent);
|
||||
void gm_question_dialog(gchar * message, GtkWindow * parent);
|
||||
|
||||
void gm_do_events();
|
||||
|
||||
gchar *gm_str_escape(gchar * line);
|
||||
void gm_directory_remove_all(const gchar * path, gboolean remove_self);
|
||||
|
||||
gint gm_url_regex_match(const gchar *msg, int len, GArray *start, GArray *end);
|
||||
void gm_open_url (const gchar *url);
|
||||
|
||||
GmFetchHandle * gm_fetch(const GList *source, const GList *dest,
|
||||
GFunc cb, gpointer user_data);
|
||||
void gm_fetch_handle_free(GmFetchHandle *g);
|
||||
|
||||
gboolean gm_is_end_scrolled(GtkScrolledWindow *wnd, guint charHeight);
|
||||
void gm_scroll_end(GtkTextView *view, gboolean needs);
|
||||
|
||||
typedef void (*OpenLogProgress) (long, long, gchar *, gpointer);
|
||||
GString *gm_read_file(const gchar *fname, gboolean readall,
|
||||
OpenLogProgress func, gpointer user_data);
|
||||
GtkWidget *gm_create_tab_label(const gchar *icon, const gchar *caption,
|
||||
gboolean has_exit, GmLabelInfo *info);
|
||||
void gm_widget_destroy_data(GtkWidget *caller, GtkWidget *destroyer);
|
||||
const gchar *gm_default_charset();
|
||||
void gm_notebook_focus_from_label(GtkNotebook *note, gchar *caption);
|
||||
|
||||
void gm_string_skip_space(gchar **ptr);
|
||||
void gm_string_skip_nonspace(gchar **ptr);
|
||||
void gm_string_skip_till(gchar **ptr, gchar const *find);
|
||||
|
||||
gchar *gm_to_utf8_with_fallback(gchar const *text, gssize len, gchar const *from,
|
||||
gchar const *fallback);
|
||||
|
||||
#endif /* __GM_SUPPORT_H__ */
|
|
@ -1,55 +0,0 @@
|
|||
|
||||
#include "gm-tray.h"
|
||||
#include "eggtrayicon.h"
|
||||
|
||||
#define GM_TRAY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_TRAY, GmTrayPrivate))
|
||||
|
||||
typedef enum _tray_type {
|
||||
TRAY_ICON_DEFAULT,
|
||||
TRAY_ICON_ACTIVE,
|
||||
TRAY_ICON_NOTIFY
|
||||
} tray_type;
|
||||
|
||||
struct _GmTrayPrivate {
|
||||
GtkWidget *event_box;
|
||||
GtkWidget *image;
|
||||
GtkTooltips *tooltips;
|
||||
|
||||
GtkWidget *popup_menu;
|
||||
GtkWidget *show_popup_item;
|
||||
GtkWidget *hide_popup_item;
|
||||
|
||||
guint flash_timeout;
|
||||
tray_type iconnr;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint tray_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmTray, gm_tray, EGG_TYPE_TRAY_ICON)
|
||||
|
||||
static void
|
||||
gm_tray_finalize(GObject *object) {
|
||||
GmTray *view = GM_TRAY(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_tray_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_tray_class_init(GmTrayClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_tray_finalize;
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmTrayPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_tray_init(GmTray *tray) {
|
||||
tray->private = GM_TRAY_GET_PRIVATE(tray);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef __GM_TRAY_H__
|
||||
#define __GM_TRAY_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "eggtrayicon.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_TRAY (gm_tray_get_type())
|
||||
#define GM_TRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TRAY, GmTray))
|
||||
#define GM_TRAY_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TRAY, GmTray const))
|
||||
#define GM_TRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_TRAY, GmTrayClass))
|
||||
#define GM_IS_TRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_TRAY))
|
||||
#define GM_IS_TRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_TRAY))
|
||||
#define GM_TRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_TRAY, GmTrayClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmTrayPrivate GmTrayPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmTray GmTray;
|
||||
|
||||
struct _GmTray {
|
||||
EggTrayIcon trayicon;
|
||||
|
||||
/*< private > */
|
||||
GmTrayPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmTrayClass GmTrayClass;
|
||||
|
||||
struct _GmTrayClass {
|
||||
EggTrayIconClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
};
|
||||
|
||||
GType gm_tray_get_type(void) G_GNUC_CONST;
|
||||
GmTray *gm_tray_new(void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_TRAY_H__ */
|
|
@ -1,440 +0,0 @@
|
|||
#include <strings.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include "gm-triggers.h"
|
||||
#include "gm-debug.h"
|
||||
|
||||
#define GM_TRIGGERS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_TRIGGERS, GmTriggersPrivate))
|
||||
|
||||
typedef struct _trigger_trans {
|
||||
gint type;
|
||||
const gchar *name;
|
||||
} trigger_trans;
|
||||
|
||||
static const trigger_trans table_conditions[] = {
|
||||
{TCT_CONTAINS, "contains"},
|
||||
{TCT_NOT_CONTAINS, "not-contains"},
|
||||
{TCT_BEGINS, "begins"},
|
||||
{TCT_NOT_BEGINS, "not-begins"},
|
||||
{TCT_ENDS, "ends"},
|
||||
{TCT_NOT_ENDS, "not-ends"},
|
||||
{TCT_MATCHES, "matches"},
|
||||
{TCT_NOT_MATCHES, "not-matches"},
|
||||
{TCT_USER_ONLINE, "online"},
|
||||
{TCT_USER_OFFLINE, "offline"},
|
||||
{TCT_USER_IDLE, "idle"},
|
||||
{TCT_USER_IDLE_OFF, "idle-off"},
|
||||
{TCT_USER_AWAY, "away"},
|
||||
{TCT_USER_AWAY_OFF, "away-off"},
|
||||
{-1, NULL}
|
||||
};
|
||||
|
||||
static const trigger_trans table_actions[] = {
|
||||
{TAT_HIGHLIGHT_LINE, "highlight-line"},
|
||||
{TAT_HIGHLIGHT_MATCH, "highlight-match"},
|
||||
{TAT_BEEP, "beep"},
|
||||
{TAT_PLAY_SOUND, "play-sound"},
|
||||
{TAT_NOTIFY, "notify"},
|
||||
#ifdef HASRUBY
|
||||
{TAT_RUN_SCRIPT, "run-script"},
|
||||
#endif
|
||||
{TAT_RUN, "run"},
|
||||
{-1, NULL}
|
||||
};
|
||||
|
||||
struct _GmTriggersPrivate {
|
||||
GList *triggers;
|
||||
gchar *path;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
/*enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint triggers_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(GmTriggers, gm_triggers, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_triggers_finalize(GObject *object) {
|
||||
GmTriggers *trg = GM_TRIGGERS(object);
|
||||
GList *item;
|
||||
|
||||
for (item = trg->priv->triggers; item; item = item->next) {
|
||||
gm_trigger_free((GmTrigger *)(item->data));
|
||||
}
|
||||
|
||||
g_free(trg->priv->path);
|
||||
g_list_free(trg->priv->triggers);
|
||||
|
||||
G_OBJECT_CLASS(gm_triggers_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_triggers_class_init(GmTriggersClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_triggers_finalize;
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmTriggersPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_triggers_init(GmTriggers *trg) {
|
||||
trg->priv = GM_TRIGGERS_GET_PRIVATE(trg);
|
||||
trg->priv->triggers = NULL;
|
||||
trg->priv->path = NULL;
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_trigger_new() {
|
||||
return g_new0(GmTrigger, 1);
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_trigger_list_dup(GList *list) {
|
||||
GList *result = NULL;
|
||||
GList *item;
|
||||
GmTriggerData *data;
|
||||
|
||||
for (item = list; item; item = item->next) {
|
||||
data = (GmTriggerData *)(item->data);
|
||||
result = g_list_append(result, gm_trigger_data_new(data->type,
|
||||
g_strdup(data->data)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GmTrigger *
|
||||
gm_trigger_dup(GmTrigger *source) {
|
||||
GmTrigger *result = gm_trigger_new();
|
||||
|
||||
result->name = g_strdup(source->name);
|
||||
result->event = source->event;
|
||||
result->conditions = gm_trigger_list_dup(source->conditions);
|
||||
result->actions = gm_trigger_list_dup(source->actions);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_set_name(GmTrigger *trigger, const gchar *name) {
|
||||
g_free(trigger->name);
|
||||
trigger->name = g_strdup(name);
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_free_list(GList *list) {
|
||||
GList *item;
|
||||
GmTriggerData *data;
|
||||
|
||||
for (item = list; item; item = item->next) {
|
||||
data = (GmTriggerData *)(item->data);
|
||||
gm_trigger_data_free(data);
|
||||
}
|
||||
|
||||
g_list_free(list);
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_free(GmTrigger *trigger) {
|
||||
gm_trigger_free_list(trigger->conditions);
|
||||
gm_trigger_free_list(trigger->actions);
|
||||
g_free(trigger->name);
|
||||
|
||||
g_free(trigger);
|
||||
}
|
||||
|
||||
GmTriggerData *
|
||||
gm_trigger_data_new(gint type, gchar *data) {
|
||||
GmTriggerData *tdata = g_new0(GmTriggerData, 1);
|
||||
tdata->type = type;
|
||||
tdata->data = data;
|
||||
|
||||
memset(&(tdata->expr), 0, sizeof(regex_t));
|
||||
|
||||
switch (tdata->type) {
|
||||
case TCT_MATCHES: case TCT_NOT_MATCHES: case TCT_USER_ONLINE:
|
||||
case TCT_USER_OFFLINE: case TCT_USER_IDLE: case TCT_USER_IDLE_OFF:
|
||||
case TCT_USER_AWAY: case TCT_USER_AWAY_OFF:
|
||||
regcomp(&(tdata->expr), tdata->data, REG_EXTENDED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return tdata;
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_data_free(GmTriggerData *tdata) {
|
||||
g_free(tdata->data);
|
||||
g_free(tdata);
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_add_condition(GmTrigger *trigger, GmTriggerData *condition) {
|
||||
trigger->conditions = g_list_append(trigger->conditions, condition);
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_add_action(GmTrigger *trigger, GmTriggerData *action) {
|
||||
trigger->actions = g_list_append(trigger->actions, action);
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_set_conditions(GmTrigger *trigger, GList *conditions) {
|
||||
gm_trigger_free_list(trigger->conditions);
|
||||
trigger->conditions = conditions;
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_set_actions(GmTrigger *trigger, GList *actions) {
|
||||
gm_trigger_free_list(trigger->actions);
|
||||
trigger->actions = actions;
|
||||
}
|
||||
|
||||
gint
|
||||
gm_trigger_type_from_name(const gchar *name,
|
||||
const trigger_trans *trans_table) {
|
||||
int i;
|
||||
|
||||
for (i = 0; trans_table[i].type != -1; i++) {
|
||||
if (strcasecmp(trans_table[i].name, name) == 0) {
|
||||
return trans_table[i].type;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_trigger_name_from_type(gint type, const trigger_trans *trans_table) {
|
||||
int i;
|
||||
|
||||
for (i = 0; trans_table[i].type != -1; i++) {
|
||||
if (trans_table[i].type == type) {
|
||||
return trans_table[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_parse_trigger(GmTriggers *trg, xmlDocPtr doc, xmlNodePtr node) {
|
||||
GmTrigger *result = gm_trigger_new();
|
||||
xmlChar *tmp, *tmp2;
|
||||
gint type;
|
||||
|
||||
tmp = xmlGetProp(node, (const xmlChar *)"name");
|
||||
result->name = (gchar *)tmp;
|
||||
|
||||
tmp = xmlGetProp(node, (const xmlChar *)"event");
|
||||
|
||||
if (xmlStrcmp(tmp, (const xmlChar *)("world")) == 0) {
|
||||
result->event = TT_OUTPUT;
|
||||
} else if (xmlStrcmp(tmp, (const xmlChar *)("player")) == 0){
|
||||
result->event = TT_USERS;
|
||||
} else {
|
||||
xmlFree(tmp);
|
||||
gm_trigger_free(result);
|
||||
return;
|
||||
}
|
||||
|
||||
xmlFree(tmp);
|
||||
|
||||
for (node = node->xmlChildrenNode; node; node = node->next) {
|
||||
tmp = xmlGetProp(node, (const xmlChar *)"type");
|
||||
tmp2 = xmlGetProp(node, (const xmlChar *)"data");
|
||||
|
||||
if (xmlStrcmp(node->name, (const xmlChar *)("condition")) == 0) {
|
||||
type = gm_trigger_type_from_name((const gchar *)(tmp),
|
||||
table_conditions);
|
||||
|
||||
if (type != -1) {
|
||||
gm_trigger_add_condition(result, gm_trigger_data_new(type,
|
||||
g_strdup((char *)tmp2)));
|
||||
}
|
||||
} else if (xmlStrcmp(node->name, (const xmlChar *)("action")) == 0) {
|
||||
type = gm_trigger_type_from_name((const gchar *)(tmp),
|
||||
table_actions);
|
||||
|
||||
if (type != -1) {
|
||||
gm_trigger_add_action(result, gm_trigger_data_new(type,
|
||||
g_strdup((char *)tmp2)));
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(tmp2);
|
||||
xmlFree(tmp);
|
||||
}
|
||||
|
||||
gm_triggers_add(trg, result);
|
||||
}
|
||||
|
||||
GmTriggers *
|
||||
gm_triggers_new() {
|
||||
GmTriggers *trg = GM_TRIGGERS(g_object_new(GM_TYPE_TRIGGERS, NULL));
|
||||
|
||||
return trg;
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_add(GmTriggers *trg, GmTrigger *t) {
|
||||
trg->priv->triggers = g_list_append(trg->priv->triggers, t);
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_clear(GmTriggers *trg) {
|
||||
GList *item;
|
||||
|
||||
for (item = trg->priv->triggers; item; item = item->next) {
|
||||
gm_trigger_free((GmTrigger *)(item->data));
|
||||
}
|
||||
|
||||
g_list_free(trg->priv->triggers);
|
||||
trg->priv->triggers = NULL;
|
||||
}
|
||||
|
||||
GmTriggers *
|
||||
gm_triggers_new_from_file(gchar *filename) {
|
||||
GmTriggers *trg = GM_TRIGGERS(g_object_new(GM_TYPE_TRIGGERS, NULL));
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
|
||||
if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmTriggers.NewFromFile: Trigger file does not exist");
|
||||
return trg;
|
||||
|
||||
}
|
||||
|
||||
trg->priv->path = g_strdup(filename);
|
||||
doc = xmlParseFile(filename);
|
||||
|
||||
if (doc == NULL) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmTriggers.NewFromFile: Error on parsing triggers");
|
||||
return trg;
|
||||
}
|
||||
|
||||
cur = xmlDocGetRootElement(doc);
|
||||
|
||||
if (cur == NULL) {
|
||||
xmlFreeDoc(doc);
|
||||
return trg;
|
||||
}
|
||||
|
||||
if (xmlStrcmp(cur->name, (const xmlChar *)("triggers"))) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmTriggers.NewFromFile: invalid root node");
|
||||
xmlFreeDoc(doc);
|
||||
return trg;
|
||||
}
|
||||
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)("trigger"))) {
|
||||
gm_triggers_parse_trigger(trg, doc, cur);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
return trg;
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_set_path(GmTriggers *trg, gchar *path) {
|
||||
g_free(trg->priv->path);
|
||||
trg->priv->path = g_strdup(path);
|
||||
}
|
||||
|
||||
void
|
||||
gm_trigger_rules_xml(GmTrigger *t, xmlNodePtr trig) {
|
||||
GmTriggerData *data;
|
||||
GList *item;
|
||||
xmlNodePtr child;
|
||||
|
||||
for (item = t->conditions; item; item = item->next) {
|
||||
data = (GmTriggerData *)(item->data);
|
||||
child = xmlNewChild(trig, NULL, (const xmlChar *)("condition"), NULL);
|
||||
xmlNewProp(child, (const xmlChar *)("type"), (const xmlChar *)
|
||||
(gm_trigger_name_from_type(data->type, table_conditions)));
|
||||
|
||||
if (data->data) {
|
||||
xmlNewProp(child, (const xmlChar *)("data"), (const xmlChar *)
|
||||
(data->data));
|
||||
}
|
||||
}
|
||||
|
||||
for (item = t->actions; item; item = item->next) {
|
||||
data = (GmTriggerData *)(item->data);
|
||||
child = xmlNewChild(trig, NULL, (const xmlChar *)("action"), NULL);
|
||||
xmlNewProp(child, (const xmlChar *)("type"), (const xmlChar *)
|
||||
(gm_trigger_name_from_type(data->type, table_actions)));
|
||||
|
||||
if (data->data) {
|
||||
xmlNewProp(child, (const xmlChar *)("data"), (const xmlChar *)
|
||||
(data->data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_save(GmTriggers *trg) {
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr root;
|
||||
xmlNodePtr trig;
|
||||
GList *item;
|
||||
GmTrigger *t;
|
||||
|
||||
g_return_if_fail(trg->priv->path != NULL);
|
||||
|
||||
doc = xmlNewDoc((const xmlChar *)("1.0"));
|
||||
root = xmlNewNode(NULL, (const xmlChar *)("triggers"));
|
||||
xmlDocSetRootElement(doc, root);
|
||||
|
||||
for (item = trg->priv->triggers; item; item = item->next) {
|
||||
t = (GmTrigger *)(item->data);
|
||||
trig = xmlNewChild(root, NULL, (const xmlChar *)("trigger"), NULL);
|
||||
xmlNewProp(trig, (const xmlChar *)("name"), (const xmlChar *)(t->name));
|
||||
|
||||
if (t->event == TT_OUTPUT) {
|
||||
xmlNewProp(trig, (const xmlChar *)("event"), (const xmlChar *)("world"));
|
||||
} else {
|
||||
xmlNewProp(trig, (const xmlChar *)("event"), (const xmlChar *)("player"));
|
||||
}
|
||||
|
||||
gm_trigger_rules_xml(t, trig);
|
||||
}
|
||||
|
||||
xmlSaveFormatFileEnc(trg->priv->path, doc, "UTF-8", 1);
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
||||
void
|
||||
gm_triggers_save_as(GmTriggers *trg, const gchar *path) {
|
||||
g_free(trg->priv->path);
|
||||
trg->priv->path = g_strdup(path);
|
||||
gm_triggers_save(trg);
|
||||
}
|
||||
|
||||
GmTriggers *
|
||||
gm_triggers_dup(GmTriggers *source) {
|
||||
GmTriggers *trg = GM_TRIGGERS(g_object_new(GM_TYPE_TRIGGERS, NULL));
|
||||
GList *item;
|
||||
|
||||
for (item = source->priv->triggers; item; item = item->next) {
|
||||
trg->priv->triggers = g_list_append(trg->priv->triggers,
|
||||
gm_trigger_dup((GmTrigger *)(item->data)));
|
||||
}
|
||||
|
||||
return trg;
|
||||
}
|
||||
|
||||
const GList *
|
||||
gm_triggers_list(GmTriggers *trg) {
|
||||
return trg->priv->triggers;
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
#ifndef __GM_TRIGGERS_H__
|
||||
#define __GM_TRIGGERS_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <regex.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_TRIGGERS (gm_triggers_get_type())
|
||||
#define GM_TRIGGERS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TRIGGERS, GmTriggers))
|
||||
#define GM_TRIGGERS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TRIGGERS, GmTriggers const))
|
||||
#define GM_TRIGGERS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_TRIGGERS, GmTriggersClass))
|
||||
#define GM_IS_TRIGGERS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_TRIGGERS))
|
||||
#define GM_IS_TRIGGERS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_TRIGGERS))
|
||||
#define GM_TRIGGERS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_TRIGGERS, GmTriggersClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmTriggersPrivate GmTriggersPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmTriggers GmTriggers;
|
||||
|
||||
struct _GmTriggers {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmTriggersPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmTriggersClass GmTriggersClass;
|
||||
|
||||
struct _GmTriggersClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
};
|
||||
|
||||
typedef enum _GmTriggerType {
|
||||
TT_OUTPUT = 0,
|
||||
TT_USERS
|
||||
} GmTriggerType;
|
||||
|
||||
typedef enum _GmTriggerConditionType {
|
||||
TCT_CONTAINS = 0,
|
||||
TCT_NOT_CONTAINS,
|
||||
TCT_BEGINS,
|
||||
TCT_NOT_BEGINS,
|
||||
TCT_ENDS,
|
||||
TCT_NOT_ENDS,
|
||||
TCT_MATCHES,
|
||||
TCT_NOT_MATCHES,
|
||||
TCT_USER_ONLINE,
|
||||
TCT_USER_OFFLINE,
|
||||
TCT_USER_IDLE,
|
||||
TCT_USER_IDLE_OFF,
|
||||
TCT_USER_AWAY,
|
||||
TCT_USER_AWAY_OFF
|
||||
} GmTriggerConditionType;
|
||||
|
||||
typedef enum _GmTriggerActionType {
|
||||
TAT_HIGHLIGHT_LINE = 0,
|
||||
TAT_HIGHLIGHT_MATCH,
|
||||
TAT_BEEP,
|
||||
TAT_PLAY_SOUND,
|
||||
TAT_NOTIFY,
|
||||
TAT_RUN_SCRIPT,
|
||||
TAT_RUN
|
||||
} GmTriggerActionType;
|
||||
|
||||
typedef struct _GmTriggerData {
|
||||
gint type;
|
||||
gchar *data;
|
||||
regex_t expr;
|
||||
} GmTriggerData;
|
||||
|
||||
typedef struct _GmTrigger {
|
||||
gchar *name;
|
||||
GmTriggerType event;
|
||||
|
||||
GList *conditions;
|
||||
GList *actions;
|
||||
} GmTrigger;
|
||||
|
||||
GType gm_triggers_get_type(void) G_GNUC_CONST;
|
||||
GmTriggers *gm_triggers_new(void);
|
||||
GmTriggers *gm_triggers_new_from_file(gchar *filename);
|
||||
void gm_triggers_save(GmTriggers *triggers);
|
||||
void gm_triggers_save_as(GmTriggers *trg, const gchar *path);
|
||||
void gm_triggers_set_path(GmTriggers *trg, gchar *path);
|
||||
GmTriggers *gm_triggers_dup(GmTriggers *source);
|
||||
const GList *gm_triggers_list(GmTriggers *trg);
|
||||
void gm_triggers_add(GmTriggers *trg, GmTrigger *t);
|
||||
void gm_triggers_clear(GmTriggers *trg);
|
||||
|
||||
GmTrigger *gm_trigger_new();
|
||||
void gm_trigger_free(GmTrigger *trigger);
|
||||
GmTrigger *gm_trigger_dup(GmTrigger *source);
|
||||
void gm_trigger_set_name(GmTrigger *trigger, const gchar *name);
|
||||
void gm_trigger_free_list(GList *list);
|
||||
void gm_trigger_add_condition(GmTrigger *trigger, GmTriggerData *condition);
|
||||
void gm_trigger_add_action(GmTrigger *trigger, GmTriggerData *action);
|
||||
void gm_trigger_set_conditions(GmTrigger *trigger, GList *conditions);
|
||||
void gm_trigger_set_actions(GmTrigger *trigger, GList *actions);
|
||||
|
||||
GmTriggerData *gm_trigger_data_new(gint type, gchar *data);
|
||||
void gm_trigger_data_free(GmTriggerData *tdata);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_TRIGGERS_H__ */
|
77
src/gm-ui.h
77
src/gm-ui.h
|
@ -1,77 +0,0 @@
|
|||
#ifndef __GM_UI_H__
|
||||
#define __GM_UI_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "widgets/gm-app-view.h"
|
||||
#include "gm-support.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
static const GtkActionEntry gm_sensitive_menu_entries[] =
|
||||
{
|
||||
/* Toplevel */
|
||||
{"World", NULL, N_("_World")},
|
||||
{"Edit", NULL, N_("_Edit")},
|
||||
{"View", NULL, N_("_View")},
|
||||
{"Help", NULL, N_("_Help")},
|
||||
|
||||
/* World menu */
|
||||
{"WorldNew", GTK_STOCK_NEW, N_("New World..."), "<control>N",
|
||||
N_("Create a new world"), G_CALLBACK(on_gm_app_view_world_new)},
|
||||
{"WorldQuit", GTK_STOCK_QUIT, NULL, NULL,
|
||||
N_("Quit the program"), G_CALLBACK(on_gm_app_view_world_quit)},
|
||||
|
||||
/* Edit menu */
|
||||
{"EditWorlds", NULL, N_("Worlds..."), "<control>L",
|
||||
N_("Edit worlds"), G_CALLBACK(on_gm_app_view_edit_worlds)},
|
||||
{"EditPreferences", GTK_STOCK_PREFERENCES, NULL, NULL,
|
||||
N_("Configure the application"),
|
||||
G_CALLBACK(on_gm_app_view_edit_preferences)},
|
||||
|
||||
/* View menu */
|
||||
{"ViewMcp", NULL, N_("MCP"), NULL,
|
||||
N_("View MCP console"), G_CALLBACK(on_gm_app_view_view_mcp)},
|
||||
{"ViewScripts", NULL, N_("Scripts"), NULL,
|
||||
N_("View scripts"), G_CALLBACK(on_gm_app_view_view_scripts)},
|
||||
|
||||
/* Help menu */
|
||||
{"HelpAbout", GTK_STOCK_ABOUT, NULL, NULL,
|
||||
N_("About this application"), G_CALLBACK(on_gm_app_view_help_about)}
|
||||
};
|
||||
|
||||
static const GtkActionEntry gm_menu_entries[] =
|
||||
{
|
||||
/* File menu */
|
||||
{"WorldConnect", GTK_STOCK_NETWORK, N_("Connect"), "<control><shift>C",
|
||||
N_("Connect or disconnect the current world"),
|
||||
G_CALLBACK(on_gm_app_view_world_connect)},
|
||||
{"WorldClose", GTK_STOCK_CLOSE, NULL, NULL,
|
||||
N_("Close current world"), G_CALLBACK(on_gm_app_view_world_close)},
|
||||
{"WorldLogs", GTK_STOCK_FILE, N_("Logs"), NULL,
|
||||
N_("View current world logs"), G_CALLBACK(on_gm_app_view_world_logs)},
|
||||
{"WorldInfo", GTK_STOCK_ABOUT, N_("In_fo"), NULL,
|
||||
N_("View current world info"), G_CALLBACK(on_gm_app_view_world_info)},
|
||||
|
||||
/* Edit menu */
|
||||
{"EditCut", GTK_STOCK_CUT, NULL, "<control>X",
|
||||
N_("Cut the selection"), G_CALLBACK(on_gm_app_view_edit_cut)},
|
||||
{"EditCopy", GTK_STOCK_COPY, NULL, "<control>C",
|
||||
N_("Copy the selection"), G_CALLBACK(on_gm_app_view_edit_copy)},
|
||||
{"EditPaste", GTK_STOCK_PASTE, NULL, "<control>V",
|
||||
N_("Paste the clipboard"), G_CALLBACK(on_gm_app_view_edit_paste)},
|
||||
{"EditWorld", NULL, N_("Current world..."), "<control>E",
|
||||
N_("Edit the current world"), G_CALLBACK(on_gm_app_view_edit_world)},
|
||||
{"EditFind", GTK_STOCK_FIND, NULL, "<control>F",
|
||||
N_("Find text"), G_CALLBACK(on_gm_app_view_edit_find)},
|
||||
{"EditFindNext", GTK_STOCK_FIND, N_("Find next"), "<control>G",
|
||||
N_("Find next occurence"),
|
||||
G_CALLBACK(on_gm_app_view_edit_find_next)},
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GEDIT_UI_H__ */
|
900
src/gm-world.c
900
src/gm-world.c
|
@ -1,900 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "gm-world.h"
|
||||
#include "gm-app.h"
|
||||
#include "mcp/gm-mcp-session.h"
|
||||
#include "gm-triggers.h"
|
||||
#include "gm-marshal.h"
|
||||
#include "gm-net.h"
|
||||
#include "gm-bogus.h"
|
||||
#include "gm-support.h"
|
||||
#include "gm-debug.h"
|
||||
|
||||
#define GM_WORLD_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_WORLD, GmWorldPrivate))
|
||||
|
||||
void gm_world_save_input_history(GmWorld *world);
|
||||
void gm_world_load_input_history(GmWorld *world);
|
||||
void gm_world_load_triggers(GmWorld *world);
|
||||
|
||||
void on_gm_world_net_state_changing(GmNet *net, GmNetState state,
|
||||
GmWorld *world);
|
||||
void on_gm_world_net_net_error(GmNet *net, gchar *error, gint code,
|
||||
GmWorld *world);
|
||||
void on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
|
||||
GmWorld *world);
|
||||
void on_gm_world_options_option_changed(GmOptions *options, gchar *key,
|
||||
GmWorld *world);
|
||||
|
||||
struct _GmWorldPrivate {
|
||||
gchar *path;
|
||||
gboolean loaded;
|
||||
gboolean active;
|
||||
guint activity;
|
||||
gchar *buffer;
|
||||
gchar *status;
|
||||
|
||||
GmOptions *options;
|
||||
GmTriggers *triggers;
|
||||
GmNet *net;
|
||||
GmMcpSession *mcp;
|
||||
GList *history;
|
||||
GList *editors;
|
||||
GmWorldInfo info;
|
||||
GmEditingInfo editing_info;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
ACTIVATE_REQUEST,
|
||||
LOAD,
|
||||
UNLOAD,
|
||||
STATE_CHANGING,
|
||||
WORLD_ERROR,
|
||||
TEXT_RECEIVED,
|
||||
EDITOR_ADDED,
|
||||
EDITOR_REMOVED,
|
||||
NAME_CHANGED,
|
||||
ACTIVE_CHANGED,
|
||||
ACTIVITY_CHANGED,
|
||||
STATUS_CHANGED,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint world_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmWorld, gm_world, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_world_finalize(GObject *object) {
|
||||
GmWorld *world = GM_WORLD(object);
|
||||
gchar *tmp_dir;
|
||||
|
||||
if (world->priv->path) {
|
||||
gm_options_save(world->priv->options);
|
||||
gm_world_save_input_history(world);
|
||||
gm_triggers_save(world->priv->triggers);
|
||||
|
||||
// Removing all tmp files
|
||||
tmp_dir = g_strconcat(world->priv->path, "/tmp", NULL);
|
||||
gm_directory_remove_all(tmp_dir, FALSE);
|
||||
g_free(tmp_dir);
|
||||
}
|
||||
|
||||
g_list_free_simple(world->priv->history);
|
||||
|
||||
g_free(world->priv->path);
|
||||
g_free(world->priv->buffer);
|
||||
g_free(world->priv->status);
|
||||
g_free(world->priv->editing_info.name);
|
||||
g_free(world->priv->editing_info.upload);
|
||||
g_list_free(world->priv->editing_info.lines);
|
||||
|
||||
g_object_unref(world->priv->triggers);
|
||||
g_object_unref(world->priv->options);
|
||||
g_object_unref(world->priv->net);
|
||||
g_object_unref(world->priv->mcp);
|
||||
|
||||
G_OBJECT_CLASS(gm_world_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_class_init(GmWorldClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_world_finalize;
|
||||
|
||||
world_signals[ACTIVATE_REQUEST] =
|
||||
g_signal_new("activate_request",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, activate_request),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
world_signals[LOAD] =
|
||||
g_signal_new("load",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, load),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
world_signals[UNLOAD] =
|
||||
g_signal_new("unload",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, unload),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
world_signals[STATE_CHANGING] =
|
||||
g_signal_new("state_changing",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, state_changing),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_UINT);
|
||||
|
||||
world_signals[WORLD_ERROR] =
|
||||
g_signal_new("world_error",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, world_error),
|
||||
NULL, NULL,
|
||||
gm_marshal_VOID__STRING_INT,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_INT);
|
||||
|
||||
world_signals[TEXT_RECEIVED] =
|
||||
g_signal_new("text_received",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, text_received),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
world_signals[EDITOR_ADDED] =
|
||||
g_signal_new("editor_added",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, editor_added),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
world_signals[EDITOR_REMOVED] =
|
||||
g_signal_new("editor_removed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, editor_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
world_signals[NAME_CHANGED] =
|
||||
g_signal_new("name_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, name_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
world_signals[ACTIVE_CHANGED] =
|
||||
g_signal_new("active_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, active_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOOLEAN,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_BOOLEAN);
|
||||
|
||||
world_signals[ACTIVITY_CHANGED] =
|
||||
g_signal_new("activity_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, activity_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__INT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_INT);
|
||||
|
||||
world_signals[STATUS_CHANGED] =
|
||||
g_signal_new("status_changed",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldClass, status_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmWorldPrivate));
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_create_default_settings(GmWorld *world) {
|
||||
const gchar *loc = gm_default_charset();
|
||||
|
||||
world->priv->options = gm_options_new();
|
||||
|
||||
gm_options_set(world->priv->options, "name", "");
|
||||
gm_options_set(world->priv->options, "autoload", "0");
|
||||
gm_options_set(world->priv->options, "host", "");
|
||||
gm_options_set(world->priv->options, "port", "1111");
|
||||
gm_options_set(world->priv->options, "player_name", "");
|
||||
gm_options_set(world->priv->options, "reconnect", "0");
|
||||
gm_options_set(world->priv->options, "password", "");
|
||||
gm_options_set(world->priv->options, "charset", (gchar *)loc);
|
||||
gm_options_set(world->priv->options, "history_length", "500");
|
||||
|
||||
// Non configurable options
|
||||
gm_options_set(world->priv->options, "pane_position", "150");
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_init(GmWorld *world) {
|
||||
world->priv = GM_WORLD_GET_PRIVATE(world);
|
||||
|
||||
gm_world_create_default_settings(world);
|
||||
world->priv->path = NULL;
|
||||
world->priv->loaded = FALSE;
|
||||
world->priv->history = NULL;
|
||||
world->priv->activity = 0;
|
||||
world->priv->triggers = gm_triggers_new();
|
||||
world->priv->net = gm_net_new();
|
||||
world->priv->mcp = gm_mcp_session_new(G_OBJECT(world));
|
||||
world->priv->buffer = NULL;
|
||||
world->priv->editing_info.is_editing = FALSE;
|
||||
world->priv->status = NULL;
|
||||
|
||||
g_signal_connect(world->priv->net, "state_changing",
|
||||
G_CALLBACK(on_gm_world_net_state_changing), world);
|
||||
g_signal_connect(world->priv->net, "net_error",
|
||||
G_CALLBACK(on_gm_world_net_net_error), world);
|
||||
g_signal_connect(world->priv->net, "bytes_recv",
|
||||
G_CALLBACK(on_gm_world_net_bytes_recv), world);
|
||||
g_signal_connect(world->priv->options, "option_changed",
|
||||
G_CALLBACK(on_gm_world_options_option_changed), world);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_load_input_history(GmWorld *world) {
|
||||
FILE *f;
|
||||
gchar line[1024], *filename;
|
||||
GString *str;
|
||||
|
||||
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history",
|
||||
NULL);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.LoadInputHistory: loading history (%s)!", filename);
|
||||
|
||||
if ((f = fopen(filename, "r")) != NULL) {
|
||||
str = g_string_new("");
|
||||
|
||||
while (fgets(line, 1024 - 1, f) != NULL) {
|
||||
g_string_append(str, line);
|
||||
if (line[strlen(line) - 1] == '\n') {
|
||||
if (line[1] != '\0') { // Empty lines, we don't need to process those
|
||||
world->priv->history = g_list_append(world->priv->history,
|
||||
g_strndup(str->str, strlen(str->str) - 1));
|
||||
}
|
||||
g_string_erase(str, 0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
g_string_free(str, TRUE);
|
||||
fclose(f);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.LoadInputHistory: could not retrieve contents of "
|
||||
"file %s (%s)", filename, strerror(errno));
|
||||
}
|
||||
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_save_input_history(GmWorld *world) {
|
||||
FILE *f;
|
||||
gchar *filename;
|
||||
GList *elem;
|
||||
|
||||
if (world->priv->path == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history", NULL);
|
||||
f = fopen(filename, "w");
|
||||
|
||||
if (f) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SaveInputHistory: saving input history to %s",
|
||||
filename);
|
||||
|
||||
for (elem = world->priv->history; elem; elem = elem->next) {
|
||||
fprintf(f, "%s\n", (gchar *) (elem->data));
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
chmod(filename, 0660);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SaveInputHistory: couldn't open history file (%s)"
|
||||
" for saving: %s", filename, strerror(errno));
|
||||
}
|
||||
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_load_triggers(GmWorld *world) {
|
||||
gchar *path;
|
||||
|
||||
if (world->priv->triggers) {
|
||||
g_object_unref(world->priv->triggers);
|
||||
}
|
||||
|
||||
path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "triggers", NULL);
|
||||
world->priv->triggers = gm_triggers_new_from_file(path);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
/* Public */
|
||||
GmWorld *
|
||||
gm_world_new(gchar *path) {
|
||||
GmWorld *world = GM_WORLD(g_object_new(GM_TYPE_WORLD, NULL));
|
||||
gchar *options_path;
|
||||
|
||||
if (path != NULL) {
|
||||
options_path = g_strconcat(path, "/settings", NULL);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.new: creating new world for %s", path);
|
||||
world->priv->path = g_strdup(path);
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.new: creating default world settings for %s", path);
|
||||
gm_options_load(world->priv->options, options_path);
|
||||
|
||||
if (strlen(gm_options_get(world->priv->options, "charset")) == 0) {
|
||||
gm_options_set(world->priv->options, "charset",
|
||||
gm_default_charset());
|
||||
}
|
||||
|
||||
g_free(options_path);
|
||||
|
||||
gm_world_load_input_history(world);
|
||||
gm_world_load_triggers(world);
|
||||
}
|
||||
|
||||
/* CHECK: all done? */
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
GmWorld *
|
||||
gm_world_dup(GmWorld *source) {
|
||||
GmWorld *copy = gm_world_new(NULL);
|
||||
|
||||
g_object_unref(copy->priv->options);
|
||||
|
||||
copy->priv->options = gm_options_dup(source->priv->options);
|
||||
copy->priv->triggers = gm_triggers_dup(source->priv->triggers);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_load(GmWorld *world) {
|
||||
if (world->priv->loaded) {
|
||||
g_signal_emit(world, world_signals[ACTIVATE_REQUEST], 0);
|
||||
return;
|
||||
}
|
||||
|
||||
world->priv->loaded = TRUE;
|
||||
g_signal_emit(world, world_signals[LOAD], 0);
|
||||
g_signal_emit(world, world_signals[ACTIVATE_REQUEST], 0);
|
||||
gm_world_connect(world);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_unload(GmWorld *world) {
|
||||
//GList *w;
|
||||
|
||||
if (world->priv->loaded) {
|
||||
world->priv->loaded = FALSE;
|
||||
gm_world_disconnect(world);
|
||||
|
||||
//TODO: Destroy editors
|
||||
//editors_close(wld);
|
||||
|
||||
g_signal_emit(world, world_signals[UNLOAD], 0);
|
||||
}
|
||||
}
|
||||
|
||||
GmTriggers *
|
||||
gm_world_triggers(GmWorld *world) {
|
||||
return world->priv->triggers;
|
||||
}
|
||||
|
||||
GmOptions *
|
||||
gm_world_options(GmWorld *world) {
|
||||
return world->priv->options;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_world_name(GmWorld *world) {
|
||||
return gm_options_get(world->priv->options, "name");
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_world_path(GmWorld *world) {
|
||||
return world->priv->path;
|
||||
}
|
||||
|
||||
GList **
|
||||
gm_world_history(GmWorld *world) {
|
||||
return &(world->priv->history);
|
||||
}
|
||||
|
||||
GmWorldInfo
|
||||
gm_world_info(GmWorld *world) {
|
||||
return world->priv->info;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_loaded(GmWorld *world) {
|
||||
return world->priv->loaded;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_connected(GmWorld *world) {
|
||||
return gm_net_state(world->priv->net) == GM_NET_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_disconnected(GmWorld *world) {
|
||||
return gm_net_state(world->priv->net) == GM_NET_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
GmNetState
|
||||
gm_world_state(GmWorld *world) {
|
||||
return gm_net_state(world->priv->net);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_world_current_host(GmWorld *world) {
|
||||
return gm_net_current_host(world->priv->net);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gm_world_current_port(GmWorld *world) {
|
||||
return gm_net_current_port(world->priv->net);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_connect(GmWorld *world) {
|
||||
/*if (strlen(gm_options_get(world->priv->options, "host")) == 0) {
|
||||
g_signal_emit(world, world_signals[WORLD_ERROR], 0,
|
||||
_("World has no host, please fill in a host first"));
|
||||
} else if (strlen(gm_options_get(world->priv->options, "port")) == 0) {
|
||||
g_signal_emit(world, world_signals[WORLD_ERROR], 0,
|
||||
_("World has no port, please fill in a port first"));
|
||||
} else {*/
|
||||
gm_net_connect(world->priv->net,
|
||||
gm_options_get(world->priv->options, "host"),
|
||||
gm_options_get(world->priv->options, "port"));
|
||||
//}
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_connect_to(GmWorld *world, gchar *host, gchar *port) {
|
||||
gm_net_connect(world->priv->net, host, port);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_disconnect(GmWorld *world) {
|
||||
gm_net_disconnect(world->priv->net);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_log(GmWorld *world, GmLogType type, gchar *text) {
|
||||
FILE *f;
|
||||
GString *s;
|
||||
gchar *start, *log, *no_ansi;
|
||||
struct tm *timet;
|
||||
time_t timer;
|
||||
|
||||
timer = time(0);
|
||||
timet = localtime(&timer);
|
||||
|
||||
log = g_strdup_printf("%s/logs/%04d-%02d-%02d.log", world->priv->path,
|
||||
timet->tm_year + 1900, timet->tm_mon + 1, timet->tm_mday);
|
||||
|
||||
f = fopen(log, "a");
|
||||
g_free(log);
|
||||
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
|
||||
start = g_strdup_printf("[%02d:%02d:%02d] ", timet->tm_hour, timet->tm_min,
|
||||
timet->tm_sec);
|
||||
|
||||
s = g_string_new(start);
|
||||
g_free(start);
|
||||
|
||||
switch (type) {
|
||||
case LOG_IN:
|
||||
s = g_string_append_c(s, '<');
|
||||
break;
|
||||
case LOG_OUT:
|
||||
s = g_string_append_c(s, '>');
|
||||
break;
|
||||
case LOG_MCP_IN:
|
||||
s = g_string_append(s, "[MCP] <");
|
||||
break;
|
||||
case LOG_MCP_OUT:
|
||||
s = g_string_append(s, "[MCP] >");
|
||||
break;
|
||||
case LOG_STATUS:
|
||||
s = g_string_append_c(s, '#');
|
||||
break;
|
||||
}
|
||||
|
||||
s = g_string_append(s, " ");
|
||||
s = g_string_append(s, text);
|
||||
|
||||
//no_ansi = gm_ansi_strip(g_strdup(s->str));
|
||||
no_ansi = g_strdup(s->str);
|
||||
|
||||
if (no_ansi[strlen(no_ansi) - 1] != '\n') {
|
||||
fputs(no_ansi, f);
|
||||
fputc('\n', f);
|
||||
} else {
|
||||
fputs(no_ansi, f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
g_free(no_ansi);
|
||||
g_string_free(s, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_parse_legacy_editing_start(GmWorld *world, gchar *line) {
|
||||
gchar *name_start, *upload_start;
|
||||
GmEditingInfo *einfo = &(world->priv->editing_info);
|
||||
|
||||
name_start = strstr(line, "name: ");
|
||||
|
||||
if (!name_start) {
|
||||
return;
|
||||
}
|
||||
|
||||
upload_start = strstr(line, " upload: ");
|
||||
|
||||
if (!upload_start) {
|
||||
return;
|
||||
}
|
||||
|
||||
einfo->is_editing = TRUE;
|
||||
einfo->name = g_strndup(name_start + 6, (upload_start - name_start) - 6);
|
||||
einfo->upload = g_strndup(upload_start + 9, (upload_start - line) + 9);
|
||||
einfo->lines = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_process_line(GmWorld *world, gchar *line) {
|
||||
gchar *non_text_start = NULL;
|
||||
GmEditingInfo *einfo = &(world->priv->editing_info);
|
||||
|
||||
if (strncmp(line, "\x1B[0m", 4) == 0) {
|
||||
non_text_start = g_strdup(line + 4);
|
||||
} else {
|
||||
non_text_start = g_strdup(line);
|
||||
}
|
||||
|
||||
if (einfo->is_editing) {
|
||||
if (strcmp(non_text_start, ".") == 0) {
|
||||
//TODO: implementation, create new editor object, invoke signal
|
||||
gm_world_add_editor(world, gm_editor_new(einfo->name, einfo->upload,
|
||||
einfo->lines));
|
||||
|
||||
einfo->is_editing = FALSE;
|
||||
g_free(einfo->name);
|
||||
einfo->name = NULL;
|
||||
g_free(einfo->upload);
|
||||
einfo->upload = NULL;
|
||||
g_list_free(einfo->lines);
|
||||
einfo->lines = NULL;
|
||||
} else {
|
||||
einfo->lines = g_list_append(einfo->lines, g_strdup(non_text_start));
|
||||
}
|
||||
} else if (strncmp(non_text_start, "#$#", 3) == 0) {
|
||||
if (strncasecmp(non_text_start + 3, " edit ", 6) == 0) {
|
||||
gm_world_parse_legacy_editing_start(world, non_text_start + 9);
|
||||
} else {
|
||||
gm_mcp_session_handle_oob(world->priv->mcp, non_text_start + 3);
|
||||
//gm_world_log(world, LOG_MCP_IN, non_text_start);
|
||||
}
|
||||
} else {
|
||||
if (!gm_world_active(world)) {
|
||||
gm_world_set_activity(world, world->priv->activity + 1);
|
||||
}
|
||||
|
||||
if (strncmp(non_text_start, "#$\"", 3) == 0) {
|
||||
if (strlen(non_text_start) != strlen(line)) {
|
||||
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\x1B[0m");
|
||||
}
|
||||
|
||||
gm_world_log(world, LOG_IN, non_text_start + 3);
|
||||
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, non_text_start + 3);
|
||||
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n");
|
||||
} else {
|
||||
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, line);
|
||||
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n");
|
||||
gm_world_log(world, LOG_IN, line);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(non_text_start);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_process_input(GmWorld *world, gchar *text) {
|
||||
#ifdef HAVE_RUBY
|
||||
gchar *space, *script, *argstr;
|
||||
gboolean script_ran = FALSE;
|
||||
|
||||
if (g_utf8_strlen(text, -1) > 1) {
|
||||
if (text[0] == '/' && text[1] != '/') {
|
||||
space = strstr(text, " ");
|
||||
|
||||
if (space == NULL) {
|
||||
script = g_strdup(text + 1);
|
||||
argstr = g_strdup("");
|
||||
} else {
|
||||
script = g_strndup(text + 1, (space - text) - 1);
|
||||
argstr = g_strdup(space + 1);
|
||||
}
|
||||
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.ProcessInput: Trying script %s (%s)", script,
|
||||
argstr);
|
||||
script_ran = gm_scripts_run(gm_app_scripts(gm_app_instance()),
|
||||
world, script, argstr);
|
||||
|
||||
g_free(script);
|
||||
g_free(argstr);
|
||||
|
||||
if (script_ran) {
|
||||
return;
|
||||
}
|
||||
} else if (text[0] == '/' && text[1] == '/') {
|
||||
text = text + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gm_world_sendln(world, text);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_writeln(GmWorld *world, gchar *text) {
|
||||
gchar *newline = g_strconcat(text, "\n", NULL);
|
||||
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, newline);
|
||||
|
||||
g_free(newline);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_remove_editor(GmWorld *world, GmEditor *editor) {
|
||||
g_return_if_fail(g_list_find(world->priv->editors, editor) != NULL);
|
||||
|
||||
world->priv->editors = g_list_remove(world->priv->editors, editor);
|
||||
g_signal_emit(world, world_signals[EDITOR_REMOVED], 0, G_OBJECT(editor));
|
||||
|
||||
g_object_unref(editor);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_add_editor(GmWorld *world, GmEditor *editor) {
|
||||
world->priv->editors = g_list_append(world->priv->editors, editor);
|
||||
|
||||
g_signal_emit(world, world_signals[EDITOR_ADDED], 0, G_OBJECT(editor));
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_sendln(GmWorld *world, gchar *text) {
|
||||
gchar *normal;
|
||||
|
||||
// Convert text from utf-8 to the correct locale
|
||||
normal = gm_to_utf8_with_fallback(text, -1,
|
||||
gm_options_get(world->priv->options, "charset"), "?");
|
||||
|
||||
if (!normal) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.Send: conversion failed!");
|
||||
normal = g_strdup(text);
|
||||
}
|
||||
|
||||
gm_world_log(world, LOG_OUT, text);
|
||||
gm_net_send_line(world->priv->net, normal);
|
||||
g_free(normal);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_set_active(GmWorld *world, gboolean active) {
|
||||
world->priv->active = active;
|
||||
|
||||
g_signal_emit(world, world_signals[ACTIVE_CHANGED], 0, active);
|
||||
|
||||
if (active) {
|
||||
gm_world_set_activity(world, 0);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_active(GmWorld *world) {
|
||||
return world->priv->active;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_set_activity(GmWorld *world, gint activity) {
|
||||
world->priv->activity = activity;
|
||||
|
||||
g_signal_emit(world, world_signals[ACTIVITY_CHANGED], 0, activity);
|
||||
}
|
||||
|
||||
gint
|
||||
gm_world_activity(GmWorld *world) {
|
||||
return world->priv->activity;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_name_changed(GmWorld *world) {
|
||||
gchar *tmp_path = world->priv->path ? g_strdup(world->priv->path) : NULL;
|
||||
gchar *new_path = g_strconcat(gm_app_worlds_path(gm_app_instance()), "/",
|
||||
gm_options_get(world->priv->options, "name"), NULL);
|
||||
|
||||
if (tmp_path && strcmp(tmp_path, new_path) == 0) {
|
||||
g_free(new_path);
|
||||
g_free(tmp_path);
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(world->priv->path);
|
||||
world->priv->path = new_path;
|
||||
|
||||
if (tmp_path && g_file_test(tmp_path, G_FILE_TEST_EXISTS)) {
|
||||
// Then! rename the old_path to the new_path
|
||||
rename(tmp_path, world->priv->path);
|
||||
} else if (!g_file_test(world->priv->path, G_FILE_TEST_EXISTS)) {
|
||||
// There was no old path, so a new dir should be made
|
||||
mkdir(world->priv->path, 0755);
|
||||
}
|
||||
|
||||
g_free(tmp_path);
|
||||
|
||||
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "settings",
|
||||
NULL);
|
||||
gm_options_save_as(world->priv->options, tmp_path);
|
||||
g_free(tmp_path);
|
||||
|
||||
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "triggers",
|
||||
NULL);
|
||||
gm_triggers_save_as(world->priv->triggers, tmp_path);
|
||||
g_free(tmp_path);
|
||||
|
||||
g_signal_emit(world, world_signals[NAME_CHANGED], 0,
|
||||
gm_options_get(world->priv->options, "name"));
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_set_status(GmWorld *world, gchar const *status) {
|
||||
g_free(world->priv->status);
|
||||
world->priv->status = g_strdup(status);
|
||||
|
||||
g_signal_emit(world, world_signals[STATUS_CHANGED], 0,
|
||||
world->priv->status);
|
||||
}
|
||||
|
||||
gchar const *
|
||||
gm_world_get_status(GmWorld *world) {
|
||||
return world->priv->status;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
void
|
||||
on_gm_world_net_state_changing(GmNet *net, GmNetState state, GmWorld *world) {
|
||||
g_signal_emit(world, world_signals[STATE_CHANGING], 0, state);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_net_net_error(GmNet *net, gchar *error, gint code,
|
||||
GmWorld *world) {
|
||||
g_signal_emit(world, world_signals[WORLD_ERROR], 0, error, code);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
|
||||
GmWorld *world) {
|
||||
gchar *all, *utext, *ptr, *line, *p;
|
||||
gint i;
|
||||
|
||||
utext = gm_to_utf8_with_fallback(text, len,
|
||||
gm_options_get(world->priv->options, "charset"), "?");
|
||||
|
||||
if (!utext) {
|
||||
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.NetBytesRecv: conversion failed!");
|
||||
utext = g_strndup(text, len);
|
||||
}
|
||||
|
||||
if (world->priv->buffer != NULL) {
|
||||
all = g_strconcat(world->priv->buffer, utext, NULL);
|
||||
g_free(utext);
|
||||
g_free(world->priv->buffer);
|
||||
world->priv->buffer = NULL;
|
||||
} else {
|
||||
all = utext;
|
||||
}
|
||||
|
||||
// TODO: UTF-8 compliant
|
||||
line = (gchar *)(malloc((strlen(all) * sizeof(gchar)) + 1));
|
||||
i = 0;
|
||||
p = all;
|
||||
|
||||
/* Find lines in `all' and process them */
|
||||
for (ptr = all; *ptr != '\0'; ptr++) {
|
||||
if (*ptr == '\n') {
|
||||
line[i] = '\0';
|
||||
line[i + 1] = '\0';
|
||||
|
||||
gm_world_process_line(world, line);
|
||||
p = ptr + 1;
|
||||
i = 0;
|
||||
} else if (*ptr != '\r') {
|
||||
line[i] = *ptr;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
world->priv->buffer = g_strdup(p);
|
||||
}
|
||||
|
||||
g_free(all);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_options_option_changed(GmOptions *options, gchar *key,
|
||||
GmWorld *world) {
|
||||
if (strcmp(key, "name") == 0) {
|
||||
gm_world_name_changed(world);
|
||||
}
|
||||
}
|
140
src/gm-world.h
140
src/gm-world.h
|
@ -1,140 +0,0 @@
|
|||
#ifndef __GM_WORLD_H__
|
||||
#define __GM_WORLD_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gm-options.h"
|
||||
#include "gm-net.h"
|
||||
#include "gm-editor.h"
|
||||
#include "gm-triggers.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_WORLD (gm_world_get_type())
|
||||
#define GM_WORLD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD, GmWorld))
|
||||
#define GM_WORLD_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD, GmWorld const))
|
||||
#define GM_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_WORLD, GmWorldClass))
|
||||
#define GM_IS_WORLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_WORLD))
|
||||
#define GM_IS_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_WORLD))
|
||||
#define GM_WORLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_WORLD, GmWorldClass))
|
||||
|
||||
typedef struct _GmWorldInfo {
|
||||
gchar *homepage;
|
||||
gchar *location;
|
||||
gchar *admin;
|
||||
gchar *contact;
|
||||
gchar *charset;
|
||||
gchar *language;
|
||||
gchar *system;
|
||||
gchar *logo;
|
||||
} GmWorldInfo;
|
||||
|
||||
/** \ingroup world
|
||||
* \brief struct for world editing information
|
||||
*
|
||||
* Struct which contains various fields for storing editing information. This
|
||||
* is only used if editing via mcp_simpleedit can't be used.
|
||||
*/
|
||||
typedef struct _GmEditingInfo {
|
||||
gboolean is_editing; /**< are we editing at the moment? */
|
||||
GList *lines; /**< the lines to be edited */
|
||||
gchar *name; /**< the name of the editor */
|
||||
gchar *upload; /**< the command to send when sending the editor contents */
|
||||
} GmEditingInfo;
|
||||
|
||||
/** \ingroup world
|
||||
* \brief enum indicating log type
|
||||
*
|
||||
* Enumeration which indicates the log type
|
||||
*/
|
||||
typedef enum _GmLogType GmLogType;
|
||||
enum _GmLogType {
|
||||
LOG_IN, /**< incoming lines */
|
||||
LOG_OUT, /**< outgoing lines */
|
||||
LOG_MCP_IN, /**< mcp incoming lines */
|
||||
LOG_MCP_OUT, /**< mcp outgoing lines */
|
||||
LOG_STATUS /**< status lines (such as connecting information) */
|
||||
};
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmWorldPrivate GmWorldPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmWorld GmWorld;
|
||||
|
||||
struct _GmWorld {
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
GmWorldPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmWorldClass GmWorldClass;
|
||||
|
||||
struct _GmWorldClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* activate_request) (GmWorld *world);
|
||||
void (* load) (GmWorld *world);
|
||||
void (* unload) (GmWorld *world);
|
||||
void (* state_changing) (GmWorld *world, guint state);
|
||||
void (* world_error) (GmWorld *world, gchar const *error, gint code);
|
||||
void (* text_received) (GmWorld *world, gchar const *text);
|
||||
void (* editor_added) (GmWorld *world, GObject *editor);
|
||||
void (* editor_removed) (GmWorld *world, GObject *editor);
|
||||
void (* name_changed) (GmWorld *world, gchar const *name);
|
||||
void (* active_changed) (GmWorld *world, gboolean active);
|
||||
void (* activity_changed) (GmWorld *world, gint activity);
|
||||
void (* status_changed) (GmWorld *world, gchar const *status);
|
||||
};
|
||||
|
||||
GType gm_world_get_type(void) G_GNUC_CONST;
|
||||
GmWorld *gm_world_new(gchar *path);
|
||||
|
||||
GmWorld *gm_world_dup(GmWorld *source);
|
||||
void gm_world_load(GmWorld *world);
|
||||
void gm_world_unload(GmWorld *world);
|
||||
|
||||
const gchar *gm_world_name(GmWorld *world);
|
||||
GmOptions *gm_world_options(GmWorld *world);
|
||||
GmWorldInfo gm_world_info(GmWorld *world);
|
||||
const gchar *gm_world_path(GmWorld *world);
|
||||
GList **gm_world_history(GmWorld *world);
|
||||
gint gm_world_activity(GmWorld *world);
|
||||
gboolean gm_world_active(GmWorld *world);
|
||||
GmTriggers *gm_world_triggers(GmWorld *world);
|
||||
|
||||
const gchar *gm_world_current_host(GmWorld *world);
|
||||
const gchar *gm_world_current_port(GmWorld *world);
|
||||
|
||||
void gm_world_set_name(GmWorld *world, const gchar *name);
|
||||
void gm_world_set_activity(GmWorld *world, gint activity);
|
||||
void gm_world_set_active(GmWorld *world, gboolean active);
|
||||
void gm_world_set_status(GmWorld *world, gchar const *status);
|
||||
gchar const *gm_world_get_status(GmWorld *world);
|
||||
|
||||
gboolean gm_world_loaded(GmWorld *world);
|
||||
GmNetState gm_world_state(GmWorld *world);
|
||||
gboolean gm_world_connected(GmWorld *world);
|
||||
gboolean gm_world_disconnected(GmWorld *world);
|
||||
|
||||
void gm_world_connect(GmWorld *world);
|
||||
void gm_world_connect_to(GmWorld *world, gchar *host, gchar *port);
|
||||
void gm_world_disconnect(GmWorld *world);
|
||||
void gm_world_add_editor(GmWorld *world, GmEditor *editor);
|
||||
void gm_world_remove_editor(GmWorld *world, GmEditor *editor);
|
||||
void gm_world_sendln(GmWorld *world, gchar *text);
|
||||
void gm_world_writeln(GmWorld *world, gchar *text);
|
||||
void gm_world_process_input(GmWorld *world, gchar *text);
|
||||
void gm_world_log(GmWorld *world, GmLogType type, gchar *text);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_WORLD_H__ */
|
|
@ -1,59 +0,0 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "gm-{template-}.h"
|
||||
|
||||
#define GM_{TEMPLATE}_GET_PRIVATE(object)( \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}Private))
|
||||
|
||||
struct _Gm{Template}Private {
|
||||
|
||||
};
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_{template_}_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(Gm{Template}, gm_{template_}, GTK_TYPE_{PARENT})
|
||||
|
||||
static void
|
||||
gm_{template_}_finalize(GObject *object) {
|
||||
//Gm{Template} *obj = GM_{TEMPLATE}(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_{template_}_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_{template_}_class_init(Gm{Template}Class *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_{template_}_finalize;
|
||||
|
||||
/*gm_{template_}_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(Gm{Template}Class, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(Gm{Template}Private));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_{template_}_init(Gm{Template} *obj) {
|
||||
obj->priv = GM_{TEMPLATE}_GET_PRIVATE(obj);
|
||||
}
|
||||
|
||||
Gm{Template} *
|
||||
gm_{template_}_new() {
|
||||
Gm{Template} *obj = GM_{TEMPLATE}(g_object_new(GM_TYPE_{TEMPLATE}, NULL));
|
||||
|
||||
return obj;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
#ifndef __GM_{TEMPLATE}_H__
|
||||
#define __GM_{TEMPLATE}_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_{TEMPLATE} (gm_{template_}_get_type())
|
||||
#define GM_{TEMPLATE}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}))
|
||||
#define GM_{TEMPLATE}_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template} const))
|
||||
#define GM_{TEMPLATE}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}Class))
|
||||
#define GM_IS_{TEMPLATE}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_{TEMPLATE}))
|
||||
#define GM_IS_{TEMPLATE}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_{TEMPLATE}))
|
||||
#define GM_{TEMPLATE}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}Class))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _Gm{Template}Private Gm{Template}Private;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _Gm{Template} Gm{Template};
|
||||
|
||||
struct _Gm{Template} {
|
||||
Gtk{Parent} parent;
|
||||
|
||||
/*< private > */
|
||||
Gm{Template}Private *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _Gm{Template}Class Gm{Template}Class;
|
||||
|
||||
struct _Gm{Template}Class {
|
||||
Gtk{Parent}Class parent_class;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (Gm{Template} *obj); */
|
||||
};
|
||||
|
||||
GType gm_{template_}_get_type(void) G_GNUC_CONST;
|
||||
Gm{Template} *gm_{template_}_new(void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_{TEMPLATE}_H__ */
|
|
@ -1,13 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
mcpdir = mcp
|
||||
|
||||
gnoemoe_SOURCES += $(mcpdir)/gm-mcp-classes.c \
|
||||
$(mcpdir)/gm-mcp.c $(mcpdir)/gm-mcp.h \
|
||||
$(mcpdir)/gm-mcp-session.c $(mcpdir)/gm-mcp-session.h \
|
||||
$(mcpdir)/gm-mcp-package.c $(mcpdir)/gm-mcp-package.h \
|
||||
$(mcpdir)/gm-mcp-negotiate.c $(mcpdir)/gm-mcp-negotiate.h \
|
||||
$(mcpdir)/gm-mcp-awns-status.c $(mcpdir)/gm-mcp-awns-status.h
|
||||
|
||||
$(mcpdir)/gm-mcp-classes.c: $(mcpdir)/packages.defs
|
||||
( cd $(srcdir) && ./$(mcpdir)/mcpinit.rb \
|
||||
$(mcpdir)/packages.defs $(mcpdir)/gm-mcp-classes ) > $@
|
|
@ -1,82 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include "gm-mcp-awns-status.h"
|
||||
#include "gm-mcp-session.h"
|
||||
#include "gm-mcp.h"
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-debug.h"
|
||||
|
||||
#define GM_MCP_AWNS_STATUS_GET_PRIVATE(object)( \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_MCP_AWNS_STATUS, GmMcpAwnsStatusPrivate))
|
||||
|
||||
struct _GmMcpAwnsStatusPrivate {
|
||||
|
||||
};
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_mcp_awns_status_signals[NUM_SIGNALS] = {0};*/
|
||||
void gm_mcp_awns_status_handle_simple(GmMcpPackage *package, gchar *suffix,
|
||||
GList *fields);
|
||||
|
||||
G_DEFINE_TYPE(GmMcpAwnsStatus, gm_mcp_awns_status, GM_TYPE_MCP_PACKAGE)
|
||||
|
||||
static void
|
||||
gm_mcp_awns_status_finalize(GObject *object) {
|
||||
//GmMcpAwnsStatus *obj = GM_MCP_AWNS_STATUS(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_mcp_awns_status_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_awns_status_class_init(GmMcpAwnsStatusClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
GmMcpPackageClass *pklass = GM_MCP_PACKAGE_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_mcp_awns_status_finalize;
|
||||
|
||||
/*gm_mcp_awns_status_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmMcpAwnsStatusClass, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
pklass->name = "dns-com-awns-status";
|
||||
pklass->handle_simple = &gm_mcp_awns_status_handle_simple;
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmMcpAwnsStatusPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_awns_status_init(GmMcpAwnsStatus *obj) {
|
||||
obj->priv = GM_MCP_AWNS_STATUS_GET_PRIVATE(obj);
|
||||
}
|
||||
|
||||
/* Public */
|
||||
GmMcpAwnsStatus *
|
||||
gm_mcp_awns_status_new() {
|
||||
GmMcpAwnsStatus *obj = GM_MCP_AWNS_STATUS(g_object_new(
|
||||
GM_TYPE_MCP_AWNS_STATUS, NULL));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Private */
|
||||
void
|
||||
gm_mcp_awns_status_handle_simple(GmMcpPackage *package, gchar *suffix,
|
||||
GList *fields) {
|
||||
gchar const *text = gm_mcp_find_value(fields, "text");
|
||||
GmMcpSession *session = GM_MCP_PACKAGE_SESSION(package);
|
||||
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpAwnsStatus.HandleSimple: set status %s", text);
|
||||
gm_world_set_status(GM_MCP_SESSION_WORLD(session), text);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef __GM_MCP_AWNS_STATUS_H__
|
||||
#define __GM_MCP_AWNS_STATUS_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gm-mcp-package.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_MCP_AWNS_STATUS (gm_mcp_awns_status_get_type())
|
||||
#define GM_MCP_AWNS_STATUS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_MCP_AWNS_STATUS, GmMcpAwnsStatus))
|
||||
#define GM_MCP_AWNS_STATUS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
GM_TYPE_MCP_AWNS_STATUS, GmMcpAwnsStatus const))
|
||||
#define GM_MCP_AWNS_STATUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_MCP_AWNS_STATUS, GmMcpAwnsStatusClass))
|
||||
#define GM_IS_MCP_AWNS_STATUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_MCP_AWNS_STATUS))
|
||||
#define GM_IS_MCP_AWNS_STATUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_MCP_AWNS_STATUS))
|
||||
#define GM_MCP_AWNS_STATUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_MCP_AWNS_STATUS, GmMcpAwnsStatusClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmMcpAwnsStatusPrivate GmMcpAwnsStatusPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmMcpAwnsStatus GmMcpAwnsStatus;
|
||||
|
||||
struct _GmMcpAwnsStatus {
|
||||
GmMcpPackage parent;
|
||||
|
||||
/*< private > */
|
||||
GmMcpAwnsStatusPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmMcpAwnsStatusClass GmMcpAwnsStatusClass;
|
||||
|
||||
struct _GmMcpAwnsStatusClass {
|
||||
GmMcpPackageClass parent_class;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (GmMcpAwnsStatus *obj); */
|
||||
};
|
||||
|
||||
GType gm_mcp_awns_status_get_type(void) G_GNUC_CONST;
|
||||
GmMcpAwnsStatus *gm_mcp_awns_status_new(void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_MCP_AWNS_STATUS_H__ */
|
|
@ -1,249 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gm-mcp-negotiate.h"
|
||||
#include "gm-mcp.h"
|
||||
#include "gm-mcp-session.h"
|
||||
#include "gm-mcp-package.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-support.h"
|
||||
|
||||
#define GM_MCP_NEGOTIATE_GET_PRIVATE(object)( \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiatePrivate))
|
||||
|
||||
typedef struct _PackageInfo {
|
||||
GmMcpPackageClass *klass;
|
||||
gdouble version;
|
||||
} PackageInfo;
|
||||
|
||||
struct _GmMcpNegotiatePrivate {
|
||||
GList *packages;
|
||||
};
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_mcp_negotiate_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
void gm_mcp_negotiate_handle_simple(GmMcpPackage *package, gchar *suffix,
|
||||
GList *fields);
|
||||
|
||||
G_DEFINE_TYPE(GmMcpNegotiate, gm_mcp_negotiate, GM_TYPE_MCP_PACKAGE);
|
||||
|
||||
static void
|
||||
gm_mcp_negotiate_finalize(GObject *object) {
|
||||
//GmMcpNegotiate *obj = GM_MCP_NEGOTIATE(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_mcp_negotiate_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_negotiate_class_init(GmMcpNegotiateClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
GmMcpPackageClass *pklass = GM_MCP_PACKAGE_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_mcp_negotiate_finalize;
|
||||
|
||||
/*gm_mcp_negotiate_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmMcpNegotiateClass, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
pklass->name = "mcp-negotiate";
|
||||
pklass->handle_simple = &gm_mcp_negotiate_handle_simple;
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmMcpNegotiatePrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_negotiate_init(GmMcpNegotiate *obj) {
|
||||
obj->priv = GM_MCP_NEGOTIATE_GET_PRIVATE(obj);
|
||||
obj->priv->packages = NULL;
|
||||
}
|
||||
|
||||
PackageInfo *
|
||||
gm_mcp_negotiate_find_package(GmMcpNegotiate *package, gchar *name) {
|
||||
PackageInfo *pinfo;
|
||||
GList *elem;
|
||||
|
||||
for (elem = package->priv->packages; elem; elem = elem->next) {
|
||||
pinfo = (PackageInfo *)(elem->data);
|
||||
|
||||
if (strcasecmp(pinfo->klass->name, name) == 0) {
|
||||
return pinfo;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gm_mcp_negotiate_fix_overrides(GmMcpNegotiate *package) {
|
||||
GList *l, *item, *over;
|
||||
PackageInfo *pinfo, *pover;
|
||||
gchar *name;
|
||||
|
||||
l = g_list_copy(package->priv->packages);
|
||||
|
||||
for (item = l; item; item = item->next) {
|
||||
pinfo = (PackageInfo *)(item->data);
|
||||
|
||||
for (over = pinfo->klass->overrides; over; over = over->next) {
|
||||
name = (gchar *)(over->data);
|
||||
|
||||
if ((pover = gm_mcp_negotiate_find_package(package, name))) {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpNegotiate.FixOverrides: package %s "
|
||||
"overrides %s", pinfo->klass->name, pover->klass->name);
|
||||
package->priv->packages = g_list_remove(
|
||||
package->priv->packages, pover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(l);
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_negotiate_fix_depends(GmMcpNegotiate *package) {
|
||||
PackageInfo *pinfo, *pdep;
|
||||
GList *l, *item, *dep;
|
||||
gchar *name;
|
||||
|
||||
l = g_list_copy(package->priv->packages);
|
||||
|
||||
for (item = l; item; item = item->next) {
|
||||
pinfo = (PackageInfo *)(item->data);
|
||||
|
||||
for (dep = pinfo->klass->depends; dep; dep = dep->next) {
|
||||
name = (gchar *)(dep->data);
|
||||
|
||||
if (!(pdep = gm_mcp_negotiate_find_package(package, name))) {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpNegotiate.FixDepends: package %s depends "
|
||||
"on %s, but %s is not supported", pinfo->klass->name,
|
||||
name, name);
|
||||
|
||||
// Remove package because depencendies are not met
|
||||
package->priv->packages = g_list_remove(
|
||||
package->priv->packages, pinfo);
|
||||
break;
|
||||
} else {
|
||||
// Make sure this dependency is loaded before the package
|
||||
package->priv->packages = g_list_remove(
|
||||
package->priv->packages, pdep);
|
||||
package->priv->packages = g_list_insert_before(
|
||||
package->priv->packages,
|
||||
g_list_find(package->priv->packages, pinfo), pdep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(l);
|
||||
}
|
||||
|
||||
/* Public */
|
||||
GmMcpNegotiate *
|
||||
gm_mcp_negotiate_new() {
|
||||
GmMcpNegotiate *obj = GM_MCP_NEGOTIATE(g_object_new(GM_TYPE_MCP_NEGOTIATE,
|
||||
NULL));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Private */
|
||||
gboolean
|
||||
gm_mcp_negotiate_send_can(GmMcpPackageClass *klass, gpointer user_data) {
|
||||
GmMcpNegotiate *package = GM_MCP_NEGOTIATE(user_data);
|
||||
gchar min_v[16], max_v[16];
|
||||
|
||||
g_ascii_formatd(min_v, 16, "%.1f", klass->min_version);
|
||||
g_ascii_formatd(max_v, 16, "%.1f", klass->max_version);
|
||||
|
||||
gm_mcp_session_send_simple(GM_MCP_PACKAGE_SESSION(package),
|
||||
"mcp-negotiate-can", "package", klass->name, "min-version",
|
||||
min_v, "max-version", max_v, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_negotiate_handle_simple(GmMcpPackage *package, gchar *suffix,
|
||||
GList *fields) {
|
||||
gchar const *pname;
|
||||
GmMcpPackageClass *pklass;
|
||||
GmMcpNegotiate *negotiate = GM_MCP_NEGOTIATE(package);
|
||||
PackageInfo *pinfo;
|
||||
double version;
|
||||
gchar const *min_v, *max_v;
|
||||
gdouble cmin = 0.0, cmax = 0.0;
|
||||
GList *elem;
|
||||
|
||||
if (strcasecmp(suffix, "can") == 0) {
|
||||
// Fields has package, min-version, max-version
|
||||
pname = gm_mcp_find_value(fields, "package");
|
||||
pklass = gm_mcp_session_find_package_class(pname);
|
||||
|
||||
if (pklass) {
|
||||
min_v = gm_mcp_find_value(fields, "min-version");
|
||||
|
||||
if (min_v) {
|
||||
cmin = g_ascii_strtod(min_v, NULL);
|
||||
}
|
||||
|
||||
max_v = gm_mcp_find_value(fields, "max-version");
|
||||
|
||||
if (max_v) {
|
||||
cmax = g_ascii_strtod(max_v, NULL);
|
||||
}
|
||||
|
||||
version = gm_mcp_get_version(pklass->min_version,
|
||||
pklass->max_version, cmin, cmax);
|
||||
|
||||
if (version > 0.0) {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpNegotiate.HandleSimple: %s, "
|
||||
"package is supported", pname);
|
||||
pinfo = g_new(PackageInfo, 1);
|
||||
pinfo->klass = pklass;
|
||||
pinfo->version = version;
|
||||
|
||||
negotiate->priv->packages = g_list_append(
|
||||
negotiate->priv->packages, pinfo);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpNegotiate.HandleSimple: %s, package "
|
||||
"supported but wrong version!", pname);
|
||||
}
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpNegotiate.HandleSimple: %s, package is not "
|
||||
"supported!", pname);
|
||||
}
|
||||
} else if (strcasecmp(suffix, "end") == 0) {
|
||||
gm_mcp_session_package_class_for_each(gm_mcp_negotiate_send_can,
|
||||
(gpointer)(negotiate));
|
||||
|
||||
gm_mcp_session_send_simple(GM_MCP_PACKAGE_SESSION(negotiate),
|
||||
"mcp-negotiate-end", NULL);
|
||||
|
||||
gm_mcp_negotiate_fix_overrides(negotiate);
|
||||
gm_mcp_negotiate_fix_depends(negotiate);
|
||||
|
||||
for (elem = negotiate->priv->packages; elem; elem = elem->next) {
|
||||
pinfo = (PackageInfo *)(elem->data);
|
||||
gm_mcp_session_create_package(GM_MCP_PACKAGE_SESSION(negotiate),
|
||||
pinfo->klass, pinfo->version);
|
||||
g_free(pinfo);
|
||||
}
|
||||
|
||||
g_list_free(negotiate->priv->packages);
|
||||
negotiate->priv->packages = NULL;
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef __GM_MCP_NEGOTIATE_H__
|
||||
#define __GM_MCP_NEGOTIATE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gm-mcp-package.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_MCP_NEGOTIATE (gm_mcp_negotiate_get_type())
|
||||
#define GM_MCP_NEGOTIATE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiate))
|
||||
#define GM_MCP_NEGOTIATE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiate const))
|
||||
#define GM_MCP_NEGOTIATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiateClass))
|
||||
#define GM_IS_MCP_NEGOTIATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_MCP_NEGOTIATE))
|
||||
#define GM_IS_MCP_NEGOTIATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_MCP_NEGOTIATE))
|
||||
#define GM_MCP_NEGOTIATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiateClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmMcpNegotiatePrivate GmMcpNegotiatePrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmMcpNegotiate GmMcpNegotiate;
|
||||
|
||||
struct _GmMcpNegotiate {
|
||||
GmMcpPackage parent;
|
||||
|
||||
/*< private > */
|
||||
GmMcpNegotiatePrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmMcpNegotiateClass GmMcpNegotiateClass;
|
||||
|
||||
struct _GmMcpNegotiateClass {
|
||||
GmMcpPackageClass parent_class;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (GmMcpNegotiate *obj); */
|
||||
};
|
||||
|
||||
GType gm_mcp_negotiate_get_type(void) G_GNUC_CONST;
|
||||
GmMcpNegotiate *gm_mcp_negotiate_new(void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_MCP_NEGOTIATE_H__ */
|
|
@ -1,140 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include "gm-mcp-session.h"
|
||||
#include "gm-mcp-package.h"
|
||||
#include "../gm-support.h"
|
||||
|
||||
#define GM_MCP_PACKAGE_GET_PRIVATE(object)( \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_MCP_PACKAGE, GmMcpPackagePrivate))
|
||||
|
||||
struct _GmMcpPackagePrivate {
|
||||
GmMcpSession *session;
|
||||
gdouble version;
|
||||
};
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_mcp_package_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(GmMcpPackage, gm_mcp_package, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_mcp_package_finalize(GObject *object) {
|
||||
//GmMcpPackage *package = GM_MCP_PACKAGE(object);
|
||||
G_OBJECT_CLASS(gm_mcp_package_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_package_class_init(GmMcpPackageClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_mcp_package_finalize;
|
||||
|
||||
/*gm_mcp_package_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmMcpPackageClass, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
klass->handle_simple = NULL;
|
||||
klass->handle_multi = NULL;
|
||||
klass->depends = NULL;
|
||||
klass->overrides = NULL;
|
||||
klass->name = NULL;
|
||||
klass->min_version = 1.0;
|
||||
klass->max_version = 1.0;
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmMcpPackagePrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_package_init(GmMcpPackage *obj) {
|
||||
obj->priv = GM_MCP_PACKAGE_GET_PRIVATE(obj);
|
||||
obj->priv->session = NULL;
|
||||
obj->priv->version = 1.0;
|
||||
}
|
||||
|
||||
/* Public */
|
||||
GmMcpPackage *
|
||||
gm_mcp_package_new() {
|
||||
GmMcpPackage *obj = GM_MCP_PACKAGE(g_object_new(GM_TYPE_MCP_PACKAGE, NULL));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_package_handle_simple(GmMcpPackage *package, gchar *suffix,
|
||||
GList *fields) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->handle_simple(package,
|
||||
suffix, fields);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_mcp_package_can_handle_simple(GmMcpPackage *package) {
|
||||
return (GM_MCP_PACKAGE_GET_CLASS(package)->handle_simple != NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_mcp_package_handle_multi(GmMcpPackage *package, gchar *data_tag,
|
||||
gchar *key, gchar *value, GList *allValues) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->handle_multi(package,
|
||||
data_tag, key, value, allValues);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_mcp_package_can_handle_multi(GmMcpPackage *package) {
|
||||
return (GM_MCP_PACKAGE_GET_CLASS(package)->handle_multi != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_package_set_session(GmMcpPackage *package, GObject *session) {
|
||||
package->priv->session = GM_MCP_SESSION(session);
|
||||
}
|
||||
|
||||
GObject *
|
||||
gm_mcp_package_get_session(GmMcpPackage *package) {
|
||||
return G_OBJECT(package->priv->session);
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_package_set_version(GmMcpPackage *package, gdouble version) {
|
||||
package->priv->version = version;
|
||||
}
|
||||
|
||||
gdouble
|
||||
gm_mcp_package_get_version(GmMcpPackage *package) {
|
||||
return package->priv->version;
|
||||
}
|
||||
|
||||
gchar const *
|
||||
gm_mcp_package_get_name(GmMcpPackage *package) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->name;
|
||||
}
|
||||
|
||||
GList const *
|
||||
gm_mcp_package_get_depends(GmMcpPackage *package) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->depends;
|
||||
}
|
||||
|
||||
GList const *
|
||||
gm_mcp_package_get_overrides(GmMcpPackage *package) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->overrides;
|
||||
}
|
||||
|
||||
gdouble
|
||||
gm_mcp_package_get_min_version(GmMcpPackage *package) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->min_version;
|
||||
}
|
||||
|
||||
gdouble
|
||||
gm_mcp_package_get_max_version(GmMcpPackage *package) {
|
||||
return GM_MCP_PACKAGE_GET_CLASS(package)->max_version;
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
#ifndef __GM_MCP_PACKAGE_H__
|
||||
#define __GM_MCP_PACKAGE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_MCP_PACKAGE (gm_mcp_package_get_type())
|
||||
#define GM_MCP_PACKAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_MCP_PACKAGE, GmMcpPackage))
|
||||
#define GM_MCP_PACKAGE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
GM_TYPE_MCP_PACKAGE, GmMcpPackage const))
|
||||
#define GM_MCP_PACKAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_MCP_PACKAGE, GmMcpPackageClass))
|
||||
#define GM_IS_MCP_PACKAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_MCP_PACKAGE))
|
||||
#define GM_IS_MCP_PACKAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_MCP_PACKAGE))
|
||||
#define GM_MCP_PACKAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_MCP_PACKAGE, GmMcpPackageClass))
|
||||
#define GM_MCP_PACKAGE_SESSION(obj) (GM_MCP_SESSION( \
|
||||
gm_mcp_package_get_session(GM_MCP_PACKAGE(obj))))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmMcpPackagePrivate GmMcpPackagePrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmMcpPackage GmMcpPackage;
|
||||
|
||||
struct _GmMcpPackage {
|
||||
GObject parent;
|
||||
|
||||
/*< private > */
|
||||
GmMcpPackagePrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmMcpPackageClass GmMcpPackageClass;
|
||||
|
||||
struct _GmMcpPackageClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
gchar *name;
|
||||
gdouble min_version;
|
||||
gdouble max_version;
|
||||
GList *depends;
|
||||
GList *overrides;
|
||||
|
||||
void (* handle_simple)(GmMcpPackage *package, gchar *suffix, GList *fields);
|
||||
gboolean (* handle_multi)(GmMcpPackage *package, gchar *data_tag,
|
||||
gchar *key, gchar *value, GList *allValues);
|
||||
|
||||
/* Signals
|
||||
void (* proto) (GmMcpPackage *obj); */
|
||||
};
|
||||
|
||||
/* Public */
|
||||
GType gm_mcp_package_get_type(void) G_GNUC_CONST;
|
||||
GmMcpPackage *gm_mcp_package_new();
|
||||
void gm_mcp_package_set_session(GmMcpPackage *package, GObject *session);
|
||||
|
||||
void gm_mcp_package_handle_simple(GmMcpPackage *package, gchar *suffix,
|
||||
GList *fields);
|
||||
gboolean gm_mcp_package_can_handle_simple(GmMcpPackage *package);
|
||||
|
||||
gboolean gm_mcp_package_handle_multi(GmMcpPackage *package, gchar *data_tag,
|
||||
gchar *key, gchar *value, GList *allValues);
|
||||
gboolean gm_mcp_package_can_handle_multi(GmMcpPackage *package);
|
||||
|
||||
void gm_mcp_package_set_version(GmMcpPackage *package, gdouble version);
|
||||
gdouble gm_mcp_package_get_version(GmMcpPackage *package);
|
||||
GObject *gm_mcp_package_get_session(GmMcpPackage *package);
|
||||
|
||||
/* Class getters */
|
||||
gchar const *gm_mcp_package_get_name(GmMcpPackage *package);
|
||||
GList const *gm_mcp_package_get_depends(GmMcpPackage *package);
|
||||
GList const *gm_mcp_package_get_overrides(GmMcpPackage *package);
|
||||
gdouble gm_mcp_package_get_min_version(GmMcpPackage *package);
|
||||
gdouble gm_mcp_package_get_max_version(GmMcpPackage *package);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_MCP_PACKAGE_H__ */
|
|
@ -1,501 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gm-mcp-session.h"
|
||||
#include "gm-mcp-classes.h"
|
||||
#include "gm-mcp.h"
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-options.h"
|
||||
|
||||
#define GM_MCP_SESSION_GET_PRIVATE(object)( \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_MCP_SESSION, GmMcpSessionPrivate))
|
||||
|
||||
struct _GmMcpSessionPrivate {
|
||||
GmWorld *world;
|
||||
gchar *authkey;
|
||||
gdouble version;
|
||||
|
||||
GList *packages;
|
||||
GList *multiline;
|
||||
};
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_mcp_session_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(GmMcpSession, gm_mcp_session, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_mcp_session_finalize(GObject *object) {
|
||||
//GmMcpSession *obj = GM_MCP_SESSION(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_mcp_session_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_session_class_init(GmMcpSessionClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_mcp_session_finalize;
|
||||
klass->available_packages = gm_mcp_classes_initialize();
|
||||
|
||||
/*gm_mcp_session_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmMcpSessionClass, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmMcpSessionPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_mcp_session_init(GmMcpSession *obj) {
|
||||
obj->priv = GM_MCP_SESSION_GET_PRIVATE(obj);
|
||||
obj->priv->packages = NULL;
|
||||
obj->priv->version = -1;
|
||||
obj->priv->authkey = NULL;
|
||||
obj->priv->multiline = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_handle_open(GmMcpSession *session, gchar *line) {
|
||||
GList *fields = gm_mcp_process_key_values(line);
|
||||
GmMcpPackage *p;
|
||||
GmMcpPackageClass *pklass;
|
||||
gchar const *min_version = gm_mcp_find_value(fields, "version");
|
||||
gchar const *max_version = gm_mcp_find_value(fields, "to");
|
||||
//gchar *minc, *maxc;
|
||||
gdouble min_v, max_v, version;
|
||||
|
||||
if (!(min_version && max_version)) {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOpen: invalid opening, "
|
||||
"min version or max_version not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
//minc = gm_fix_decimal_point(g_strdup(min_version), strlen(min_version));
|
||||
//maxc = gm_fix_decimal_point(g_strdup(max_version), strlen(max_version));
|
||||
|
||||
min_v = g_ascii_strtod(min_version, NULL);
|
||||
max_v = g_ascii_strtod(max_version, NULL);
|
||||
|
||||
//g_free(minc);
|
||||
//g_free(maxc);
|
||||
|
||||
gm_debug_msg(DEBUG_MCP, "MinMaxVersion: %fd %fd", min_v, max_v);
|
||||
|
||||
version = gm_mcp_get_version(MCP_MIN_VERSION, MCP_MAX_VERSION,
|
||||
min_v, max_v);
|
||||
|
||||
if (version > 0.0) {
|
||||
session->priv->authkey = gm_mcp_generate_auth_key();
|
||||
session->priv->version = version;
|
||||
|
||||
gm_mcp_session_send_simple(session, "mcp", "authentication-key",
|
||||
session->priv->authkey, "version", "2.1", "to", "2.1", NULL);
|
||||
|
||||
pklass = gm_mcp_session_find_package_class("mcp-negotiate");
|
||||
p = gm_mcp_session_create_package(session, pklass,
|
||||
pklass->max_version);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOpen: mcp server version "
|
||||
"does not match client version!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_invoke_multiline_handle(GmMcpSession *session, gchar *data_tag,
|
||||
gchar *key, gchar *value) {
|
||||
GList *elem;
|
||||
GmMcpPackage *p;
|
||||
McpMultilineInfo *minfo;
|
||||
gboolean handle_all = FALSE;
|
||||
|
||||
// Now find the data_tag and emit the handle_multiline
|
||||
for (elem = session->priv->multiline; elem; elem = elem->next) {
|
||||
minfo = (McpMultilineInfo *)(elem->data);
|
||||
|
||||
if (strcmp(minfo->data_tag, data_tag) == 0) {
|
||||
p = minfo->package;
|
||||
|
||||
if (gm_mcp_package_can_handle_multi(p)) {
|
||||
if (key) {
|
||||
if (!gm_mcp_package_handle_multi(p, data_tag, key, value,
|
||||
NULL)) {
|
||||
// Not handled a single value, store it for later
|
||||
minfo->data = g_list_append(minfo->data,
|
||||
g_strdup(value));
|
||||
}
|
||||
} else {
|
||||
handle_all = gm_mcp_package_handle_multi(p, data_tag, NULL,
|
||||
NULL, minfo->data);
|
||||
}
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
// This is the end, remove the minfo
|
||||
g_free(minfo->data_tag);
|
||||
g_free(minfo->key);
|
||||
|
||||
// Lines should only be freed when allValues is not handled!
|
||||
if (!handle_all) {
|
||||
g_list_free_simple(minfo->data);
|
||||
} else {
|
||||
g_list_free(minfo->data);
|
||||
}
|
||||
|
||||
session->priv->multiline = g_list_remove(
|
||||
session->priv->multiline, minfo);
|
||||
g_free(minfo);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_handle_multiline(GmMcpSession *session, gchar *line) {
|
||||
gchar *data_tag, *key, *value, *ptr = line, *key_start;
|
||||
|
||||
gm_string_skip_nonspace(&ptr);
|
||||
|
||||
if (*ptr == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
data_tag = g_strndup(line, ptr - line);
|
||||
gm_string_skip_space(&ptr);
|
||||
|
||||
key_start = ptr;
|
||||
|
||||
gm_string_skip_nonspace(&ptr);
|
||||
|
||||
if (*ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
key = g_strndup(key_start, (ptr - key_start) - 1);
|
||||
value = g_strdup(ptr + 1);
|
||||
|
||||
gm_mcp_session_invoke_multiline_handle(session, data_tag, key, value);
|
||||
|
||||
g_free(data_tag);
|
||||
g_free(key);
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_handle_multiline_end(GmMcpSession *session, gchar *line) {
|
||||
gchar *ptr = line;
|
||||
gchar *data_tag;
|
||||
|
||||
while (*ptr != '\0' && g_unichar_isspace(g_utf8_get_char(ptr))) {
|
||||
ptr = g_utf8_next_char(ptr);
|
||||
}
|
||||
|
||||
data_tag = g_strndup(line, ptr - line);
|
||||
gm_mcp_session_invoke_multiline_handle(session, data_tag, NULL, NULL);
|
||||
g_free(data_tag);
|
||||
}
|
||||
|
||||
/* Public */
|
||||
GmMcpSession *
|
||||
gm_mcp_session_new(GObject *world) {
|
||||
GmMcpSession *obj = GM_MCP_SESSION(g_object_new(GM_TYPE_MCP_SESSION, NULL));
|
||||
|
||||
obj->priv->world = GM_WORLD(world);
|
||||
return obj;
|
||||
}
|
||||
|
||||
GList const *
|
||||
gm_mcp_session_get_packages(GmMcpSession *session) {
|
||||
return session->priv->packages;
|
||||
}
|
||||
|
||||
GmMcpPackageClass *
|
||||
gm_mcp_session_package_class_for_each(GmPackageClassFunc func,
|
||||
gpointer user_data) {
|
||||
GmMcpSessionClass *klass = g_type_class_peek(GM_TYPE_MCP_SESSION);
|
||||
GList *item;
|
||||
GmMcpPackageClass *package_klass;
|
||||
|
||||
for (item = klass->available_packages; item; item = item->next) {
|
||||
package_klass = GM_MCP_PACKAGE_CLASS(item->data);
|
||||
|
||||
if (func(package_klass, user_data)) {
|
||||
return package_klass;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_send_multiline(GmMcpSession *session, gchar const *data_tag,
|
||||
gchar const *key, GList const *lines) {
|
||||
gchar *msg = g_strconcat("#$#* ", data_tag, " ", key, ": ", NULL);
|
||||
gchar *msg_line = NULL;
|
||||
|
||||
while (lines) {
|
||||
msg_line = g_strconcat(msg, (gchar *)(lines->data), NULL);
|
||||
gm_world_sendln(session->priv->world, msg_line);
|
||||
gm_world_log(session->priv->world, LOG_MCP_OUT, msg_line);
|
||||
|
||||
g_free(msg_line);
|
||||
lines = lines->next;
|
||||
}
|
||||
|
||||
g_free(msg);
|
||||
msg_line = g_strconcat("#$#: ", data_tag, NULL);
|
||||
|
||||
gm_world_sendln(session->priv->world, msg_line);
|
||||
gm_world_log(session->priv->world, LOG_MCP_OUT, msg_line);
|
||||
|
||||
g_free(msg_line);
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_send_simple(GmMcpSession *session, gchar const *pname,
|
||||
gchar const *first_key, ...) {
|
||||
GString *msg = NULL;
|
||||
va_list args;
|
||||
gchar const *key, *value;
|
||||
gchar *esvalue;
|
||||
|
||||
msg = g_string_new("#$#");
|
||||
msg = g_string_append(msg, pname);
|
||||
|
||||
if (strcasecmp(pname, "mcp") != 0) {
|
||||
msg = g_string_append(msg, " ");
|
||||
msg = g_string_append(msg, session->priv->authkey);
|
||||
}
|
||||
|
||||
msg = g_string_append(msg, " ");
|
||||
|
||||
if (first_key != NULL) {
|
||||
va_start(args, first_key);
|
||||
key = first_key;
|
||||
|
||||
while (key) {
|
||||
value = va_arg(args, gchar *);
|
||||
|
||||
if (value) {
|
||||
msg = g_string_append(msg, key);
|
||||
msg = g_string_append(msg, ": ");
|
||||
esvalue = gm_mcp_escape_if_needed(value);
|
||||
msg = g_string_append(msg, esvalue);
|
||||
g_free(esvalue);
|
||||
msg = g_string_append(msg, " ");
|
||||
key = va_arg(args, gchar *);
|
||||
} else {
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
gm_world_sendln(session->priv->world, msg->str);
|
||||
gm_world_log(session->priv->world, LOG_MCP_OUT, msg->str);
|
||||
g_string_free(msg, TRUE);
|
||||
}
|
||||
|
||||
GmMcpPackage *
|
||||
gm_mcp_session_has_package_of_class(GmMcpSession *session,
|
||||
GmMcpPackageClass *klass) {
|
||||
GList *item;
|
||||
GmMcpPackage *package;
|
||||
GType klass_type = G_TYPE_FROM_CLASS(klass);
|
||||
|
||||
for (item = session->priv->packages; item; item = item->next) {
|
||||
package = (GmMcpPackage *)(item->data);
|
||||
|
||||
if (G_TYPE_FROM_CLASS(GM_MCP_PACKAGE_GET_CLASS(package)) ==
|
||||
klass_type) {
|
||||
return package;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GmMcpPackage *
|
||||
gm_mcp_session_find_package(GmMcpSession *session, gchar const *pname) {
|
||||
GList *elem;
|
||||
GmMcpPackage *package;
|
||||
GmMcpPackageClass *package_klass;
|
||||
|
||||
for (elem = session->priv->packages; elem; elem = elem->next) {
|
||||
package = (GmMcpPackage *) (elem->data);
|
||||
package_klass = GM_MCP_PACKAGE_GET_CLASS(package);
|
||||
|
||||
if (strncasecmp(pname, package_klass->name,
|
||||
strlen(package_klass->name)) == 0 && (strlen(pname) ==
|
||||
strlen(package_klass->name) ||
|
||||
pname[strlen(package_klass->name)] == '-')) {
|
||||
return package;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GmMcpPackage *
|
||||
gm_mcp_session_create_package(GmMcpSession *session, GmMcpPackageClass *klass,
|
||||
gdouble version) {
|
||||
GmMcpPackage *package;
|
||||
|
||||
if (!klass) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!gm_mcp_session_has_package_of_class(session, klass)) {
|
||||
package = g_object_new(G_TYPE_FROM_CLASS(G_OBJECT_CLASS(klass)), NULL);
|
||||
|
||||
gm_mcp_package_set_session(package, G_OBJECT(session));
|
||||
gm_mcp_package_set_version(package, version);
|
||||
|
||||
session->priv->packages = g_list_append(session->priv->packages,
|
||||
package);
|
||||
return package;
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.CreatePackage: package (%s) is "
|
||||
"already registered for %s", klass->name,
|
||||
gm_options_get(gm_world_options(session->priv->world), "name"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_mcp_session_find_package_class_real(GmMcpPackageClass *klass,
|
||||
gpointer user_data) {
|
||||
gchar *name = (gchar *)(user_data);
|
||||
return strcmp(name, klass->name) == 0;
|
||||
}
|
||||
|
||||
GmMcpPackageClass *
|
||||
gm_mcp_session_find_package_class(gchar const *name) {
|
||||
return gm_mcp_session_package_class_for_each(
|
||||
&gm_mcp_session_find_package_class_real, (gpointer)(name));
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_session_handle_oob(GmMcpSession *session, gchar *line) {
|
||||
McpMessageInfo info;
|
||||
GmMcpPackage *package;
|
||||
McpMultilineInfo *minfo;
|
||||
gchar *suffix;
|
||||
gchar const *value, *full;
|
||||
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: %s", line);
|
||||
|
||||
info.fields = NULL;
|
||||
info.authkey = NULL;
|
||||
info.name = NULL;
|
||||
|
||||
if (strncmp(line, "mcp ", 4) == 0 && session->priv->version == -1) {
|
||||
gm_mcp_session_handle_open(session, line + 3);
|
||||
} else if (session->priv->version == -1) {
|
||||
// No session, drop
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: No session found for %s, "
|
||||
"ignoring out of bound command!", gm_options_get(
|
||||
gm_world_options(session->priv->world), "name"));
|
||||
} else if (strncmp(line, "* ", 2) == 0) {
|
||||
// Multiline
|
||||
gm_mcp_session_handle_multiline(session, line + 2);
|
||||
} else if (strncmp(line, ": ", 2) == 0) {
|
||||
// Multiline end
|
||||
gm_mcp_session_handle_multiline_end(session, line + 2);
|
||||
} else {
|
||||
if (gm_mcp_parse_line(line, &info)) {
|
||||
// Line is valid mcp
|
||||
if (strcmp(info.authkey, session->priv->authkey) == 0) {
|
||||
// Valid authentication
|
||||
if ((package = gm_mcp_session_find_package(session,
|
||||
info.name))) {
|
||||
// Find package
|
||||
if ((value = gm_mcp_find_multiline_tag(info.fields))) {
|
||||
// This is multiline start!
|
||||
if (gm_mcp_find_value(info.fields,
|
||||
"_data-tag")) {
|
||||
// This package requests a multiline opening!
|
||||
minfo = g_new(McpMultilineInfo, 1);
|
||||
minfo->key = g_strdup(value);
|
||||
minfo->data_tag = g_strdup(
|
||||
gm_mcp_find_value(info.fields,
|
||||
"_data-tag"));
|
||||
minfo->data = NULL;
|
||||
minfo->package = package;
|
||||
|
||||
session->priv->multiline = g_list_append(
|
||||
session->priv->multiline, minfo);
|
||||
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: multiline "
|
||||
"opening detected and stored "
|
||||
"(data_tag = %s, key = %s)",
|
||||
minfo->data_tag,
|
||||
minfo->key);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: multiline "
|
||||
"opening detected, but no _data-tag specified, "
|
||||
"ignore message");
|
||||
}
|
||||
}
|
||||
|
||||
if (gm_mcp_package_can_handle_simple(package)) {
|
||||
full = gm_mcp_package_get_name(package);
|
||||
if (strlen(full) < strlen(info.name)) {
|
||||
suffix = info.name + (strlen(full) + 1);
|
||||
} else {
|
||||
suffix = NULL;
|
||||
}
|
||||
|
||||
gm_mcp_package_handle_simple(package, suffix,
|
||||
info.fields);
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: can't handle simple message!");
|
||||
}
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: unsupported package "
|
||||
"%s, ignore message", info.name);
|
||||
}
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: invalid authentication "
|
||||
"key %s instead of %s, ignore message", info.authkey,
|
||||
session->priv->authkey);
|
||||
}
|
||||
} else {
|
||||
gm_debug_msg(DEBUG_MCP, "GmMcpSession.HandleOob: invalid message "
|
||||
"(could not parse), ignore message");
|
||||
}
|
||||
|
||||
// Free the info
|
||||
if (info.authkey) {
|
||||
g_free(info.authkey);
|
||||
}
|
||||
|
||||
if (info.name) {
|
||||
g_free(info.name);
|
||||
}
|
||||
if (info.fields) {
|
||||
gm_mcp_destroy_fields(info.fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GObject *gm_mcp_session_world(GmMcpSession *session) {
|
||||
return G_OBJECT(session->priv->world);
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
#ifndef __GM_MCP_SESSION_H__
|
||||
#define __GM_MCP_SESSION_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gm-mcp-package.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_MCP_SESSION (gm_mcp_session_get_type())
|
||||
#define GM_MCP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_MCP_SESSION, GmMcpSession))
|
||||
#define GM_MCP_SESSION_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
GM_TYPE_MCP_SESSION, GmMcpSession const))
|
||||
#define GM_MCP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_MCP_SESSION, GmMcpSessionClass))
|
||||
#define GM_IS_MCP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_MCP_SESSION))
|
||||
#define GM_IS_MCP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_MCP_SESSION))
|
||||
#define GM_MCP_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_MCP_SESSION, GmMcpSessionClass))
|
||||
#define GM_MCP_SESSION_WORLD(obj) (GM_WORLD(gm_mcp_session_world(obj)))
|
||||
|
||||
typedef struct _McpMultilineInfo {
|
||||
gchar *key;
|
||||
gchar *data_tag;
|
||||
GList *data;
|
||||
GmMcpPackage *package;
|
||||
} McpMultilineInfo;
|
||||
|
||||
typedef gboolean (* GmPackageClassFunc) (GmMcpPackageClass *klass,
|
||||
gpointer user_data);
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmMcpSessionPrivate GmMcpSessionPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmMcpSession GmMcpSession;
|
||||
|
||||
struct _GmMcpSession {
|
||||
GObject parent;
|
||||
|
||||
/*< private > */
|
||||
GmMcpSessionPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmMcpSessionClass GmMcpSessionClass;
|
||||
|
||||
struct _GmMcpSessionClass {
|
||||
GObjectClass parent_class;
|
||||
GList *available_packages;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (GmMcpSession *obj); */
|
||||
};
|
||||
|
||||
GType gm_mcp_session_get_type(void) G_GNUC_CONST;
|
||||
GmMcpSession *gm_mcp_session_new(GObject *world);
|
||||
|
||||
GObject *gm_mcp_session_world(GmMcpSession *session);
|
||||
GList const *gm_mcp_session_get_packages(GmMcpSession *session);
|
||||
void gm_mcp_session_handle_oob(GmMcpSession *session, gchar *line);
|
||||
|
||||
GmMcpPackage *gm_mcp_session_has_package_of_class(GmMcpSession *session,
|
||||
GmMcpPackageClass *klass);
|
||||
GmMcpPackageClass *gm_mcp_session_find_package_class(gchar const *name);
|
||||
GmMcpPackage *gm_mcp_session_find_package(GmMcpSession *session,
|
||||
gchar const *pname);
|
||||
GmMcpPackageClass *gm_mcp_session_package_class_for_each(
|
||||
GmPackageClassFunc func, gpointer user_data);
|
||||
|
||||
GmMcpPackage *gm_mcp_session_create_package(GmMcpSession *session,
|
||||
GmMcpPackageClass *klass, gdouble version);
|
||||
|
||||
void gm_mcp_session_send_simple(GmMcpSession *session, gchar const *pname,
|
||||
gchar const *first_key, ...);
|
||||
void gm_mcp_session_send_multiline(GmMcpSession *session, gchar const *data_tag,
|
||||
gchar const *key, GList const *lines);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_MCP_SESSION_H__ */
|
263
src/mcp/gm-mcp.c
263
src/mcp/gm-mcp.c
|
@ -1,263 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "gm-mcp.h"
|
||||
#include "../gm-support.h"
|
||||
|
||||
gdouble
|
||||
gm_mcp_get_version(gdouble client_min, gdouble client_max, gdouble server_min,
|
||||
gdouble server_max) {
|
||||
if (client_max >= server_min && server_max >= client_min) {
|
||||
if (client_max < server_max) {
|
||||
return server_max;
|
||||
} else {
|
||||
return client_max;
|
||||
}
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
gchar const *
|
||||
gm_mcp_find_value(GList const *fields, gchar const *key) {
|
||||
GmKeyValuePair *tmp;
|
||||
|
||||
while (fields) {
|
||||
tmp = (GmKeyValuePair *)(fields->data);
|
||||
|
||||
if (strcasecmp(key, tmp->key) == 0) {
|
||||
return tmp->value;
|
||||
}
|
||||
|
||||
fields = fields->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_mcp_escape_if_needed(gchar const *line) {
|
||||
GString *new_line;
|
||||
gchar const *ptr = line;
|
||||
gchar *result;
|
||||
|
||||
if (*line == '\0') {
|
||||
return g_strdup("\"\"");
|
||||
}
|
||||
|
||||
if (g_utf8_strchr(line, -1, ' ') || g_utf8_strchr(line, -1, '"') ||
|
||||
g_utf8_strchr(line, -1, '\\')) {
|
||||
new_line = g_string_new("\"");
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (*ptr == '"' || *ptr == '\\') {
|
||||
new_line = g_string_append_c(new_line, '\\');
|
||||
}
|
||||
|
||||
new_line = g_string_append_c(new_line, *ptr);
|
||||
++ptr;
|
||||
}
|
||||
|
||||
new_line = g_string_append_c(new_line, '"');
|
||||
result = new_line->str;
|
||||
g_string_free(new_line, FALSE);
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return g_strdup(line);
|
||||
}
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_mcp_un_escape(gchar *line) {
|
||||
gchar *ptri = line, *ptrj = line;
|
||||
gboolean shifted = FALSE;
|
||||
|
||||
while (*ptri != '\0') {
|
||||
if (*ptri == '\\') {
|
||||
shifted = TRUE;
|
||||
++ptri;
|
||||
}
|
||||
|
||||
if (shifted) {
|
||||
*ptrj = *ptri;
|
||||
}
|
||||
|
||||
++ptrj;
|
||||
++ptri;
|
||||
}
|
||||
|
||||
*ptrj = '\0';
|
||||
return line;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_mcp_process_keyval(GList **info, gchar *line) {
|
||||
gchar *keystart;
|
||||
gchar *valuestart;
|
||||
int keylen, valuelen;
|
||||
GmKeyValuePair *newKeyValue;
|
||||
|
||||
if (*line != ' ' || line[1] == '\0' || line[1] == ' ') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keystart = ++line;
|
||||
gm_string_skip_till(&line, ": ");
|
||||
|
||||
if (*line != ':') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keylen = line - keystart;
|
||||
line = g_utf8_next_char(line);
|
||||
|
||||
if (line[1] == '\0' || *line != ' ') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
line = g_utf8_next_char(line);
|
||||
|
||||
if (*line == ' ') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
valuestart = line;
|
||||
|
||||
if (*line == '"') {
|
||||
++valuestart;
|
||||
++line;
|
||||
|
||||
while (*line != '\0' && *line != '"') {
|
||||
if (*line == '\\') {
|
||||
++line;
|
||||
}
|
||||
|
||||
++line;
|
||||
}
|
||||
|
||||
valuelen = line - valuestart;
|
||||
|
||||
if (*line != '"') {
|
||||
--valuelen;
|
||||
} else {
|
||||
++line;
|
||||
}
|
||||
} else {
|
||||
gm_string_skip_nonspace(&line);
|
||||
valuelen = line - valuestart;
|
||||
}
|
||||
|
||||
newKeyValue = g_new(GmKeyValuePair, 1);
|
||||
newKeyValue->key = g_strndup(keystart, keylen);
|
||||
newKeyValue->value = gm_mcp_un_escape(g_strndup(valuestart, valuelen));
|
||||
|
||||
*info = g_list_append(*info, newKeyValue);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
GList *
|
||||
gm_mcp_process_key_values(gchar *line) {
|
||||
GList *result = NULL;
|
||||
|
||||
while (line && *line != '\0') {
|
||||
line = gm_mcp_process_keyval(&result, line);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_mcp_parse_line(gchar *line, McpMessageInfo *info) {
|
||||
gchar *p = g_utf8_strchr(line, -1, ' ');
|
||||
|
||||
if (!p || p == line) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->name = g_strndup(line, (p - line));
|
||||
line = p + 1;
|
||||
|
||||
// Now there should be a authentication key!
|
||||
p = g_utf8_strchr(line, -1, ' ');
|
||||
|
||||
if (!p) {
|
||||
p = line + strlen(line);
|
||||
}
|
||||
|
||||
info->authkey = g_strndup(line, (p - line));
|
||||
|
||||
// Now process the keyvals
|
||||
info->fields = gm_mcp_process_key_values(p);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_mcp_generate_key(gint len) {
|
||||
gchar *s = g_malloc(len + 1);
|
||||
gchar ref[] =
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||||
gint n = strlen(ref);
|
||||
gint i;
|
||||
|
||||
srand((int) time(NULL));
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
s[i] = ref[rand() % n];
|
||||
}
|
||||
|
||||
s[i] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_mcp_generate_data_tag() {
|
||||
return gm_mcp_generate_key(10);
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_mcp_generate_auth_key() {
|
||||
return gm_mcp_generate_key(6);
|
||||
}
|
||||
|
||||
gchar const *
|
||||
gm_mcp_find_multiline_tag(GList const *fields) {
|
||||
GmKeyValuePair *data;
|
||||
gunichar last;
|
||||
|
||||
while (fields) {
|
||||
data = (GmKeyValuePair *)(fields->data);
|
||||
last = g_utf8_get_char(g_utf8_prev_char(data->key + strlen(data->key)));
|
||||
|
||||
if (last == '*') {
|
||||
return data->key;
|
||||
}
|
||||
|
||||
fields = fields->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gm_mcp_destroy_fields(GList *fields) {
|
||||
GmKeyValuePair *tmp;
|
||||
GList *elem = fields;
|
||||
|
||||
while (elem) {
|
||||
tmp = (GmKeyValuePair *) (elem->data);
|
||||
|
||||
g_free(tmp->key);
|
||||
g_free(tmp->value);
|
||||
|
||||
g_free(elem->data);
|
||||
elem->data = NULL;
|
||||
|
||||
elem = elem->next;
|
||||
}
|
||||
|
||||
g_list_free(fields);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef __GM_MCP_H__
|
||||
#define __GM_MCP_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "gm-mcp.h"
|
||||
|
||||
#define MCP_MIN_VERSION 2.1
|
||||
#define MCP_MAX_VERSION 2.1
|
||||
|
||||
typedef struct _McpMessageInfo {
|
||||
gchar *name;
|
||||
gchar *authkey;
|
||||
GList *fields;
|
||||
} McpMessageInfo;
|
||||
|
||||
gdouble gm_mcp_get_version(gdouble client_min, gdouble client_max,
|
||||
gdouble server_min, gdouble server_max);
|
||||
gchar const *gm_mcp_find_value(GList const *fields, gchar const *key);
|
||||
gchar *gm_mcp_escape_if_needed(gchar const *line);
|
||||
gchar *gm_mcp_un_escape(gchar *line);
|
||||
GList *gm_mcp_process_key_values(gchar *line);
|
||||
gboolean gm_mcp_parse_line(gchar *line, McpMessageInfo *info);
|
||||
gchar *gm_mcp_generate_data_tag();
|
||||
gchar *gm_mcp_generate_auth_key();
|
||||
gchar const *gm_mcp_find_multiline_tag(GList const *fields);
|
||||
void gm_mcp_destroy_fields(GList *fields);
|
||||
|
||||
#endif /* __GM_MCP_H__ */
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
begin
|
||||
defs = File.readlines(ARGV[0])
|
||||
defs.collect! {|elem| elem.chomp}
|
||||
|
||||
fout = File.open(ARGV[1] + '.c', 'w')
|
||||
|
||||
includes = ['<glib-object.h>']
|
||||
content = "GList *\ngm_mcp_classes_initialize() {\n\tGList *result = NULL;\n\n"
|
||||
|
||||
defs.each do |line|
|
||||
ucase = line.gsub(/[A-Z]+[a-z]+/) do |s|
|
||||
s.upcase + '_'
|
||||
end
|
||||
|
||||
ucase.chop!
|
||||
mcase = ucase.downcase.gsub('_', '-')
|
||||
|
||||
includes << '"gm-mcp-' + mcase + '.h"'
|
||||
content += "\tresult = g_list_append(result, \n\t\t\tg_type_class_ref(GM_TYPE_MCP_" + ucase + "));\n"
|
||||
end
|
||||
|
||||
includes.each {|inc| fout.write('#include ' + inc + "\n")}
|
||||
fout.write("\n" + content + "\treturn result;\n}\n")
|
||||
fout.close
|
||||
|
||||
fout = File.open(ARGV[1] + '.h', 'w')
|
||||
fout.write("GList *gm_mcp_classes_initialize();\n")
|
||||
fout.close
|
||||
rescue StandardError => boom
|
||||
p boom
|
||||
exit(1)
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
Negotiate
|
||||
AwnsStatus
|
|
@ -1,59 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include "gm-{template-}.h"
|
||||
|
||||
#define GM_{TEMPLATE}_GET_PRIVATE(object)( \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}Private))
|
||||
|
||||
struct _Gm{Template}Private {
|
||||
|
||||
};
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_{template_}_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(Gm{Template}, gm_{template_}, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_{template_}_finalize(GObject *object) {
|
||||
//Gm{Template} *obj = GM_{TEMPLATE}(object);
|
||||
|
||||
G_OBJECT_CLASS(gm_{template_}_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_{template_}_class_init(Gm{Template}Class *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_{template_}_finalize;
|
||||
|
||||
/*gm_{template_}_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(Gm{Template}Class, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(Gm{Template}Private));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_{template_}_init(Gm{Template} *obj) {
|
||||
obj->priv = GM_{TEMPLATE}_GET_PRIVATE(obj);
|
||||
}
|
||||
|
||||
Gm{Template} *
|
||||
gm_{template_}_new() {
|
||||
Gm{Template} *obj = GM_{TEMPLATE}(g_object_new(GM_TYPE_{TEMPLATE}, NULL));
|
||||
|
||||
return obj;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
#ifndef __GM_{TEMPLATE}_H__
|
||||
#define __GM_{TEMPLATE}_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_{TEMPLATE} (gm_{template_}_get_type())
|
||||
#define GM_{TEMPLATE}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}))
|
||||
#define GM_{TEMPLATE}_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template} const))
|
||||
#define GM_{TEMPLATE}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}Class))
|
||||
#define GM_IS_{TEMPLATE}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
||||
GM_TYPE_{TEMPLATE}))
|
||||
#define GM_IS_{TEMPLATE}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
GM_TYPE_{TEMPLATE}))
|
||||
#define GM_{TEMPLATE}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
GM_TYPE_{TEMPLATE}, Gm{Template}Class))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _Gm{Template}Private Gm{Template}Private;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _Gm{Template} Gm{Template};
|
||||
|
||||
struct _Gm{Template} {
|
||||
GObject parent;
|
||||
|
||||
/*< private > */
|
||||
Gm{Template}Private *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _Gm{Template}Class Gm{Template}Class;
|
||||
|
||||
struct _Gm{Template}Class {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (Gm{Template} *obj); */
|
||||
};
|
||||
|
||||
GType gm_{template_}_get_type(void) G_GNUC_CONST;
|
||||
Gm{Template} *gm_{template_}_new(void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_{TEMPLATE}_H__ */
|
|
@ -1,10 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
widgetsdir = widgets
|
||||
|
||||
gnoemoe_SOURCES += \
|
||||
$(widgetsdir)/gm-app-view.c $(widgetsdir)/gm-app-view.h \
|
||||
$(widgetsdir)/gm-world-view.c $(widgetsdir)/gm-world-view.h \
|
||||
$(widgetsdir)/gm-world-text-view.c $(widgetsdir)/gm-world-text-view.h \
|
||||
$(widgetsdir)/gm-world-input-view.c $(widgetsdir)/gm-world-input-view.h \
|
||||
$(widgetsdir)/gm-world-tab.c $(widgetsdir)/gm-world-tab.h \
|
||||
$(widgetsdir)/gm-text-scroller.c $(widgetsdir)/gm-text-scroller.h
|
File diff suppressed because it is too large
Load diff
|
@ -1,78 +0,0 @@
|
|||
#ifndef __GM_APP_VIEW_H__
|
||||
#define __GM_APP_VIEW_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
#include <glade/glade.h>
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-app.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_APP_VIEW (gm_app_view_get_type())
|
||||
#define GM_APP_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_APP_VIEW, GmAppView))
|
||||
#define GM_APP_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_APP_VIEW, GmAppView const))
|
||||
#define GM_APP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_APP_VIEW, GmAppViewClass))
|
||||
#define GM_IS_APP_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_APP_VIEW))
|
||||
#define GM_IS_APP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_APP_VIEW))
|
||||
#define GM_APP_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_APP_VIEW, GmAppViewClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmAppViewPrivate GmAppViewPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmAppView GmAppView;
|
||||
|
||||
struct _GmAppView {
|
||||
GtkWindow window;
|
||||
|
||||
/*< private > */
|
||||
GmAppViewPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmAppViewClass GmAppViewClass;
|
||||
|
||||
struct _GmAppViewClass {
|
||||
GtkWindowClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
};
|
||||
|
||||
GType gm_app_view_get_type(void) G_GNUC_CONST;
|
||||
GmAppView *gm_app_view_new(GmApp *application);
|
||||
const GmApp *gm_app_view_application(GmAppView *view);
|
||||
|
||||
/* Callbacks */
|
||||
void on_gm_app_view_world_new(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_world_connect(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_world_logs(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_world_info(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_world_close(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_world_quit(GtkMenuItem * menuitem, GmAppView *view);
|
||||
|
||||
void on_gm_app_view_edit_cut(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_copy(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_paste(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_worlds(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_world(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_find(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_find_next(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_edit_preferences(
|
||||
GtkMenuItem * menuitem, GmAppView *view);
|
||||
|
||||
void on_gm_app_view_view_mcp(GtkMenuItem * menuitem, GmAppView *view);
|
||||
void on_gm_app_view_view_scripts(GtkMenuItem * menuitem, GmAppView *view);
|
||||
|
||||
void on_gm_app_view_help_about(GtkMenuItem * menuitem, GmAppView *view);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GM_APP_VIEW__ */
|
|
@ -1,259 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
#include "gm-text-scroller.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-support.h"
|
||||
|
||||
#define GM_TEXT_SCROLLER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_TEXT_SCROLLER, GmTextScrollerPrivate))
|
||||
|
||||
struct _GmTextScrollerPrivate {
|
||||
GtkTextView *text_view;
|
||||
GtkTextBuffer *text_buffer;
|
||||
GtkScrolledWindow *scrolled_window;
|
||||
|
||||
gint character_height;
|
||||
gboolean end_scrolled;
|
||||
gint idle_handler;
|
||||
};
|
||||
|
||||
void on_gm_text_scroller_text_view_style_set(GtkTextView *view,
|
||||
GtkStyle *previous_style, GmTextScroller *scroller);
|
||||
void on_gm_text_scroller_text_buffer_changed(GtkTextBuffer *text_buffer,
|
||||
GmTextScroller *scroller);
|
||||
void on_gm_text_scroller_text_view_notify(GtkTextView *text_view, GParamSpec *arg1,
|
||||
GmTextScroller *scroller);
|
||||
void on_gm_text_scroller_text_view_destroy(GtkTextView *text_view,
|
||||
GmTextScroller *scroller);
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_text_scroller_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(GmTextScroller, gm_text_scroller, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_text_scroller_finalize(GObject *object) {
|
||||
GmTextScroller *obj = GM_TEXT_SCROLLER(object);
|
||||
|
||||
if (obj->priv->text_buffer != NULL) {
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_buffer,
|
||||
G_CALLBACK(on_gm_text_scroller_text_buffer_changed),
|
||||
obj);
|
||||
|
||||
g_object_unref(obj->priv->text_buffer);
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_view,
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_notify), obj);
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_view,
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_style_set), obj);
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_view,
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_destroy), obj);
|
||||
|
||||
G_OBJECT_CLASS(gm_text_scroller_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_text_scroller_class_init(GmTextScrollerClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_text_scroller_finalize;
|
||||
|
||||
/*gm_text_scroller_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmTextScrollerClass, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmTextScrollerPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_text_scroller_init(GmTextScroller *obj) {
|
||||
obj->priv = GM_TEXT_SCROLLER_GET_PRIVATE(obj);
|
||||
|
||||
obj->priv->character_height = 10;
|
||||
obj->priv->end_scrolled = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_update_text_buffer(GmTextScroller *scroller) {
|
||||
if (scroller->priv->text_buffer != NULL) {
|
||||
g_signal_handlers_disconnect_by_func(scroller->priv->text_buffer,
|
||||
G_CALLBACK(on_gm_text_scroller_text_buffer_changed),
|
||||
scroller);
|
||||
|
||||
g_object_unref(scroller->priv->text_buffer);
|
||||
}
|
||||
|
||||
scroller->priv->text_buffer =
|
||||
gtk_text_view_get_buffer(scroller->priv->text_view);
|
||||
|
||||
if (scroller->priv->text_buffer != NULL) {
|
||||
g_object_ref(scroller->priv->text_buffer);
|
||||
|
||||
g_signal_connect(scroller->priv->text_buffer, "changed",
|
||||
G_CALLBACK(on_gm_text_scroller_text_buffer_changed), scroller);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_scroll_end(GmTextScroller *scroller) {
|
||||
GtkTextMark *mark;
|
||||
GtkTextIter iter;
|
||||
|
||||
mark = gtk_text_buffer_get_mark(scroller->priv->text_buffer,
|
||||
"end-of-buffer");
|
||||
|
||||
if (mark == NULL) {
|
||||
gtk_text_buffer_get_end_iter(scroller->priv->text_buffer, &iter);
|
||||
mark = gtk_text_buffer_create_mark(scroller->priv->text_buffer,
|
||||
"end-of-buffer", &iter, FALSE);
|
||||
}
|
||||
|
||||
gtk_text_view_scroll_to_mark(scroller->priv->text_view, mark, 0.0,
|
||||
TRUE, 1.0, 1.0);
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_scroll_begin(GmTextScroller *scroller) {
|
||||
GtkTextMark *mark;
|
||||
GtkTextIter iter;
|
||||
|
||||
mark = gtk_text_buffer_get_mark(scroller->priv->text_buffer,
|
||||
"begin-of-buffer");
|
||||
|
||||
if (mark == NULL) {
|
||||
gtk_text_buffer_get_start_iter(scroller->priv->text_buffer, &iter);
|
||||
mark = gtk_text_buffer_create_mark(scroller->priv->text_buffer,
|
||||
"begin-of-buffer", &iter, TRUE);
|
||||
}
|
||||
|
||||
gtk_text_view_scroll_to_mark(scroller->priv->text_view, mark, 0.0,
|
||||
TRUE, 0.0, 0.0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_text_scroller_scroll_end_idle(GmTextScroller *scroller) {
|
||||
scroller->priv->idle_handler = 0;
|
||||
gm_text_scroller_scroll_end(scroller);
|
||||
scroller->priv->end_scrolled = FALSE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gm_text_scroller_prepare(GmTextScroller *scroller) {
|
||||
GtkAdjustment *ad = gtk_scrolled_window_get_vadjustment(
|
||||
scroller->priv->scrolled_window);
|
||||
|
||||
scroller->priv->end_scrolled = scroller->priv->end_scrolled ||
|
||||
((ad->page_size + ad->value) >= ad->upper -
|
||||
(double)(scroller->priv->character_height));
|
||||
|
||||
if (scroller->priv->idle_handler == 0 && scroller->priv->end_scrolled) {
|
||||
scroller->priv->idle_handler = g_idle_add((GSourceFunc)
|
||||
gm_text_scroller_scroll_end_idle, scroller);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_update_character_height(GmTextScroller *scroller) {
|
||||
GtkRcStyle *style = gtk_widget_get_modifier_style(GTK_WIDGET(
|
||||
scroller->priv->text_view));
|
||||
PangoContext *pc = gtk_widget_create_pango_context(GTK_WIDGET(
|
||||
scroller->priv->text_view));
|
||||
PangoLayout *pl;
|
||||
gint cwidth, cheight;
|
||||
|
||||
if (style->font_desc != NULL) {
|
||||
pango_context_set_font_description(pc, style->font_desc);
|
||||
pl = pango_layout_new(pc);
|
||||
|
||||
pango_layout_set_text(pl, "G", 1);
|
||||
pango_layout_get_pixel_size(pl, &(cwidth),
|
||||
&(cheight));
|
||||
|
||||
if (scroller->priv->character_height != cheight) {
|
||||
scroller->priv->character_height = cheight;
|
||||
}
|
||||
|
||||
g_object_unref(pl);
|
||||
}
|
||||
|
||||
g_object_unref(pc);
|
||||
}
|
||||
|
||||
GmTextScroller *
|
||||
gm_text_scroller_new(GtkTextView *text_view) {
|
||||
GmTextScroller *obj;
|
||||
GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(text_view));
|
||||
|
||||
if (parent == NULL || !GTK_IS_SCROLLED_WINDOW(parent)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = GM_TEXT_SCROLLER(g_object_new(GM_TYPE_TEXT_SCROLLER,
|
||||
NULL));
|
||||
|
||||
obj->priv->text_view = text_view;
|
||||
obj->priv->scrolled_window = GTK_SCROLLED_WINDOW(parent);
|
||||
|
||||
gm_text_scroller_update_text_buffer(obj);
|
||||
gm_text_scroller_update_character_height(obj);
|
||||
|
||||
g_signal_connect(text_view, "notify",
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_notify), obj);
|
||||
g_signal_connect(text_view, "style-set",
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_style_set), obj);
|
||||
g_signal_connect(text_view, "destroy",
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_destroy), obj);
|
||||
|
||||
obj->priv->idle_handler = g_idle_add((GSourceFunc)
|
||||
gm_text_scroller_scroll_end_idle, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_view_notify(GtkTextView *text_view, GParamSpec *arg1,
|
||||
GmTextScroller *scroller) {
|
||||
if (strcmp(arg1->name, "buffer") == 0) {
|
||||
// Buffer changed
|
||||
gm_text_scroller_update_text_buffer(scroller);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_view_style_set(GtkTextView *view,
|
||||
GtkStyle *previous_style, GmTextScroller *scroller) {
|
||||
gm_text_scroller_update_character_height(scroller);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_buffer_changed(GtkTextBuffer *text_buffer,
|
||||
GmTextScroller *scroller) {
|
||||
// Changed...
|
||||
gm_text_scroller_prepare(scroller);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_view_destroy(GtkTextView *text_view,
|
||||
GmTextScroller *scroller) {
|
||||
// Remove ourselfs when the text view dies
|
||||
g_object_unref(scroller);
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef __GM_TEXT_SCROLLER_H__
|
||||
#define __GM_TEXT_SCROLLER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_TEXT_SCROLLER (gm_text_scroller_get_type())
|
||||
#define GM_TEXT_SCROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TEXT_SCROLLER, GmTextScroller))
|
||||
#define GM_TEXT_SCROLLER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TEXT_SCROLLER, GmTextScroller const))
|
||||
#define GM_TEXT_SCROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_TEXT_SCROLLER, GmTextScrollerClass))
|
||||
#define GM_IS_TEXT_SCROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_TEXT_SCROLLER))
|
||||
#define GM_IS_TEXT_SCROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_TEXT_SCROLLER))
|
||||
#define GM_TEXT_SCROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_TEXT_SCROLLER, GmTextScrollerClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmTextScrollerPrivate GmTextScrollerPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmTextScroller GmTextScroller;
|
||||
|
||||
struct _GmTextScroller {
|
||||
GObject parent;
|
||||
|
||||
/*< private > */
|
||||
GmTextScrollerPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmTextScrollerClass GmTextScrollerClass;
|
||||
|
||||
struct _GmTextScrollerClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (GmTextScroller *obj); */
|
||||
};
|
||||
|
||||
GType gm_text_scroller_get_type(void) G_GNUC_CONST;
|
||||
GmTextScroller *gm_text_scroller_new(GtkTextView *text_view);
|
||||
void gm_text_scroller_scroll_end(GmTextScroller *scroller);
|
||||
void gm_text_scroller_scroll_begin(GmTextScroller *scroller);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_TEXT_SCROLLER_H__ */
|
|
@ -1,392 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "gm-world-input-view.h"
|
||||
#include "gm-world-view.h"
|
||||
#include "../gm-world.h"
|
||||
#include "../gm-color-table.h"
|
||||
#include "../gm-debug.h"
|
||||
|
||||
#define GM_WORLD_INPUT_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_WORLD_INPUT_VIEW, GmWorldInputViewPrivate))
|
||||
|
||||
void on_gm_world_input_view_color_table_color_changed(GmColorTable *table,
|
||||
gchar *name, GmWorldInputView *view);
|
||||
void on_gm_world_input_view_color_table_font_changed(GmColorTable *table,
|
||||
gchar *font_description, GmWorldInputView *view);
|
||||
|
||||
gboolean on_gm_world_input_view_key_pressed(GtkWidget *widget,
|
||||
GdkEventKey * event, gpointer userdata);
|
||||
gboolean on_gm_world_input_view_key_released(GtkWidget *widget,
|
||||
GdkEventKey *event, gpointer userdata);
|
||||
|
||||
struct _GmWorldInputViewPrivate {
|
||||
GmColorTable *color_table;
|
||||
GList **history;
|
||||
GList *position;
|
||||
gchar *prefix;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
TEXT_ACTIVATE,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint world_input_view_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmWorldInputView, gm_world_input_view, GTK_TYPE_TEXT_VIEW)
|
||||
|
||||
/* Private functions */
|
||||
static void
|
||||
gm_world_input_view_finalize(GObject *object) {
|
||||
GmWorldInputView *view = GM_WORLD_INPUT_VIEW(object);
|
||||
|
||||
gm_world_input_view_set_color_table(view, NULL);
|
||||
|
||||
G_OBJECT_CLASS(gm_world_input_view_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_input_view_class_init(GmWorldInputViewClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_world_input_view_finalize;
|
||||
|
||||
world_input_view_signals[TEXT_ACTIVATE] =
|
||||
g_signal_new("text_activate",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldInputViewClass, text_activate),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmWorldInputViewPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_input_view_init(GmWorldInputView *view) {
|
||||
view->priv = GM_WORLD_INPUT_VIEW_GET_PRIVATE(view);
|
||||
|
||||
view->priv->color_table = NULL;
|
||||
view->priv->history = NULL;
|
||||
view->priv->position = NULL;
|
||||
view->priv->prefix = NULL;
|
||||
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
|
||||
gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(view), TRUE);
|
||||
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 3);
|
||||
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(view), 3);
|
||||
gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(view), 1);
|
||||
gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(view), 1);
|
||||
|
||||
g_signal_connect(view, "key_press_event",
|
||||
G_CALLBACK(on_gm_world_input_view_key_pressed), NULL);
|
||||
g_signal_connect(view, "key_release_event",
|
||||
G_CALLBACK(on_gm_world_input_view_key_released), NULL);
|
||||
}
|
||||
|
||||
gchar *
|
||||
gm_world_input_view_str_new_value(gchar *old, gchar *new) {
|
||||
g_free(old);
|
||||
|
||||
if (new) {
|
||||
return g_strdup(new);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_input_view_set_text(GmWorldInputView *view, gchar *text, gint len) {
|
||||
GtkTextIter end;
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
|
||||
|
||||
gtk_text_buffer_set_text(buffer, text, len);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
gtk_text_buffer_place_cursor(buffer, &end);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_input_view_update_colors(GmWorldInputView *view) {
|
||||
/*GdkColor col;
|
||||
|
||||
if (view->priv->color_table != NULL) {
|
||||
if (gm_color_table_get(view->priv->color_table, "bg_default", &col)) {
|
||||
gtk_widget_modify_base(GTK_WIDGET(view), GTK_STATE_NORMAL,
|
||||
&col);
|
||||
}
|
||||
if (gm_color_table_get(view->priv->color_table, "fg_default", &col)) {
|
||||
gtk_widget_modify_text(GTK_WIDGET(view), GTK_STATE_NORMAL,
|
||||
&col);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_input_view_update_font(GmWorldInputView *view) {
|
||||
PangoFontDescription *f = pango_font_description_from_string(
|
||||
gm_color_table_font_description(view->priv->color_table));
|
||||
|
||||
if (f != NULL) {
|
||||
gtk_widget_modify_font(GTK_WIDGET(view), f);
|
||||
pango_font_description_free(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
GtkWidget *
|
||||
gm_world_input_view_new() {
|
||||
GtkWidget *result;
|
||||
GmColorTable *table = gm_color_table_new();
|
||||
result = gm_world_input_view_new_with_color_table(table);
|
||||
g_object_unref(table);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_world_input_view_new_with_color_table(GmColorTable *color_table) {
|
||||
GmWorldInputView *view = GM_WORLD_INPUT_VIEW(
|
||||
g_object_new(GM_TYPE_WORLD_INPUT_VIEW, NULL));
|
||||
|
||||
gm_world_input_view_set_color_table(view, color_table);
|
||||
|
||||
return GTK_WIDGET(view);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_input_view_set_history(GmWorldInputView *view, GList **history) {
|
||||
view->priv->history = history;
|
||||
|
||||
view->priv->position = NULL;
|
||||
view->priv->prefix = NULL;
|
||||
}
|
||||
|
||||
GList **
|
||||
gm_world_input_view_history(GmWorldInputView *view) {
|
||||
return view->priv->history;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_input_view_set_color_table(GmWorldInputView *view,
|
||||
GmColorTable *color_table) {
|
||||
if (view->priv->color_table != NULL) {
|
||||
g_signal_handlers_disconnect_by_func(view->priv->color_table,
|
||||
on_gm_world_input_view_color_table_color_changed, view);
|
||||
g_signal_handlers_disconnect_by_func(view->priv->color_table,
|
||||
on_gm_world_input_view_color_table_font_changed, view);
|
||||
g_object_unref(view->priv->color_table);
|
||||
}
|
||||
|
||||
if (color_table != NULL) {
|
||||
view->priv->color_table = g_object_ref(color_table);
|
||||
g_signal_connect(view->priv->color_table, "color_changed",
|
||||
G_CALLBACK(on_gm_world_input_view_color_table_color_changed), view);
|
||||
g_signal_connect(view->priv->color_table, "font_changed",
|
||||
G_CALLBACK(on_gm_world_input_view_color_table_font_changed), view);
|
||||
|
||||
gm_world_input_view_update_colors(view);
|
||||
gm_world_input_view_update_font(view);
|
||||
} else {
|
||||
view->priv->color_table = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GmColorTable *
|
||||
gm_world_input_view_color_table(GmWorldInputView *view) {
|
||||
return view->priv->color_table;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
void
|
||||
on_gm_world_input_view_color_table_color_changed(GmColorTable *table,
|
||||
gchar *name, GmWorldInputView *view) {
|
||||
if (strcmp(name, "fg_default") == 0 || strcmp(name, "bg_default") == 0) {
|
||||
gm_world_input_view_update_colors(view);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_input_view_color_table_font_changed(GmColorTable *table,
|
||||
gchar *font_description, GmWorldInputView *view) {
|
||||
gm_world_input_view_update_font(view);
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_gm_world_input_view_key_released(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer userdata) {
|
||||
GmWorldInputView *view = GM_WORLD_INPUT_VIEW(widget);
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter start, end;
|
||||
gchar *text;
|
||||
|
||||
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
|
||||
gtk_text_buffer_get_bounds(buffer, &start, &end);
|
||||
text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
|
||||
|
||||
switch (event->keyval) {
|
||||
case GDK_Delete: case GDK_BackSpace:
|
||||
if (text[0] == '\0') {
|
||||
// Reset position to the last item in the history
|
||||
view->priv->position = g_list_last(*view->priv->history);
|
||||
|
||||
// Reset prefix to NULL
|
||||
view->priv->prefix = gm_world_input_view_str_new_value(
|
||||
view->priv->prefix, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_gm_world_input_view_key_pressed(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer userdata) {
|
||||
GmWorldInputView *view = GM_WORLD_INPUT_VIEW(widget);
|
||||
gchar *text;
|
||||
gboolean result = TRUE, isUp;
|
||||
GtkTextBuffer *buf;
|
||||
GtkTextIter start, end, cursor;
|
||||
GtkTextMark *insert;
|
||||
GList *item, *found = NULL;
|
||||
gint line;
|
||||
|
||||
buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
|
||||
|
||||
gtk_text_buffer_get_bounds(buf, &start, &end);
|
||||
text = gtk_text_buffer_get_text(buf, &start, &end, FALSE);
|
||||
|
||||
switch (event->keyval) {
|
||||
case GDK_Up: case GDK_Down:
|
||||
isUp = event->keyval == GDK_Up;
|
||||
|
||||
if (!view->priv->history) {
|
||||
break;
|
||||
}
|
||||
|
||||
insert = gtk_text_buffer_get_insert(buf);
|
||||
gtk_text_buffer_get_iter_at_mark(buf, &cursor, insert);
|
||||
line = gtk_text_iter_get_line(&cursor);
|
||||
|
||||
if ((isUp && line != 0) || (!isUp && line !=
|
||||
gtk_text_buffer_get_line_count(buf) - 1)) {
|
||||
g_free(text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If the current position is empty then append a new history item
|
||||
if (!view->priv->position) {
|
||||
*view->priv->history = g_list_append(*view->priv->history,
|
||||
g_strdup(text));
|
||||
view->priv->position = g_list_last(*view->priv->history);
|
||||
}
|
||||
|
||||
// If there is nowhere to move, don't even bother
|
||||
if ((isUp && !view->priv->position->prev)
|
||||
|| (!isUp && !view->priv->position->next)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If the current prefix is NULL then we set the new prefix to
|
||||
// the current text
|
||||
if (view->priv->prefix == NULL) {
|
||||
view->priv->prefix = g_strdup(text);
|
||||
}
|
||||
|
||||
// If the prefix is an empty string then simply advance to the
|
||||
// next item
|
||||
if (view->priv->prefix[0] == '\0') {
|
||||
if (isUp) {
|
||||
found = view->priv->position->prev;
|
||||
} else {
|
||||
found = view->priv->position->next;
|
||||
}
|
||||
} else {
|
||||
// Else find the closest matching history line
|
||||
item = isUp ? view->priv->position->prev :
|
||||
view->priv->position->next;
|
||||
while (item) {
|
||||
if (strncmp((gchar *)item->data, view->priv->prefix,
|
||||
strlen(view->priv->prefix)) == 0) {
|
||||
// Change current position to the matched item
|
||||
found = item;
|
||||
break;
|
||||
}
|
||||
|
||||
item = isUp ? item->prev : item->next;
|
||||
}
|
||||
}
|
||||
|
||||
// If a match is found then set this history text
|
||||
if (found) {
|
||||
// Change the data of the current position to the text
|
||||
// now in the buffer.
|
||||
view->priv->position->data =
|
||||
gm_world_input_view_str_new_value(
|
||||
view->priv->position->data, text);
|
||||
gm_world_input_view_set_text(view, (gchar *)found->data, -1);
|
||||
view->priv->position = found;
|
||||
|
||||
if (found == g_list_last(*view->priv->history)) {
|
||||
view->priv->prefix = gm_world_input_view_str_new_value(
|
||||
view->priv->prefix, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GDK_Return:
|
||||
// Emit the text_activate signal
|
||||
if (!(event->state & GDK_CONTROL_MASK) &&
|
||||
!(event->state & GDK_SHIFT_MASK)) {
|
||||
|
||||
g_signal_emit(view, world_input_view_signals[TEXT_ACTIVATE], 0,
|
||||
text);
|
||||
|
||||
if (view->priv->history) {
|
||||
item = g_list_last(*view->priv->history);
|
||||
|
||||
if (item) {
|
||||
item->data = gm_world_input_view_str_new_value(
|
||||
(gchar *)(item->data), text);
|
||||
} else {
|
||||
*view->priv->history =
|
||||
g_list_append(*view->priv->history,
|
||||
g_strdup(text));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: manage history length
|
||||
|
||||
// Append new empty history item which will become our new
|
||||
// current item
|
||||
if (view->priv->history) {
|
||||
*view->priv->history =
|
||||
g_list_append(*view->priv->history, g_strdup(""));
|
||||
view->priv->position = g_list_last(*view->priv->history);
|
||||
}
|
||||
|
||||
// Reset prefix to NULL
|
||||
view->priv->prefix = gm_world_input_view_str_new_value(
|
||||
view->priv->prefix, NULL);
|
||||
|
||||
// Set textview text to an empty string
|
||||
gm_world_input_view_set_text(view, "", 0);
|
||||
} else {
|
||||
result = FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(text);
|
||||
return result;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef __GM_WORLD_INPUT_VIEW_H__
|
||||
#define __GM_WORLD_INPUT_VIEW_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "../gm-color-table.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_WORLD_INPUT_VIEW (gm_world_input_view_get_type())
|
||||
#define GM_WORLD_INPUT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_INPUT_VIEW, GmWorldInputView))
|
||||
#define GM_WORLD_INPUT_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_INPUT_VIEW, GmWorldInputView const))
|
||||
#define GM_WORLD_INPUT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_WORLD_INPUT_VIEW, GmWorldInputViewClass))
|
||||
#define GM_IS_WORLD_INPUT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_WORLD_INPUT_VIEW))
|
||||
#define GM_IS_WORLD_INPUT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_WORLD_INPUT_VIEW))
|
||||
#define GM_WORLD_INPUT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_WORLD_INPUT_VIEW, GmWorldInputViewClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmWorldInputViewPrivate GmWorldInputViewPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmWorldInputView GmWorldInputView;
|
||||
|
||||
struct _GmWorldInputView {
|
||||
GtkTextView textview;
|
||||
|
||||
/*< private > */
|
||||
GmWorldInputViewPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmWorldInputViewClass GmWorldInputViewClass;
|
||||
|
||||
struct _GmWorldInputViewClass {
|
||||
GtkTextViewClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* text_activate) (GmWorldInputView *view, const gchar *text);
|
||||
};
|
||||
|
||||
GType gm_world_input_view_get_type(void) G_GNUC_CONST;
|
||||
GtkWidget *gm_world_input_view_new();
|
||||
GtkWidget *gm_world_input_view_new_with_color_table(GmColorTable *table);
|
||||
void gm_world_input_view_set_color_table(GmWorldInputView *view,
|
||||
GmColorTable *color_table);
|
||||
GmColorTable *gm_world_input_view_color_table(GmWorldInputView *view);
|
||||
void gm_world_input_view_set_history(GmWorldInputView *view, GList **history);
|
||||
GList **gm_world_input_view_history(GmWorldInputView *view);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_WORLD_INPUT_VIEW_H__ */
|
|
@ -1,196 +0,0 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "../gm-world.h"
|
||||
#include "gm-world-tab.h"
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-pixbuf.h"
|
||||
#include "../gm-debug.h"
|
||||
|
||||
#define GM_WORLD_TAB_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_WORLD_TAB, GmWorldTabPrivate))
|
||||
|
||||
void on_gm_world_tab_button_clicked(GtkButton *button, GmWorldTab *tab);
|
||||
void on_gm_world_tab_world_activity_changed(GmWorld *world, gint activity,
|
||||
GmWorldTab *tab);
|
||||
void on_gm_world_tab_world_name_changed(GmWorld *world, gchar *text,
|
||||
GmWorldTab *tab);
|
||||
|
||||
struct _GmWorldTabPrivate {
|
||||
GmWorld *world;
|
||||
|
||||
GtkImage *image;
|
||||
GtkLabel *label;
|
||||
GtkButton *button;
|
||||
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
// Signals
|
||||
|
||||
enum {
|
||||
CLOSE,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_world_tab_signals[NUM_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_TYPE(GmWorldTab, gm_world_tab, GTK_TYPE_HBOX)
|
||||
|
||||
static void
|
||||
gm_world_tab_stop_recolor(GmWorldTab *tab) {
|
||||
if (tab->priv->source_id != 0) {
|
||||
g_source_remove(tab->priv->source_id);
|
||||
tab->priv->source_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_tab_finalize(GObject *object) {
|
||||
GmWorldTab *obj = GM_WORLD_TAB(object);
|
||||
|
||||
gm_world_tab_stop_recolor(obj);
|
||||
|
||||
if (obj->priv->world) {
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->world,
|
||||
G_CALLBACK(on_gm_world_tab_world_activity_changed), obj);
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->world,
|
||||
G_CALLBACK(on_gm_world_tab_world_name_changed), obj);
|
||||
g_object_unref(obj->priv->world);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(gm_world_tab_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_tab_class_init(GmWorldTabClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_world_tab_finalize;
|
||||
|
||||
gm_world_tab_signals[CLOSE] =
|
||||
g_signal_new("close",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmWorldTabClass, close),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmWorldTabPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_tab_create_interface(GmWorldTab *obj) {
|
||||
GtkWidget *image, *label, *button, *image_button;
|
||||
|
||||
image = gtk_image_new();
|
||||
label = gtk_label_new("");
|
||||
button = gtk_button_new();
|
||||
|
||||
image_button = gtk_image_new_from_stock(GTK_STOCK_CLOSE,
|
||||
GTK_ICON_SIZE_BUTTON);
|
||||
gtk_widget_set_size_request(button, 16, 16);
|
||||
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
|
||||
gtk_container_add(GTK_CONTAINER(button), image_button);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(obj), image, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 0);
|
||||
gtk_box_pack_end(GTK_BOX(obj), button, FALSE, FALSE, 0);
|
||||
|
||||
gtk_box_set_spacing(GTK_BOX(obj), 6);
|
||||
|
||||
obj->priv->image = GTK_IMAGE(image);
|
||||
obj->priv->label = GTK_LABEL(label);
|
||||
obj->priv->button = GTK_BUTTON(button);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_tab_init(GmWorldTab *obj) {
|
||||
obj->priv = GM_WORLD_TAB_GET_PRIVATE(obj);
|
||||
obj->priv->source_id = 0;
|
||||
obj->priv->world = NULL;
|
||||
|
||||
gm_world_tab_create_interface(obj);
|
||||
|
||||
g_signal_connect(obj->priv->button, "clicked",
|
||||
G_CALLBACK(on_gm_world_tab_button_clicked), obj);
|
||||
|
||||
gtk_widget_show_all(GTK_WIDGET(obj));
|
||||
gtk_widget_hide(GTK_WIDGET(obj));
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_tab_update_color(GmWorldTab *tab) {
|
||||
gchar *text;
|
||||
gint activity = gm_world_activity(tab->priv->world);
|
||||
|
||||
text = g_strdup_printf("<span color=\"#0000%02x\">%s [%i]</span>",
|
||||
CALC_COLOR_RANGE(activity),
|
||||
gm_world_name(tab->priv->world), activity);
|
||||
|
||||
gtk_label_set_markup(tab->priv->label, text);
|
||||
g_free(text);
|
||||
|
||||
tab->priv->source_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_tab_update(GmWorldTab *tab) {
|
||||
gint activity = gm_world_activity(tab->priv->world);
|
||||
gchar *text;
|
||||
|
||||
gm_world_tab_stop_recolor(tab);
|
||||
|
||||
if (activity) {
|
||||
text = g_strdup_printf("<span color=\"#%02x0000\">%s [%i]</span>",
|
||||
CALC_COLOR_RANGE(activity),
|
||||
gm_world_name(tab->priv->world), activity);
|
||||
gtk_image_set_from_pixbuf(tab->priv->image,
|
||||
gm_pixbuf_get_at_size("world_activity.svg", 16, 16));
|
||||
tab->priv->source_id = g_idle_add((GSourceFunc)
|
||||
gm_world_tab_update_color, tab);
|
||||
} else {
|
||||
text = g_strdup(gm_world_name(tab->priv->world));
|
||||
gtk_image_set_from_pixbuf(tab->priv->image,
|
||||
gm_pixbuf_get_at_size("world.svg", 16, 16));
|
||||
}
|
||||
|
||||
gtk_label_set_markup(tab->priv->label, text);
|
||||
g_free(text);
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
GmWorldTab *
|
||||
gm_world_tab_new(GmWorld *world) {
|
||||
GmWorldTab *obj = GM_WORLD_TAB(g_object_new(GM_TYPE_WORLD_TAB, NULL));
|
||||
|
||||
obj->priv->world = g_object_ref(world);
|
||||
|
||||
g_signal_connect(world, "activity_changed",
|
||||
G_CALLBACK(on_gm_world_tab_world_activity_changed), obj);
|
||||
g_signal_connect(world, "name_changed",
|
||||
G_CALLBACK(on_gm_world_tab_world_name_changed), obj);
|
||||
|
||||
gm_world_tab_update(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
|
||||
void
|
||||
on_gm_world_tab_button_clicked(GtkButton *button, GmWorldTab *tab) {
|
||||
g_signal_emit(tab, gm_world_tab_signals[CLOSE], 0);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_tab_world_activity_changed(GmWorld *world, gint activity,
|
||||
GmWorldTab *tab) {
|
||||
gm_world_tab_update(tab);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_tab_world_name_changed(GmWorld *world, gchar *text,
|
||||
GmWorldTab *tab) {
|
||||
gm_world_tab_update(tab);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef __GM_WORLD_TAB_H__
|
||||
#define __GM_WORLD_TAB_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_WORLD_TAB (gm_world_tab_get_type())
|
||||
#define GM_WORLD_TAB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_TAB, GmWorldTab))
|
||||
#define GM_WORLD_TAB_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_TAB, GmWorldTab const))
|
||||
#define GM_WORLD_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_WORLD_TAB, GmWorldTabClass))
|
||||
#define GM_IS_WORLD_TAB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_WORLD_TAB))
|
||||
#define GM_IS_WORLD_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_WORLD_TAB))
|
||||
#define GM_WORLD_TAB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_WORLD_TAB, GmWorldTabClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmWorldTabPrivate GmWorldTabPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmWorldTab GmWorldTab;
|
||||
|
||||
struct _GmWorldTab {
|
||||
GtkHBox parent;
|
||||
|
||||
/*< private > */
|
||||
GmWorldTabPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmWorldTabClass GmWorldTabClass;
|
||||
|
||||
struct _GmWorldTabClass {
|
||||
GtkHBoxClass parent_class;
|
||||
|
||||
// Signals
|
||||
void (* close) (GmWorldTab *obj);
|
||||
};
|
||||
|
||||
GType gm_world_tab_get_type(void) G_GNUC_CONST;
|
||||
GmWorldTab *gm_world_tab_new(GmWorld *world);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_WORLD_TAB_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,59 +0,0 @@
|
|||
#ifndef __GM_WORLD_TEXT_VIEW_H__
|
||||
#define __GM_WORLD_TEXT_VIEW_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "../gm-color-table.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_WORLD_TEXT_VIEW (gm_world_text_view_get_type())
|
||||
#define GM_WORLD_TEXT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_TEXT_VIEW, GmWorldTextView))
|
||||
#define GM_WORLD_TEXT_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_TEXT_VIEW, GmWorldTextView const))
|
||||
#define GM_WORLD_TEXT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_WORLD_TEXT_VIEW, GmWorldTextViewClass))
|
||||
#define GM_IS_WORLD_TEXT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_WORLD_TEXT_VIEW))
|
||||
#define GM_IS_WORLD_TEXT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_WORLD_TEXT_VIEW))
|
||||
#define GM_WORLD_TEXT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_WORLD_TEXT_VIEW, GmWorldTextViewClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmWorldTextViewPrivate GmWorldTextViewPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmWorldTextView GmWorldTextView;
|
||||
|
||||
struct _GmWorldTextView {
|
||||
GtkTextView textview;
|
||||
|
||||
/*< private > */
|
||||
GmWorldTextViewPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmWorldTextViewClass GmWorldTextViewClass;
|
||||
|
||||
struct _GmWorldTextViewClass {
|
||||
GtkTextViewClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* url_activate) (GmWorldTextView *view, const gchar *url);
|
||||
void (* character_size_changed) (GmWorldTextView *view, gint width,
|
||||
gint height);
|
||||
};
|
||||
|
||||
GType gm_world_text_view_get_type(void) G_GNUC_CONST;
|
||||
GtkWidget *gm_world_text_view_new(void);
|
||||
GtkWidget *gm_world_text_view_new_with_color_table(GmColorTable *color_table);
|
||||
gchar *gm_world_text_view_insert(GmWorldTextView *view, const gchar *text);
|
||||
GmColorTable *gm_world_text_view_color_table(GmWorldTextView *view);
|
||||
void gm_world_text_view_set_color_table(GmWorldTextView *view,
|
||||
GmColorTable *color_table);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_WORLD_TEXT_VIEW_H__ */
|
||||
|
|
@ -1,567 +0,0 @@
|
|||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "../gm-app.h"
|
||||
#include "gm-world-view.h"
|
||||
#include "gm-world-text-view.h"
|
||||
#include "gm-world-input-view.h"
|
||||
#include "gm-text-scroller.h"
|
||||
#include "../gm-debug.h"
|
||||
#include "../gm-color-table.h"
|
||||
|
||||
#define GM_WORLD_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
||||
GM_TYPE_WORLD_VIEW, GmWorldViewPrivate))
|
||||
|
||||
struct _GmWorldViewPrivate {
|
||||
GmWorld *world;
|
||||
|
||||
GtkStatusbar *statusbar;
|
||||
GtkHPaned *hpaned;
|
||||
GtkTreeView *tree_view_userlist;
|
||||
GtkTreeModel *tree_model_userlist;
|
||||
GmWorldTextView *text_view_world;
|
||||
GmWorldInputView *text_view_input;
|
||||
GmTextScroller *text_scroller_world;
|
||||
};
|
||||
|
||||
enum {
|
||||
GM_WORLD_VIEW_USERLIST_ICON,
|
||||
GM_WORLD_VIEW_USERLIST_NAME,
|
||||
GM_WORLD_VIEW_USERLIST_OBJ,
|
||||
GM_WORLD_VIEW_USERLIST_SORT,
|
||||
GM_WORLD_VIEW_USERLIST_N_COLUMNS
|
||||
};
|
||||
|
||||
void on_gm_world_view_world_text_received(GmWorld *world, gchar *text,
|
||||
GmWorldView *view);
|
||||
void on_gm_world_view_world_error(GmWorld *world, gchar *text, gint code,
|
||||
GmWorldView *view);
|
||||
void on_gm_world_input_view_world_text_activate(GmWorldInputView *iview,
|
||||
gchar *text, GmWorldView *view);
|
||||
void on_gm_world_view_world_state_changing(GmWorld *world, guint state,
|
||||
GmWorldView *view);
|
||||
void on_gm_world_view_world_active_changed(GmWorld *world, gboolean active,
|
||||
GmWorldView *view);
|
||||
void on_gm_world_view_world_status_changed(GmWorld *world, gchar const *text,
|
||||
GmWorldView *view);
|
||||
|
||||
gboolean on_gm_world_view_world_text_view_scroll_event(GmWorldView *view,
|
||||
GdkEventScroll *event, GmWorldTextView *text);
|
||||
gboolean on_gm_world_view_world_input_view_key_pressed(GtkWidget *widget,
|
||||
GdkEventKey *event, GmWorldView *view);
|
||||
|
||||
/* Signals */
|
||||
|
||||
/*enum {
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint world_view_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(GmWorldView, gm_world_view, GTK_TYPE_NOTEBOOK)
|
||||
|
||||
static void
|
||||
gm_world_view_finalize(GObject *object) {
|
||||
GmWorldView *view = GM_WORLD_VIEW(object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func(view->priv->world,
|
||||
G_CALLBACK(on_gm_world_view_world_text_received), view);
|
||||
g_signal_handlers_disconnect_by_func(view->priv->world,
|
||||
G_CALLBACK(on_gm_world_view_world_error), view);
|
||||
g_signal_handlers_disconnect_by_func(view->priv->world,
|
||||
G_CALLBACK(on_gm_world_view_world_state_changing), view);
|
||||
g_signal_handlers_disconnect_by_func(view->priv->world,
|
||||
G_CALLBACK(on_gm_world_view_world_active_changed), view);
|
||||
g_signal_handlers_disconnect_by_func(view->priv->world,
|
||||
G_CALLBACK(on_gm_world_view_world_status_changed), view);
|
||||
|
||||
g_object_unref(view->priv->world);
|
||||
G_OBJECT_CLASS(gm_world_view_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_view_class_init(GmWorldViewClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_world_view_finalize;
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmWorldViewPrivate));
|
||||
}
|
||||
|
||||
GtkTreeModel *
|
||||
gm_world_view_userlist_model_new(GmWorldView *view) {
|
||||
GtkListStore *store =
|
||||
gtk_list_store_new(GM_WORLD_VIEW_USERLIST_N_COLUMNS, GDK_TYPE_PIXBUF,
|
||||
G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
|
||||
GtkTreeModel *model = gtk_tree_model_sort_new_with_model(
|
||||
GTK_TREE_MODEL(store));
|
||||
|
||||
view->priv->tree_model_userlist = model;
|
||||
return model;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_world_view_userlist_new(GmWorldView *view) {
|
||||
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
|
||||
GtkTreeModel *model = gm_world_view_userlist_model_new(view);
|
||||
GtkWidget *tree_view = gtk_tree_view_new_with_model(model);
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_SHADOW_IN);
|
||||
gtk_widget_set_size_request(scrolled_window, 150, -1);
|
||||
gtk_widget_set_size_request(tree_view, 150, -1);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
|
||||
|
||||
renderer = gtk_cell_renderer_pixbuf_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("I"), renderer, "pixbuf",
|
||||
GM_WORLD_VIEW_USERLIST_ICON, NULL);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
|
||||
gtk_tree_view_column_set_min_width(column, 30);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
|
||||
"text", GM_WORLD_VIEW_USERLIST_NAME, NULL);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
|
||||
|
||||
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
|
||||
GM_WORLD_VIEW_USERLIST_SORT, GTK_SORT_ASCENDING);
|
||||
|
||||
GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(tree_view), GTK_CAN_FOCUS);
|
||||
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree_view));
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
|
||||
view->priv->tree_view_userlist = GTK_TREE_VIEW(tree_view);
|
||||
|
||||
return scrolled_window;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_world_view_create_input_text_view(GmWorldView *view) {
|
||||
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
|
||||
GtkWidget *input_text_view = gm_world_input_view_new_with_color_table(
|
||||
gm_app_color_table(gm_app_instance()));
|
||||
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_NEVER);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_SHADOW_IN);
|
||||
gtk_container_add(GTK_CONTAINER(scrolled_window), input_text_view);
|
||||
|
||||
view->priv->text_view_input = GM_WORLD_INPUT_VIEW(input_text_view);
|
||||
|
||||
g_signal_connect(input_text_view, "key_press_event",
|
||||
G_CALLBACK(on_gm_world_view_world_input_view_key_pressed), view);
|
||||
return scrolled_window;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_world_view_create_world_text_view(GmWorldView *view) {
|
||||
GtkWidget *world_text_view = gm_world_text_view_new_with_color_table(
|
||||
gm_app_color_table(gm_app_instance()));
|
||||
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
|
||||
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_SHADOW_IN);
|
||||
gtk_container_add(GTK_CONTAINER(scrolled_window), world_text_view);
|
||||
|
||||
view->priv->text_view_world = GM_WORLD_TEXT_VIEW(world_text_view);
|
||||
|
||||
// Create new text scroller, this object will take care of itself and will
|
||||
// destroy itself when the view dies, neat!
|
||||
view->priv->text_scroller_world =
|
||||
gm_text_scroller_new(GTK_TEXT_VIEW(view->priv->text_view_world));
|
||||
|
||||
g_signal_connect(world_text_view, "scroll_event",
|
||||
G_CALLBACK(on_gm_world_view_world_text_view_scroll_event), view);
|
||||
return scrolled_window;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_update_status(GmWorldView *view, gchar const *status) {
|
||||
gtk_statusbar_pop(view->priv->statusbar, 0);
|
||||
|
||||
if (status == NULL) {
|
||||
gtk_statusbar_push(view->priv->statusbar, 0,
|
||||
_("Welcome to GnoeMoe, explorer of new worlds!"));
|
||||
} else {
|
||||
gtk_statusbar_push(view->priv->statusbar, 0,
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_world_view_world_page_new(GmWorldView *view) {
|
||||
GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
|
||||
GtkWidget *hpaned = gtk_hpaned_new();
|
||||
GtkWidget *status = gtk_statusbar_new();
|
||||
GtkWidget *vbox_world = gtk_vbox_new(FALSE, 3);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox_world),
|
||||
gm_world_view_create_world_text_view(view), TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox_world),
|
||||
gm_world_view_create_input_text_view(view), FALSE, FALSE, 0);
|
||||
|
||||
gtk_container_set_border_width(GTK_CONTAINER(vbox_world), 3);
|
||||
gtk_paned_pack1(GTK_PANED(hpaned), vbox_world, TRUE, TRUE);
|
||||
gtk_paned_pack2(GTK_PANED(hpaned), gm_world_view_userlist_new(view),
|
||||
FALSE, TRUE);
|
||||
|
||||
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), FALSE);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), status, FALSE, FALSE, 0);
|
||||
|
||||
view->priv->statusbar = GTK_STATUSBAR(status);
|
||||
view->priv->hpaned = GTK_HPANED(hpaned);
|
||||
|
||||
gm_world_view_update_status(view, NULL);
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static void
|
||||
gm_world_view_init(GmWorldView *view) {
|
||||
GtkWidget *label;
|
||||
GmLabelInfo info;
|
||||
|
||||
view->priv = GM_WORLD_VIEW_GET_PRIVATE(view);
|
||||
|
||||
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(view), FALSE);
|
||||
gtk_notebook_set_show_border(GTK_NOTEBOOK(view), FALSE);
|
||||
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(view), GTK_POS_BOTTOM);
|
||||
gtk_notebook_set_scrollable(GTK_NOTEBOOK(view), TRUE);
|
||||
|
||||
label = gm_create_tab_label("world.svg", _("World"), FALSE, &info);
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(view),
|
||||
gm_world_view_world_page_new(view), label);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_destroy(GmWorldView *view, gpointer user_data) {
|
||||
gm_options_set_int(gm_world_options(view->priv->world), "pane_position",
|
||||
GTK_WIDGET(view->priv->hpaned)->allocation.width -
|
||||
gtk_paned_get_position(GTK_PANED(view->priv->hpaned)));
|
||||
|
||||
gm_options_save(gm_world_options(view->priv->world));
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_show(GmWorldView *view, gpointer user_data) {
|
||||
gm_do_events();
|
||||
|
||||
gtk_paned_set_position(GTK_PANED(view->priv->hpaned),
|
||||
GTK_WIDGET(view->priv->hpaned)->allocation.width
|
||||
- gm_options_get_int(gm_world_options(view->priv->world),
|
||||
"pane_position"));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gm_world_view_new(GmWorld *world) {
|
||||
GmWorldView *view = GM_WORLD_VIEW(g_object_new(GM_TYPE_WORLD_VIEW, NULL));
|
||||
|
||||
view->priv->world = g_object_ref(world);
|
||||
|
||||
gm_world_input_view_set_history(view->priv->text_view_input,
|
||||
gm_world_history(view->priv->world));
|
||||
|
||||
g_signal_connect(world, "text_received",
|
||||
G_CALLBACK(on_gm_world_view_world_text_received), view);
|
||||
g_signal_connect(world, "world_error",
|
||||
G_CALLBACK(on_gm_world_view_world_error), view);
|
||||
g_signal_connect(world, "state_changing",
|
||||
G_CALLBACK(on_gm_world_view_world_state_changing), view);
|
||||
g_signal_connect(world, "active_changed",
|
||||
G_CALLBACK(on_gm_world_view_world_active_changed), view);
|
||||
g_signal_connect(world, "status_changed",
|
||||
G_CALLBACK(on_gm_world_view_world_status_changed), view);
|
||||
|
||||
g_signal_connect(view->priv->text_view_input, "text_activate",
|
||||
G_CALLBACK(on_gm_world_input_view_world_text_activate), view);
|
||||
g_signal_connect(view, "destroy",
|
||||
G_CALLBACK(on_gm_world_view_destroy), NULL);
|
||||
g_signal_connect(view, "show",
|
||||
G_CALLBACK(on_gm_world_view_show), NULL);
|
||||
|
||||
return GTK_WIDGET(view);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_view_find_first(GmWorldView *view, const gchar *str,
|
||||
GmWorldViewSearchFlags flags) {
|
||||
GtkTextView *tview = GTK_TEXT_VIEW(view->priv->text_view_world);
|
||||
GtkTextIter iter;
|
||||
GtkTextBuffer *buffer;
|
||||
|
||||
if (tview) {
|
||||
buffer = gtk_text_view_get_buffer(tview);
|
||||
|
||||
if (buffer) {
|
||||
if (flags & GM_WORLD_VIEW_SEARCH_BACKWARDS) {
|
||||
gtk_text_buffer_get_end_iter(buffer, &iter);
|
||||
} else {
|
||||
gtk_text_buffer_get_start_iter(buffer, &iter);
|
||||
}
|
||||
|
||||
gtk_text_buffer_place_cursor(buffer, &iter);
|
||||
|
||||
return gm_world_view_find_next(view, str, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_view_find_next(GmWorldView *view, const gchar *str,
|
||||
GmWorldViewSearchFlags flags) {
|
||||
GtkTextBuffer *buffer = NULL;
|
||||
GtkTextView *tview = NULL;
|
||||
GtkTextIter end, start, matchStart, matchEnd;
|
||||
gboolean found = FALSE;
|
||||
|
||||
if (*str == '\0') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tview = GTK_TEXT_VIEW(view->priv->text_view_world);
|
||||
|
||||
if (tview) {
|
||||
buffer = gtk_text_view_get_buffer(tview);
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) {
|
||||
if (flags & GM_WORLD_VIEW_SEARCH_BACKWARDS) {
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
} else {
|
||||
gtk_text_buffer_get_start_iter(buffer, &end);
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
|
||||
if (flags & GM_WORLD_VIEW_SEARCH_FORWARDS) {
|
||||
found = gtk_text_iter_forward_search(&end, str,
|
||||
GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY,
|
||||
&matchStart, &matchEnd, NULL);
|
||||
} else {
|
||||
found = gtk_text_iter_backward_search(&start, str,
|
||||
GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY,
|
||||
&matchStart, &matchEnd, NULL);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
gtk_text_buffer_place_cursor(buffer, &matchStart);
|
||||
gtk_text_buffer_move_mark_by_name(buffer, "selection_bound",
|
||||
&matchEnd);
|
||||
gtk_text_view_scroll_to_iter(tview, &matchStart,
|
||||
0.0, FALSE, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_world_view_text_active(GmWorldView *view) {
|
||||
return gtk_notebook_get_current_page(GTK_NOTEBOOK(view)) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_scroll_end_prepare(GmWorldView *view) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_scroll_end(GmWorldView *view) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
GmWorld *
|
||||
gm_world_view_world(GmWorldView *view) {
|
||||
return view->priv->world;
|
||||
}
|
||||
|
||||
GmWorldInputView *
|
||||
gm_world_view_input(GmWorldView *view) {
|
||||
return view->priv->text_view_input;
|
||||
}
|
||||
|
||||
GtkTextBuffer *
|
||||
gm_world_view_buffer(GmWorldView *view) {
|
||||
return gtk_text_view_get_buffer(GTK_TEXT_VIEW(view->priv->text_view_world));
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_open_log(GmWorldView *view, const gchar *filename,
|
||||
OpenLogProgress callback, gpointer user_data) {
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_set_userlist_width(GmWorldView *view, gint width) {
|
||||
gtk_paned_set_position(GTK_PANED(view->priv->hpaned),
|
||||
GTK_WIDGET(view->priv->hpaned)->allocation.width - width);
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_set_focus(GmWorldView *view) {
|
||||
gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input));
|
||||
}
|
||||
|
||||
void
|
||||
gm_world_view_change_font_size(GmWorldView *view, gint size_change) {
|
||||
GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(view));
|
||||
PangoFontDescription *desc = style->font_desc;
|
||||
PangoFontDescription *copy = pango_font_description_copy(desc);
|
||||
gchar *new_font;
|
||||
|
||||
pango_font_description_set_size(copy,
|
||||
pango_font_description_get_size(copy) +
|
||||
(size_change * PANGO_SCALE));
|
||||
new_font = pango_font_description_to_string(copy);
|
||||
gm_color_table_set_font_description(gm_app_color_table(gm_app_instance()),
|
||||
new_font);
|
||||
|
||||
pango_font_description_free(copy);
|
||||
g_free(new_font);
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
void
|
||||
on_gm_world_input_view_world_text_activate(GmWorldInputView *iview, gchar *text,
|
||||
GmWorldView *view) {
|
||||
gm_world_process_input(view->priv->world, text);
|
||||
gm_text_scroller_scroll_end(view->priv->text_scroller_world);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_world_text_received(GmWorld *world, gchar *text,
|
||||
GmWorldView *view) {
|
||||
gchar *inserted =
|
||||
gm_world_text_view_insert(view->priv->text_view_world, text);
|
||||
|
||||
g_free(inserted);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_world_error(GmWorld *world, gchar *text, gint code,
|
||||
GmWorldView *view) {
|
||||
gchar *line;
|
||||
|
||||
switch (code) {
|
||||
case GM_NET_ERROR_CONNECTING:
|
||||
line = g_strdup_printf(_("# Connect failed: %s"), text);
|
||||
break;
|
||||
case GM_NET_ERROR_DISCONNECTED:
|
||||
line = g_strdup_printf(_("# Connection lost... (%s)"), text);
|
||||
break;
|
||||
default:
|
||||
line = g_strdup_printf(_("# Error: %s"), text);
|
||||
break;
|
||||
}
|
||||
|
||||
gm_world_writeln(world, line);
|
||||
g_free(line);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_world_state_changing(GmWorld *world, guint state,
|
||||
GmWorldView *view) {
|
||||
gchar *line = NULL;
|
||||
GmNetState pstate = gm_world_state(world);
|
||||
|
||||
switch (state) {
|
||||
case GM_NET_STATE_TRY_ADDRESS:
|
||||
line = g_strdup_printf(_("# Trying %s port %s"),
|
||||
gm_world_current_host(world), gm_world_current_port(world));
|
||||
break;
|
||||
case GM_NET_STATE_CONNECTING:
|
||||
line = g_strdup_printf(_("# Connecting to %s port %s"),
|
||||
gm_world_current_host(world), gm_world_current_port(world));
|
||||
break;
|
||||
case GM_NET_STATE_CONNECTED:
|
||||
line = g_strdup(_("# Connected"));
|
||||
break;
|
||||
case GM_NET_STATE_DISCONNECTED:
|
||||
if (pstate == GM_NET_STATE_CONNECTED ||
|
||||
pstate == GM_NET_STATE_DISCONNECTING) {
|
||||
line = g_strdup(_("# Disconnected"));
|
||||
}
|
||||
break;
|
||||
case GM_NET_STATE_DISCONNECTING:
|
||||
line = g_strdup(_("# Disconnecting"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (line) {
|
||||
gm_world_writeln(world, line);
|
||||
g_free(line);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_world_active_changed(GmWorld *world, gboolean active,
|
||||
GmWorldView *view) {
|
||||
if (active) {
|
||||
gtk_widget_grab_focus(GTK_WIDGET(view->priv->text_view_input));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_world_view_world_status_changed(GmWorld *world, gchar const *text,
|
||||
GmWorldView *view) {
|
||||
gm_world_view_update_status(view, text);
|
||||
}
|
||||
|
||||
gboolean on_gm_world_view_world_text_view_scroll_event(GmWorldView *view,
|
||||
GdkEventScroll *event, GmWorldTextView *text) {
|
||||
if (event->state & GDK_CONTROL_MASK) {
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
// Decrease font size
|
||||
gm_world_view_change_font_size(view, -1);
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
// Increase font size
|
||||
gm_world_view_change_font_size(view, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_gm_world_view_world_input_view_key_pressed(GtkWidget *widget,
|
||||
GdkEventKey *event, GmWorldView *view) {
|
||||
switch (event->keyval) {
|
||||
case GDK_Home: case GDK_End:
|
||||
if ((event->state | GDK_CONTROL_MASK) == event->state) {
|
||||
if (event->keyval == GDK_End) {
|
||||
gm_text_scroller_scroll_end(
|
||||
view->priv->text_scroller_world);
|
||||
} else {
|
||||
gm_text_scroller_scroll_begin(
|
||||
view->priv->text_scroller_world);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
#ifndef __GM_WORLD_VIEW_H__
|
||||
#define __GM_WORLD_VIEW_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "../gm-support.h"
|
||||
#include "../gm-world.h"
|
||||
#include "gm-world-input-view.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_WORLD_VIEW (gm_world_view_get_type())
|
||||
#define GM_WORLD_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_VIEW, GmWorldView))
|
||||
#define GM_WORLD_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD_VIEW, GmWorldView const))
|
||||
#define GM_WORLD_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_WORLD_VIEW, GmWorldViewClass))
|
||||
#define GM_IS_WORLD_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_WORLD_VIEW))
|
||||
#define GM_IS_WORLD_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_WORLD_VIEW))
|
||||
#define GM_WORLD_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_WORLD_VIEW, GmWorldViewClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmWorldViewPrivate GmWorldViewPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmWorldView GmWorldView;
|
||||
|
||||
struct _GmWorldView {
|
||||
GtkNotebook notebook;
|
||||
|
||||
/*< private > */
|
||||
GmWorldViewPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmWorldViewClass GmWorldViewClass;
|
||||
|
||||
struct _GmWorldViewClass {
|
||||
GtkNotebookClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
};
|
||||
|
||||
typedef enum _GmWorldViewSearchFlags {
|
||||
GM_WORLD_VIEW_SEARCH_NONE = 0,
|
||||
GM_WORLD_VIEW_SEARCH_FORWARDS = 1 << 0,
|
||||
GM_WORLD_VIEW_SEARCH_BACKWARDS = 1 << 1
|
||||
} GmWorldViewSearchFlags;
|
||||
|
||||
GType gm_world_view_get_type(void) G_GNUC_CONST;
|
||||
GtkWidget *gm_world_view_new(GmWorld *world);
|
||||
|
||||
gboolean gm_world_view_find_first(GmWorldView *view, const gchar *str,
|
||||
GmWorldViewSearchFlags flags);
|
||||
gboolean gm_world_view_find_next(GmWorldView *view, const gchar *str,
|
||||
GmWorldViewSearchFlags flags);
|
||||
|
||||
void gm_world_view_scroll_end_prepare(GmWorldView *view);
|
||||
void gm_world_view_scroll_end(GmWorldView *view);
|
||||
GmWorld *gm_world_view_world(GmWorldView *view);
|
||||
GmWorldInputView *gm_world_view_input(GmWorldView *view);
|
||||
GtkTextBuffer *gm_world_view_buffer(GmWorldView *view);
|
||||
gboolean gm_world_view_text_active(GmWorldView *view);
|
||||
|
||||
void gm_world_view_open_log(GmWorldView *view, const gchar *filename,
|
||||
OpenLogProgress callback, gpointer user_data);
|
||||
void gm_world_view_set_userlist_width(GmWorldView *view, gint width);
|
||||
void gm_world_view_set_focus(GmWorldView *view);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_WORLD_VIEW_H__ */
|
Reference in a new issue