summary refs log tree commit diff stats
path: root/src/fe-gtk/fkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-gtk/fkeys.c')
-rw-r--r--src/fe-gtk/fkeys.c153
1 files changed, 87 insertions, 66 deletions
diff --git a/src/fe-gtk/fkeys.c b/src/fe-gtk/fkeys.c
index 59086a5e..e762d208 100644
--- a/src/fe-gtk/fkeys.c
+++ b/src/fe-gtk/fkeys.c
@@ -198,6 +198,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
 	"ACCEL=Down\nNext Command\nD1!\nD2!\n\n"\
 	"ACCEL=Up\nLast Command\nD1!\nD2!\n\n"\
 	"ACCEL=Tab\nComplete nick/command\nD1!\nD2!\n\n"\
+	"ACCEL=<Shift>ISO_Left_Tab\nComplete nick/command\nD1:Previous\nD2!\n\n"\
 	"ACCEL=space\nCheck For Replace\nD1!\nD2!\n\n"\
 	"ACCEL=Return\nCheck For Replace\nD1!\nD2!\n\n"\
 	"ACCEL=KP_Enter\nCheck For Replace\nD1!\nD2!\n\n"\
@@ -241,10 +242,8 @@ key_free (gpointer data)
 
 	g_return_if_fail (kb != NULL);
 
-	if (kb->data1)
-		g_free (kb->data1);
-	if (kb->data2)
-		g_free (kb->data2);
+	g_free (kb->data1);
+	g_free (kb->data2);
 	g_free (kb);
 }
 
@@ -323,7 +322,7 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
 		return FALSE;
 	current_sess = sess;
 
-	if (plugin_emit_keypress (sess, evt->state, evt->keyval, evt->length, evt->string))
+	if (plugin_emit_keypress (sess, evt->state, evt->keyval, gdk_keyval_to_unicode (evt->keyval)))
 		return 1;
 
 	/* maybe the plugin closed this tab? */
@@ -567,7 +566,7 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
 	{
 		do
 		{
-			kb = (struct key_binding *) g_malloc0 (sizeof (struct key_binding));
+			kb = g_new0 (struct key_binding, 1);
 
 			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ACCEL_COLUMN, &accel,
 															ACTION_COLUMN, &actiontext,
@@ -598,7 +597,8 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
 			else
 				keybind_list = g_slist_append (keybind_list, kb);
 
-		} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
+		}
+		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
 	}
 
 	if (key_save_kbs () == 0)
@@ -666,6 +666,7 @@ key_dialog_treeview_new (GtkWidget *box)
 	view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
 	gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
+	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
 
 	g_signal_connect (G_OBJECT (view), "key-press-event",
 					G_CALLBACK (key_dialog_keypress), NULL);
@@ -850,7 +851,7 @@ key_save_kbs (void)
 									 0x180, XOF_DOMODE);
 	if (fd < 0)
 		return 1;
-	write (fd, buf, snprintf (buf, 510, "# HexChat key bindings config file\n\n"));
+	write (fd, buf, g_snprintf (buf, 510, "# HexChat key bindings config file\n\n"));
 
 	while (list)
 	{
@@ -858,17 +859,17 @@ key_save_kbs (void)
 
 		accel_text = gtk_accelerator_name (kb->keyval, kb->mod);
 
-		snprintf (buf, 510, "ACCEL=%s\n%s\n", accel_text, key_actions[kb->action].name);
+		g_snprintf (buf, 510, "ACCEL=%s\n%s\n", accel_text, key_actions[kb->action].name);
 		write (fd, buf, strlen (buf));
 		g_free (accel_text);
 
 		if (kb->data1 && kb->data1[0])
-			write (fd, buf, snprintf (buf, 510, "D1:%s\n", kb->data1));
+			write (fd, buf, g_snprintf (buf, 510, "D1:%s\n", kb->data1));
 		else
 			write (fd, "D1!\n", 4);
 
 		if (kb->data2 && kb->data2[0])
-			write (fd, buf, snprintf (buf, 510, "D2:%s\n", kb->data2));
+			write (fd, buf, g_snprintf (buf, 510, "D2:%s\n", kb->data2));
 		else
 			write (fd, "D2!\n", 4);
 
@@ -946,7 +947,7 @@ key_load_kbs (void)
 	fd = hexchat_open_file ("keybindings.conf", O_RDONLY, 0, 0);
 	if (fd < 0)
 	{
-		ibuf = strdup (default_kb_cfg);
+		ibuf = g_strdup (default_kb_cfg);
 		size = strlen (default_kb_cfg);
 	}
 	else
@@ -957,7 +958,7 @@ key_load_kbs (void)
 			return 1;
 		}
 
-		ibuf = malloc (st.st_size);
+		ibuf = g_malloc(st.st_size);
 		read (fd, ibuf, st.st_size);
 		size = st.st_size;
 		close (fd);
