summary refs log blame commit diff stats
path: root/src/fe-gtk/fe-gtk.h
blob: ab776f63b1fe31612aa3fc26f64e0076f09d7fc0 (plain) (tree)


















                                                                            


                        
                   
 
                              


                      

      
                       
                    




                              
                    
 
                          
                          






                          
 



                                  






























                                                                                        
                                                                              
                                






                                                                                                                              


                                                                              







                                                                                          
                              



                                                               
                                                                         



















































                                                                                     


                                                                                                                 
                      
















                                                                                    
                                                                             




                                                                                   

      
/* 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_FE_GTK_H
#define HEXCHAT_FE_GTK_H

#include "config.h"

#define DISPLAY_NAME "HexChat"

#ifndef WIN32
#include <sys/types.h>
#endif

#include <glib/gi18n.h>
#include <gtk/gtk.h>

#ifdef HAVE_GTK_MAC
#include <gtkosxapplication.h>
#endif

#include "banlist.h"

#define flag_c flag_wid[0]
#define flag_n flag_wid[1]
#define flag_t flag_wid[2]
#define flag_i flag_wid[3]
#define flag_m flag_wid[4]
#define flag_l flag_wid[5]
#define flag_k flag_wid[6]
#define flag_b flag_wid[7]
#define NUM_FLAG_WIDS 8

#ifdef HAVE_GTK_MAC
extern GtkosxApplication *osx_app;
#endif

struct server_gui
{
	GtkWidget *rawlog_window;
	GtkWidget *rawlog_textlist;

	/* join dialog */
	GtkWidget *joind_win;
	GtkWidget *joind_entry;
	GtkWidget *joind_radio1;
	GtkWidget *joind_radio2;
	GtkWidget *joind_check;

	/* chanlist variables */
	GtkWidget *chanlist_wild;		/* GtkEntry */
	GtkWidget *chanlist_window;
	GtkWidget *chanlist_list;
	GtkWidget *chanlist_label;
	GtkWidget *chanlist_min_spin;	/* minusers GtkSpinButton */
	GtkWidget *chanlist_refresh;	/* buttons */
	GtkWidget *chanlist_join;
	GtkWidget *chanlist_savelist;
	GtkWidget *chanlist_search;

	GSList *chanlist_data_stored_rows;	/* stored list so it can be resorted  */
	GSList *chanlist_pending_rows;
	gint chanlist_tag;
	gint chanlist_flash_tag;

	gboolean chanlist_match_wants_channel;	/* match in channel name */
	gboolean chanlist_match_wants_topic;	/* match in topic */

	GRegex *chanlist_match_regex;	/* compiled regular expression here */
	unsigned int have_regex;

	guint chanlist_users_found_count;	/* users total for all channels */
	guint chanlist_users_shown_count;	/* users total for displayed channels */
	guint chanlist_channels_found_count;	/* channel total for /LIST operation */
	guint chanlist_channels_shown_count;	/* total number of displayed 
														   channels */

	guint32 chanlist_maxusers;
	guint32 chanlist_minusers;
	guint32 chanlist_minusers_downloaded;	/* used by LIST IRC command */
	int chanlist_search_type;		/* 0=simple 1=pattern/wildcard 2=regexp */
	gboolean chanlist_caption_is_stale;
};

/* this struct is persistant even when delinking/relinking */

typedef struct restore_gui
{
	banlist_info *banlist;

	void *tab;			/* (chan *) */

	/* information stored when this tab isn't front-most */
	GtkListStore *user_model;	/* for filling the GtkTreeView */
	void *buffer;		/* xtext_Buffer */
	char *input_text;	/* input text buffer (while not-front tab) */
	char *topic_text;	/* topic GtkEntry buffer */
	char *key_text;
	char *limit_text;
	gfloat old_ul_value;	/* old userlist value (for adj) */
	gfloat lag_value;	/* lag-o-meter */
	char *lag_text;	/* lag-o-meter text */
	char *lag_tip;		/* lag-o-meter tooltip */
	gfloat queue_value; /* outbound queue meter */
	char *queue_text;		/* outbound queue text */
	char *queue_tip;		/* outbound queue tooltip */
	short flag_wid_state[NUM_FLAG_WIDS];
	unsigned int c_graph:1;	/* connecting graph, is there one? */
} restore_gui;

