aboutsummaryrefslogtreecommitdiff
path: root/src/lua_interface.c
diff options
context:
space:
mode:
authormitchell <70453897+667e-11@users.noreply.github.com>2009-07-08 19:14:33 -0400
committermitchell <70453897+667e-11@users.noreply.github.com>2009-07-08 19:14:33 -0400
commit9827462bc8ac4ecc6009f2285c2397bf6ff64777 (patch)
treecc2d9b16d23a904d1107b111bf19f39ced993db1 /src/lua_interface.c
parentbfef6fc70792fe002df7f8c0bfc82749fcd08152 (diff)
downloadtextadept-9827462bc8ac4ecc6009f2285c2397bf6ff64777.tar.gz
textadept-9827462bc8ac4ecc6009f2285c2397bf6ff64777.zip
Extended the event system to include project manager, find, command entry, etc.
Diffstat (limited to 'src/lua_interface.c')
-rw-r--r--src/lua_interface.c524
1 files changed, 232 insertions, 292 deletions
diff --git a/src/lua_interface.c b/src/lua_interface.c
index 9a126cbf..b8101e20 100644
--- a/src/lua_interface.c
+++ b/src/lua_interface.c
@@ -58,12 +58,12 @@ static int l_buffer_mt_index(lua_State *lua),
l_ce_mt_index(lua_State *lua),
l_ce_mt_newindex(lua_State *lua);
-static int l_cf_ta_buffer_new(lua_State *lua),
- l_cf_buffer_delete(lua_State *lua),
+static int l_cf_buffer_delete(lua_State *lua),
l_cf_buffer_text_range(lua_State *lua),
l_cf_view_focus(lua_State *lua),
l_cf_view_split(lua_State *lua),
l_cf_view_unsplit(lua_State *lua),
+ l_cf_ta_buffer_new(lua_State *lua),
l_cf_ta_get_split_table(lua_State *lua),
l_cf_ta_goto_window(lua_State *lua),
l_cf_view_goto_buffer(lua_State *lua),
@@ -71,16 +71,19 @@ static int l_cf_ta_buffer_new(lua_State *lua),
l_cf_ta_iconv(lua_State *lua),
l_cf_ta_reset(lua_State *lua),
l_cf_ta_quit(lua_State *lua),
- l_cf_pm_focus(lua_State *lua),
- l_cf_pm_clear(lua_State *lua),
l_cf_pm_activate(lua_State *lua),
l_cf_pm_add_browser(lua_State *lua),
+ l_cf_pm_clear(lua_State *lua),
+ l_cf_pm_fill(lua_State *lua),
+ l_cf_pm_focus(lua_State *lua),
+ l_cf_pm_show_context_menu(lua_State *lua),
l_cf_find_focus(lua_State *lua),
- l_cf_call_find_next(lua_State *lua),
- l_cf_call_find_prev(lua_State *lua),
- l_cf_call_replace(lua_State *lua),
- l_cf_call_replace_all(lua_State *lua),
- l_cf_ce_focus(lua_State *lua);
+ l_cf_find_next(lua_State *lua),
+ l_cf_find_prev(lua_State *lua),
+ l_cf_find_replace(lua_State *lua),
+ l_cf_find_replace_all(lua_State *lua),
+ l_cf_ce_focus(lua_State *lua),
+ l_cf_ce_show_completions(lua_State *lua);
/**
* Inits or re-inits the Lua State.
@@ -114,31 +117,34 @@ bool l_init(int argc, char **argv, bool reinit) {
lua_newtable(lua);
lua_newtable(lua);
- l_cfunc(lua, l_cf_pm_focus, "focus");
- l_cfunc(lua, l_cf_pm_clear, "clear");
l_cfunc(lua, l_cf_pm_activate, "activate");
l_cfunc(lua, l_cf_pm_add_browser, "add_browser");
+ l_cfunc(lua, l_cf_pm_clear, "clear");
+ l_cfunc(lua, l_cf_pm_fill, "fill");
+ l_cfunc(lua, l_cf_pm_focus, "focus");
+ l_cfunc(lua, l_cf_pm_show_context_menu, "show_context_menu");
l_mt(lua, "_pm_mt", l_pm_mt_index, l_pm_mt_newindex);
lua_setfield(lua, -2, "pm");
lua_newtable(lua);
+ l_cfunc(lua, l_cf_find_next, "find_next");
+ l_cfunc(lua, l_cf_find_prev, "find_prev");
l_cfunc(lua, l_cf_find_focus, "focus");
- l_cfunc(lua, l_cf_call_find_next, "call_find_next");
- l_cfunc(lua, l_cf_call_find_prev, "call_find_prev");
- l_cfunc(lua, l_cf_call_replace, "call_replace");
- l_cfunc(lua, l_cf_call_replace_all, "call_replace_all");
+ l_cfunc(lua, l_cf_find_replace, "replace");
+ l_cfunc(lua, l_cf_find_replace_all, "replace_all");
l_mt(lua, "_find_mt", l_find_mt_index, l_find_mt_newindex);
lua_setfield(lua, -2, "find");
lua_newtable(lua);
l_cfunc(lua, l_cf_ce_focus, "focus");
+ l_cfunc(lua, l_cf_ce_show_completions, "show_completions");
l_mt(lua, "_ce_mt", l_ce_mt_index, l_ce_mt_newindex);
lua_setfield(lua, -2, "command_entry");
- l_cfunc(lua, l_cf_ta_buffer_new, "new_buffer");
- l_cfunc(lua, l_cf_ta_goto_window, "goto_view");
l_cfunc(lua, l_cf_ta_get_split_table, "get_split_table");
+ l_cfunc(lua, l_cf_ta_goto_window, "goto_view");
l_cfunc(lua, l_cf_ta_gtkmenu, "gtkmenu");
l_cfunc(lua, l_cf_ta_iconv, "iconv");
- l_cfunc(lua, l_cf_ta_reset, "reset");
+ l_cfunc(lua, l_cf_ta_buffer_new, "new_buffer");
l_cfunc(lua, l_cf_ta_quit, "quit");
+ l_cfunc(lua, l_cf_ta_reset, "reset");
l_mt(lua, "_textadept_mt", l_ta_mt_index, l_ta_mt_newindex);
lua_setglobal(lua, "textadept");
@@ -272,9 +278,9 @@ void l_goto_scintilla_window(GtkWidget *editor, int n, bool absolute) {
lua_rawgeti(lua, -1, n);
}
editor = l_checkview(lua, -1);
- if (!closing) l_handle_event("view_before_switch");
+ if (!closing) l_handle_event("view_before_switch", -1);
gtk_widget_grab_focus(editor);
- if (!closing) l_handle_event("view_after_switch");
+ if (!closing) l_handle_event("view_after_switch", -1);
lua_pop(lua, 2); // view table and views
}
@@ -374,16 +380,6 @@ unsigned int l_get_docpointer_index(sptr_t doc) {
return idx;
}
-#define l_set_bufferp(k, v) { \
- lua_pushstring(lua, k); \
- lua_pushinteger(lua, v); \
- lua_rawset(lua, -3); \
-}
-#define l_get_bufferp(k, i) { \
- lua_pushstring(lua, k); \
- lua_rawget(lua, (i < 0) ? i - 1 : i); \
-}
-
/**
* Changes a Scintilla window's document to one in the global 'buffers' table.
* Before doing so, it saves the scroll and caret positions in the current
@@ -414,10 +410,10 @@ void l_goto_scintilla_buffer(GtkWidget *editor, int n, bool absolute) {
lua_rawgeti(lua, -1, n);
}
sptr_t doc = l_checkdocpointer(lua, -1);
- if (!closing) l_handle_event("buffer_before_switch");
+ if (!closing) l_handle_event("buffer_before_switch", -1);
SS(sci, SCI_SETDOCPOINTER, 0, doc);
l_set_buffer_global(sci);
- if (!closing) l_handle_event("buffer_after_switch");
+ if (!closing) l_handle_event("buffer_after_switch", -1);
lua_pop(lua, 2); // buffer table and buffers
}
@@ -509,13 +505,19 @@ bool l_ista2function(const char *table, const char *key) {
* values at the top of the stack. If false, discards the return values.
* Defaults to false.
*/
-bool l_call_function(int nargs, int retn=0, bool keep_return=false) {
+static bool l_call_function(int nargs, int retn=0, bool keep_return=false) {
int ret = lua_pcall(lua, nargs, retn, 0);
if (ret == 0) {
bool result = (retn > 0) ? lua_toboolean(lua, -1) == 1 : true;
if (retn > 0 && !keep_return) lua_pop(lua, retn); // retn
return result;
- } else l_handle_error(NULL);
+ } else {
+ if (focused_editor)
+ l_handle_event("error", LUA_TSTRING, lua_tostring(lua, -1), -1);
+ else
+ printf("Lua Error: %s\n", lua_tostring(lua, -1));
+ lua_settop(lua, 0);
+ }
return false;
}
@@ -637,47 +639,48 @@ static void l_check_focused_buffer(lua_State *lua, int narg) {
// Notification/event handlers
/**
- * Handles a Lua error.
- * The main error message is at the top of the Lua stack.
- * @param extramsg An additional error message to display.
- */
-void l_handle_error(const char *extramsg) {
- if (focused_editor && l_ista2function("events", "error")) {
- l_insert(lua, -1); // shift error message down
- if (extramsg) lua_pushstring(lua, extramsg);
- l_call_function(extramsg ? 2 : 1);
- } else {
- printf("Lua Error: %s\n", lua_tostring(lua, -1));
- if (extramsg) printf("%s\n", extramsg);
- }
- lua_settop(lua, 0);
-}
-
-/**
* Handles a Textadept event.
* @param s String event name.
- * @param arg Optional string argument.
- */
-bool l_handle_event(const char *s, const char *arg) {
- if (!l_ista2function("events", s)) return false;
- if (arg) lua_pushstring(lua, arg);
- return l_call_function(arg ? 1 : 0, 1);
-}
-
-/**
- * Handles a Textadept keypress.
- * @param keyval The key value of the key pressed.
- * @param shift Flag indicating whether or not the shift modifier was held.
- * @param control Flag indicating whether or not the control modifier was held.
- * @param alt Flag indicating whether or not the alt modifier was held.
+ * @param ... Optional arguments to pass to the handler. The variable argument
+ * list should contain Lua types followed by the data of that type to pass.
+ * The list is terminated by a -1.
*/
-bool l_handle_keypress(int keyval, bool shift, bool control, bool alt) {
- if (!l_ista2function("events", "keypress")) return false;
- lua_pushinteger(lua, keyval);
- lua_pushboolean(lua, shift);
- lua_pushboolean(lua, control);
- lua_pushboolean(lua, alt);
- return l_call_function(4, 1);
+bool l_handle_event(const char *s, ...) {
+ if (!l_ista2function("events", "handle")) return false;
+ lua_pushstring(lua, s);
+ int n = 1;
+ va_list ap;
+ va_start(ap, s);
+ int type = va_arg(ap, int);
+ while (type != -1) {
+ void *arg = va_arg(ap, void*);
+ switch(type) {
+ case LUA_TNIL:
+ lua_pushnil(lua);
+ break;
+ case LUA_TBOOLEAN:
+ lua_pushboolean(lua, reinterpret_cast<long>(arg));
+ break;
+ case LUA_TNUMBER:
+ lua_pushinteger(lua, reinterpret_cast<long>(arg));
+ break;
+ case LUA_TSTRING:
+ lua_pushstring(lua, reinterpret_cast<char*>(arg));
+ break;
+ case LUA_TLIGHTUSERDATA:
+ case LUA_TTABLE: {
+ long ref = reinterpret_cast<long>(arg);
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, ref);
+ luaL_unref(lua, LUA_REGISTRYINDEX, ref);
+ break;
+ } default:
+ warn("events.handle: ignored invalid argument type");
+ }
+ n++;
+ type = va_arg(ap, int);
+ }
+ va_end(ap);
+ return l_call_function(n, 1);
}
#define l_pushscninteger(i, n) { \
@@ -740,206 +743,52 @@ void l_ta_popup_context_menu(GdkEventButton *event) {
// Project Manager
/**
- * Creates and pushes a Lua table of parent nodes for the given Project Manager
- * treeview path.
+ * Creates a Lua table of parent nodes for the given Project Manager treeview
+ * path and returns a reference to it.
* The first table item is the PM Entry text, the next items are parents of the
* given node in descending order, and the last item is the given node itself.
+ * The reference can be retrieved using lua_rawgeti.
* @param store The GtkTreeStore of the PM view.
* @param path The GtkTreePath of the node. If NULL, only the PM Entry text is
* contained in the resulting table.
+ * @return int reference to the created table in LUA_REGISTRYINDEX.
*/
-void l_pushpathtable(GtkTreeStore *store, GtkTreePath *path) {
+int l_pm_pathtableref(GtkTreeStore *store, GtkTreePath *path) {
lua_newtable(lua);
lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(pm_entry)));
lua_rawseti(lua, -2, 1);
- if (!path) return;
- GtkTreeIter iter;
- while (gtk_tree_path_get_depth(path) > 0) {
- char *item = 0;
- gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
- gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 1, &item, -1);
- lua_pushstring(lua, item);
- lua_rawseti(lua, -2, gtk_tree_path_get_depth(path) + 1);
- g_free(item);
- gtk_tree_path_up(path);
- }
-}
-
-/**
- * Requests and adds contents to the Project Manager view.
- * @param store The GtkTreeStore of the PM view.
- * @param initial_iter An initial GtkTreeIter. If NULL, contents will be added
- * to the treeview root. Otherwise they will be added to this parent node.
- */
-void l_pm_view_fill(GtkTreeStore *store, GtkTreeIter *initial_iter) {
- if (!l_ista2function("pm", "get_contents_for")) return;
- if (initial_iter) {
- GtkTreePath *path =
- gtk_tree_model_get_path(GTK_TREE_MODEL(store), initial_iter);
- l_pushpathtable(store, path);
- gtk_tree_path_free(path);
- } else l_pushpathtable(store, NULL);
- lua_pushboolean(lua, initial_iter != NULL);
- l_call_function(2, 1, true);
- if (!lua_istable(lua, -1)) {
- if (!lua_isnil(lua, -1)) warn("pm.get_contents_for: table expected");
- lua_pop(lua, 1); // non-table return
- return;
- }
-
- if (!initial_iter) gtk_tree_store_clear(store);
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- if (lua_istable(lua, -1) && lua_type(lua, -2) == LUA_TSTRING) {
- GtkTreeIter iter, child;
- gtk_tree_store_append(store, &iter, initial_iter);
- gtk_tree_store_set(store, &iter, 1, lua_tostring(lua, -2), -1);
- lua_getfield(lua, -1, "parent");
- if (lua_toboolean(lua, -1)) {
- gtk_tree_store_append(store, &child, &iter);
- gtk_tree_store_set(store, &child, 1, "\0dummy", -1);
- }
- lua_pop(lua, 1); // parent
- lua_getfield(lua, -1, "pixbuf");
- if (lua_isstring(lua, -1))
- gtk_tree_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
- else if (!lua_isnil(lua, -1))
- warn("pm.fill: non-string pixbuf key ignored");
- lua_pop(lua, 1); // pixbuf
- lua_getfield(lua, -1, "text");
- gtk_tree_store_set(store, &iter, 2, lua_isstring(lua, -1) ?
- lua_tostring(lua, -1) : lua_tostring(lua, -3), -1);
- lua_pop(lua, 1); // display text
- } else warn("pm.fill: string id key must have table value");
- lua_pop(lua, 1); // value
+ if (path) {
+ GtkTreeIter iter;
+ while (gtk_tree_path_get_depth(path) > 0) {
+ char *item = 0;
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 1, &item, -1);
+ lua_pushstring(lua, item);
+ lua_rawseti(lua, -2, gtk_tree_path_get_depth(path) + 1);
+ g_free(item);
+ gtk_tree_path_up(path);
+ }
}
- lua_pop(lua, 1); // returned table
-
- l_handle_event("pm_view_filled");
+ return luaL_ref(lua, LUA_REGISTRYINDEX);
}
/**
- * Requests and pops up a context menu for a selected Project Manager item.
- * @param store The GtkTreeStore of the PM view.
- * @param path The GtkTreePath of the item.
+ * Requests a popup context menu for a selected Project Manager item.
* @param event The mouse button event.
- * @param callback The GCallback associated with each menu item.
- */
-void l_pm_popup_context_menu(GtkTreeStore *store, GtkTreePath *path,
- GdkEventButton *event, GCallback callback) {
- if (!l_ista2function("pm", "get_context_menu")) return;
- l_pushpathtable(store, path);
- l_call_function(1, 1, true);
- if (lua_istable(lua, -1)) {
- GtkWidget *menu = l_create_gtkmenu(lua, callback, false);
- gtk_widget_show_all(menu);
- gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
- event ? event->button : 0,
- gdk_event_get_time(reinterpret_cast<GdkEvent*>(event)));
- } else warn("pm.get_context_menu: table expected");
- lua_pop(lua, 1); // returned value
-}
-
-/**
- * Performs an action for the selected Project Manager item.
- * @param store The GtkTreeStore of the PM view.
- * @param path The GtkTreePath of the item.
- */
-void l_pm_perform_action(GtkTreeStore *store, GtkTreePath *path) {
- if (!l_ista2function("pm", "perform_action")) return;
- l_pushpathtable(store, path);
- l_call_function(1);
-}
-
-/**
- * Performs a selected menu action from a Project Manager item's context menu.
- * @param store The GtkTreeStore of the PM view.
- * @param path The GtkTreePath of the item.
- * @param id The numeric ID for the menu item.
- */
-void l_pm_perform_menu_action(GtkTreeStore *store, GtkTreePath *path, int id) {
- if (!l_ista2function("pm", "perform_menu_action")) return;
- lua_pushnumber(lua, id);
- l_pushpathtable(store, path);
- l_call_function(2);
-}
-
-// Find/Replace
-
-/**
- * Finds text in the current document.
- * @param ftext The text to find.
- * @param next Flag indicating whether or not to find next. If false, finds
- * previous matches.
- */
-void l_find(const char *ftext, bool next) {
- if (!l_ista2function("find", "find")) return;
- lua_pushstring(lua, ftext);
- lua_pushboolean(lua, next);
- l_call_function(2);
-}
-
-/**
- * Replaces text in the current document.
- * @param rtext The text to replace the found text with.
- */
-void l_find_replace(const char *rtext) {
- if (!l_ista2function("find", "replace")) return;
- lua_pushstring(lua, rtext);
- l_call_function(1);
-}
-
-/**
- * Replaces all found text in the current document.
- * @param ftext The text to find.
- * @param rtext The text to replace the found text with.
- */
-void l_find_replace_all(const char *ftext, const char *rtext) {
- if (!l_ista2function("find", "replace_all")) return;
- lua_pushstring(lua, ftext);
- lua_pushstring(lua, rtext);
- l_call_function(2);
-}
-
-// Command Entry
-
-/**
- * Executes a given command string as Lua code.
- * @param command Lua code to execute.
- */
-void l_ce_command(const char *command) {
- int top = lua_gettop(lua);
- if (luaL_dostring(lua, command) == 0) {
- l_handle_event("update_ui");
- lua_settop(lua, top);
- } else l_handle_error("Error executing command");
-}
-
-/**
- * Requests and adds completions for the Command Entry Completion.
- * @param store The GtkListStore to populate.
*/
-void l_cec_fill(GtkListStore *store) {
- if (!l_ista2function("command_entry", "get_completions_for")) return;
- lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(command_entry)));
- l_call_function(1, 1, true);
- if (!lua_istable(lua, -1)) {
- if (!lua_isnil(lua, -1)) warn("ce.get_completions_for: table expected");
- lua_pop(lua, 1); // non-table return
- return;
- }
-
- gtk_list_store_clear(store);
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- if (lua_type(lua, -1) == LUA_TSTRING) {
- GtkTreeIter iter;
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
- } else warn("ce.get_completions_for: non-string value ignored");
- lua_pop(lua, 1); // value
- }
- lua_pop(lua, 1); // returned table
+void l_pm_popup_context_menu(GdkEventButton *event) {
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view));
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view));
+ if (gtk_tree_selection_get_selected(sel, NULL, &iter))
+ path = gtk_tree_model_get_path(model, &iter);
+ lua_pushlightuserdata(lua, const_cast<GdkEventButton*>(event));
+ int ref = luaL_ref(lua, LUA_REGISTRYINDEX);
+ l_handle_event("pm_context_menu_request", LUA_TTABLE,
+ l_pm_pathtableref(GTK_TREE_STORE(model), path),
+ LUA_TLIGHTUSERDATA, ref, -1);
+ if (path) gtk_tree_path_free(path);
}
// Lua functions (stack maintenence is unnecessary)
@@ -1308,13 +1157,6 @@ static int l_ce_mt_newindex(lua_State *lua) {
// Lua CFunctions. For documentation, consult the LuaDoc.
-static int l_cf_ta_buffer_new(lua_State *lua) {
- new_scintilla_buffer(SCINTILLA(focused_editor), true, true);
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_rawgeti(lua, -1, lua_objlen(lua, -1));
- return 1;
-}
-
static int l_cf_buffer_delete(lua_State *lua) {
l_check_focused_buffer(lua, 1);
sptr_t doc = l_checkdocpointer(lua, 1);
@@ -1324,10 +1166,17 @@ static int l_cf_buffer_delete(lua_State *lua) {
else
new_scintilla_buffer(SCINTILLA(focused_editor), true, true);
remove_scintilla_buffer(doc);
- l_handle_event("buffer_deleted");
+ l_handle_event("buffer_deleted", -1);
return 0;
}
+static int l_cf_ta_buffer_new(lua_State *lua) {
+ new_scintilla_buffer(SCINTILLA(focused_editor), true, true);
+ lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
+ lua_rawgeti(lua, -1, lua_objlen(lua, -1));
+ return 1;
+}
+
static int l_cf_buffer_text_range(lua_State *lua) {
l_check_focused_buffer(lua, 1);
#ifndef MAC
@@ -1414,10 +1263,6 @@ static int l_cf_ta_goto_(lua_State *lua, GtkWidget *editor, bool buffer) {
return 0;
}
-static int l_cf_ta_goto_window(lua_State *lua) {
- return l_cf_ta_goto_(lua, focused_editor, false);
-}
-
// If the indexed view is not currently focused, temporarily focus it so calls
// to handlers will not throw 'indexed buffer is not the focused one' error.
static int l_cf_view_goto_buffer(lua_State *lua) {
@@ -1434,12 +1279,12 @@ static int l_cf_view_goto_buffer(lua_State *lua) {
return 0;
}
+static int l_cf_ta_goto_window(lua_State *lua) {
+ return l_cf_ta_goto_(lua, focused_editor, false);
+}
+
static void t_menu_activate(GtkWidget *, gpointer id) {
- int menu_id = GPOINTER_TO_INT(id);
- char *menu_id_str = static_cast<char*>(malloc(sizeof(char) * 12));
- sprintf(menu_id_str, "%i", menu_id);
- l_handle_event("menu_clicked", menu_id_str);
- g_free(menu_id_str);
+ l_handle_event("menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id), -1);
}
static int l_cf_ta_gtkmenu(lua_State *lua) {
@@ -1462,8 +1307,17 @@ static int l_cf_ta_iconv(lua_State *lua) {
return 1;
}
+static int l_cf_ta_quit(lua_State *) {
+ GdkEventAny event;
+ event.type = GDK_DELETE;
+ event.window = window->window;
+ event.send_event = TRUE;
+ gdk_event_put(reinterpret_cast<GdkEvent*>(&event));
+ return 0;
+}
+
static int l_cf_ta_reset(lua_State *lua) {
- l_handle_event("resetting");
+ l_handle_event("resetting", -1);
l_init(0, NULL, true);
lua_pushboolean(lua, true);
lua_setglobal(lua, "RESETTING");
@@ -1475,17 +1329,14 @@ static int l_cf_ta_reset(lua_State *lua) {
return 0;
}
-static int l_cf_ta_quit(lua_State *) {
- GdkEventAny event;
- event.type = GDK_DELETE;
- event.window = window->window;
- event.send_event = TRUE;
- gdk_event_put(reinterpret_cast<GdkEvent*>(&event));
+static int l_cf_pm_activate(lua_State *) {
+ g_signal_emit_by_name(G_OBJECT(pm_entry), "activate");
return 0;
}
-static int l_cf_pm_focus(lua_State *) {
- pm_toggle_focus();
+static int l_cf_pm_add_browser(lua_State *lua) {
+ GtkWidget *pm_combo = gtk_widget_get_parent(pm_entry);
+ gtk_combo_box_append_text(GTK_COMBO_BOX(pm_combo), lua_tostring(lua, -1));
return 0;
}
@@ -1495,14 +1346,83 @@ static int l_cf_pm_clear(lua_State *) {
return 0;
}
-static int l_cf_pm_activate(lua_State *) {
- g_signal_emit_by_name(G_OBJECT(pm_entry), "activate");
+static int l_cf_pm_fill(lua_State *lua) {
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view));
+ GtkTreeStore *store = GTK_TREE_STORE(model);
+ GtkTreeIter initial_iter, *initial_iter_p = NULL;
+ if (lua_gettop(lua) > 1 && lua_type(lua, 2) == LUA_TSTRING &&
+ gtk_tree_model_get_iter_from_string(model, &initial_iter,
+ lua_tostring(lua, 2)))
+ initial_iter_p = &initial_iter;
+ if (!initial_iter_p) gtk_tree_store_clear(store);
+ GtkTreeIter iter, child;
+ lua_pushnil(lua);
+ while (lua_next(lua, 1)) {
+ if (lua_istable(lua, -1) && lua_type(lua, -2) == LUA_TSTRING) {
+ gtk_tree_store_append(store, &iter, initial_iter_p);
+ gtk_tree_store_set(store, &iter, 1, lua_tostring(lua, -2), -1);
+ lua_getfield(lua, -1, "parent");
+ if (lua_toboolean(lua, -1)) {
+ gtk_tree_store_append(store, &child, &iter);
+ gtk_tree_store_set(store, &child, 1, "\0dummy", -1);
+ }
+ lua_pop(lua, 1); // parent
+ lua_getfield(lua, -1, "pixbuf");
+ if (lua_isstring(lua, -1))
+ gtk_tree_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
+ else if (!lua_isnil(lua, -1))
+ warn("pm.fill: non-string pixbuf key ignored");
+ lua_pop(lua, 1); // pixbuf
+ lua_getfield(lua, -1, "text");
+ gtk_tree_store_set(store, &iter, 2, lua_isstring(lua, -1) ?
+ lua_tostring(lua, -1) : lua_tostring(lua, -3), -1);
+ lua_pop(lua, 1); // display text
+ } else warn("pm.fill: string id key must have table value");
+ lua_pop(lua, 1); // value
+ }
+ if (initial_iter_p) {
+ char *item;
+ gtk_tree_model_iter_nth_child(model, &child, initial_iter_p, 0);
+ gtk_tree_model_get(model, &child, 1, &item, -1);
+ if (strcmp(reinterpret_cast<const char*>(item), "\0dummy") == 0)
+ gtk_tree_store_remove(store, &child);
+ g_free(item);
+ }
return 0;
}
-static int l_cf_pm_add_browser(lua_State *lua) {
- GtkWidget *pm_combo = gtk_widget_get_parent(pm_entry);
- gtk_combo_box_append_text(GTK_COMBO_BOX(pm_combo), lua_tostring(lua, -1));
+static void pm_menu_activate(GtkWidget *, gpointer id) {
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view));
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view));
+ if (gtk_tree_selection_get_selected(sel, NULL, &iter))
+ path = gtk_tree_model_get_path(model, &iter);
+ l_handle_event("pm_menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id),
+ LUA_TTABLE, l_pm_pathtableref(GTK_TREE_STORE(model), path),
+ -1);
+ if (path) gtk_tree_path_free(path);
+}
+
+static int l_cf_pm_show_context_menu(lua_State *lua) {
+ GdkEventButton *event = NULL;
+ if (lua_gettop(lua) > 1) {
+ if (lua_isuserdata(lua, 2))
+ event = reinterpret_cast<GdkEventButton*>(lua_touserdata(lua, 2));
+ lua_pop(lua, 1); // userdata
+ }
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ GtkWidget *menu = l_create_gtkmenu(lua, G_CALLBACK(pm_menu_activate), false);
+ gtk_widget_show_all(menu);
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+ event ? event->button : 0,
+ gdk_event_get_time(reinterpret_cast<GdkEvent*>(event)));
+ return 0;
+}
+
+static int l_cf_pm_focus(lua_State *) {
+ pm_toggle_focus();
return 0;
}
@@ -1511,22 +1431,22 @@ static int l_cf_find_focus(lua_State *) {
return 0;
}
-static int l_cf_call_find_next(lua_State *) {
+static int l_cf_find_next(lua_State *) {
g_signal_emit_by_name(G_OBJECT(fnext_button), "clicked");
return 0;
}
-static int l_cf_call_find_prev(lua_State *) {
+static int l_cf_find_prev(lua_State *) {
g_signal_emit_by_name(G_OBJECT(fprev_button), "clicked");
return 0;
}
-static int l_cf_call_replace(lua_State *) {
+static int l_cf_find_replace(lua_State *) {
g_signal_emit_by_name(G_OBJECT(r_button), "clicked");
return 0;
}
-static int l_cf_call_replace_all(lua_State *) {
+static int l_cf_find_replace_all(lua_State *) {
g_signal_emit_by_name(G_OBJECT(ra_button), "clicked");
return 0;
}
@@ -1535,3 +1455,23 @@ static int l_cf_ce_focus(lua_State *) {
ce_toggle_focus();
return 0;
}
+
+static int l_cf_ce_show_completions(lua_State *lua) {
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ GtkEntryCompletion *completion =
+ gtk_entry_get_completion(GTK_ENTRY(command_entry));
+ GtkListStore *store =
+ GTK_LIST_STORE(gtk_entry_completion_get_model(completion));
+ gtk_list_store_clear(store);
+ lua_pushnil(lua);
+ while (lua_next(lua, 1)) {
+ if (lua_type(lua, -1) == LUA_TSTRING) {
+ GtkTreeIter iter;
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
+ } else warn("command_entry.show_completions: non-string value ignored");
+ lua_pop(lua, 1); // value
+ }
+ gtk_entry_completion_complete(completion);
+ return 0;
+}