@@ -979,7 +980,7 @@ key_load_kbs (void)
 		switch (state)
 		{
 		case KBSTATE_MOD:
-			kb = (struct key_binding *) g_malloc0 (sizeof (struct key_binding));
+			kb = g_new0 (struct key_binding, 1);
 
 			/* New format */
 			if (strncmp (buf, "ACCEL=", 6) == 0)
@@ -1010,7 +1011,7 @@ key_load_kbs (void)
 			keyval = gdk_keyval_from_name (buf);
 			if (keyval == 0)
 			{
-				free (ibuf);
+				g_free (ibuf);
 				return 2;
 			}
 
@@ -1026,7 +1027,7 @@ key_load_kbs (void)
 
 			if (kb->action == KEY_MAX_ACTIONS + 1)
 			{
-				free (ibuf);
+				g_free (ibuf);
 				return 3;
 			}
 
@@ -1043,7 +1044,7 @@ key_load_kbs (void)
 
 			if (buf[0] != 'D')
 			{
-				free (ibuf);
+				g_free (ibuf);
 				return 4;
 			}
 
@@ -1069,12 +1070,10 @@ key_load_kbs (void)
 				len -= 3;
 				if (state == KBSTATE_DT1)
 				{
-					kb->data1 = g_malloc (len);
-					memcpy (kb->data1, &buf[3], len);
+					kb->data1 = g_strndup (&buf[3], len);
 				} else
 				{
-					kb->data2 = g_malloc (len);
-					memcpy (kb->data2, &buf[3], len);
+					kb->data2 = g_strndup (&buf[3], len);
 				}
 			} else if (buf[2] == '!')
 			{
@@ -1097,12 +1096,12 @@ key_load_kbs (void)
 			continue;
 		}
 	}
-	free (ibuf);
+	g_free (ibuf);
 	return 0;
 
 corrupt_file:
-	free (ibuf);
-	free (kb);
+	g_free (ibuf);
+	g_free (kb);
 	return 5;
 }
 
@@ -1410,9 +1409,6 @@ key_action_tab_clean(void)
 	}
 }
 
-/* Used in the followig completers */
-#define COMP_BUF 2048
-
 /* For use in sorting the user list for completion */
 static int
 talked_recent_cmp (struct User *a, struct User *b)
@@ -1426,16 +1422,31 @@ talked_recent_cmp (struct User *a, struct User *b)
 	return 0;
 }
 