typedef struct session_gui
{
	GtkWidget
		*xtext,
		*vscrollbar,
		*window,	/* toplevel */
		*topic_entry,
		*note_book,
		*main_table,
		*user_tree,	/* GtkTreeView */
		*user_box,	/* userlist box */
		*button_box_parent,
		*button_box,	/* userlist buttons' box */
		*dialogbutton_box,
		*topicbutton_box,
		*meter_box,	/* all the meters inside this */
		*lagometer,
		*laginfo,
		*throttlemeter,
		*throttleinfo,
		*topic_bar,
		*hpane_left,
		*hpane_right,
		*vpane_left,
		*vpane_right,
		*menu,
		*bar,				/* connecting progress bar */
		*nick_box,		/* contains label to the left of input_box */
		*nick_label,
		*op_xpm,			/* icon to the left of nickname */
		*namelistinfo,	/* label above userlist */
		*input_box,
		*flag_wid[NUM_FLAG_WIDS],		/* channelmode buttons */
		*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 14
	GtkWidget *menu_item[MENU_ID_NUM+1]; /* some items we may change state of */

	void *chanview;	/* chanview.h */

	int bartag;		/*connecting progressbar timeout */

	int pane_left_size;	/*last position of the pane*/
	int pane_right_size;

	guint16 is_tab;	/* is tab or toplevel? */
	guint16 ul_hidden;	/* userlist hidden? */

} session_gui;

extern GdkPixmap *channelwin_pix;
extern GdkPixmap *dialogwin_pix;

#define SPELL_ENTRY_GET_TEXT(e) ((char *)(gtk_entry_get_text (GTK_ENTRY(e))))
#define SPELL_ENTRY_SET_TEXT(e,txt) gtk_entry_set_text(GTK_ENTRY(e),txt)
#define SPELL_ENTRY_SET_EDITABLE(e,v) gtk_editable_set_editable(GTK_EDITABLE(e),v)
#define SPELL_ENTRY_GET_POS(e) gtk_editable_get_position(GTK_EDITABLE(e))
#define SPELL_ENTRY_SET_POS(e,p) gtk_editable_set_position(GTK_EDITABLE(e),p);
#define SPELL_ENTRY_INSERT(e,t,l,p) gtk_editable_insert_text(GTK_EDITABLE(e),t,l,p)

