From ccd4945504a5db0a4f1334c31da6eec026dbb9d0 Mon Sep 17 00:00:00 2001 From: TingPing Date: Sat, 20 Jul 2013 18:00:19 -0400 Subject: [PATCH 1/6] Merge xchat r1525 Fixes possible crash --- src/common/plugin.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/plugin.c b/src/common/plugin.c index 7d118b8b..50157ea1 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -522,7 +522,7 @@ plugin_hook_find (GSList *list, int type, char *name) while (list) { hook = list->data; - if (hook->type == type) + if (hook && hook->type == type) { if (g_ascii_strcasecmp (hook->name, name) == 0) return list; @@ -600,7 +600,7 @@ xit: { hook = list->data; next = list->next; - if (hook->type == HOOK_DELETED) + if (!hook || hook->type == HOOK_DELETED) { hook_list = g_slist_remove (hook_list, hook); free (hook); @@ -750,7 +750,7 @@ plugin_insert_hook (hexchat_hook *new_hook) while (list) { hook = list->data; - if (hook->type == new_hook->type && hook->pri <= new_hook->pri) + if (hook && hook->type == new_hook->type && hook->pri <= new_hook->pri) { hook_list = g_slist_insert_before (hook_list, list, new_hook); return; @@ -828,7 +828,7 @@ plugin_command_list(GList *tmp_list) while (list) { hook = list->data; - if (hook->type == HOOK_COMMAND) + if (hook && hook->type == HOOK_COMMAND) tmp_list = g_list_prepend(tmp_list, hook->name); list = list->next; } @@ -846,7 +846,7 @@ plugin_command_foreach (session *sess, void *userdata, while (list) { hook = list->data; - if (hook->type == HOOK_COMMAND && hook->name[0]) + if (hook && hook->type == HOOK_COMMAND && hook->name[0]) { cb (sess, userdata, hook->name, hook->help_text); } From 414b591358c1c97c05dda94e27df0de3d9e531a7 Mon Sep 17 00:00:00 2001 From: TingPing Date: Fri, 19 Jul 2013 10:25:46 -0400 Subject: [PATCH 2/6] Python: Add support for attributes in hooks --- plugins/python/python.c | 274 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 264 insertions(+), 10 deletions(-) diff --git a/plugins/python/python.c b/plugins/python/python.c index b34ed0a9..ea16438b 100644 --- a/plugins/python/python.c +++ b/plugins/python/python.c @@ -211,7 +211,8 @@ static PyThreadState *pTempThread; ((PluginObject *)(x))->gui = (y); #define HOOK_XCHAT 1 -#define HOOK_UNLOAD 2 +#define HOOK_XCHAT_ATTR 2 +#define HOOK_UNLOAD 3 /* ===================================================================== */ /* Object definitions */ @@ -226,6 +227,11 @@ typedef struct { hexchat_context *context; } ContextObject; +typedef struct { + PyObject_HEAD + PyObject *time; +} AttributeObject; + typedef struct { PyObject_HEAD const char *listname; @@ -261,8 +267,9 @@ static PyObject *Util_BuildList(char *word[]); static void Util_Autoload(); static char *Util_Expand(char *filename); +static int Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata); static int Callback_Command(char *word[], char *word_eol[], void *userdata); -static int Callback_Print(char *word[], void *userdata); +static int Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata); static int Callback_Timer(void *userdata); static int Callback_ThreadTimer(void *userdata); @@ -270,6 +277,8 @@ static PyObject *XChatOut_New(); static PyObject *XChatOut_write(PyObject *self, PyObject *args); static void XChatOut_dealloc(PyObject *self); +static PyObject *Attribute_New(hexchat_event_attrs *attrs); + static void Context_dealloc(PyObject *self); static PyObject *Context_set(ContextObject *self, PyObject *args); static PyObject *Context_command(ContextObject *self, PyObject *args); @@ -331,6 +340,7 @@ static PyTypeObject Plugin_Type; static PyTypeObject XChatOut_Type; static PyTypeObject Context_Type; static PyTypeObject ListItem_Type; +static PyTypeObject Attribute_Type; static PyThreadState *main_tstate = NULL; static void *thread_timer = NULL; @@ -487,6 +497,58 @@ Util_ReleaseThread(PyThreadState *tstate) /* Hookable functions. These are the entry points to python code, besides * the load function, and the hooks for interactive interpreter. */ +static int +Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata) +{ + Hook *hook = (Hook *) userdata; + PyObject *retobj; + PyObject *word_list, *word_eol_list; + PyObject *attributes; + int ret = 0; + PyObject *plugin; + + plugin = hook->plugin; + BEGIN_PLUGIN(plugin); + + word_list = Util_BuildList(word+1); + if (word_list == NULL) { + END_PLUGIN(plugin); + return 0; + } + word_eol_list = Util_BuildList(word_eol+1); + if (word_eol_list == NULL) { + Py_DECREF(word_list); + END_PLUGIN(plugin); + return 0; + } + + attributes = Attribute_New(attrs); + + if (hook->type == HOOK_XCHAT_ATTR) + retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list, + word_eol_list, hook->userdata, attributes); + else + retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list, + word_eol_list, hook->userdata); + Py_DECREF(word_list); + Py_DECREF(word_eol_list); + Py_DECREF(attributes); + + if (retobj == Py_None) { + ret = HEXCHAT_EAT_NONE; + Py_DECREF(retobj); + } else if (retobj) { + ret = PyLong_AsLong(retobj); + Py_DECREF(retobj); + } else { + PyErr_Print(); + } + + END_PLUGIN(plugin); + + return ret; +} + static int Callback_Command(char *word[], char *word_eol[], void *userdata) { @@ -534,12 +596,13 @@ Callback_Command(char *word[], char *word_eol[], void *userdata) /* No Callback_Server() here. We use Callback_Command() as well. */ static int -Callback_Print(char *word[], void *userdata) +Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata) { Hook *hook = (Hook *) userdata; PyObject *retobj; PyObject *word_list; PyObject *word_eol_list; + PyObject *attributes; char **word_eol; char *word_eol_raw; int listsize = 0; @@ -597,10 +660,18 @@ Callback_Print(char *word[], void *userdata) return 0; } - retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list, - word_eol_list, hook->userdata); + attributes = Attribute_New(attrs); + + if (hook->type == HOOK_XCHAT_ATTR) + retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list, + word_eol_list, hook->userdata, attributes); + else + retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list, + word_eol_list, hook->userdata); + Py_DECREF(word_list); Py_DECREF(word_eol_list); + Py_DECREF(attributes); g_free(word_eol_raw); g_free(word_eol); @@ -822,6 +893,84 @@ static PyTypeObject XChatOut_Type = { }; +/* ===================================================================== */ +/* Attribute object */ + +#define OFF(x) offsetof(AttributeObject, x) + +static PyMemberDef Attribute_members[] = { + {"time", T_OBJECT, OFF(time), 0}, + {0} +}; + +static void +Attribute_dealloc(PyObject *self) +{ + Py_DECREF(((AttributeObject*)self)->time); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject * +Attribute_repr(PyObject *self) +{ + return PyUnicode_FromFormat("", self); +} + +static PyTypeObject Attribute_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "hexchat.Attribute", /*tp_name*/ + sizeof(AttributeObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + Attribute_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + Attribute_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr,/*tp_getattro*/ + PyObject_GenericSetAttr,/*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + Attribute_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + PyType_GenericAlloc, /*tp_alloc*/ + PyType_GenericNew, /*tp_new*/ + PyObject_Del, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +static PyObject * +Attribute_New(hexchat_event_attrs *attrs) +{ + AttributeObject *attr; + attr = PyObject_New(AttributeObject, &Attribute_Type); + if (attr != NULL) { + attr->time = PyLong_FromLong((long)attrs->server_time_utc); + } + return (PyObject *) attr; +} + + /* ===================================================================== */ /* Context object */ @@ -1232,7 +1381,7 @@ Plugin_RemoveHook(PyObject *plugin, Hook *hook) list = g_slist_find(Plugin_GetHooks(plugin), hook); if (list) { /* Ok, unhook it. */ - if (hook->type == HOOK_XCHAT) { + if (hook->type != HOOK_UNLOAD) { /* This is an xchat hook. Unregister it. */ BEGIN_XCHAT_CALLS(NONE); hexchat_unhook(ph, (hexchat_hook*)hook->data); @@ -1255,7 +1404,7 @@ Plugin_RemoveAllHooks(PyObject *plugin) GSList *list = Plugin_GetHooks(plugin); while (list) { Hook *hook = (Hook *) list->data; - if (hook->type == HOOK_XCHAT) { + if (hook->type != HOOK_UNLOAD) { /* This is an xchat hook. Unregister it. */ BEGIN_XCHAT_CALLS(NONE); hexchat_unhook(ph, (hexchat_hook*)hook->data); @@ -1530,6 +1679,33 @@ Module_hexchat_emit_print(PyObject *self, PyObject *args) return PyLong_FromLong(res); } +static PyObject * +Module_hexchat_emit_print_at(PyObject *self, PyObject *args) +{ + char *argv[10]; + char *name; + long time; + int res; + hexchat_event_attrs* attrs; + memset(&argv, 0, sizeof(char*)*10); + if (!PyArg_ParseTuple(args, "ls|ssssss:print_event_at", &time, &name, + &argv[0], &argv[1], &argv[2], + &argv[3], &argv[4], &argv[5], + &argv[6], &argv[7], &argv[8])) + return NULL; + BEGIN_XCHAT_CALLS(RESTORE_CONTEXT|ALLOW_THREADS); + attrs = hexchat_event_attrs_create(ph); + attrs->server_time_utc = (time_t)time; + + res = hexchat_emit_print_attrs(ph, attrs, name, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8]); + + hexchat_event_attrs_free(ph, attrs); + END_XCHAT_CALLS(); + return PyLong_FromLong(res); +} + static PyObject * Module_hexchat_get_info(PyObject *self, PyObject *args) { @@ -1789,8 +1965,44 @@ Module_hexchat_hook_server(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; BEGIN_XCHAT_CALLS(NONE); - hook->data = (void*)hexchat_hook_server(ph, name, priority, - Callback_Command, hook); + hook->data = (void*)hexchat_hook_server_attrs(ph, name, priority, + Callback_Server, hook); + END_XCHAT_CALLS(); + + return PyLong_FromLong((long)hook); +} + +static PyObject * +Module_hexchat_hook_server_attrs(PyObject *self, PyObject *args, PyObject *kwargs) +{ + char *name; + PyObject *callback; + PyObject *userdata = Py_None; + int priority = HEXCHAT_PRI_NORM; + PyObject *plugin; + Hook *hook; + char *kwlist[] = {"name", "callback", "userdata", "priority", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|Oi:hook_server", + kwlist, &name, &callback, &userdata, + &priority)) + return NULL; + + plugin = Plugin_GetCurrent(); + if (plugin == NULL) + return NULL; + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "callback is not callable"); + return NULL; + } + + hook = Plugin_AddHook(HOOK_XCHAT_ATTR, plugin, callback, userdata, NULL, NULL); + if (hook == NULL) + return NULL; + + BEGIN_XCHAT_CALLS(NONE); + hook->data = (void*)hexchat_hook_server_attrs(ph, name, priority, + Callback_Server, hook); END_XCHAT_CALLS(); return PyLong_FromLong((long)hook); @@ -1825,7 +2037,43 @@ Module_hexchat_hook_print(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; BEGIN_XCHAT_CALLS(NONE); - hook->data = (void*)hexchat_hook_print(ph, name, priority, + hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority, + Callback_Print, hook); + END_XCHAT_CALLS(); + + return PyLong_FromLong((long)hook); +} + +static PyObject * +Module_hexchat_hook_print_attrs(PyObject *self, PyObject *args, PyObject *kwargs) +{ + char *name; + PyObject *callback; + PyObject *userdata = Py_None; + int priority = HEXCHAT_PRI_NORM; + PyObject *plugin; + Hook *hook; + char *kwlist[] = {"name", "callback", "userdata", "priority", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|Oi:hook_print_attrs", + kwlist, &name, &callback, &userdata, + &priority)) + return NULL; + + plugin = Plugin_GetCurrent(); + if (plugin == NULL) + return NULL; + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "callback is not callable"); + return NULL; + } + + hook = Plugin_AddHook(HOOK_XCHAT_ATTR, plugin, callback, userdata, name, NULL); + if (hook == NULL) + return NULL; + + BEGIN_XCHAT_CALLS(NONE); + hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority, Callback_Print, hook); END_XCHAT_CALLS(); @@ -2068,6 +2316,8 @@ static PyMethodDef Module_xchat_methods[] = { METH_VARARGS}, {"emit_print", Module_hexchat_emit_print, METH_VARARGS}, + {"emit_print_at", Module_hexchat_emit_print_at, + METH_VARARGS}, {"get_info", Module_hexchat_get_info, METH_VARARGS}, {"get_prefs", Module_xchat_get_prefs, @@ -2088,8 +2338,12 @@ static PyMethodDef Module_xchat_methods[] = { METH_VARARGS|METH_KEYWORDS}, {"hook_server", (PyCFunction)Module_hexchat_hook_server, METH_VARARGS|METH_KEYWORDS}, + {"hook_server_attrs", (PyCFunction)Module_hexchat_hook_server_attrs, + METH_VARARGS|METH_KEYWORDS}, {"hook_print", (PyCFunction)Module_hexchat_hook_print, METH_VARARGS|METH_KEYWORDS}, + {"hook_print_attrs", (PyCFunction)Module_hexchat_hook_print_attrs, + METH_VARARGS|METH_KEYWORDS}, {"hook_timer", (PyCFunction)Module_hexchat_hook_timer, METH_VARARGS|METH_KEYWORDS}, {"hook_unload", (PyCFunction)Module_hexchat_hook_unload, From e5cb69db5df42ba216317a03ee8d83175dd01c11 Mon Sep 17 00:00:00 2001 From: TingPing Date: Fri, 19 Jul 2013 14:14:26 -0400 Subject: [PATCH 3/6] Python: Use keywords for attributes in emit_print() --- plugins/python/python.c | 77 ++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/plugins/python/python.c b/plugins/python/python.c index ea16438b..eb38a344 100644 --- a/plugins/python/python.c +++ b/plugins/python/python.c @@ -1018,22 +1018,31 @@ Context_prnt(ContextObject *self, PyObject *args) } static PyObject * -Context_emit_print(ContextObject *self, PyObject *args) +Context_emit_print(ContextObject *self, PyObject *args, PyObject *kwargs) { - char *argv[10]; + char *argv[6]; char *name; int res; - memset(&argv, 0, sizeof(char*)*10); - if (!PyArg_ParseTuple(args, "s|ssssss:print_event", &name, + long time = 0; + hexchat_event_attrs *attrs; + char *kwlist[] = {"name", "arg1", "arg2", "arg3", + "arg4", "arg5", "arg6", + "time", NULL}; + memset(&argv, 0, sizeof(char*)*6); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ssssssl:print_event", kwlist, &name, &argv[0], &argv[1], &argv[2], &argv[3], &argv[4], &argv[5], - &argv[6], &argv[7], &argv[8])) + &time)) return NULL; BEGIN_XCHAT_CALLS(ALLOW_THREADS); hexchat_set_context(ph, self->context); - res = hexchat_emit_print(ph, name, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8]); + attrs = hexchat_event_attrs_create(ph); + attrs->server_time_utc = (time_t)time; + + res = hexchat_emit_print_attrs(ph, attrs, name, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], NULL); + + hexchat_event_attrs_free(ph, attrs); END_XCHAT_CALLS(); return PyLong_FromLong(res); } @@ -1094,7 +1103,7 @@ static PyMethodDef Context_methods[] = { {"set", (PyCFunction) Context_set, METH_NOARGS}, {"command", (PyCFunction) Context_command, METH_VARARGS}, {"prnt", (PyCFunction) Context_prnt, METH_VARARGS}, - {"emit_print", (PyCFunction) Context_emit_print, METH_VARARGS}, + {"emit_print", (PyCFunction) Context_emit_print, METH_VARARGS|METH_KEYWORDS}, {"get_info", (PyCFunction) Context_get_info, METH_VARARGS}, {"get_list", (PyCFunction) Context_get_list, METH_VARARGS}, {NULL, NULL} @@ -1660,46 +1669,28 @@ Module_xchat_prnt(PyObject *self, PyObject *args) } static PyObject * -Module_hexchat_emit_print(PyObject *self, PyObject *args) +Module_hexchat_emit_print(PyObject *self, PyObject *args, PyObject *kwargs) { - char *argv[10]; + char *argv[6]; char *name; int res; - memset(&argv, 0, sizeof(char*)*10); - if (!PyArg_ParseTuple(args, "s|ssssss:print_event", &name, + long time = 0; + hexchat_event_attrs *attrs; + char *kwlist[] = {"name", "arg1", "arg2", "arg3", + "arg4", "arg5", "arg6", + "time", NULL}; + memset(&argv, 0, sizeof(char*)*6); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ssssssl:print_event", kwlist, &name, &argv[0], &argv[1], &argv[2], &argv[3], &argv[4], &argv[5], - &argv[6], &argv[7], &argv[8])) - return NULL; - BEGIN_XCHAT_CALLS(RESTORE_CONTEXT|ALLOW_THREADS); - res = hexchat_emit_print(ph, name, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8]); - END_XCHAT_CALLS(); - return PyLong_FromLong(res); -} - -static PyObject * -Module_hexchat_emit_print_at(PyObject *self, PyObject *args) -{ - char *argv[10]; - char *name; - long time; - int res; - hexchat_event_attrs* attrs; - memset(&argv, 0, sizeof(char*)*10); - if (!PyArg_ParseTuple(args, "ls|ssssss:print_event_at", &time, &name, - &argv[0], &argv[1], &argv[2], - &argv[3], &argv[4], &argv[5], - &argv[6], &argv[7], &argv[8])) + &time)) return NULL; BEGIN_XCHAT_CALLS(RESTORE_CONTEXT|ALLOW_THREADS); attrs = hexchat_event_attrs_create(ph); - attrs->server_time_utc = (time_t)time; - + attrs->server_time_utc = (time_t)time; + res = hexchat_emit_print_attrs(ph, attrs, name, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8]); + argv[3], argv[4], argv[5], NULL); hexchat_event_attrs_free(ph, attrs); END_XCHAT_CALLS(); @@ -2314,10 +2305,8 @@ static PyMethodDef Module_xchat_methods[] = { METH_VARARGS}, {"prnt", Module_xchat_prnt, METH_VARARGS}, - {"emit_print", Module_hexchat_emit_print, - METH_VARARGS}, - {"emit_print_at", Module_hexchat_emit_print_at, - METH_VARARGS}, + {"emit_print", (PyCFunction)Module_hexchat_emit_print, + METH_VARARGS|METH_KEYWORDS}, {"get_info", Module_hexchat_get_info, METH_VARARGS}, {"get_prefs", Module_xchat_get_prefs, From 4721a3747ec5044c6bd2569108e1d153a0e1dc2f Mon Sep 17 00:00:00 2001 From: TingPing Date: Sun, 21 Jul 2013 16:40:38 -0400 Subject: [PATCH 4/6] Python: return hooks with PyLong_FromVoidPtr Fixes #685 --- plugins/python/python.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/python/python.c b/plugins/python/python.c index eb38a344..90dbb22d 100644 --- a/plugins/python/python.c +++ b/plugins/python/python.c @@ -1924,7 +1924,7 @@ Module_hexchat_hook_command(PyObject *self, PyObject *args, PyObject *kwargs) Callback_Command, help, hook); END_XCHAT_CALLS(); - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -1960,7 +1960,7 @@ Module_hexchat_hook_server(PyObject *self, PyObject *args, PyObject *kwargs) Callback_Server, hook); END_XCHAT_CALLS(); - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -1996,7 +1996,7 @@ Module_hexchat_hook_server_attrs(PyObject *self, PyObject *args, PyObject *kwarg Callback_Server, hook); END_XCHAT_CALLS(); - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -2032,7 +2032,7 @@ Module_hexchat_hook_print(PyObject *self, PyObject *args, PyObject *kwargs) Callback_Print, hook); END_XCHAT_CALLS(); - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -2068,7 +2068,7 @@ Module_hexchat_hook_print_attrs(PyObject *self, PyObject *args, PyObject *kwargs Callback_Print, hook); END_XCHAT_CALLS(); - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -2103,7 +2103,7 @@ Module_hexchat_hook_timer(PyObject *self, PyObject *args, PyObject *kwargs) Callback_Timer, hook); END_XCHAT_CALLS(); - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -2131,7 +2131,7 @@ Module_hexchat_hook_unload(PyObject *self, PyObject *args, PyObject *kwargs) if (hook == NULL) return NULL; - return PyLong_FromLong((long)hook); + return PyLong_FromVoidPtr(hook); } static PyObject * @@ -2157,7 +2157,7 @@ Module_hexchat_unhook(PyObject *self, PyObject *args) } else { - hook = (Hook *)PyLong_AsLong(obj); + hook = (Hook *)PyLong_AsVoidPtr(obj); Plugin_RemoveHook(plugin, hook); } From aa37686bbd69a6fab9dea6492a2f6a8b818845f0 Mon Sep 17 00:00:00 2001 From: Eustachy Kapusta Date: Wed, 24 Jul 2013 20:56:36 +0200 Subject: [PATCH 5/6] Move optimization settings from all subsequent projects to hexchat.props --- plugins/checksum/checksum.vcxproj | 2 -- plugins/dns/dns.vcxproj | 2 -- plugins/doat/doat.vcxproj | 2 -- plugins/exec/exec.vcxproj | 2 -- plugins/fishlim/fishlim.vcxproj | 2 -- plugins/hextray/hextray.vcxproj | 2 -- plugins/mpcinfo/mpcinfo.vcxproj | 2 -- plugins/perl/perl.vcxproj | 2 -- plugins/python/python2.vcxproj | 2 -- plugins/python/python3.vcxproj | 2 -- plugins/sysinfo/sysinfo.vcxproj | 2 -- plugins/upd/upd.vcxproj | 2 -- plugins/winamp/winamp.vcxproj | 2 -- src/common/common.vcxproj | 2 -- src/common/make-te.vcxproj | 2 -- src/fe-gtk/fe-gtk.vcxproj | 2 -- src/fe-text/fe-text.vcxproj | 2 -- src/pixmaps/pixmaps.vcxproj | 2 -- src/version/version.vcxproj | 2 -- win32/copy/copy.vcxproj | 2 -- win32/hexchat.props | 5 +++++ win32/installer/installer.vcxproj | 2 -- win32/nls/nls.vcxproj | 2 -- 23 files changed, 5 insertions(+), 44 deletions(-) diff --git a/plugins/checksum/checksum.vcxproj b/plugins/checksum/checksum.vcxproj index 4090675c..ce75d68b 100644 --- a/plugins/checksum/checksum.vcxproj +++ b/plugins/checksum/checksum.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions) @@ -80,7 +79,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/dns/dns.vcxproj b/plugins/dns/dns.vcxproj index 39e47f67..f34c7bc3 100644 --- a/plugins/dns/dns.vcxproj +++ b/plugins/dns/dns.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;DNS_EXPORTS;%(PreprocessorDefinitions) @@ -80,7 +79,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;DNS_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/doat/doat.vcxproj b/plugins/doat/doat.vcxproj index bb44030d..32ac7055 100644 --- a/plugins/doat/doat.vcxproj +++ b/plugins/doat/doat.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;DOAT_EXPORTS;%(PreprocessorDefinitions) @@ -78,7 +77,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;DOAT_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/exec/exec.vcxproj b/plugins/exec/exec.vcxproj index f1710119..e789767f 100644 --- a/plugins/exec/exec.vcxproj +++ b/plugins/exec/exec.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;EXEC_EXPORTS;%(PreprocessorDefinitions) @@ -78,7 +77,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;EXEC_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/fishlim/fishlim.vcxproj b/plugins/fishlim/fishlim.vcxproj index 3743057c..d21c21ad 100644 --- a/plugins/fishlim/fishlim.vcxproj +++ b/plugins/fishlim/fishlim.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions) @@ -80,7 +79,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/hextray/hextray.vcxproj b/plugins/hextray/hextray.vcxproj index 9cac1368..3c48e9d0 100644 --- a/plugins/hextray/hextray.vcxproj +++ b/plugins/hextray/hextray.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;XTRAY_EXPORTS;%(PreprocessorDefinitions) @@ -78,7 +77,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;XTRAY_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/mpcinfo/mpcinfo.vcxproj b/plugins/mpcinfo/mpcinfo.vcxproj index a63962a9..756fddf2 100644 --- a/plugins/mpcinfo/mpcinfo.vcxproj +++ b/plugins/mpcinfo/mpcinfo.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;MPCINFO_EXPORTS;%(PreprocessorDefinitions) @@ -78,7 +77,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;MPCINFO_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/perl/perl.vcxproj b/plugins/perl/perl.vcxproj index af173966..afaaa08f 100644 --- a/plugins/perl/perl.vcxproj +++ b/plugins/perl/perl.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;PERL518_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) @@ -89,7 +88,6 @@ move xchat.pm.h "$(IntDir)" - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PERL518_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) diff --git a/plugins/python/python2.vcxproj b/plugins/python/python2.vcxproj index 1f524134..6730f45e 100644 --- a/plugins/python/python2.vcxproj +++ b/plugins/python/python2.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) @@ -80,7 +79,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) diff --git a/plugins/python/python3.vcxproj b/plugins/python/python3.vcxproj index ddf56132..28ffc80c 100644 --- a/plugins/python/python3.vcxproj +++ b/plugins/python/python3.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) @@ -80,7 +79,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) diff --git a/plugins/sysinfo/sysinfo.vcxproj b/plugins/sysinfo/sysinfo.vcxproj index 0446e723..88c090cc 100644 --- a/plugins/sysinfo/sysinfo.vcxproj +++ b/plugins/sysinfo/sysinfo.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;SYSINFO_EXPORTS;%(PreprocessorDefinitions) @@ -81,7 +80,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;SYSINFO_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/upd/upd.vcxproj b/plugins/upd/upd.vcxproj index 1b3009dc..a06085b2 100644 --- a/plugins/upd/upd.vcxproj +++ b/plugins/upd/upd.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;UPD_EXPORTS;%(PreprocessorDefinitions) @@ -80,7 +79,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;UPD_EXPORTS;%(PreprocessorDefinitions) diff --git a/plugins/winamp/winamp.vcxproj b/plugins/winamp/winamp.vcxproj index 667ec598..e140f55f 100644 --- a/plugins/winamp/winamp.vcxproj +++ b/plugins/winamp/winamp.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;WINAMP_EXPORTS;%(PreprocessorDefinitions) @@ -78,7 +77,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;WINAMP_EXPORTS;%(PreprocessorDefinitions) diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index c71d6ced..5568409e 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -119,7 +119,6 @@ - MaxSpeed true true WIN32;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions) @@ -137,7 +136,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions) diff --git a/src/common/make-te.vcxproj b/src/common/make-te.vcxproj index 07bb5ca4..b9f0f11f 100644 --- a/src/common/make-te.vcxproj +++ b/src/common/make-te.vcxproj @@ -57,7 +57,6 @@ - MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) @@ -77,7 +76,6 @@ - MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj index 0c149928..f8c6377a 100644 --- a/src/fe-gtk/fe-gtk.vcxproj +++ b/src/fe-gtk/fe-gtk.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions) @@ -81,7 +80,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions) diff --git a/src/fe-text/fe-text.vcxproj b/src/fe-text/fe-text.vcxproj index 1c42c967..2a7c3742 100644 --- a/src/fe-text/fe-text.vcxproj +++ b/src/fe-text/fe-text.vcxproj @@ -59,7 +59,6 @@ - MaxSpeed true true WIN32;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions) @@ -79,7 +78,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions) diff --git a/src/pixmaps/pixmaps.vcxproj b/src/pixmaps/pixmaps.vcxproj index dbb18520..a86a7e13 100644 --- a/src/pixmaps/pixmaps.vcxproj +++ b/src/pixmaps/pixmaps.vcxproj @@ -57,7 +57,6 @@ - MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) @@ -76,7 +75,6 @@ - MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) diff --git a/src/version/version.vcxproj b/src/version/version.vcxproj index ca429b08..f1520f73 100644 --- a/src/version/version.vcxproj +++ b/src/version/version.vcxproj @@ -57,7 +57,6 @@ - MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) @@ -77,7 +76,6 @@ - MaxSpeed true true WIN32;_WIN64;_AMD64_;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index 3146e6be..1586d200 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -52,7 +52,6 @@ - MaxSpeed true true @@ -67,7 +66,6 @@ - MaxSpeed true true diff --git a/win32/hexchat.props b/win32/hexchat.props index 453240d8..25fdb14a 100644 --- a/win32/hexchat.props +++ b/win32/hexchat.props @@ -100,6 +100,11 @@ xcopy /q /s /i "$(DepsRoot)\share\locale" "$(HexChatRel)\share\locale" Level3 4996 + + + MaxSpeed + + diff --git a/win32/installer/installer.vcxproj b/win32/installer/installer.vcxproj index faa13c06..87142c2c 100644 --- a/win32/installer/installer.vcxproj +++ b/win32/installer/installer.vcxproj @@ -52,7 +52,6 @@ - MaxSpeed true true @@ -76,7 +75,6 @@ type hexchat-x86.skel.iss >> "$(OutDir)\hexchat-x86.iss" - MaxSpeed true true diff --git a/win32/nls/nls.vcxproj b/win32/nls/nls.vcxproj index c1da078a..35ca3e9d 100644 --- a/win32/nls/nls.vcxproj +++ b/win32/nls/nls.vcxproj @@ -52,7 +52,6 @@ - MaxSpeed true true @@ -73,7 +72,6 @@ mkdir "$(OutDir)\locale\%%~nA\LC_MESSAGES" - MaxSpeed true true From b0b8f40791de39eb6a7ee301d2edada80ad32338 Mon Sep 17 00:00:00 2001 From: TingPing Date: Wed, 24 Jul 2013 20:47:01 -0400 Subject: [PATCH 6/6] Replace search window with a searchbar --- src/common/cfgfiles.c | 2 +- src/common/hexchat.h | 2 +- src/fe-gtk/Makefile.am | 4 +- src/fe-gtk/fe-gtk.h | 3 + src/fe-gtk/fe-gtk.vcxproj | 2 - src/fe-gtk/fe-gtk.vcxproj.filters | 6 - src/fe-gtk/maingui.c | 198 +++++++++++++++++++++++- src/fe-gtk/maingui.h | 6 +- src/fe-gtk/menu.c | 33 +--- src/fe-gtk/search.c | 246 ------------------------------ src/fe-gtk/search.h | 25 --- 11 files changed, 214 insertions(+), 313 deletions(-) delete mode 100644 src/fe-gtk/search.c delete mode 100644 src/fe-gtk/search.h diff --git a/src/common/cfgfiles.c b/src/common/cfgfiles.c index 008a0787..675ed837 100644 --- a/src/common/cfgfiles.c +++ b/src/common/cfgfiles.c @@ -438,6 +438,7 @@ const struct prefs vars[] = {"gui_pane_right_size", P_OFFINT (hex_gui_pane_right_size), TYPE_INT}, {"gui_pane_right_size_min", P_OFFINT (hex_gui_pane_right_size_min), TYPE_INT}, {"gui_quit_dialog", P_OFFINT (hex_gui_quit_dialog), TYPE_BOOL}, + {"gui_search_pos", P_OFFINT (hex_gui_search_pos), TYPE_INT}, /* {"gui_single", P_OFFINT (hex_gui_single), TYPE_BOOL}, */ {"gui_slist_fav", P_OFFINT (hex_gui_slist_fav), TYPE_BOOL}, {"gui_slist_select", P_OFFINT (hex_gui_slist_select), TYPE_INT}, @@ -573,7 +574,6 @@ const struct prefs vars[] = {"text_max_lines", P_OFFINT (hex_text_max_lines), TYPE_INT}, {"text_replay", P_OFFINT (hex_text_replay), TYPE_BOOL}, {"text_search_case_match", P_OFFINT (hex_text_search_case_match), TYPE_BOOL}, - {"text_search_backward", P_OFFINT (hex_text_search_backward), TYPE_BOOL}, {"text_search_highlight_all", P_OFFINT (hex_text_search_highlight_all), TYPE_BOOL}, {"text_search_follow", P_OFFINT (hex_text_search_follow), TYPE_BOOL}, {"text_search_regexp", P_OFFINT (hex_text_search_regexp), TYPE_BOOL}, diff --git a/src/common/hexchat.h b/src/common/hexchat.h index 074d5a22..76d6c3c3 100644 --- a/src/common/hexchat.h +++ b/src/common/hexchat.h @@ -231,7 +231,6 @@ struct hexchatprefs unsigned int hex_text_indent; unsigned int hex_text_replay; unsigned int hex_text_search_case_match; - unsigned int hex_text_search_backward; unsigned int hex_text_search_highlight_all; unsigned int hex_text_search_follow; unsigned int hex_text_search_regexp; @@ -278,6 +277,7 @@ struct hexchatprefs int hex_gui_pane_left_size; int hex_gui_pane_right_size; int hex_gui_pane_right_size_min; + int hex_gui_search_pos; int hex_gui_slist_select; int hex_gui_tab_layout; int hex_gui_tab_newtofront; diff --git a/src/fe-gtk/Makefile.am b/src/fe-gtk/Makefile.am index 8bbad35d..1890edbf 100644 --- a/src/fe-gtk/Makefile.am +++ b/src/fe-gtk/Makefile.am @@ -10,7 +10,7 @@ EXTRA_DIST = \ about.h ascii.h banlist.h chanlist.h chanview.h chanview-tabs.c \ chanview-tree.c custom-list.h editlist.h fe-gtk.h fkeys.h gtkutil.h joind.h \ maingui.h menu.h mmx_cmod.S mmx_cmod.h notifygui.h palette.h pixmaps.h \ - plugin-tray.h plugingui.c plugingui.h rawlog.h search.h sexy-iso-codes.h \ + plugin-tray.h plugingui.c plugingui.h rawlog.h sexy-iso-codes.h \ sexy-spell-entry.h sexy-marshal.h textgui.h urlgrab.h userlistgui.h xtext.h if USE_MMX @@ -29,5 +29,5 @@ endif hexchat_SOURCES = about.c ascii.c banlist.c chanlist.c chanview.c custom-list.c \ dccgui.c editlist.c fe-gtk.c fkeys.c gtkutil.c ignoregui.c joind.c menu.c \ maingui.c $(mmx_cmod_S) notifygui.c palette.c pixmaps.c plugin-tray.c $(plugingui_c) \ - rawlog.c search.c servlistgui.c setup.c $(sexy_spell) textgui.c \ + rawlog.c servlistgui.c setup.c $(sexy_spell) textgui.c \ urlgrab.c userlistgui.c xtext.c diff --git a/src/fe-gtk/fe-gtk.h b/src/fe-gtk/fe-gtk.h index 7b4132da..80788761 100644 --- a/src/fe-gtk/fe-gtk.h +++ b/src/fe-gtk/fe-gtk.h @@ -176,6 +176,9 @@ typedef struct session_gui *limit_entry, /* +l */ *key_entry; /* +k */ + GtkWidget *shbox, *shentry; /* search bar hbox */ + gulong search_changed_signal; /* hook for search change event so blanking the box doesn't suck */ + #define MENU_ID_NUM 12 GtkWidget *menu_item[MENU_ID_NUM+1]; /* some items we may change state of */ diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj index f8c6377a..405b5207 100644 --- a/src/fe-gtk/fe-gtk.vcxproj +++ b/src/fe-gtk/fe-gtk.vcxproj @@ -118,7 +118,6 @@ - @@ -151,7 +150,6 @@ - diff --git a/src/fe-gtk/fe-gtk.vcxproj.filters b/src/fe-gtk/fe-gtk.vcxproj.filters index a319babd..0f1f8203 100644 --- a/src/fe-gtk/fe-gtk.vcxproj.filters +++ b/src/fe-gtk/fe-gtk.vcxproj.filters @@ -75,9 +75,6 @@ Header Files - - Header Files - Header Files @@ -170,9 +167,6 @@ Source Files - - Source Files - Source Files diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 2a486b17..91bc9d6f 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -21,6 +21,8 @@ #include #include +#include + #include "../common/hexchat.h" #include "../common/fe.h" #include "../common/server.h" @@ -33,6 +35,7 @@ #include "../common/util.h" #include "../common/text.h" #include "../common/chanopt.h" +#include "../common/cfgfiles.h" #include "fe-gtk.h" #include "banlist.h" @@ -77,6 +80,7 @@ enum #define TAG_UTIL 1 /* dcc, notify, chanlist */ static void mg_create_entry (session *sess, GtkWidget *box); +static void mg_create_search (session *sess, GtkWidget *box); static void mg_link_irctab (session *sess, int focus); static session_gui static_mg_gui; @@ -2619,7 +2623,18 @@ mg_create_center (session *sess, session_gui *gui, GtkWidget *box) vbox = gtk_vbox_new (FALSE, 3); gtk_notebook_append_page (GTK_NOTEBOOK (book), vbox, NULL); mg_create_topicbar (sess, vbox); - mg_create_textarea (sess, vbox); + + if (prefs.hex_gui_search_pos) + { + mg_create_search (sess, vbox); + mg_create_textarea (sess, vbox); + } + else + { + mg_create_textarea (sess, vbox); + mg_create_search (sess, vbox); + } + mg_create_entry (sess, vbox); mg_add_pane_signals (gui); @@ -2814,6 +2829,183 @@ mg_inputbox_rightclick (GtkEntry *entry, GtkWidget *menu) mg_create_color_menu (menu, NULL); } +/* Search bar adapted from Conspire's by William Pitcock */ + +#define SEARCH_CHANGE 1 +#define SEARCH_NEXT 2 +#define SEARCH_PREVIOUS 3 +#define SEARCH_REFRESH 4 + +static void +search_handle_event(int search_type, session *sess) +{ + textentry *last; + const gchar *text = NULL; + gtk_xtext_search_flags flags; + GError *err = NULL; + gboolean backwards = FALSE; + + /* When just typing show most recent first */ + if (search_type == SEARCH_PREVIOUS || search_type == SEARCH_CHANGE) + backwards = TRUE; + + flags = ((prefs.hex_text_search_case_match == 1? case_match: 0) | + (backwards? backward: 0) | + (prefs.hex_text_search_highlight_all == 1? highlight: 0) | + (prefs.hex_text_search_follow == 1? follow: 0) | + (prefs.hex_text_search_regexp == 1? regexp: 0)); + + if (search_type != SEARCH_REFRESH) + text = gtk_entry_get_text (GTK_ENTRY(sess->gui->shentry)); + last = gtk_xtext_search (GTK_XTEXT (sess->gui->xtext), text, flags, &err); + + if (err) + { + gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); + gtk_entry_set_icon_tooltip_text (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, _(err->message)); + g_error_free (err); + } + else if (!last) + { + /* Either end of search or not found, try again to wrap if only end */ + last = gtk_xtext_search (GTK_XTEXT (sess->gui->xtext), text, flags, &err); + if (!last) /* Not found error */ + { + gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); + gtk_entry_set_icon_tooltip_text (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, _("No results found.")); + } + } + else + { + gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); + } +} + +static void +search_handle_change(GtkWidget *wid, session *sess) +{ + search_handle_event(SEARCH_CHANGE, sess); +} + +static void +search_handle_refresh(GtkWidget *wid, session *sess) +{ + search_handle_event(SEARCH_REFRESH, sess); +} + +void +mg_search_handle_previous(GtkWidget *wid, session *sess) +{ + search_handle_event(SEARCH_PREVIOUS, sess); +} + +void +mg_search_handle_next(GtkWidget *wid, session *sess) +{ + search_handle_event(SEARCH_NEXT, sess); +} + +static void +search_set_option (GtkToggleButton *but, guint *pref) +{ + *pref = gtk_toggle_button_get_active(but); + save_config(); +} + +void +mg_search_toggle(session *sess) +{ + if (gtk_widget_get_visible(sess->gui->shbox)) + { + gtk_widget_hide(sess->gui->shbox); + gtk_widget_grab_focus(sess->gui->input_box); + gtk_entry_set_text(GTK_ENTRY(sess->gui->shentry), ""); + } + else + { + /* Reset search state */ + gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); + + /* Show and focus */ + gtk_widget_show(sess->gui->shbox); + gtk_widget_grab_focus(sess->gui->shentry); + } +} + +static gboolean +search_handle_esc (GtkWidget *win, GdkEventKey *key, session *sess) +{ + if (key->keyval == GDK_KEY_Escape) + mg_search_toggle(sess); + + return FALSE; +} + +static void +mg_create_search(session *sess, GtkWidget *box) +{ + GtkWidget *entry, *label, *next, *previous, *highlight, *matchcase, *regex, *close; + session_gui *gui = sess->gui; + + gui->shbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(box), gui->shbox, FALSE, FALSE, 0); + + close = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (close), gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief(GTK_BUTTON(close), GTK_RELIEF_NONE); + gtk_widget_set_can_focus (close, FALSE); + gtk_box_pack_start(GTK_BOX(gui->shbox), close, FALSE, FALSE, 0); + g_signal_connect_swapped(G_OBJECT(close), "clicked", G_CALLBACK(mg_search_toggle), sess); + + label = gtk_label_new(_("Find:")); + gtk_box_pack_start(GTK_BOX(gui->shbox), label, FALSE, FALSE, 0); + + gui->shentry = entry = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(gui->shbox), entry, FALSE, FALSE, 0); + gtk_widget_set_size_request (gui->shentry, 180, -1); + gui->search_changed_signal = g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(search_handle_change), sess); + g_signal_connect (G_OBJECT (entry), "key_press_event", G_CALLBACK (search_handle_esc), sess); + g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(mg_search_handle_next), sess); + gtk_entry_set_icon_activatable (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, FALSE); + gtk_entry_set_icon_tooltip_text (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, _("Search hit end or not found.")); + + previous = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (previous), gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief(GTK_BUTTON(previous), GTK_RELIEF_NONE); + gtk_widget_set_can_focus (previous, FALSE); + gtk_box_pack_start(GTK_BOX(gui->shbox), previous, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(previous), "clicked", G_CALLBACK(mg_search_handle_previous), sess); + + next = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (next), gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief(GTK_BUTTON(next), GTK_RELIEF_NONE); + gtk_widget_set_can_focus (next, FALSE); + gtk_box_pack_start(GTK_BOX(gui->shbox), next, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(next), "clicked", G_CALLBACK(mg_search_handle_next), sess); + + highlight = gtk_check_button_new_with_mnemonic (_("Highlight _all")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(highlight), prefs.hex_text_search_case_match); + gtk_widget_set_can_focus (highlight, FALSE); + g_signal_connect (G_OBJECT (highlight), "toggled", G_CALLBACK (search_set_option), &prefs.hex_text_search_highlight_all); + g_signal_connect (G_OBJECT (highlight), "toggled", G_CALLBACK (search_handle_refresh), sess); + gtk_box_pack_start(GTK_BOX(gui->shbox), highlight, FALSE, FALSE, 0); + add_tip (highlight, _("Highlight all occurrences, and underline the current occurrence.")); + + matchcase = gtk_check_button_new_with_mnemonic (_("Mat_ch case")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(matchcase), prefs.hex_text_search_case_match); + gtk_widget_set_can_focus (matchcase, FALSE); + g_signal_connect (G_OBJECT (matchcase), "toggled", G_CALLBACK (search_set_option), &prefs.hex_text_search_case_match); + gtk_box_pack_start(GTK_BOX(gui->shbox), matchcase, FALSE, FALSE, 0); + add_tip (matchcase, _("Perform a case-sensitive search.")); + + regex = gtk_check_button_new_with_mnemonic (_("_Regex")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(regex), prefs.hex_text_search_regexp); + gtk_widget_set_can_focus (regex, FALSE); + g_signal_connect (G_OBJECT (regex), "toggled", G_CALLBACK (search_set_option), &prefs.hex_text_search_regexp); + gtk_box_pack_start(GTK_BOX(gui->shbox), regex, FALSE, FALSE, 0); + add_tip (regex, _("Regard search string as a regular expression.")); +} + static void mg_create_entry (session *sess, GtkWidget *box) { @@ -3055,6 +3247,8 @@ mg_create_topwindow (session *sess) if (!prefs.hex_gui_input_nick) gtk_widget_hide (sess->gui->nick_box); + gtk_widget_hide(sess->gui->shbox); + mg_decide_userlist (sess, FALSE); if (sess->type == SESS_DIALOG) @@ -3158,6 +3352,8 @@ mg_create_tabwindow (session *sess) if (!prefs.hex_gui_input_nick) gtk_widget_hide (sess->gui->nick_box); + gtk_widget_hide (sess->gui->shbox); + mg_place_userlist_and_chanview (sess->gui); gtk_widget_show (win); diff --git a/src/fe-gtk/maingui.h b/src/fe-gtk/maingui.h index a35f3684..6099e6ff 100644 --- a/src/fe-gtk/maingui.h +++ b/src/fe-gtk/maingui.h @@ -52,6 +52,10 @@ GtkWidget *mg_submenu (GtkWidget *menu, char *text); gboolean mg_drag_begin_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata); void mg_drag_end_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata); gboolean mg_drag_drop_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer user_data); -gboolean mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer user_data); +gboolean mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer user_data); +/* search */ +void mg_search_toggle(session *sess); +void mg_search_handle_previous(GtkWidget *wid, session *sess); +void mg_search_handle_next(GtkWidget *wid, session *sess); #endif diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 58c28e51..dd3223a1 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -1237,41 +1237,19 @@ menu_quit (GtkWidget * wid, gpointer none) static void menu_search () { - search_open (current_sess); + mg_search_toggle (current_sess); } static void -menu_search_next () +menu_search_next (GtkWidget *wid) { - GtkXText *xtext = GTK_XTEXT (current_sess->gui->xtext); - xtext_buffer *buf = xtext->buffer; - - if (!gtk_xtext_search (xtext, buf->search_text, - (buf->search_flags & (case_match | follow | regexp)), NULL)) - { - fe_message (_("Search hit end, not found."), FE_MSG_ERROR); - } + mg_search_handle_next(wid, current_sess); } static void -menu_search_prev () +menu_search_prev (GtkWidget *wid) { - GtkXText *xtext = GTK_XTEXT (current_sess->gui->xtext); - xtext_buffer *buf = xtext->buffer; - - if (!gtk_xtext_search(xtext, buf->search_text, - (buf->search_flags & (case_match | follow | regexp)) | backward, NULL)) - { - fe_message (_("Search hit end, not found."), FE_MSG_ERROR); - } -} - -static void -menu_search_reset () -{ - GtkXText *xtext = GTK_XTEXT (current_sess->gui->xtext); - - gtk_xtext_search (xtext, "", 0, NULL); + mg_search_handle_previous(wid, current_sess); } static void @@ -1732,7 +1710,6 @@ static struct mymenu mymenu[] = { #define SEARCH_OFFSET 68 {N_("Search"), 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 0, 1}, {N_("Search Text..."), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_f}, - {N_("Reset Search"), menu_search_reset, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_F}, {N_("Search Next" ), menu_search_next, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_g}, {N_("Search Previous" ), menu_search_prev, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_G}, {0, 0, 0, M_END, 0, 0, 0}, diff --git a/src/fe-gtk/search.c b/src/fe-gtk/search.c deleted file mode 100644 index 8d251694..00000000 --- a/src/fe-gtk/search.c +++ /dev/null @@ -1,246 +0,0 @@ -/* X-Chat - * Copyright (C) 1998 Peter Zelezny. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include - -#include "fe-gtk.h" - -#include "../common/hexchat.h" -#include "../common/fe.h" -#include "../common/util.h" -#include "../common/hexchatc.h" -#include "../common/cfgfiles.h" -#include "gtkutil.h" -#include "xtext.h" -#include "maingui.h" - -GtkWidget *searchwin; -GtkWidget *searchentry; - -static void -search_search (session * sess, const gchar *text) -{ - gtk_xtext_search_flags flags; - textentry *last; - GError *err = NULL; - - flags = ((prefs.hex_text_search_case_match == 1? case_match: 0) | - (prefs.hex_text_search_backward == 1? backward: 0) | - (prefs.hex_text_search_highlight_all == 1? highlight: 0) | - (prefs.hex_text_search_follow == 1? follow: 0) | - (prefs.hex_text_search_regexp == 1? regexp: 0)); - if (!is_session (sess)) - { - fe_message (_("The window you opened this Search " - "for doesn't exist anymore."), FE_MSG_ERROR); - return; - } - - last = gtk_xtext_search (GTK_XTEXT (sess->gui->xtext), text, flags, &err); - if (text == NULL || text[0] == 0) - { - return; - } - if (err) - { - fe_message (_(err->message), FE_MSG_ERROR); - g_error_free (err); - } - else if (!last) - { - gtk_entry_set_icon_from_stock (GTK_ENTRY (searchentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); - } - else - { - gtk_entry_set_icon_from_stock (GTK_ENTRY (searchentry), GTK_ENTRY_ICON_SECONDARY, NULL); - } -} - -static void -search_find_cb (GtkWidget * button, session * sess) -{ - GtkEntry *entry; - const gchar *text; - - entry = g_object_get_data (G_OBJECT (button), "e"); - text = gtk_entry_get_text (entry); - search_search (sess, text); -} - -static void -search_close_cb (GtkWidget * button, GtkWidget * win) -{ - gtk_widget_destroy (win); - searchwin = NULL; -} - -static void -search_reset_cb (GtkWidget * button, session * sess) -{ - search_search (sess, ""); - if (searchwin) - { - search_close_cb (button, searchwin); - } -} - -static void -search_cleanup_cb (GtkWidget * button, GtkWidget * win) -{ - searchwin = NULL; -} - -static void -search_entry_cb (GtkWidget * entry, session * sess) -{ - search_search (sess, gtk_entry_get_text (GTK_ENTRY (entry))); -} - -static void -search_changed_cb (GtkWidget * entry, gpointer userdata) -{ - gtk_entry_set_icon_from_stock (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, NULL); -} - -static void -search_caseign_cb (GtkToggleButton * but, session * sess) -{ - prefs.hex_text_search_case_match = (but->active)? 1: 0; - save_config(); -} - -static void -search_dirbwd_cb (GtkToggleButton * but, session * sess) -{ - prefs.hex_text_search_backward = (but->active)? 1: 0; - save_config(); -} - -static void -search_regexp_cb (GtkToggleButton * but, session * sess) -{ - prefs.hex_text_search_regexp = (but->active)? 1: 0; - save_config(); -} - -static void -search_highlight_cb (GtkToggleButton * but, session * sess) -{ - prefs.hex_text_search_highlight_all = (but->active)? 1: 0; - save_config(); - search_search (sess, NULL); -} - -void -search_open (session * sess) -{ - GtkWidget *win, *hbox, *vbox, *entry, *wid; - gchar *text; - - if (searchwin) - { - gtk_widget_destroy (searchwin); - searchwin = NULL; - } - win = mg_create_generic_tab ("search", _(DISPLAY_NAME": Search"), TRUE, FALSE, - search_cleanup_cb, NULL, 0, 0, &vbox, 0); - gtk_container_set_border_width (GTK_CONTAINER (win), 12); - gtk_box_set_spacing (GTK_BOX (vbox), 4); - - /* First line: _____________________ _Find */ - hbox = gtk_hbox_new (0, 10); - gtk_container_add (GTK_CONTAINER (vbox), hbox); - gtk_widget_show (hbox); - - entry = searchentry = gtk_entry_new (); - text = GTK_XTEXT (sess->gui->xtext)->buffer->search_text; - gtk_entry_set_icon_activatable (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, FALSE); - gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, _("Search hit end or not found.")); - if (text) - { - gtk_entry_set_text (GTK_ENTRY (entry), text); - gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1); - } - g_signal_connect (G_OBJECT (entry), "activate", - G_CALLBACK (search_entry_cb), sess); - g_signal_connect (G_OBJECT (entry), "changed", - G_CALLBACK (search_changed_cb), NULL); - gtk_container_add (GTK_CONTAINER (hbox), entry); - gtk_widget_show (entry); - gtk_widget_grab_focus (entry); - - wid = gtk_hbutton_box_new (); - gtk_container_add (GTK_CONTAINER (hbox), wid); - gtk_widget_show (wid); - wid = gtkutil_button (wid, GTK_STOCK_FIND, 0, search_find_cb, sess, - _("_Find")); - g_object_set_data (G_OBJECT (wid), "e", entry); - - /* Second line: X Match case */ - wid = gtk_check_button_new_with_mnemonic (_("_Match case")); - GTK_TOGGLE_BUTTON (wid)->active = prefs.hex_text_search_case_match; - g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (search_caseign_cb), sess); - gtk_container_add (GTK_CONTAINER (vbox), wid); - add_tip (wid, _("Perform a case-sensitive search.")); - gtk_widget_show (wid); - - /* Third line: X Search backwards */ - wid = gtk_check_button_new_with_mnemonic (_("Search _backwards")); - GTK_TOGGLE_BUTTON (wid)->active = prefs.hex_text_search_backward; - g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (search_dirbwd_cb), sess); - gtk_container_add (GTK_CONTAINER (vbox), wid); - add_tip (wid, _("Search from the newest text line to the oldest.")); - gtk_widget_show (wid); - - /* Fourth line: X Highlight all */ - wid = gtk_check_button_new_with_mnemonic (_("_Highlight all")); - GTK_TOGGLE_BUTTON (wid)->active = prefs.hex_text_search_highlight_all; - g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (search_highlight_cb), sess); - gtk_container_add (GTK_CONTAINER (vbox), wid); - add_tip (wid, _("Highlight all occurrences, and underline the current occurrence.")); - gtk_widget_show (wid); - - /* Fifth line: X Regular expression */ - wid = gtk_check_button_new_with_mnemonic (_("R_egular expression")); - GTK_TOGGLE_BUTTON (wid)->active = prefs.hex_text_search_regexp; - g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (search_regexp_cb), sess); - gtk_container_add (GTK_CONTAINER (vbox), wid); - add_tip (wid, _("Regard search string as a regular expression.")); - gtk_widget_show (wid); - - /* Sixth line: _Close Close and _Reset */ - hbox = gtk_hbutton_box_new (); - gtk_box_pack_start (GTK_BOX (vbox), hbox, 0, 0, 4); - gtk_widget_show (hbox); - - wid = gtkutil_button (hbox, GTK_STOCK_CLOSE, 0, search_close_cb, win, - _("_Close")); - add_tip (wid, _("Close this box, but continue searching new lines.")); - wid = gtkutil_button (hbox, "gtk-reset", 0, search_reset_cb, sess, - _("Close and _Reset")); - add_tip (wid, _("Close this box, reset highlighted search items, and stop searching new lines.")); - - /* Add recognition of the ESC key to close the box */ - gtkutil_destroy_on_esc (win); - - /* That's all, folks */ - searchwin = win; - gtk_widget_show (win); -} diff --git a/src/fe-gtk/search.h b/src/fe-gtk/search.h deleted file mode 100644 index 55f8f0b5..00000000 --- a/src/fe-gtk/search.h +++ /dev/null @@ -1,25 +0,0 @@ -/* HexChat - * Copyright (C) 1998-2010 Peter Zelezny. - * Copyright (C) 2009-2013 Berke Viktor. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef HEXCHAT_SEARCH_H -#define HEXCHAT_SEARCH_H - -void search_open (session * sess); - -#endif