2011-02-24 04:14:30 +01:00
|
|
|
/* 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
|
2012-12-23 20:36:54 +01:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2011-02-24 04:14:30 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "fe-gtk.h"
|
|
|
|
|
|
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
|
2012-10-24 21:33:02 +02:00
|
|
|
#include "../common/hexchat.h"
|
2011-02-24 04:14:30 +01:00
|
|
|
#include "../common/util.h"
|
|
|
|
#include "../common/userlist.h"
|
|
|
|
#include "../common/modes.h"
|
2013-03-09 23:57:06 +01:00
|
|
|
#include "../common/text.h"
|
2011-02-24 04:14:30 +01:00
|
|
|
#include "../common/notify.h"
|
2012-10-24 21:33:02 +02:00
|
|
|
#include "../common/hexchatc.h"
|
2012-07-21 14:26:19 +02:00
|
|
|
#include "../common/fe.h"
|
2011-02-24 04:14:30 +01:00
|
|
|
#include "gtkutil.h"
|
|
|
|
#include "palette.h"
|
|
|
|
#include "maingui.h"
|
|
|
|
#include "menu.h"
|
|
|
|
#include "pixmaps.h"
|
|
|
|
#include "userlistgui.h"
|
2012-10-21 03:03:38 +02:00
|
|
|
#include "fkeys.h"
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
COL_PIX=0, // GdkPixbuf *
|
|
|
|
COL_NICK=1, // char *
|
|
|
|
COL_HOST=2, // char *
|
|
|
|
COL_USER=3, // struct User *
|
|
|
|
COL_GDKCOLOR=4 // GdkColor *
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
GdkPixbuf *
|
|
|
|
get_user_icon (server *serv, struct User *user)
|
|
|
|
{
|
|
|
|
char *pre;
|
|
|
|
int level;
|
|
|
|
|
|
|
|
if (!user)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* these ones are hardcoded */
|
|
|
|
switch (user->prefix[0])
|
|
|
|
{
|
2012-11-03 01:42:47 +01:00
|
|
|
case 0: return NULL;
|
|
|
|
case '+': return pix_ulist_voice;
|
|
|
|
case '%': return pix_ulist_halfop;
|
|
|
|
case '@': return pix_ulist_op;
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find out how many levels above Op this user is */
|
|
|
|
pre = strchr (serv->nick_prefixes, '@');
|
|
|
|
if (pre && pre != serv->nick_prefixes)
|
|
|
|
{
|
|
|
|
pre--;
|
|
|
|
level = 0;
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (pre[0] == user->prefix[0])
|
|
|
|
{
|
|
|
|
switch (level)
|
|
|
|
{
|
2012-11-03 01:42:47 +01:00
|
|
|
case 0: return pix_ulist_owner; /* 1 level above op */
|
|
|
|
case 1: return pix_ulist_founder; /* 2 levels above op */
|
|
|
|
case 2: return pix_ulist_netop; /* 3 levels above op */
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
2012-11-02 05:54:27 +01:00
|
|
|
break; /* 4+, no icons */
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
level++;
|
|
|
|
if (pre == serv->nick_prefixes)
|
|
|
|
break;
|
|
|
|
pre--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_userlist_numbers (session *sess)
|
|
|
|
{
|
|
|
|
char tbuf[256];
|
|
|
|
|
|
|
|
if (sess == current_tab || !sess->gui->is_tab)
|
|
|
|
{
|
|
|
|
if (sess->total)
|
|
|
|
{
|
|
|
|
snprintf (tbuf, sizeof (tbuf), _("%d ops, %d total"), sess->ops, sess->total);
|
|
|
|
tbuf[sizeof (tbuf) - 1] = 0;
|
|
|
|
gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), tbuf);
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), NULL);
|
|
|
|
}
|
|
|
|
|
2012-10-22 13:49:28 +02:00
|
|
|
if (sess->type == SESS_CHANNEL && prefs.hex_gui_win_ucount)
|
2011-02-24 04:14:30 +01:00
|
|
|
fe_set_title (sess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scroll_to_iter (GtkTreeIter *iter, GtkTreeView *treeview, GtkTreeModel *model)
|
|
|
|
{
|
|
|
|
GtkTreePath *path = gtk_tree_model_get_path (model, iter);
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.5);
|
|
|
|
gtk_tree_path_free (path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* select a row in the userlist by nick-name */
|
|
|
|
|
|
|
|
void
|
|
|
|
userlist_select (session *sess, char *name)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeView *treeview = GTK_TREE_VIEW (sess->gui->user_tree);
|
|
|
|
GtkTreeModel *model = gtk_tree_view_get_model (treeview);
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
|
|
|
|
struct User *row_user;
|
|
|
|
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
gtk_tree_model_get (model, &iter, COL_USER, &row_user, -1);
|
|
|
|
if (sess->server->p_cmp (row_user->nick, name) == 0)
|
|
|
|
{
|
|
|
|
if (gtk_tree_selection_iter_is_selected (selection, &iter))
|
|
|
|
gtk_tree_selection_unselect_iter (selection, &iter);
|
|
|
|
else
|
|
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
|
|
|
|
|
|
/* and make sure it's visible */
|
|
|
|
scroll_to_iter (&iter, treeview, model);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char **
|
|
|
|
userlist_selection_list (GtkWidget *widget, int *num_ret)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeView *treeview = (GtkTreeView *) widget;
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
|
|
|
|
GtkTreeModel *model = gtk_tree_view_get_model (treeview);
|
|
|
|
struct User *user;
|
|
|
|
int i, num_sel;
|
|
|
|
char **nicks;
|
|
|
|
|
|
|
|
*num_ret = 0;
|
|
|
|
/* first, count the number of selections */
|
|
|
|
num_sel = 0;
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (gtk_tree_selection_iter_is_selected (selection, &iter))
|
|
|
|
num_sel++;
|
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_sel < 1)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nicks = malloc (sizeof (char *) * (num_sel + 1));
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
gtk_tree_model_get_iter_first (model, &iter);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (gtk_tree_selection_iter_is_selected (selection, &iter))
|
|
|
|
{
|
|
|
|
gtk_tree_model_get (model, &iter, COL_USER, &user, -1);
|
|
|
|
nicks[i] = g_strdup (user->nick);
|
|
|
|
i++;
|
|
|
|
nicks[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
|
|
|
|
*num_ret = i;
|
|
|
|
return nicks;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_userlist_set_selected (struct session *sess)
|
|
|
|
{
|
|
|
|
GtkListStore *store = sess->res->user_model;
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sess->gui->user_tree));
|
|
|
|
GtkTreeIter iter;
|
|
|
|
struct User *user;
|
|
|
|
|
|
|
|
/* if it's not front-most tab it doesn't own the GtkTreeView! */
|
|
|
|
if (store != (GtkListStore*) gtk_tree_view_get_model (GTK_TREE_VIEW (sess->gui->user_tree)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_USER, &user, -1);
|
|
|
|
|
|
|
|
if (gtk_tree_selection_iter_is_selected (selection, &iter))
|
|
|
|
user->selected = 1;
|
|
|
|
else
|
|
|
|
user->selected = 0;
|
|
|
|
|
|
|
|
} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkTreeIter *
|
|
|
|
find_row (GtkTreeView *treeview, GtkTreeModel *model, struct User *user,
|
|
|
|
int *selected)
|
|
|
|
{
|
|
|
|
static GtkTreeIter iter;
|
|
|
|
struct User *row_user;
|
|
|
|
|
|
|
|
*selected = FALSE;
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
gtk_tree_model_get (model, &iter, COL_USER, &row_user, -1);
|
|
|
|
if (row_user == user)
|
|
|
|
{
|
|
|
|
if (gtk_tree_view_get_model (treeview) == model)
|
|
|
|
{
|
|
|
|
if (gtk_tree_selection_iter_is_selected (gtk_tree_view_get_selection (treeview), &iter))
|
|
|
|
*selected = TRUE;
|
|
|
|
}
|
|
|
|
return &iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
userlist_set_value (GtkWidget *treeview, gfloat val)
|
|
|
|
{
|
|
|
|
gtk_adjustment_set_value (
|
|
|
|
gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (treeview)), val);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfloat
|
|
|
|
userlist_get_value (GtkWidget *treeview)
|
|
|
|
{
|
2013-05-12 07:43:27 +02:00
|
|
|
return gtk_adjustment_get_value (gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (treeview)));
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fe_userlist_remove (session *sess, struct User *user)
|
|
|
|
{
|
|
|
|
GtkTreeIter *iter;
|
|
|
|
/* GtkAdjustment *adj;
|
|
|
|
gfloat val, end;*/
|
|
|
|
int sel;
|
|
|
|
|
|
|
|
iter = find_row (GTK_TREE_VIEW (sess->gui->user_tree),
|
|
|
|
sess->res->user_model, user, &sel);
|
|
|
|
if (!iter)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* adj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (sess->gui->user_tree));
|
|
|
|
val = adj->value;*/
|
|
|
|
|
|
|
|
gtk_list_store_remove (sess->res->user_model, iter);
|
|
|
|
|
|
|
|
/* is it the front-most tab? */
|
|
|
|
/* if (gtk_tree_view_get_model (GTK_TREE_VIEW (sess->gui->user_tree))
|
|
|
|
== sess->res->user_model)
|
|
|
|
{
|
|
|
|
end = adj->upper - adj->lower - adj->page_size;
|
|
|
|
if (val > end)
|
|
|
|
val = end;
|
|
|
|
gtk_adjustment_set_value (adj, val);
|
|
|
|
}*/
|
|
|
|
|
|
|
|
return sel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_userlist_rehash (session *sess, struct User *user)
|
|
|
|
{
|
|
|
|
GtkTreeIter *iter;
|
|
|
|
int sel;
|
2013-03-25 07:17:58 +01:00
|
|
|
int nick_color = 0;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
iter = find_row (GTK_TREE_VIEW (sess->gui->user_tree),
|
|
|
|
sess->res->user_model, user, &sel);
|
|
|
|
if (!iter)
|
|
|
|
return;
|
|
|
|
|
2013-05-10 01:04:46 +02:00
|
|
|
if (prefs.hex_away_track && user->away)
|
2013-03-09 23:57:06 +01:00
|
|
|
nick_color = COL_AWAY;
|
|
|
|
else if (prefs.hex_gui_ulist_color)
|
|
|
|
nick_color = text_color_of(user->nick);
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
gtk_list_store_set (GTK_LIST_STORE (sess->res->user_model), iter,
|
|
|
|
COL_HOST, user->hostname,
|
2013-03-09 23:57:06 +01:00
|
|
|
COL_GDKCOLOR, nick_color ? &colors[nick_color] : NULL,
|
2011-02-24 04:14:30 +01:00
|
|
|
-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_userlist_insert (session *sess, struct User *newuser, int row, int sel)
|
|
|
|
{
|
|
|
|
GtkTreeModel *model = sess->res->user_model;
|
|
|
|
GdkPixbuf *pix = get_user_icon (sess->server, newuser);
|
|
|
|
GtkTreeIter iter;
|
|
|
|
char *nick;
|
2013-03-25 07:17:58 +01:00
|
|
|
int nick_color = 0;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
2013-05-10 01:04:46 +02:00
|
|
|
if (prefs.hex_away_track && newuser->away)
|
2013-03-09 23:57:06 +01:00
|
|
|
nick_color = COL_AWAY;
|
|
|
|
else if (prefs.hex_gui_ulist_color)
|
|
|
|
nick_color = text_color_of(newuser->nick);
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
nick = newuser->nick;
|
2012-10-22 13:49:28 +02:00
|
|
|
if (!prefs.hex_gui_ulist_icons)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
nick = malloc (strlen (newuser->nick) + 2);
|
|
|
|
nick[0] = newuser->prefix[0];
|
|
|
|
if (!nick[0] || nick[0] == ' ')
|
|
|
|
strcpy (nick, newuser->nick);
|
|
|
|
else
|
|
|
|
strcpy (nick + 1, newuser->nick);
|
|
|
|
pix = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, row,
|
|
|
|
COL_PIX, pix,
|
|
|
|
COL_NICK, nick,
|
|
|
|
COL_HOST, newuser->hostname,
|
|
|
|
COL_USER, newuser,
|
2013-03-09 23:57:06 +01:00
|
|
|
COL_GDKCOLOR, nick_color ? &colors[nick_color] : NULL,
|
2011-02-24 04:14:30 +01:00
|
|
|
-1);
|
|
|
|
|
2012-10-22 13:49:28 +02:00
|
|
|
if (!prefs.hex_gui_ulist_icons)
|
2012-10-22 06:02:15 +02:00
|
|
|
{
|
2011-02-24 04:14:30 +01:00
|
|
|
free (nick);
|
2012-10-22 06:02:15 +02:00
|
|
|
}
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
/* is it me? */
|
|
|
|
if (newuser->me && sess->gui->nick_box)
|
|
|
|
{
|
|
|
|
if (!sess->gui->is_tab || sess == current_tab)
|
|
|
|
mg_set_access_icon (sess->gui, pix, sess->server->is_away);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (prefs.hilitenotify && notify_isnotify (sess, newuser->nick))
|
|
|
|
{
|
|
|
|
gtk_clist_set_foreground ((GtkCList *) sess->gui->user_clist, row,
|
|
|
|
&colors[prefs.nu_color]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* is it the front-most tab? */
|
|
|
|
if (gtk_tree_view_get_model (GTK_TREE_VIEW (sess->gui->user_tree))
|
|
|
|
== model)
|
|
|
|
{
|
|
|
|
if (sel)
|
|
|
|
gtk_tree_selection_select_iter (gtk_tree_view_get_selection
|
|
|
|
(GTK_TREE_VIEW (sess->gui->user_tree)), &iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_userlist_move (session *sess, struct User *user, int new_row)
|
|
|
|
{
|
|
|
|
fe_userlist_insert (sess, user, new_row, fe_userlist_remove (sess, user));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_userlist_clear (session *sess)
|
|
|
|
{
|
|
|
|
gtk_list_store_clear (sess->res->user_model);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
userlist_dnd_drop (GtkTreeView *widget, GdkDragContext *context,
|
|
|
|
gint x, gint y, GtkSelectionData *selection_data,
|
|
|
|
guint info, guint ttime, gpointer userdata)
|
|
|
|
{
|
|
|
|
struct User *user;
|
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeModel *model;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
|
|
|
|
if (!gtk_tree_view_get_path_at_pos (widget, x, y, &path, NULL, NULL, NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
model = gtk_tree_view_get_model (widget);
|
|
|
|
if (!gtk_tree_model_get_iter (model, &iter, path))
|
|
|
|
return;
|
|
|
|
gtk_tree_model_get (model, &iter, COL_USER, &user, -1);
|
|
|
|
|
2013-05-12 07:43:27 +02:00
|
|
|
mg_dnd_drop_file (current_sess, user->nick, (char *)gtk_selection_data_get_data (selection_data));
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
userlist_dnd_motion (GtkTreeView *widget, GdkDragContext *context, gint x,
|
|
|
|
gint y, guint ttime, gpointer tree)
|
|
|
|
{
|
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeSelection *sel;
|
|
|
|
|
|
|
|
if (!tree)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (gtk_tree_view_get_path_at_pos (widget, x, y, &path, NULL, NULL, NULL))
|
|
|
|
{
|
|
|
|
sel = gtk_tree_view_get_selection (widget);
|
|
|
|
gtk_tree_selection_unselect_all (sel);
|
|
|
|
gtk_tree_selection_select_path (sel, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
userlist_dnd_leave (GtkTreeView *widget, GdkDragContext *context, guint ttime)
|
|
|
|
{
|
|
|
|
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (widget));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
userlist_create_model (void)
|
|
|
|
{
|
|
|
|
return gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_POINTER, GDK_TYPE_COLOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
userlist_add_columns (GtkTreeView * treeview)
|
|
|
|
{
|
|
|
|
GtkCellRenderer *renderer;
|
|
|
|
|
|
|
|
/* icon column */
|
|
|
|
renderer = gtk_cell_renderer_pixbuf_new ();
|
2012-10-22 13:49:28 +02:00
|
|
|
if (prefs.hex_gui_compact)
|
2011-02-24 04:14:30 +01:00
|
|
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
|
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
|
|
-1, NULL, renderer,
|
|
|
|
"pixbuf", 0, NULL);
|
|
|
|
|
|
|
|
/* nick column */
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
2012-10-22 13:49:28 +02:00
|
|
|
if (prefs.hex_gui_compact)
|
2011-02-24 04:14:30 +01:00
|
|
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
|
|
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
|
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
|
|
-1, NULL, renderer,
|
|
|
|
"text", 1, "foreground-gdk", 4, NULL);
|
|
|
|
|
2012-10-22 13:49:28 +02:00
|
|
|
if (prefs.hex_gui_ulist_show_hosts)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
/* hostname column */
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
2012-10-22 13:49:28 +02:00
|
|
|
if (prefs.hex_gui_compact)
|
2011-02-24 04:14:30 +01:00
|
|
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
|
|
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
|
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
|
|
-1, NULL, renderer,
|
|
|
|
"text", 2, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
|
|
userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata)
|
|
|
|
{
|
|
|
|
char **nicks;
|
|
|
|
int i;
|
|
|
|
GtkTreeSelection *sel;
|
|
|
|
GtkTreePath *path;
|
|
|
|
|
|
|
|
if (!event)
|
|
|
|
return FALSE;
|
|
|
|
|
2012-10-21 03:03:38 +02:00
|
|
|
if (!(event->state & STATE_CTRL) &&
|
2012-10-22 13:49:28 +02:00
|
|
|
event->type == GDK_2BUTTON_PRESS && prefs.hex_gui_ulist_doubleclick[0])
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
nicks = userlist_selection_list (widget, &i);
|
|
|
|
if (nicks)
|
|
|
|
{
|
2012-10-22 13:49:28 +02:00
|
|
|
nick_command_parse (current_sess, prefs.hex_gui_ulist_doubleclick, nicks[0],
|
2011-02-24 04:14:30 +01:00
|
|
|
nicks[0]);
|
|
|
|
while (i)
|
|
|
|
{
|
|
|
|
i--;
|
|
|
|
g_free (nicks[i]);
|
|
|
|
}
|
|
|
|
free (nicks);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->button == 3)
|
|
|
|
{
|
|
|
|
/* do we have a multi-selection? */
|
|
|
|
nicks = userlist_selection_list (widget, &i);
|
|
|
|
if (nicks && i > 1)
|
|
|
|
{
|
|
|
|
menu_nickmenu (current_sess, event, nicks[0], i);
|
|
|
|
while (i)
|
|
|
|
{
|
|
|
|
i--;
|
|
|
|
g_free (nicks[i]);
|
|
|
|
}
|
|
|
|
free (nicks);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (nicks)
|
|
|
|
{
|
|
|
|
g_free (nicks[0]);
|
|
|
|
free (nicks);
|
|
|
|
}
|
|
|
|
|
|
|
|
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
|
|
|
|
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
|
|
|
|
event->x, event->y, &path, 0, 0, 0))
|
|
|
|
{
|
|
|
|
gtk_tree_selection_unselect_all (sel);
|
|
|
|
gtk_tree_selection_select_path (sel, path);
|
|
|
|
gtk_tree_path_free (path);
|
|
|
|
nicks = userlist_selection_list (widget, &i);
|
|
|
|
if (nicks)
|
|
|
|
{
|
|
|
|
menu_nickmenu (current_sess, event, nicks[0], i);
|
|
|
|
while (i)
|
|
|
|
{
|
|
|
|
i--;
|
|
|
|
g_free (nicks[i]);
|
|
|
|
}
|
|
|
|
free (nicks);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
gtk_tree_selection_unselect_all (sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
userlist_key_cb (GtkWidget *wid, GdkEventKey *evt, gpointer userdata)
|
|
|
|
{
|
2013-09-15 09:21:56 +02:00
|
|
|
if (evt->keyval >= GDK_KEY_asterisk && evt->keyval <= GDK_KEY_z)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
/* dirty trick to avoid auto-selection */
|
|
|
|
SPELL_ENTRY_SET_EDITABLE (current_sess->gui->input_box, FALSE);
|
|
|
|
gtk_widget_grab_focus (current_sess->gui->input_box);
|
|
|
|
SPELL_ENTRY_SET_EDITABLE (current_sess->gui->input_box, TRUE);
|
|
|
|
gtk_widget_event (current_sess->gui->input_box, (GdkEvent *)evt);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *
|
|
|
|
userlist_create (GtkWidget *box)
|
|
|
|
{
|
|
|
|
GtkWidget *sw, *treeview;
|
|
|
|
static const GtkTargetEntry dnd_dest_targets[] =
|
|
|
|
{
|
|
|
|
{"text/uri-list", 0, 1},
|
2012-10-30 11:35:39 +01:00
|
|
|
{"HEXCHAT_CHANVIEW", GTK_TARGET_SAME_APP, 75 }
|
2011-02-24 04:14:30 +01:00
|
|
|
};
|
|
|
|
static const GtkTargetEntry dnd_src_target[] =
|
|
|
|
{
|
2012-10-30 11:35:39 +01:00
|
|
|
{"HEXCHAT_USERLIST", GTK_TARGET_SAME_APP, 75 }
|
2011-02-24 04:14:30 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
sw = gtk_scrolled_window_new (NULL, NULL);
|
|
|
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
|
|
|
|
GTK_SHADOW_ETCHED_IN);
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
2012-10-22 13:49:28 +02:00
|
|
|
prefs.hex_gui_ulist_show_hosts ?
|
2011-02-24 04:14:30 +01:00
|
|
|
GTK_POLICY_AUTOMATIC :
|
|
|
|
GTK_POLICY_NEVER,
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (sw);
|
|
|
|
|
|
|
|
treeview = gtk_tree_view_new ();
|
2012-11-11 15:23:48 +01:00
|
|
|
gtk_widget_set_name (treeview, "hexchat-userlist");
|
2011-02-24 04:14:30 +01:00
|
|
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
|
|
|
gtk_tree_selection_set_mode (gtk_tree_view_get_selection
|
|
|
|
(GTK_TREE_VIEW (treeview)),
|
|
|
|
GTK_SELECTION_MULTIPLE);
|
|
|
|
|
|
|
|
/* set up drops */
|
|
|
|
gtk_drag_dest_set (treeview, GTK_DEST_DEFAULT_ALL, dnd_dest_targets, 2,
|
|
|
|
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
|
|
|
|
gtk_drag_source_set (treeview, GDK_BUTTON1_MASK, dnd_src_target, 1, GDK_ACTION_MOVE);
|
|
|
|
|
|
|
|
/* file DND (for DCC) */
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_motion",
|
|
|
|
G_CALLBACK (userlist_dnd_motion), treeview);
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_leave",
|
|
|
|
G_CALLBACK (userlist_dnd_leave), 0);
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_data_received",
|
|
|
|
G_CALLBACK (userlist_dnd_drop), treeview);
|
|
|
|
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "button_press_event",
|
|
|
|
G_CALLBACK (userlist_click_cb), 0);
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "key_press_event",
|
|
|
|
G_CALLBACK (userlist_key_cb), 0);
|
|
|
|
|
|
|
|
/* tree/chanview DND */
|
|
|
|
#ifndef WIN32 /* leaks GDI pool memory, don't enable */
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_begin",
|
|
|
|
G_CALLBACK (mg_drag_begin_cb), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_drop",
|
|
|
|
G_CALLBACK (mg_drag_drop_cb), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_motion",
|
|
|
|
G_CALLBACK (mg_drag_motion_cb), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (treeview), "drag_end",
|
|
|
|
G_CALLBACK (mg_drag_end_cb), NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
userlist_add_columns (GTK_TREE_VIEW (treeview));
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (sw), treeview);
|
|
|
|
gtk_widget_show (treeview);
|
|
|
|
|
|
|
|
return treeview;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
userlist_show (session *sess)
|
|
|
|
{
|
|
|
|
gtk_tree_view_set_model (GTK_TREE_VIEW (sess->gui->user_tree),
|
|
|
|
sess->res->user_model);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fe_uselect (session *sess, char *word[], int do_clear, int scroll_to)
|
|
|
|
{
|
|
|
|
int thisname;
|
|
|
|
char *name;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeView *treeview = GTK_TREE_VIEW (sess->gui->user_tree);
|
|
|
|
GtkTreeModel *model = gtk_tree_view_get_model (treeview);
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
|
|
|
|
struct User *row_user;
|
|
|
|
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
|
|
{
|
|
|
|
if (do_clear)
|
|
|
|
gtk_tree_selection_unselect_all (selection);
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (*word[0])
|
|
|
|
{
|
|
|
|
gtk_tree_model_get (model, &iter, COL_USER, &row_user, -1);
|
|
|
|
thisname = 0;
|
|
|
|
while ( *(name = word[thisname++]) )
|
|
|
|
{
|
|
|
|
if (sess->server->p_cmp (row_user->nick, name) == 0)
|
|
|
|
{
|
|
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
|
|
if (scroll_to)
|
|
|
|
scroll_to_iter (&iter, treeview, model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
}
|
|
|
|
}
|