#endif
t); } gtk_tree_path_free (path); } return ret; } static void cv_tree_init (chanview *cv) { GtkWidget *view, *win; GtkCellRenderer *renderer; GtkTreeViewColumn *col; int wid1, wid2; static const GtkTargetEntry dnd_src_target[] = { {"HEXCHAT_CHANVIEW", GTK_TARGET_SAME_APP, 75 } }; static const GtkTargetEntry dnd_dest_target[] = { {"HEXCHAT_USERLIST", GTK_TARGET_SAME_APP, 75 } }; win = gtk_scrolled_window_new (0, 0); /*gtk_container_set_border_width (GTK_CONTAINER (win), 1);*/ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (win), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (cv->box), win); gtk_widget_show (win); view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cv->store)); gtk_widget_set_name (view, "hexchat-tree"); if (cv->style) gtk_widget_set_style (view, cv->style); /*gtk_widget_modify_base (view, GTK_STATE_NORMAL, &colors[COL_BG]);*/ GTK_WIDGET_UNSET_FLAGS (view, GTK_CAN_FOCUS); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); if (prefs.hex_gui_tab_dots) { gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (view), TRUE); } /* Indented channels with no server looks silly, but we still want expanders */ if (!prefs.hex_gui_tab_server) { gtk_widget_style_get (view, "expander-size", &wid1, "horizontal-separator", &wid2, NULL); gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (view), -wid1 - wid2); } gtk_container_add (GTK_CONTAINER (win), view); col = gtk_tree_view_column_new(); /* icon column */ if (cv->use_icons) { renderer = gtk_cell_renderer_pixbuf_new (); if (prefs.hex_gui_compact) g_object_set (G_OBJECT (renderer), "ypad", 0, NULL); gtk_tree_view_column_pack_start(col, renderer, FALSE); gtk_tree_view_column_set_attributes (col, renderer, "pixbuf", COL_PIXBUF, NULL); } /* main column */ renderer = gtk_cell_renderer_text_new (); if (prefs.hex_gui_compact) 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_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_set_attributes (col, renderer, "text", COL_NAME, "attributes", COL_ATTR, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (view))), "changed", G_CALLBACK (cv_tree_sel_cb), cv); g_signal_connect (G_OBJECT (view), "button-press-event", G_CALLBACK (cv_tree_click_cb), cv); g_signal_connect (G_OBJECT (view), "row-activated", G_CALLBACK (cv_tree_activated_cb), NULL); gtk_drag_dest_set (view, GTK_DEST_DEFAULT_ALL, dnd_dest_target, 1, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); gtk_drag_source_set (view, GDK_BUTTON1_MASK, dnd_src_target, 1, GDK_ACTION_COPY); #ifndef WIN32 g_signal_connect (G_OBJECT (view), "drag_begin", G_CALLBACK (mg_drag_begin_cb), NULL); g_signal_connect (G_OBJECT (view), "drag_drop", G_CALLBACK (mg_drag_drop_cb), NULL); g_signal_connect (G_OBJECT (view), "drag_motion", G_CALLBACK (mg_drag_motion_cb), NULL); g_signal_connect (G_OBJECT (view), "drag_end", G_CALLBACK (mg_drag_end_cb), NULL); #endif ((treeview *)cv)->tree = GTK_TREE_VIEW (view); ((treeview *)cv)->scrollw = win; gtk_widget_show (view); } static void cv_tree_postinit (chanview *cv) { gtk_tree_view_expand_all (((treeview *)cv)->tree); } static void * cv_tree_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent) { GtkTreePath *path; if (parent) { /* expand the parent node */ path = gtk_tree_model_get_path (GTK_TREE_MODEL (cv->store), parent); if (path) { gtk_tree_view_expand_row (((treeview *)cv)->tree, path, FALSE); gtk_tree_path_free (path); } } return NULL; } static void cv_tree_change_orientation (chanview *cv) { } static void cv_tree_focus (chan *ch) { GtkTreeView *tree = ((treeview *)ch->cv)->tree; GtkTreeModel *model = gtk_tree_view_get_model (tree); GtkTreePath *path; GtkTreeIter parent; GdkRectangle cell_rect; GdkRectangle vis_rect; gint dest_y; /* expand the parent node */ if (gtk_tree_model_iter_parent (model, &parent, &ch->iter)) { path = gtk_tree_model_get_path (model, &parent); if (path) { /*if (!gtk_tree_view_row_expanded (tree, path)) { gtk_tree_path_free (path); return; }*/ gtk_tree_view_expand_row (tree, path, FALSE); gtk_tree_path_free (path); } } path = gtk_tree_model_get_path (model, &ch->iter); if (path) { /* This full section does what * gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0.5); * does, except it only scrolls the window if the provided cell is * not visible. Basic algorithm taken from gtktreeview.c */ /* obtain information to see if the cell is visible */ gtk_tree_view_get_background_area (tree, path, NULL, &cell_rect); gtk_tree_view_get_visible_rect (tree, &vis_rect); /* The cordinates aren't offset correctly */ gtk_tree_view_widget_to_tree_coords( tree, cell_rect.x, cell_rect.y, NULL, &cell_rect.y ); /* only need to scroll if out of bounds */ if (cell_rect.y < vis_rect.y || cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height) { dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * 0.5); if (dest_y < 0) dest_y = 0; gtk_tree_view_scroll_to_point (tree, -1, dest_y); } /* theft done, now make it focused like */ gtk_tree_view_set_cursor (tree, path, NULL, FALSE); gtk_tree_path_free (path); } } static void cv_tree_move_focus (chanview *cv, gboolean relative, int num) { chan *ch; if (relative) { num += cv_find_number_of_chan (cv, cv->focused); num %= cv->size; /* make it wrap around at both ends */ if (num < 0) num = cv->size - 1; } ch = cv_find_chan_by_number (cv, num); if (ch) cv_tree_focus (ch); } static void cv_tree_remove (chan *ch) { } static void move_row (chan *ch, int delta, GtkTreeIter *parent) { GtkTreeStore *store = ch->cv->store; GtkTreeIter *src = &ch->iter; GtkTreeIter dest = ch->iter; GtkTreePath *dest_path; if (delta < 0) /* down */ { if (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &dest)) gtk_tree_store_swap (store, src, &dest); else /* move to top */ gtk_tree_store_move_after (store, src, NULL); } else { dest_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &dest); if (gtk_tree_path_prev (dest_path)) { gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &dest, dest_path); gtk_tree_store_swap (store, src, &dest); } else { /* move to bottom */ gtk_tree_store_move_before (store, src, NULL); } gtk_tree_path_free (dest_path); } } static void cv_tree_move (chan *ch, int delta) { GtkTreeIter parent; /* do nothing if this is a server row */ if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (ch->cv->store), &parent, &ch->iter)) move_row (ch, delta, &parent); } static void cv_tree_move_family (chan *ch, int delta) { move_row (ch, delta, NULL); } static void cv_tree_cleanup (chanview *cv) { if (cv->box) /* kill the scrolled window */ gtk_widget_destroy (((treeview *)cv)->scrollw); } static void cv_tree_set_color (chan *ch, PangoAttrList *list) { /* nothing to do, it's already set in the store */ } static void cv_tree_rename (chan *ch, char *name) { /* nothing to do, it's already renamed in the store */ } static chan * cv_tree_get_parent (chan *ch) { chan *parent_ch = NULL; GtkTreeIter parent; if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (ch->cv->store), &parent, &ch->iter)) { gtk_tree_model_get (GTK_TREE_MODEL (ch->cv->store), &parent, COL_CHAN, &parent_ch, -1); } return parent_ch; } static gboolean cv_tree_is_collapsed (chan *ch) { chan *parent = cv_tree_get_parent (ch); GtkTreePath *path = NULL; gboolean ret; if (parent == NULL) return FALSE; path = gtk_tree_model_get_path (GTK_TREE_MODEL (parent->cv->store), &parent->iter); ret = !gtk_tree_view_row_expanded (((treeview *)parent->cv)->tree, path); gtk_tree_path_free (path); return ret; }