+#define COMP_BUF 2048
+
+static inline glong
+len_to_offset (const char *str, glong len)
+{
+	return g_utf8_pointer_to_offset (str, str + len);
+}
+
+static inline glong
+offset_to_len (const char *str, glong offset)
+{
+	return g_utf8_offset_to_pointer (str, offset) - str;
+}
+
 static int
 key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 							struct session *sess)
 {
-	int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, found = 0,
-	    prefix_len, skip_len = 0, is_nick, is_cmd = 0;
-	char buf[COMP_BUF], ent[CHANLEN], *postfix = NULL, *result, *ch;
+	int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, prefix_len, skip_len = 0;
+	gboolean is_nick = FALSE, is_cmd = FALSE, found = FALSE, has_nick_prefix = FALSE;
+	char ent[CHANLEN], *postfix = NULL, *result, *ch;
 	GList *list = NULL, *tmp_list = NULL;
 	const char *text;
 	GCompletion *gcomp = NULL;
+	GString *buf;
 
 	/* force the IM Context to reset */
 	SPELL_ENTRY_SET_EDITABLE (t, FALSE);
@@ -1449,8 +1460,6 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 
 	cursor_pos = SPELL_ENTRY_GET_POS (t);
 
-	buf[0] = 0; /* make sure we don't get garbage in the buffer */
-
 	/* handle "nick: " or "nick " or "#channel "*/
 	ch = g_utf8_find_prev_char(text, g_utf8_offset_to_pointer(text,cursor_pos));
 	if (ch && ch[0] == ' ')
@@ -1489,15 +1498,23 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 	if (ent_start == 0 && text[0] == prefs.hex_input_command_char[0])
 	{
 		ent_start++;
-		is_cmd = 1;
+		is_cmd = TRUE;
 	}
-	
+	else if (strchr (sess->server->chantypes, text[ent_start]) == NULL)
+	{
+		is_nick = TRUE;
+		if (strchr (sess->server->nick_prefixes, text[ent_start]) != NULL)
+		{
+			if (ent_start == 0)
+				has_nick_prefix = TRUE;
+			ent_start++;
+		}
+	}
+
 	prefix_len = ent_start;
 	elen = cursor_pos - ent_start;
 
 	g_utf8_strncpy (ent, g_utf8_offset_to_pointer (text, prefix_len), elen);
-
-	is_nick = (ent[0] == '#' || ent[0] == '&' || is_cmd) ? 0 : 1;
 	
 	if (sess->type == SESS_DIALOG && is_nick)
 	{
@@ -1505,7 +1522,7 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 		if (rfc_ncasecmp (sess->channel, ent, elen) == 0)
 		{
 			result =  sess->channel;
-			is_nick = 0;
+			is_nick = FALSE;
 		}
 		else
 			return 2;
@@ -1562,7 +1579,7 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 			{
 				if(rfc_ncasecmp(list->data, ent, elen) == 0)
 				{
-					found = 1;
+					found = TRUE;
 					break;
 				}
 				list = list->next;
@@ -1600,7 +1617,7 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 			old_gcomp.elen = elen;
 
 			/* Get the first nick and put out the data for future nickcompletes */
-			if (prefs.hex_completion_amount && g_list_length (list) <= prefs.hex_completion_amount)
+			if (prefs.hex_completion_amount > 0 && g_list_length (list) <= (guint) prefs.hex_completion_amount)
 			{
 				g_free(result);
 				result = (char*)list->data;
@@ -1610,40 +1627,42 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 				/* bash style completion */
 				if (g_list_next(list) != NULL)
 				{
+					buf = g_string_sized_new (MAX(COMP_BUF, len + NICKLEN));
 					if (strlen (result) > elen) /* the largest common prefix is larger than nick, change the data */
 					{
 						if (prefix_len)
-							g_utf8_strncpy (buf, text, prefix_len);
-						strncat (buf, result, COMP_BUF - prefix_len);
-						cursor_pos = strlen (buf);
+							g_string_append_len (buf, text, offset_to_len (text, prefix_len));
+						g_string_append (buf, result);
+						cursor_pos = buf->len;
 						g_free(result);
 						if (postfix)
 						{
-							strcat (buf, " ");
-							strncat (buf, postfix, COMP_BUF - cursor_pos -1);
+							g_string_append_c (buf, ' ');
+							g_string_append (buf, postfix);
 						}
-						SPELL_ENTRY_SET_TEXT (t, buf);
-						SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos));
-						buf[0] = 0;
+						SPELL_ENTRY_SET_TEXT (t, buf->str);
+						SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos));
+						g_string_erase (buf, 0, -1);
 					}
 					else
 						g_free(result);
+
 					while (list)
 					{
-						len = strlen (buf);	/* current buffer */
+						len = buf->len;
 						elen = strlen (list->data);	/* next item to add */
 						if (len + elen + 2 >= COMP_BUF) /* +2 is space + null */
 						{
-							PrintText (sess, buf);
-							buf[0] = 0;
-							len = 0;
+							PrintText (sess, buf->str);
+							g_string_erase (buf, 0, -1);
 						}
-						strcpy (buf + len, (char *) list->data);
-						strcpy (buf + len + elen, " ");
+						g_string_append (buf, (char*)list->data);
+						g_string_append_c (buf, ' ');
 						list = list->next;
 					}
-					PrintText (sess, buf);
+					PrintText (sess, buf->str);
 					g_completion_free(gcomp);
+					g_string_free (buf, TRUE);
 					return 2;
 				}
 				/* Only one matching entry */
@@ -1655,17 +1674,19 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 	
 	if(result)
 	{
+		buf = g_string_sized_new (len + NICKLEN);
 		if (prefix_len)
-			g_utf8_strncpy(buf, text, prefix_len);
-		strncat (buf, result, COMP_BUF - (prefix_len + 3)); /* make sure nicksuffix and space fits */
-		if(!prefix_len && is_nick)
-			strcat (buf, &prefs.hex_completion_suffix[0]);
-		strcat (buf, " ");
-		cursor_pos = strlen (buf);
+			g_string_append_len (buf, text, offset_to_len (text, prefix_len));
+		g_string_append (buf, result);
+		if((!prefix_len || has_nick_prefix) && is_nick && prefs.hex_completion_suffix[0] != '\0')
+			g_string_append_unichar (buf, g_utf8_get_char_validated (prefs.hex_completion_suffix, -1));
+		g_string_append_c (buf, ' ');
+		cursor_pos = buf->len;
 		if (postfix)
-			strncat (buf, postfix, COMP_BUF - cursor_pos - 2);
-		SPELL_ENTRY_SET_TEXT (t, buf);
-		SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos));
+			g_string_append (buf, postfix);
+		SPELL_ENTRY_SET_TEXT (t, buf->str);
+		SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos));
+		g_string_free (buf, TRUE);
 	}
 	if (gcomp)
 		g_completion_free(gcomp);
@@ -1794,10 +1815,10 @@ replace_handle (GtkWidget *t)
 			memcpy (outbuf, text, xlen);
 			outbuf[xlen] = 0;
 			if (postfix_pnt == NULL)
-				snprintf (word, sizeof (word), "%s", pop->cmd);
+				g_snprintf (word, sizeof (word), "%s", pop->cmd);
 			else
-				snprintf (word, sizeof (word), "%s%s", pop->cmd, postfix);
-			strcat (outbuf, word);
+				g_snprintf (word, sizeof (word), "%s%s", pop->cmd, postfix);
+			g_strlcat (outbuf, word, sizeof(outbuf));
 			SPELL_ENTRY_SET_TEXT (t, outbuf);
 			SPELL_ENTRY_SET_POS (t, -1);
 			return;