~haaaad/geany/master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
 *      demoproxy.c - this file is part of Geany, a fast and lightweight IDE
 *
 *      Copyright 2015 Thomas Martitz <kugel(at)rockbox(dot)org>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License along
 *      with this program; if not, write to the Free Software Foundation, Inc.,
 *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/**
 * Demo proxy - example of a basic proxy plugin for Geany. Sub-plugins add menu items to the
 * Tools menu and have a help dialog.
 *
 * Note: This is compiled but not installed by default. On Unix, you can install it by compiling
 * Geany and then copying (or symlinking) to the plugins/demoproxy.so and
 * plugins/demoproxytest.px files to ~/.config/geany/plugins
 * - it will be loaded at next startup.
 */

/* plugin API, always comes first */
#include "geanyplugin.h"

typedef struct {
	GKeyFile       *file;
	gchar          *help_text;
	GSList         *menu_items;
}
PluginContext;


static gboolean proxy_init(GeanyPlugin *plugin, gpointer pdata)
{
	PluginContext *data;
	gint i = 0;
	gchar *text;

	data = (PluginContext *) pdata;

	/* Normally, you would instruct the VM/interpreter to call into the actual plugin. The
	 * plugin would be identified by pdata. Because there is no interpreter for
	 * .ini files we do it inline, as this is just a demo */
	data->help_text = g_key_file_get_locale_string(data->file, "Help", "text", NULL, NULL);
	while (TRUE)
	{
		GtkWidget *item;
		gchar *key = g_strdup_printf("item%d", i++);
		text = g_key_file_get_locale_string(data->file, "Init", key, NULL, NULL);
		g_free(key);

		if (!text)
			break;

		item = gtk_menu_item_new_with_label(text);
		gtk_widget_show(item);
		gtk_container_add(GTK_CONTAINER(plugin->geany_data->main_widgets->tools_menu), item);
		gtk_widget_set_sensitive(item, FALSE);
		data->menu_items = g_slist_prepend(data->menu_items, (gpointer) item);
		g_free(text);
	}

	return TRUE;
}


static void proxy_help(GeanyPlugin *plugin, gpointer pdata)
{
	PluginContext *data;
	GtkWidget *dialog;

	data = (PluginContext *) pdata;

	dialog = gtk_message_dialog_new(
		GTK_WINDOW(plugin->geany_data->main_widgets->window),
		GTK_DIALOG_DESTROY_WITH_PARENT,
		GTK_MESSAGE_INFO,
		GTK_BUTTONS_OK,
		"%s", data->help_text);
	gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		_("(From the %s plugin)"), plugin->info->name);

	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
}


static void proxy_cleanup(GeanyPlugin *plugin, gpointer pdata)
{
	PluginContext *data = (PluginContext *) pdata;

	g_slist_free_full(data->menu_items, (GDestroyNotify) gtk_widget_destroy);
	g_free(data->help_text);
}


static gint demoproxy_probe(GeanyPlugin *proxy, const gchar *filename, gpointer pdata)
{
	/* We know the extension is right (Geany checks that). For demo purposes we perform an
	 * additional check. This is not necessary when the extension is unique enough. */
	gboolean match = FALSE;
	gchar linebuf[128];
	FILE *f = fopen(filename, "r");
	if (f != NULL)
	{
		if (fgets(linebuf, sizeof(linebuf), f) != NULL)
			match = utils_str_equal(linebuf, "#!!PROXY_MAGIC!!\n");
		fclose(f);
	}
	return match ? GEANY_PROXY_MATCH : GEANY_PROXY_IGNORE;
}


static gpointer demoproxy_load(GeanyPlugin *proxy, GeanyPlugin *plugin,
                               const gchar *filename, gpointer pdata)
{
	GKeyFile *file;
	gboolean result;

	file = g_key_file_new();
	result = g_key_file_load_from_file(file, filename, 0, NULL);

	if (result)
	{
		PluginContext *data = g_new0(PluginContext, 1);
		data->file = file;

		plugin->info->name = g_key_file_get_locale_string(data->file, "Info", "name", NULL, NULL);
		plugin->info->description = g_key_file_get_locale_string(data->file, "Info", "description", NULL, NULL);
		plugin->info->version = g_key_file_get_locale_string(data->file, "Info", "version", NULL, NULL);
		plugin->info->author = g_key_file_get_locale_string(data->file, "Info", "author", NULL, NULL);

		plugin->funcs->init = proxy_init;
		plugin->funcs->help = proxy_help;
		plugin->funcs->cleanup = proxy_cleanup;

		/* Cannot pass g_free as free_func be Geany calls it before unloading, and since 
		 * demoproxy_unload() accesses the data this would be catastrophic */
		GEANY_PLUGIN_REGISTER_FULL(plugin, 225, data, NULL);
		return data;
	}

	g_key_file_free(file);
	return NULL;
}


static void demoproxy_unload(GeanyPlugin *proxy, GeanyPlugin *plugin, gpointer load_data, gpointer pdata)
{
	PluginContext *data = load_data;

	g_free((gchar *)plugin->info->name);
	g_free((gchar *)plugin->info->description);
	g_free((gchar *)plugin->info->version);
	g_free((gchar *)plugin->info->author);

	g_key_file_free(data->file);
	g_free(data);
}


/* Called by Geany to initialize the plugin. */
static gboolean demoproxy_init(GeanyPlugin *plugin, gpointer pdata)
{
	const gchar *extensions[] = { "ini", "px", NULL };

	plugin->proxy_funcs->probe  = demoproxy_probe;
	plugin->proxy_funcs->load   = demoproxy_load;
	plugin->proxy_funcs->unload = demoproxy_unload;

	return geany_plugin_register_proxy(plugin, extensions);
}


/* Called by Geany before unloading the plugin. */
static void demoproxy_cleanup(GeanyPlugin *plugin, gpointer data)
{
}


G_MODULE_EXPORT
void geany_load_module(GeanyPlugin *plugin)
{
	plugin->info->name = _("Demo Proxy");
	plugin->info->description = _("Example Proxy.");
	plugin->info->version = "0.1";
	plugin->info->author = _("The Geany developer team");

	plugin->funcs->init = demoproxy_init;
	plugin->funcs->cleanup = demoproxy_cleanup;

	GEANY_PLUGIN_REGISTER(plugin, 225);
}