diff options
Diffstat (limited to 'src/fe-gtk')
46 files changed, 1514 insertions, 842 deletions
diff --git a/src/fe-gtk/Makefile.am b/src/fe-gtk/Makefile.am index a8f43ac5..71179853 100644 --- a/src/fe-gtk/Makefile.am +++ b/src/fe-gtk/Makefile.am @@ -1,3 +1,6 @@ + +include $(top_srcdir)/m4/clang-analyze.am + localedir = $(datadir)/locale bin_PROGRAMS = hexchat @@ -9,7 +12,7 @@ hexchat_LDADD = ../common/libhexchatcommon.a $(GUI_LIBS) EXTRA_DIST = \ 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 notifygui.h palette.h pixmaps.h \ + maingui.h menu.h notifygui.h notifications palette.h pixmaps.h plugin-notification.h \ plugin-tray.h plugingui.c plugingui.h rawlog.h sexy-iso-codes.h \ sexy-spell-entry.h textgui.h urlgrab.h userlistgui.h xtext.h \ ../../data/hexchat.gresource.xml @@ -26,12 +29,29 @@ if HAVE_ISO_CODES iso_codes_c = sexy-iso-codes.c endif +if USE_LIBNOTIFY +notify_c = notifications/notification-libnotify.c +else +if HAVE_GTK_MAC +notify_c = notifications/notification-osx.m +hexchat_LDFLAGS = -framework Foundation +else +notify_c = notifications/notification-dummy.c +endif +endif + hexchat_SOURCES = 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 notifygui.c palette.c pixmaps.c plugin-tray.c $(plugingui_c) \ - rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \ + maingui.c notifygui.c $(notify_c) palette.c pixmaps.c plugin-tray.c $(plugingui_c) \ + plugin-notification.c rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \ sexy-spell-entry.c textgui.c urlgrab.c userlistgui.c xtext.c hexchat_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/common resources.c: $(top_srcdir)/data/hexchat.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(top_srcdir)/data --generate-dependencies $(top_srcdir)/data/hexchat.gresource.xml) $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(top_srcdir)/data --generate-source $< + +if DO_STATIC_ANALYSIS +analyze_plists = $(hexchat_SOURCES:%.c=%.plist) +all-local: $(analyze_plists) +MOSTLYCLEANFILES = $(analyze_plists) +endif diff --git a/src/fe-gtk/banlist.c b/src/fe-gtk/banlist.c index d6f44811..e10aaa67 100644 --- a/src/fe-gtk/banlist.c +++ b/src/fe-gtk/banlist.c @@ -491,7 +491,7 @@ banlist_unban_inner (gpointer none, banlist_info *banl, int mode_num) if (!gtk_tree_model_get_iter_first (model, &iter)) return 0; - masks = g_malloc (sizeof (char *) * banl->line_ct); + masks = g_new (char *, banl->line_ct); num_sel = 0; do { @@ -577,17 +577,17 @@ static void banlist_add_selected_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GSList **lp = data; - GSList *list = NULL; GtkTreeIter *copy; - if (!lp) return; - list = *lp; - copy = g_malloc (sizeof (GtkTreeIter)); - g_return_if_fail (copy != NULL); + if (lp == NULL) + { + return; + } + + copy = g_new (GtkTreeIter, 1); *copy = *iter; - list = g_slist_append (list, copy); - *(GSList **)data = list; + *lp = g_slist_append (*lp, copy); } static void @@ -786,14 +786,9 @@ banlist_opengui (struct session *sess) return; } - if (!sess->res->banlist) + if (sess->res->banlist == NULL) { - sess->res->banlist = g_malloc0 (sizeof (banlist_info)); - if (!sess->res->banlist) - { - fe_message (_("Banlist initialization failed."), FE_MSG_ERROR); - return; - } + sess->res->banlist = g_new0 (banlist_info, 1); } banl = sess->res->banlist; if (banl->window) diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index f3a2259d..f6ef46f3 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -94,7 +94,7 @@ chanlist_update_caption (server *serv) { gchar tbuf[256]; - snprintf (tbuf, sizeof tbuf, + g_snprintf (tbuf, sizeof tbuf, _("Displaying %d/%d users on %d/%d channels."), serv->gui->chanlist_users_shown_count, serv->gui->chanlist_users_found_count, @@ -148,7 +148,7 @@ chanlist_data_free (server *serv) data = rows->data; g_free (data->topic); g_free (data->collation_key); - free (data); + g_free (data); } g_slist_free (serv->gui->chanlist_data_stored_rows); @@ -370,7 +370,7 @@ fe_add_chan_list (server *serv, char *chan, char *users, char *topic) int len = strlen (chan) + 1; /* we allocate the struct and channel string in one go */ - next_row = malloc (sizeof (chanlistrow) + len); + next_row = g_malloc (sizeof (chanlistrow) + len); memcpy (((char *)next_row) + sizeof (chanlistrow), chan, len); next_row->topic = strip_color (topic, -1, STRIP_ALL); next_row->collation_key = g_utf8_collate_key (chan, len-1); @@ -456,7 +456,7 @@ chanlist_join (GtkWidget * wid, server *serv) { if (serv->connected && (strcmp (chan, "*") != 0)) { - snprintf (tbuf, sizeof (tbuf), "join %s", chan); + g_snprintf (tbuf, sizeof (tbuf), "join %s", chan); handle_command (serv->server_session, tbuf, FALSE); } else gdk_beep (); @@ -482,7 +482,7 @@ chanlist_filereq_done (server *serv, char *file) if (fh == -1) return; - snprintf (buf, sizeof buf, "HexChat Channel List: %s - %s\n", + g_snprintf (buf, sizeof buf, "HexChat Channel List: %s - %s\n", serv->servername, ctime (&t)); write (fh, buf, strlen (buf)); @@ -494,7 +494,7 @@ chanlist_filereq_done (server *serv, char *file) COL_CHANNEL, &chan, COL_USERS, &users, COL_TOPIC, &topic, -1); - snprintf (buf, sizeof buf, "%-16s %-5d%s\n", chan, users, topic); + g_snprintf (buf, sizeof buf, "%-16s %-5d%s\n", chan, users, topic); g_free (chan); g_free (topic); write (fh, buf, strlen (buf)); @@ -717,7 +717,7 @@ chanlist_opengui (server *serv, int do_refresh) return; } - snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Channel List (%s)"), + g_snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Channel List (%s)"), server_get_network (serv, TRUE)); serv->gui->chanlist_pending_rows = NULL; diff --git a/src/fe-gtk/chanview-tabs.c b/src/fe-gtk/chanview-tabs.c index 8f940c24..5681f9d6 100644 --- a/src/fe-gtk/chanview-tabs.c +++ b/src/fe-gtk/chanview-tabs.c @@ -62,12 +62,13 @@ cv_tabs_sizerequest (GtkWidget *viewport, GtkRequisition *requisition, chanview static void cv_tabs_sizealloc (GtkWidget *widget, GtkAllocation *allocation, chanview *cv) { + GdkWindow *parent_win; GtkAdjustment *adj; GtkWidget *inner; gint viewport_size; inner = ((tabview *)cv)->inner; - GdkWindow *parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner)); + parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner)); if (cv->vertical) { @@ -141,7 +142,7 @@ tab_scroll_left_up_clicked (GtkWidget *widget, chanview *cv) gfloat new_value; GtkWidget *inner; GdkWindow *parent_win; - gfloat i; + gdouble i; inner = ((tabview *)cv)->inner; parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner)); @@ -190,7 +191,7 @@ tab_scroll_right_down_clicked (GtkWidget *widget, chanview *cv) gfloat new_value; GtkWidget *inner; GdkWindow *parent_win; - gfloat i; + gdouble i; inner = ((tabview *)cv)->inner; parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner)); diff --git a/src/fe-gtk/chanview.c b/src/fe-gtk/chanview.c index 4c50d922..e5556d9f 100644 --- a/src/fe-gtk/chanview.c +++ b/src/fe-gtk/chanview.c @@ -111,9 +111,8 @@ truncate_tab_name (char *name, int max) if (max > 2 && g_utf8_strlen (name, -1) > max) { /* truncate long channel names */ - buf = malloc (strlen (name) + 4); - strcpy (buf, name); - g_utf8_offset_to_pointer (buf, max)[0] = 0; + buf = g_malloc (strlen (name) + 4); + g_utf8_strncpy (buf, name, max); strcat (buf, ".."); return buf; } @@ -231,7 +230,7 @@ chanview_free_ch (chanview *cv, GtkTreeIter *iter) chan *ch; gtk_tree_model_get (GTK_TREE_MODEL (cv->store), iter, COL_CHAN, &ch, -1); - free (ch); + g_free (ch); } static void @@ -251,7 +250,7 @@ chanview_destroy (chanview *cv) gtk_widget_destroy (cv->box); chanview_destroy_store (cv); - free (cv); + g_free (cv); } static void @@ -267,7 +266,7 @@ chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, { chanview *cv; - cv = calloc (1, sizeof (chanview)); + cv = g_new0 (chanview, 1); cv->store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF); cv->style = style; @@ -368,7 +367,7 @@ chanview_add_real (chanview *cv, char *name, void *family, void *userdata, if (!ch) { - ch = calloc (1, sizeof (chan)); + ch = g_new0 (chan, 1); ch->userdata = userdata; ch->family = family; ch->cv = cv; @@ -401,7 +400,7 @@ chanview_add (chanview *cv, char *name, void *family, void *userdata, gboolean a ret = chanview_add_real (cv, new_name, family, userdata, allow_closure, tag, icon, NULL, NULL); if (new_name != name) - free (new_name); + g_free (new_name); return ret; } @@ -492,7 +491,7 @@ chan_rename (chan *ch, char *name, int trunc_len) ch->cv->trunc_len = trunc_len; if (new_name != name) - free (new_name); + g_free (new_name); } /* this thing is overly complicated */ @@ -645,7 +644,7 @@ chan_remove (chan *ch, gboolean force) ch->cv->size--; gtk_tree_store_remove (ch->cv->store, &ch->iter); - free (ch); + g_free (ch); return TRUE; } diff --git a/src/fe-gtk/custom-list.c b/src/fe-gtk/custom-list.c index a954b4a0..f1241947 100644 --- a/src/fe-gtk/custom-list.c +++ b/src/fe-gtk/custom-list.c @@ -134,7 +134,6 @@ custom_list_get_type (void) return custom_list_type; /* Some boilerplate type registration stuff */ - if (1) { static const GTypeInfo custom_list_info = { sizeof (CustomListClass), @@ -154,7 +153,6 @@ custom_list_get_type (void) } /* Here we register our GtkTreeModel interface with the type system */ - if (1) { static const GInterfaceInfo tree_model_info = { (GInterfaceInitFunc) custom_list_tree_model_init, @@ -167,7 +165,6 @@ custom_list_get_type (void) } /* Add GtkTreeSortable interface */ - if (1) { static const GInterfaceInfo tree_sortable_info = { (GInterfaceInitFunc) custom_list_sortable_init, @@ -336,7 +333,7 @@ custom_list_get_iter (GtkTreeModel * tree_model, gint n; n = gtk_tree_path_get_indices (path)[0]; - if (n >= custom_list->num_rows || n < 0) + if (n < 0 || (guint) n >= custom_list->num_rows) return FALSE; record = custom_list->rows[n]; @@ -533,7 +530,7 @@ custom_list_iter_nth_child (GtkTreeModel * tree_model, return FALSE; /* special case: if parent == NULL, set iter to n-th top-level row */ - if (n >= custom_list->num_rows) + if (n < 0 || (guint) n >= custom_list->num_rows) return FALSE; iter->user_data = custom_list->rows[n]; @@ -730,7 +727,7 @@ custom_list_resort (CustomList * custom_list) custom_list); /* let other objects know about the new order */ - neworder = malloc (sizeof (gint) * custom_list->num_rows); + neworder = g_new (gint, custom_list->num_rows); for (i = custom_list->num_rows - 1; i >= 0; i--) { @@ -747,7 +744,7 @@ custom_list_resort (CustomList * custom_list) gtk_tree_model_rows_reordered (GTK_TREE_MODEL (custom_list), path, NULL, neworder); gtk_tree_path_free (path); - free (neworder); + g_free (neworder); } void diff --git a/src/fe-gtk/custom-list.h b/src/fe-gtk/custom-list.h index 64f0535f..30a73919 100644 --- a/src/fe-gtk/custom-list.h +++ b/src/fe-gtk/custom-list.h @@ -77,10 +77,10 @@ struct _CustomList { GObject parent; - guint num_rows; /* number of rows that we have used */ - guint num_alloc; /* number of rows allocated */ - chanlistrow **rows; /* a dynamically allocated array of pointers to the - * CustomRecord structure for each row */ + guint num_rows; /* number of rows that we have used */ + guint num_alloc; /* number of rows allocated */ + chanlistrow **rows; /* a dynamically allocated array of pointers to the + * CustomRecord structure for each row */ gint n_columns; GType column_types[CUSTOM_LIST_N_COLUMNS]; diff --git a/src/fe-gtk/dccgui.c b/src/fe-gtk/dccgui.c index 10ec8388..8c9dc8b4 100644 --- a/src/fe-gtk/dccgui.c +++ b/src/fe-gtk/dccgui.c @@ -88,7 +88,7 @@ struct my_dcc_send { struct session *sess; char *nick; - int maxcps; + gint64 maxcps; int passive; }; @@ -105,7 +105,7 @@ static short view_mode; /* 1=download 2=upload 3=both */ static void -proper_unit (DCC_SIZE size, char *buf, int buf_len) +proper_unit (guint64 size, char *buf, size_t buf_len) { gchar *formatted_str; GFormatSizeFlags format_flags = G_FORMAT_SIZE_DEFAULT; @@ -117,7 +117,7 @@ proper_unit (DCC_SIZE size, char *buf, int buf_len) format_flags = G_FORMAT_SIZE_IEC_UNITS; #endif - formatted_str = g_format_size_full ((guint64)size, format_flags); + formatted_str = g_format_size_full (size, format_flags); g_strlcpy (buf, formatted_str, buf_len); g_free (formatted_str); @@ -130,45 +130,45 @@ dcc_send_filereq_file (struct my_dcc_send *mdc, char *file) dcc_send (mdc->sess, mdc->nick, file, mdc->maxcps, mdc->passive); else { - free (mdc->nick); - free (mdc); + g_free (mdc->nick); + g_free (mdc); } } void fe_dcc_send_filereq (struct session *sess, char *nick, int maxcps, int passive) { - char tbuf[128]; - struct my_dcc_send *mdc; - - mdc = malloc (sizeof (*mdc)); + char* tbuf = g_strdup_printf (_("Send file to %s"), nick); + + struct my_dcc_send *mdc = g_new (struct my_dcc_send, 1); mdc->sess = sess; - mdc->nick = strdup (nick); + mdc->nick = g_strdup (nick); mdc->maxcps = maxcps; mdc->passive = passive; - snprintf (tbuf, sizeof tbuf, _("Send file to %s"), nick); gtkutil_file_req (tbuf, dcc_send_filereq_file, mdc, prefs.hex_dcc_dir, NULL, FRF_MULTIPLE|FRF_FILTERISINITIAL); + + g_free (tbuf); } static void dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, gboolean update_only) { - static char pos[16], siz[16]; + static char pos[16], size[16]; char *date; date = ctime (&dcc->starttime); date[strlen (date) - 1] = 0; /* remove the \n */ proper_unit (dcc->pos, pos, sizeof (pos)); - proper_unit (dcc->size, siz, sizeof (siz)); + proper_unit (dcc->size, size, sizeof (size)); gtk_list_store_set (store, iter, CCOL_STATUS, _(dccstat[dcc->dccstat].name), CCOL_NICK, dcc->nick, CCOL_RECV, pos, - CCOL_SENT, siz, + CCOL_SENT, size, CCOL_START, date, CCOL_DCC, dcc, CCOL_COLOR, @@ -194,13 +194,12 @@ dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, per = (float) ((dcc->ack * 100.00) / dcc->size); proper_unit (dcc->size, size, sizeof (size)); proper_unit (dcc->pos, pos, sizeof (pos)); - snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024); -/* proper_unit (dcc->ack, ack, sizeof (ack));*/ - snprintf (perc, sizeof (perc), "%.0f%%", per); + g_snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024); + g_snprintf (perc, sizeof (perc), "%.0f%%", per); if (dcc->cps != 0) { to_go = (dcc->size - dcc->ack) / dcc->cps; - snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d", + g_snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d", to_go / 3600, (to_go / 60) % 60, to_go % 60); } else strcpy (eta, "--:--:--"); @@ -253,14 +252,14 @@ dcc_prepare_row_recv (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, proper_unit (dcc->resumable, pos, sizeof (pos)); else proper_unit (dcc->pos, pos, sizeof (pos)); - snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024); + g_snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024); /* percentage recv'ed */ per = (float) ((dcc->pos * 100.00) / dcc->size); - snprintf (perc, sizeof (perc), "%.0f%%", per); + g_snprintf (perc, sizeof (perc), "%.0f%%", per); if (dcc->cps != 0) { to_go = (dcc->size - dcc->pos) / dcc->cps; - snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d", + g_snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d", to_go / 3600, (to_go / 60) % 60, to_go % 60); } else strcpy (eta, "--:--:--"); @@ -526,7 +525,7 @@ resume_clicked (GtkWidget * wid, gpointer none) fe_message (_("That file is not resumable."), FE_MSG_ERROR); break; case 1: - snprintf (buf, sizeof (buf), + g_snprintf (buf, sizeof (buf), _( "Cannot access file: %s\n" "%s.\n" "Resuming not possible."), dcc->destfile, @@ -607,7 +606,7 @@ browse_folder (char *dir) #else char buf[512]; - snprintf (buf, sizeof (buf), "file://%s", dir); + g_snprintf (buf, sizeof (buf), "file://%s", dir); fe_open_url (buf); #endif } @@ -640,7 +639,7 @@ dcc_details_populate (struct DCC *dcc) gtk_label_set_text (GTK_LABEL (dccfwin.file_label), dcc->file); /* address and port */ - snprintf (buf, sizeof (buf), "%s : %d", net_ip (dcc->addr), dcc->port); + g_snprintf (buf, sizeof (buf), "%s : %d", net_ip (dcc->addr), dcc->port); gtk_label_set_text (GTK_LABEL (dccfwin.address_label), buf); } @@ -738,7 +737,7 @@ dcc_detail_label (char *text, GtkWidget *box, int num) char buf[64]; label = gtk_label_new (NULL); - snprintf (buf, sizeof (buf), "<b>%s</b>", text); + g_snprintf (buf, sizeof (buf), "<b>%s</b>", text); gtk_label_set_markup (GTK_LABEL (label), buf); gtk_misc_set_alignment (GTK_MISC (label), 0, 0); gtk_table_attach (GTK_TABLE (box), label, 0, 1, 0 + num, 1 + num, GTK_FILL, GTK_FILL, 0, 0); diff --git a/src/fe-gtk/editlist.c b/src/fe-gtk/editlist.c index f7e22d52..4b236dc1 100644 --- a/src/fe-gtk/editlist.c +++ b/src/fe-gtk/editlist.c @@ -283,6 +283,7 @@ editlist_treeview_new (GtkWidget *box, char *title1, char *title2) 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 (editlist_keypress), NULL); @@ -313,7 +314,6 @@ editlist_treeview_new (GtkWidget *box, char *title1, char *title2) gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_view_column_set_min_width (col, 100); - col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), CMD_COLUMN); gtk_container_add (GTK_CONTAINER (scroll), view); gtk_container_add (GTK_CONTAINER (box), scroll); diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index 4b7d916f..8c163eb7 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -52,6 +52,7 @@ #include "plugin-tray.h" #include "urlgrab.h" #include "setup.h" +#include "plugin-notification.h" #ifdef USE_LIBCANBERRA #include <canberra.h> @@ -224,7 +225,7 @@ fe_args (int argc, char *argv[]) /* cuts can. So we have to set the current dir manually, to the path */ /* of the exe. */ { - char *tmp = strdup (argv[0]); + char *tmp = g_strdup (argv[0]); char *sl; sl = strrchr (tmp, G_DIR_SEPARATOR); @@ -233,7 +234,7 @@ fe_args (int argc, char *argv[]) *sl = 0; chdir (tmp); } - free (tmp); + g_free (tmp); } #endif @@ -265,7 +266,7 @@ create_input_style (GtkStyle *style) /* fall back */ if (pango_font_description_get_size (style->font_desc) == 0) { - snprintf (buf, sizeof (buf), _("Failed to open font:\n\n%s"), prefs.hex_text_font); + g_snprintf (buf, sizeof (buf), _("Failed to open font:\n\n%s"), prefs.hex_text_font); fe_message (buf, FE_MSG_ERROR); pango_font_description_free (style->font_desc); style->font_desc = pango_font_description_from_string ("sans 11"); @@ -381,6 +382,8 @@ fe_idle (gpointer data) { session *sess = sess_list->data; + plugin_add (sess, NULL, NULL, notification_plugin_init, notification_plugin_deinit, NULL, FALSE); + plugin_add (sess, NULL, NULL, tray_plugin_init, tray_plugin_deinit, NULL, FALSE); if (arg_minimize == 1) @@ -424,8 +427,7 @@ fe_new_window (session *sess, int focus) void fe_new_server (struct server *serv) { - serv->gui = malloc (sizeof (struct server_gui)); - memset (serv->gui, 0, sizeof (struct server_gui)); + serv->gui = g_new0 (struct server_gui, 1); } void @@ -510,18 +512,15 @@ fe_set_topic (session *sess, char *topic, char *stripped_topic) } else { - if (sess->res->topic_text) - { - free (sess->res->topic_text); - } + g_free (sess->res->topic_text); if (prefs.hex_text_stripcolor_topic) { - sess->res->topic_text = strdup (stripped_topic); + sess->res->topic_text = g_strdup (stripped_topic); } else { - sess->res->topic_text = strdup (topic); + sess->res->topic_text = g_strdup (topic); } } } @@ -547,9 +546,8 @@ fe_update_mode_entry (session *sess, GtkWidget *entry, char **text, char *new_te { if (sess->gui->is_tab) { - if (*text) - free (*text); - *text = strdup (new_text); + g_free (*text); + *text = g_strdup (new_text); } } } @@ -721,7 +719,7 @@ fe_lastlog (session *sess, session *lastlog_sess, char *sstr, gtk_xtext_search_f lbuf->search_lnee = strlen (lbuf->search_nee); } lbuf->search_flags = flags; - lbuf->search_text = strdup (sstr); + lbuf->search_text = g_strdup (sstr); gtk_xtext_lastlog (lbuf, buf); } @@ -751,9 +749,9 @@ fe_set_lag (server *serv, long lag) if (per > 1.0) per = 1.0; - snprintf (lagtext, sizeof (lagtext) - 1, "%s%ld.%lds", + g_snprintf (lagtext, sizeof (lagtext) - 1, "%s%ld.%lds", serv->lag_sent ? "+" : "", lag / 1000, (lag/100) % 10); - snprintf (lagtip, sizeof (lagtip) - 1, "Lag: %s%ld.%ld seconds", + g_snprintf (lagtip, sizeof (lagtip) - 1, "Lag: %s%ld.%ld seconds", serv->lag_sent ? "+" : "", lag / 1000, (lag/100) % 10); while (list) @@ -761,9 +759,8 @@ fe_set_lag (server *serv, long lag) sess = list->data; if (sess->server == serv) { - if (sess->res->lag_tip) - free (sess->res->lag_tip); - sess->res->lag_tip = strdup (lagtip); + g_free (sess->res->lag_tip); + sess->res->lag_tip = g_strdup (lagtip); if (!sess->gui->is_tab || current_tab == sess) { @@ -777,9 +774,8 @@ fe_set_lag (server *serv, long lag) } else { sess->res->lag_value = per; - if (sess->res->lag_text) - free (sess->res->lag_text); - sess->res->lag_text = strdup (lagtext); + g_free (sess->res->lag_text); + sess->res->lag_text = g_strdup (lagtext); } } list = list->next; @@ -804,12 +800,11 @@ fe_set_throttle (server *serv) sess = list->data; if (sess->server == serv) { - snprintf (tbuf, sizeof (tbuf) - 1, _("%d bytes"), serv->sendq_len); - snprintf (tip, sizeof (tip) - 1, _("Network send queue: %d bytes"), serv->sendq_len); + g_snprintf (tbuf, sizeof (tbuf) - 1, _("%d bytes"), serv->sendq_len); + g_snprintf (tip, sizeof (tip) - 1, _("Network send queue: %d bytes"), serv->sendq_len); - if (sess->res->queue_tip) - free (sess->res->queue_tip); - sess->res->queue_tip = strdup (tip); + g_free (sess->res->queue_tip); + sess->res->queue_tip = g_strdup (tip); if (!sess->gui->is_tab || current_tab == sess) { @@ -823,9 +818,8 @@ fe_set_throttle (server *serv) } else { sess->res->queue_value = per; - if (sess->res->queue_text) - free (sess->res->queue_text); - sess->res->queue_text = strdup (tbuf); + g_free (sess->res->queue_text); + sess->res->queue_text = g_strdup (tbuf); } } list = list->next; @@ -882,11 +876,10 @@ fe_confirm (const char *message, void (*yesproc)(void *), void (*noproc)(void *) { /* warning, assuming fe_confirm is used by DCC only! */ struct DCC *dcc = ud; - char *filepath; if (dcc->file) { - filepath = g_build_filename (prefs.hex_dcc_dir, dcc->file, NULL); + char *filepath = g_build_filename (prefs.hex_dcc_dir, dcc->file, NULL); gtkutil_file_req (message, dcc_saveas_cb, ud, filepath, NULL, FRF_WRITE|FRF_NOASKOVERWRITE|FRF_FILTERISINITIAL); g_free (filepath); @@ -978,9 +971,8 @@ fe_set_inputbox_contents (session *sess, char *text) SPELL_ENTRY_SET_TEXT (sess->gui->input_box, text); } else { - if (sess->res->input_text) - free (sess->res->input_text); - sess->res->input_text = strdup (text); + g_free (sess->res->input_text); + sess->res->input_text = g_strdup (text); } } @@ -1092,9 +1084,9 @@ fe_open_url (const char *url) /* the http:// part's missing, prepend it, otherwise it won't always work */ else if (strchr (url, ':') == NULL) { - url = g_strdup_printf ("http://%s", url); - fe_open_url_inner (url); - g_free ((char *)url); + uri = g_strdup_printf ("http://%s", url); + fe_open_url_inner (uri); + g_free (uri); } /* we have a sane URL, send it to the browser untouched */ else diff --git a/src/fe-gtk/fe-gtk.h b/src/fe-gtk/fe-gtk.h index 17d1ab4d..ab776f63 100644 --- a/src/fe-gtk/fe-gtk.h +++ b/src/fe-gtk/fe-gtk.h @@ -20,7 +20,7 @@ #ifndef HEXCHAT_FE_GTK_H #define HEXCHAT_FE_GTK_H -#include "../../config.h" +#include "config.h" #define DISPLAY_NAME "HexChat" @@ -39,14 +39,13 @@ #define flag_c flag_wid[0] #define flag_n flag_wid[1] -#define flag_r flag_wid[2] -#define flag_t flag_wid[3] -#define flag_i flag_wid[4] -#define flag_m flag_wid[5] -#define flag_l flag_wid[6] -#define flag_k flag_wid[7] -#define flag_b flag_wid[8] -#define NUM_FLAG_WIDS 9 +#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; @@ -92,9 +91,9 @@ struct server_gui guint chanlist_channels_shown_count; /* total number of displayed channels */ - int chanlist_maxusers; - int chanlist_minusers; - int chanlist_minusers_downloaded; /* used by LIST IRC command */ + 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; }; @@ -108,7 +107,7 @@ typedef struct restore_gui void *tab; /* (chan *) */ /* information stored when this tab isn't front-most */ - void *user_model; /* for filling the GtkTreeView */ + 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 */ diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj index 59ab17c6..401518b4 100644 --- a/src/fe-gtk/fe-gtk.vcxproj +++ b/src/fe-gtk/fe-gtk.vcxproj @@ -2,6 +2,7 @@ <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup Label="Configuration"> <PlatformToolset>v120</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> </PropertyGroup> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Release|Win32"> @@ -19,79 +20,38 @@ <RootNamespace>fegtk</RootNamespace> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - <Import Project="..\..\win32\hexchat.props" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - <Import Project="..\..\win32\hexchat.props" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <TargetName>hexchat</TargetName> - <OutDir>$(HexChatBin)</OutDir> - <IntDir>$(HexChatObj)$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <LinkIncremental>false</LinkIncremental> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\win32\hexchat.props" /> + <PropertyGroup> <TargetName>hexchat</TargetName> - <OutDir>$(HexChatBin)</OutDir> - <IntDir>$(HexChatObj)$(ProjectName)\</IntDir> + <OutDir>$(HexChatRel)</OutDir> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> - <PrecompiledHeader> - </PrecompiledHeader> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> + <!-- WholeProgramOptimization must be turned off for gresource constructors to work, otherwise the .CRT$XCU section is not emitted. --> + <WholeProgramOptimization>false</WholeProgramOptimization> <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <MultiProcessorCompilation>true</MultiProcessorCompilation> + <AdditionalIncludeDirectories>..\common;$(HexChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> </ClCompile> <Link> - <SubSystem>Windows</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>$(DepLibs);common.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>$(DepLibs);$(HexChatLib)common.lib;%(AdditionalDependencies)</AdditionalDependencies> <EntryPointSymbol>mainCRTStartup</EntryPointSymbol> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> - <PrecompiledHeader> - </PrecompiledHeader> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> + <!-- WholeProgramOptimization must be turned off for gresource constructors to work, otherwise the .CRT$XCU section is not emitted. --> + <WholeProgramOptimization>false</WholeProgramOptimization> <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <MultiProcessorCompilation>true</MultiProcessorCompilation> + <AdditionalIncludeDirectories>..\common;$(HexChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings> </ClCompile> <Link> - <SubSystem>Windows</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>$(DepLibs);common.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>$(DepLibs);$(HexChatLib)common.lib;%(AdditionalDependencies)</AdditionalDependencies> <EntryPointSymbol>mainCRTStartup</EntryPointSymbol> </Link> </ItemDefinitionGroup> @@ -99,10 +59,10 @@ <PreBuildEvent> <Command><![CDATA[ SET SOLUTIONDIR=$(SolutionDir)..\ -powershell -File "$(SolutionDir)..\win32\version-template.ps1" "$(SolutionDir)..\src\fe-gtk\hexchat.rc.tt" "$(SolutionDir)..\src\fe-gtk\hexchat.rc.utf8" +powershell -File "$(SolutionDir)..\win32\version-template.ps1" "$(SolutionDir)..\src\fe-gtk\hexchat.rc.tt" "$(HexChatLib)hexchat.rc.utf8" REM hexchat.rc needs to be in UCS-2 or Resource Compiler will complain -powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.utf8' | Out-File '$(SolutionDir)..\src\fe-gtk\hexchat.rc'; Remove-Item '$(SolutionDir)..\src\fe-gtk\hexchat.rc.utf8'" -"$(DepsRoot)\bin\glib-compile-resources.exe" --generate-source --sourcedir "$(DataDir)" --target "$(ProjectDir)resources.c" "$(DataDir)hexchat.gresource.xml" +powershell "Get-Content -Encoding UTF8 '$(HexChatLib)hexchat.rc.utf8' | Out-File '$(HexChatLib)hexchat.rc'; Remove-Item '$(HexChatLib)hexchat.rc.utf8'" +"$(DepsRoot)\bin\glib-compile-resources.exe" --generate-source --sourcedir "$(DataDir)" --target "$(HexChatLib)resources.c" "$(DataDir)hexchat.gresource.xml" ]]></Command> <Message>Build hexchat.rc and gresource file</Message> </PreBuildEvent> @@ -120,6 +80,7 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u <ClInclude Include="joind.h" /> <ClInclude Include="maingui.h" /> <ClInclude Include="menu.h" /> + <ClInclude Include="notifications\notification-backend.h" /> <ClInclude Include="notifygui.h" /> <ClInclude Include="palette.h" /> <ClInclude Include="pixmaps.h" /> @@ -150,13 +111,15 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u <ClCompile Include="joind.c" /> <ClCompile Include="maingui.c" /> <ClCompile Include="menu.c" /> + <ClCompile Include="notifications\notification-windows.c" /> <ClCompile Include="notifygui.c" /> <ClCompile Include="palette.c" /> <ClCompile Include="pixmaps.c" /> + <ClCompile Include="plugin-notification.c" /> <ClCompile Include="plugin-tray.c" /> <ClCompile Include="plugingui.c" /> <ClCompile Include="rawlog.c" /> - <ClCompile Include="resources.c" /> + <ClCompile Include="$(HexChatLib)resources.c" /> <ClCompile Include="servlistgui.c" /> <ClCompile Include="setup.c" /> <ClCompile Include="sexy-iso-codes.c" /> @@ -167,11 +130,11 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u <ClCompile Include="xtext.c" /> </ItemGroup> <ItemGroup> - <Manifest Include="hexchat.exe.manifest" /> + <Manifest Include="..\..\win32\hexchat.exe.manifest" /> </ItemGroup> <ItemGroup> <None Include="hexchat.rc.tt" /> - <ResourceCompile Include="hexchat.rc" /> + <ResourceCompile Include="$(HexChatLib)hexchat.rc" /> </ItemGroup> <ItemGroup> <None Include="..\..\data\icons\hexchat.ico" /> @@ -180,6 +143,4 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u <Xml Include="..\..\data\hexchat.gresource.xml" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/src/fe-gtk/fe-gtk.vcxproj.filters b/src/fe-gtk/fe-gtk.vcxproj.filters index 4598b1f2..fe211a2d 100644 --- a/src/fe-gtk/fe-gtk.vcxproj.filters +++ b/src/fe-gtk/fe-gtk.vcxproj.filters @@ -93,6 +93,9 @@ <ClInclude Include="setup.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="notifications\notification-backend.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="ascii.c"> @@ -179,17 +182,23 @@ <ClCompile Include="xtext.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="resources.c"> + <ClCompile Include="$(HexChatLib)resources.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="plugin-notification.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="notifications\notification-windows.c"> <Filter>Source Files</Filter> </ClCompile> </ItemGroup> <ItemGroup> - <Manifest Include="hexchat.exe.manifest"> + <Manifest Include="..\..\win32\hexchat.exe.manifest"> <Filter>Resource Files</Filter> </Manifest> </ItemGroup> <ItemGroup> - <ResourceCompile Include="hexchat.rc"> + <ResourceCompile Include="$(HexChatLib)hexchat.rc"> <Filter>Resource Files</Filter> </ResourceCompile> </ItemGroup> 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; diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index eabe9c75..e2ca1192 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -62,7 +62,7 @@ static void gtkutil_file_req_destroy (GtkWidget * wid, struct file_req *freq) { freq->callback (freq->userdata, NULL); - free (freq); + g_free (freq); } static void @@ -255,7 +255,7 @@ gtkutil_file_req (const char *title, void *callback, void *userdata, char *filte gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), get_xdir (), NULL); - freq = malloc (sizeof (struct file_req)); + freq = g_new (struct file_req, 1); freq->dialog = dialog; freq->flags = flags; freq->callback = callback; diff --git a/src/fe-gtk/gtkutil.h b/src/fe-gtk/gtkutil.h index 87beed08..9547cb3b 100644 --- a/src/fe-gtk/gtkutil.h +++ b/src/fe-gtk/gtkutil.h @@ -33,14 +33,6 @@ GtkWidget *gtkutil_button (GtkWidget *box, char *stock, char *tip, void *callbac void gtkutil_label_new (char *text, GtkWidget * box); GtkWidget *gtkutil_entry_new (int max, GtkWidget * box, void *callback, gpointer userdata); -GtkWidget *gtkutil_clist_new (int columns, char *titles[], GtkWidget * box, - int policy, void *select_callback, - gpointer select_userdata, - void *unselect_callback, - gpointer unselect_userdata, int selection_mode); -int gtkutil_clist_selection (GtkWidget * clist); -int gtkutil_clist_multiple_selection (GtkWidget * clist, - int ** rows, const int max_rows); void show_and_unfocus (GtkWidget * wid); void gtkutil_set_icon (GtkWidget *win); GtkWidget *gtkutil_window_new (char *title, char *role, int width, int height, int flags); diff --git a/src/fe-gtk/hexchat.exe.manifest b/src/fe-gtk/hexchat.exe.manifest deleted file mode 100644 index 39c4eb4c..00000000 --- a/src/fe-gtk/hexchat.exe.manifest +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> - <assemblyIdentity - name="HexChat" - processorArchitecture="*" - version="1.0.0.0" - type="win32" - /> - <description>HexChat IRC Client</description> - <dependency> - <dependentAssembly> - <assemblyIdentity - type="win32" - name="Microsoft.Windows.Common-Controls" - version="6.0.0.0" - processorArchitecture="*" - publicKeyToken="6595b64144ccf1df" - language="*" - /> - </dependentAssembly> - </dependency> -</assembly> diff --git a/src/fe-gtk/hexchat.rc.tt b/src/fe-gtk/hexchat.rc.tt index 684ddfdb..35b0e6aa 100644 --- a/src/fe-gtk/hexchat.rc.tt +++ b/src/fe-gtk/hexchat.rc.tt @@ -1,9 +1,9 @@ #include <winver.h> -#include "../../config.h" +#include "config.h" #define COMMA_VERSION <#= [string]::Join(',', $versionParts) #>,0 -XC_ICON ICON "../../data/icons/hexchat.ico" +XC_ICON ICON "<#= $env:SOLUTIONDIR -replace '\\', '/' #>data/icons/hexchat.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION COMMA_VERSION @@ -15,6 +15,7 @@ VS_VERSION_INFO VERSIONINFO BEGIN VALUE "FileDescription", "HexChat IRC Client" + VALUE "CompanyName", "HexChat" VALUE "ProductName", "HexChat" VALUE "ProductVersion", PACKAGE_VERSION VALUE "FileVersion", PACKAGE_VERSION diff --git a/src/fe-gtk/joind.c b/src/fe-gtk/joind.c index 61ce8828..2fdbeb32 100644 --- a/src/fe-gtk/joind.c +++ b/src/fe-gtk/joind.c @@ -151,16 +151,16 @@ joind_show_dialog (server *serv) image1 = gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image1); gtk_box_pack_start (GTK_BOX (hbox1), image1, FALSE, TRUE, 24); - gtk_misc_set_alignment (GTK_MISC (image1), 0.5, 0.06); + gtk_misc_set_alignment (GTK_MISC (image1), 0.5f, 0.06f); vbox2 = gtk_vbox_new (FALSE, 10); gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6); gtk_widget_show (vbox2); gtk_box_pack_start (GTK_BOX (hbox1), vbox2, TRUE, TRUE, 0); - snprintf (buf2, sizeof (buf2), _("Connection to %s complete."), + g_snprintf (buf2, sizeof (buf2), _("Connection to %s complete."), server_get_network (serv, TRUE)); - snprintf (buf, sizeof (buf), "\n<b>%s</b>", buf2); + g_snprintf (buf, sizeof (buf), "\n<b>%s</b>", buf2); label = gtk_label_new (buf); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); @@ -198,7 +198,7 @@ joind_show_dialog (server *serv) gtk_widget_show (entry1); gtk_box_pack_start (GTK_BOX (hbox2), entry1, TRUE, TRUE, 8); - snprintf (buf, sizeof (buf), "<small> %s</small>", + g_snprintf (buf, sizeof (buf), "<small> %s</small>", _("If you know the name of the channel you want to join, enter it here.")); label = gtk_label_new (buf); gtk_widget_show (label); @@ -210,9 +210,8 @@ joind_show_dialog (server *serv) gtk_widget_show (radiobutton3); gtk_box_pack_start (GTK_BOX (vbox2), radiobutton3, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton3), radiobutton1_group); - radiobutton1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3)); - snprintf (buf, sizeof (buf), "<small> %s</small>", + g_snprintf (buf, sizeof (buf), "<small> %s</small>", _("Retrieving the Channel-List may take a minute or two.")); label = gtk_label_new (buf); gtk_widget_show (label); @@ -250,7 +249,6 @@ joind_show_dialog (server *serv) if (g_ascii_strcasecmp(((ircnet*)serv->network)->name, "freenode") == 0) { gtk_entry_set_text (GTK_ENTRY (entry1), "#hexchat"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(radiobutton2), TRUE); } gtk_widget_grab_focus (okbutton1); diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 2d50a98c..d718dba0 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -78,7 +78,7 @@ static void mg_link_irctab (session *sess, int focus); static session_gui static_mg_gui; static session_gui *mg_gui = NULL; /* the shared irc tab */ static int ignore_chanmode = FALSE; -static const char chan_flags[] = { 'c', 'n', 'r', 't', 'i', 'm', 'l', 'k' }; +static const char chan_flags[] = { 'c', 'n', 't', 'i', 'm', 'l', 'k' }; static chan *active_tab = NULL; /* active tab */ GtkWidget *parent_window = NULL; /* the master window */ @@ -312,7 +312,7 @@ mg_inputbox_cb (GtkWidget *igad, session_gui *gui) if (cmd[0] == 0) return; - cmd = strdup (cmd); + cmd = g_strdup (cmd); /* avoid recursive loop */ ignore = TRUE; @@ -340,7 +340,7 @@ mg_inputbox_cb (GtkWidget *igad, session_gui *gui) if (sess) handle_multiline (sess, cmd, TRUE, FALSE); - free (cmd); + g_free (cmd); } static gboolean @@ -393,42 +393,42 @@ fe_set_title (session *sess) switch (type) { case SESS_DIALOG: - snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s %s @ %s", + g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s %s @ %s", _("Dialog with"), sess->channel, server_get_network (sess->server, TRUE)); break; case SESS_SERVER: - snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s", + g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s", sess->server->nick, server_get_network (sess->server, TRUE)); break; case SESS_CHANNEL: /* don't display keys in the titlebar */ if (prefs.hex_gui_win_modes) { - snprintf (tbuf, sizeof (tbuf), + g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s / %s (%s)", sess->server->nick, server_get_network (sess->server, TRUE), sess->channel, sess->current_modes ? sess->current_modes : ""); } else { - snprintf (tbuf, sizeof (tbuf), + g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s / %s", sess->server->nick, server_get_network (sess->server, TRUE), sess->channel); } if (prefs.hex_gui_win_ucount) { - snprintf (tbuf + strlen (tbuf), 9, " (%d)", sess->total); + g_snprintf (tbuf + strlen (tbuf), 9, " (%d)", sess->total); } break; case SESS_NOTICES: case SESS_SNOTICES: - snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s (notices)", + g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s (notices)", sess->server->nick, server_get_network (sess->server, TRUE)); break; default: def: - snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME); + g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME); gtk_window_set_title (GTK_WINDOW (sess->gui->window), tbuf); return; } @@ -557,7 +557,7 @@ static int mg_progressbar_update (GtkWidget *bar) { static int type = 0; - static float pos = 0; + static gdouble pos = 0; pos += 0.05; if (pos >= 0.99) @@ -609,14 +609,14 @@ mg_unpopulate (session *sess) gui = sess->gui; res = sess->res; - res->input_text = strdup (SPELL_ENTRY_GET_TEXT (gui->input_box)); - res->topic_text = strdup (gtk_entry_get_text (GTK_ENTRY (gui->topic_entry))); - res->limit_text = strdup (gtk_entry_get_text (GTK_ENTRY (gui->limit_entry))); - res->key_text = strdup (gtk_entry_get_text (GTK_ENTRY (gui->key_entry))); + res->input_text = g_strdup (SPELL_ENTRY_GET_TEXT (gui->input_box)); + res->topic_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->topic_entry))); + res->limit_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->limit_entry))); + res->key_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->key_entry))); if (gui->laginfo) - res->lag_text = strdup (gtk_label_get_text (GTK_LABEL (gui->laginfo))); + res->lag_text = g_strdup (gtk_label_get_text (GTK_LABEL (gui->laginfo))); if (gui->throttleinfo) - res->queue_text = strdup (gtk_label_get_text (GTK_LABEL (gui->throttleinfo))); + res->queue_text = g_strdup (gtk_label_get_text (GTK_LABEL (gui->throttleinfo))); for (i = 0; i < NUM_FLAG_WIDS - 1; i++) res->flag_wid_state[i] = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gui->flag_wid[i])); @@ -645,7 +645,7 @@ mg_restore_label (GtkWidget *label, char **text) if (*text) { gtk_label_set_text (GTK_LABEL (label), *text); - free (*text); + g_free (*text); *text = NULL; } else { @@ -659,7 +659,7 @@ mg_restore_entry (GtkWidget *entry, char **text) if (*text) { gtk_entry_set_text (GTK_ENTRY (entry), *text); - free (*text); + g_free (*text); *text = NULL; } else { @@ -674,7 +674,7 @@ mg_restore_speller (GtkWidget *entry, char **text) if (*text) { SPELL_ENTRY_SET_TEXT (entry, *text); - free (*text); + g_free (*text); *text = NULL; } else { @@ -1096,8 +1096,11 @@ mg_tab_close (session *sess) else { for (i = 0, list = sess_list; list; list = list->next) - if (((session *)list->data)->server == sess->server) + { + session *s = (session*)list->data; + if (s->server == sess->server && (s->type == SESS_CHANNEL || s->type == SESS_DIALOG)) i++; + } dialog = gtk_message_dialog_new (GTK_WINDOW (parent_window), 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, _("This server still has %d channels or dialogs associated with it. " @@ -1331,8 +1334,7 @@ mg_close_gen (chan *ch, GtkWidget *box) { char *title = g_object_get_data (G_OBJECT (box), "title"); - if (title) - free (title); + g_free (title); if (!ch) ch = g_object_get_data (G_OBJECT (box), "ch"); if (ch) @@ -1568,7 +1570,7 @@ mg_create_tabmenu (session *sess, GdkEventButton *event, chan *ch) if (sess) { char *name = g_markup_escape_text (sess->channel[0] ? sess->channel : _("<none>"), -1); - snprintf (buf, sizeof (buf), "<span foreground=\"#3344cc\"><b>%s</b></span>", name); + g_snprintf (buf, sizeof (buf), "<span foreground=\"#3344cc\"><b>%s</b></span>", name); g_free (name); item = gtk_menu_item_new_with_label (""); @@ -1617,7 +1619,7 @@ static gboolean mg_tab_contextmenu_cb (chanview *cv, chan *ch, int tag, gpointer ud, GdkEventButton *event) { /* middle-click or shift-click to close a tab */ - if ((event->button == 2 || (event->button == 1 && event->state & STATE_SHIFT)) + if (((prefs.hex_gui_tab_middleclose && event->button == 2) || (event->button == 1 && event->state & STATE_SHIFT)) && event->type == GDK_BUTTON_PRESS) { mg_xbutton_cb (cv, ch, tag, ud); @@ -1640,7 +1642,7 @@ mg_dnd_drop_file (session *sess, char *target, char *uri) { char *p, *data, *next, *fname; - p = data = strdup (uri); + p = data = g_strdup (uri); while (*p) { next = strchr (p, '\r'); @@ -1652,7 +1654,7 @@ mg_dnd_drop_file (session *sess, char *target, char *uri) if (fname) { /* dcc_send() expects utf-8 */ - p = hexchat_filename_to_utf8 (fname, -1, 0, 0, 0); + p = g_filename_from_utf8 (fname, -1, 0, 0, 0); if (p) { dcc_send (sess, target, p, prefs.hex_dcc_max_send_cps, 0); @@ -1667,7 +1669,7 @@ mg_dnd_drop_file (session *sess, char *target, char *uri) if (*p == '\n') p++; } - free (data); + g_free (data); } @@ -1716,7 +1718,7 @@ mg_add_chan (session *sess) { sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext)); gtk_xtext_set_time_stamp (sess->res->buffer, prefs.hex_stamp_text); - sess->res->user_model = userlist_create_model (); + sess->res->user_model = userlist_create_model (sess); } } @@ -1837,7 +1839,7 @@ mg_changui_destroy (session *sess) /* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */ /* assertion `GDK_IS_COLORMAP (cmap)' failed */ ret = sess->gui->window; - free (sess->gui); + g_free (sess->gui); sess->gui = NULL; } return ret; @@ -1941,7 +1943,7 @@ flagl_hit (GtkWidget * wid, struct session *sess) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), FALSE); return; } - snprintf (modes, sizeof (modes), "+l %d", atoi (limit_str)); + g_snprintf (modes, sizeof (modes), "+l %d", atoi (limit_str)); serv->p_mode (serv, sess->channel, modes); serv->p_join_info (serv, sess->channel); } @@ -1957,7 +1959,7 @@ flagk_hit (GtkWidget * wid, struct session *sess) if (serv->connected && sess->channel[0]) { - snprintf (modes, sizeof (modes), "-k %s", + g_snprintf (modes, sizeof (modes), "-k %s", gtk_entry_get_text (GTK_ENTRY (sess->gui->key_entry))); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid))) @@ -2001,17 +2003,24 @@ mg_flagbutton_cb (GtkWidget *but, char *flag) static GtkWidget * mg_create_flagbutton (char *tip, GtkWidget *box, char *face) { - GtkWidget *wid; + GtkWidget *btn, *lbl; + char label_markup[16]; + + g_snprintf (label_markup, sizeof(label_markup), "<tt>%s</tt>", face); + lbl = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL(lbl), label_markup); - wid = gtk_toggle_button_new_with_label (face); - gtk_widget_set_size_request (wid, 18, 0); - gtk_widget_set_tooltip_text (wid, tip); - gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0); - g_signal_connect (G_OBJECT (wid), "toggled", + btn = gtk_toggle_button_new (); + gtk_widget_set_size_request (btn, -1, 0); + gtk_widget_set_tooltip_text (btn, tip); + gtk_container_add (GTK_CONTAINER(btn), lbl); + + gtk_box_pack_start (GTK_BOX (box), btn, 0, 0, 0); + g_signal_connect (G_OBJECT (btn), "toggled", G_CALLBACK (mg_flagbutton_cb), face); - show_and_unfocus (wid); + show_and_unfocus (btn); - return wid; + return btn; } static void @@ -2023,7 +2032,7 @@ mg_key_entry_cb (GtkWidget * igad, gpointer userdata) if (serv->connected && sess->channel[0]) { - snprintf (modes, sizeof (modes), "+k %s", + g_snprintf (modes, sizeof (modes), "+k %s", gtk_entry_get_text (GTK_ENTRY (igad))); serv->p_mode (serv, sess->channel, modes); serv->p_join_info (serv, sess->channel); @@ -2046,7 +2055,7 @@ mg_limit_entry_cb (GtkWidget * igad, gpointer userdata) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess->gui->flag_l), FALSE); return; } - snprintf (modes, sizeof(modes), "+l %d", + g_snprintf (modes, sizeof(modes), "+l %d", atoi (gtk_entry_get_text (GTK_ENTRY (igad)))); serv->p_mode (serv, sess->channel, modes); serv->p_join_info (serv, sess->channel); @@ -2066,7 +2075,6 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box) { gui->flag_c = mg_create_flagbutton (_("Filter Colors"), box, "c"); gui->flag_n = mg_create_flagbutton (_("No outside messages"), box, "n"); - gui->flag_r = mg_create_flagbutton (_("Registered Only"), box, "r"); gui->flag_t = mg_create_flagbutton (_("Topic Protection"), box, "t"); gui->flag_i = mg_create_flagbutton (_("Invite Only"), box, "i"); gui->flag_m = mg_create_flagbutton (_("Moderated"), box, "m"); @@ -2287,7 +2295,7 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even) case WORD_EMAIL: word[end] = 0; word += start; - tmp = g_strdup_printf("mailto:%s", word + (ispunct (*word)? 1: 0)); + tmp = g_strdup_printf ("mailto:%s", word + (ispunct (*word) ? 1 : 0)); menu_urlmenu (even, tmp); g_free (tmp); break; @@ -2597,7 +2605,7 @@ mg_change_nick (int cancel, char *text, gpointer userdata) if (!cancel) { - snprintf (buf, sizeof (buf), "nick %s", text); + g_snprintf (buf, sizeof (buf), "nick %s", text); handle_command (current_sess, buf, FALSE); } } @@ -2940,7 +2948,7 @@ mg_create_search(session *sess, GtkWidget *box) 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")); + highlight = gtk_check_button_new_with_mnemonic (_("_Highlight all")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(highlight), prefs.hex_text_search_highlight_all); 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); @@ -3165,7 +3173,7 @@ mg_create_topwindow (session *sess) sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext)); gtk_xtext_buffer_show (GTK_XTEXT (sess->gui->xtext), sess->res->buffer, TRUE); gtk_xtext_set_time_stamp (sess->res->buffer, prefs.hex_stamp_text); - sess->res->user_model = userlist_create_model (); + sess->res->user_model = userlist_create_model (sess); } userlist_show (sess); @@ -3332,7 +3340,7 @@ mg_add_generic_tab (char *name, char *title, void *family, GtkWidget *box) ch = chanview_add (mg_gui->chanview, name, NULL, box, TRUE, TAG_UTIL, pix_tree_util); chan_set_color (ch, plain_list); /* FIXME: memory leak */ - g_object_set_data (G_OBJECT (box), "title", strdup (title)); + g_object_set_data (G_OBJECT (box), "title", g_strdup (title)); g_object_set_data (G_OBJECT (box), "ch", ch); if (prefs.hex_gui_tab_newtofront) @@ -3395,7 +3403,7 @@ fe_clear_channel (session *sess) { if (sess->res->topic_text) { - free (sess->res->topic_text); + g_free (sess->res->topic_text); sess->res->topic_text = NULL; } } @@ -3506,32 +3514,26 @@ mg_changui_new (session *sess, restore_gui *res, int tab, int focus) { int first_run = FALSE; session_gui *gui; - struct User *user = NULL; - if (!res) + if (res == NULL) { - res = malloc (sizeof (restore_gui)); - memset (res, 0, sizeof (restore_gui)); + res = g_new0 (restore_gui, 1); } sess->res = res; - if (!sess->server->front_session) + if (sess->server->front_session == NULL) + { sess->server->front_session = sess; - - if (!is_channel (sess->server, sess->channel)) - user = userlist_find_global (sess->server, sess->channel); + } if (!tab) { - gui = malloc (sizeof (session_gui)); - memset (gui, 0, sizeof (session_gui)); + gui = g_new0 (session_gui, 1); gui->is_tab = FALSE; sess->gui = gui; mg_create_topwindow (sess); fe_set_title (sess); - if (user && user->hostname) - set_topic (sess, user->hostname, user->hostname); return; } @@ -3551,9 +3553,6 @@ mg_changui_new (session *sess, restore_gui *res, int tab, int focus) gui->is_tab = TRUE; } - if (user && user->hostname) - set_topic (sess, user->hostname, user->hostname); - mg_add_chan (sess); if (first_run || (prefs.hex_gui_tab_newtofront == FOCUS_NEW_ONLY_ASKED && focus) @@ -3631,8 +3630,8 @@ mg_set_title (GtkWidget *vbox, char *title) /* for non-irc tab/window only */ old = g_object_get_data (G_OBJECT (vbox), "title"); if (old) { - g_object_set_data (G_OBJECT (vbox), "title", strdup (title)); - free (old); + g_object_set_data (G_OBJECT (vbox), "title", g_strdup (title)); + g_free (old); } else { gtk_window_set_title (GTK_WINDOW (vbox), title); @@ -3650,7 +3649,7 @@ fe_server_callback (server *serv) if (serv->gui->rawlog_window) mg_close_gen (NULL, serv->gui->rawlog_window); - free (serv->gui); + g_free (serv->gui); } /* called when a session is being killed */ @@ -3661,34 +3660,21 @@ fe_session_callback (session *sess) if (sess->res->banlist && sess->res->banlist->window) mg_close_gen (NULL, sess->res->banlist->window); - if (sess->res->input_text) - free (sess->res->input_text); - - if (sess->res->topic_text) - free (sess->res->topic_text); - - if (sess->res->limit_text) - free (sess->res->limit_text); - - if (sess->res->key_text) - free (sess->res->key_text); - - if (sess->res->queue_text) - free (sess->res->queue_text); - if (sess->res->queue_tip) - free (sess->res->queue_tip); - - if (sess->res->lag_text) - free (sess->res->lag_text); - if (sess->res->lag_tip) - free (sess->res->lag_tip); + g_free (sess->res->input_text); + g_free (sess->res->topic_text); + g_free (sess->res->limit_text); + g_free (sess->res->key_text); + g_free (sess->res->queue_text); + g_free (sess->res->queue_tip); + g_free (sess->res->lag_text); + g_free (sess->res->lag_tip); if (sess->gui->bartag) fe_timeout_remove (sess->gui->bartag); if (sess->gui != &static_mg_gui) - free (sess->gui); - free (sess->res); + g_free (sess->gui); + g_free (sess->res); } /* ===== DRAG AND DROP STUFF ===== */ diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 945f6360..902af92e 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -137,7 +137,7 @@ nick_command_parse (session *sess, char *cmd, char *nick, char *allnick) /* this can't overflow, since popup->cmd is only 256 */ len = strlen (cmd) + strlen (nick) + strlen (allnick) + 512; - buf = malloc (len); + buf = g_malloc (len); auto_insert (buf, len, cmd, 0, 0, allnick, sess->channel, "", server_get_network (sess->server, TRUE), host, @@ -145,7 +145,7 @@ nick_command_parse (session *sess, char *cmd, char *nick, char *allnick) nick_command (sess, buf); - free (buf); + g_free (buf); } /* userlist button has been clicked */ @@ -166,11 +166,12 @@ userlist_button_cb (GtkWidget * button, char *cmd) if (sess->type == SESS_DIALOG) { /* fake a selection */ - nicks = malloc (sizeof (char *) * 2); + nicks = g_new (char *, 2); nicks[0] = g_strdup (sess->channel); nicks[1] = NULL; num_sel = 1; - } else + } + else { /* find number of selected rows */ nicks = userlist_selection_list (sess->gui->user_tree, &num_sel); @@ -178,14 +179,13 @@ userlist_button_cb (GtkWidget * button, char *cmd) { nick_command_parse (sess, cmd, "", ""); - if (nicks) - free (nicks); + g_free (nicks); return; } } /* create "allnicks" string */ - allnicks = malloc (((NICKLEN + 1) * num_sel) + 1); + allnicks = g_malloc (((NICKLEN + 1) * num_sel) + 1); *allnicks = 0; i = 0; @@ -218,8 +218,8 @@ userlist_button_cb (GtkWidget * button, char *cmd) g_free (nicks[num_sel]); } - free (nicks); - free (allnicks); + g_free (nicks); + g_free (allnicks); } /* a popup-menu-item has been selected */ @@ -393,9 +393,9 @@ toggle_cb (GtkWidget *item, char *pref_name) char buf[256]; if (GTK_CHECK_MENU_ITEM (item)->active) - snprintf (buf, sizeof (buf), "set %s 1", pref_name); + g_snprintf (buf, sizeof (buf), "set %s 1", pref_name); else - snprintf (buf, sizeof (buf), "set %s 0", pref_name); + g_snprintf (buf, sizeof (buf), "set %s 0", pref_name); handle_command (current_sess, buf, FALSE); } @@ -403,12 +403,11 @@ toggle_cb (GtkWidget *item, char *pref_name) static int is_in_path (char *cmd) { - char *prog = g_strdup (cmd + 1); /* 1st char is "!" */ - char *path, *orig; + char *orig = g_strdup (cmd + 1); /* 1st char is "!" */ + char *prog = orig; char **argv; int argc; - orig = prog; /* save for free()ing */ /* special-case these default entries. */ /* 123456789012345678 */ if (strncmp (prog, "gnome-terminal -x ", 18) == 0) @@ -417,15 +416,14 @@ is_in_path (char *cmd) if (g_shell_parse_argv (prog, &argc, &argv, NULL)) { - path = g_find_program_in_path (argv[0]); + char *path = g_find_program_in_path (argv[0]); + g_strfreev (argv); if (path) { g_free (path); g_free (orig); - g_strfreev (argv); return 1; } - g_strfreev (argv); } g_free (orig); @@ -588,7 +586,7 @@ menu_nickinfo_cb (GtkWidget *menu, session *sess) return; /* issue a /WHOIS */ - snprintf (buf, sizeof (buf), "WHOIS %s %s", str_copy, str_copy); + g_snprintf (buf, sizeof (buf), "WHOIS %s %s", str_copy, str_copy); handle_command (sess, buf, FALSE); /* and hide the output */ sess->server->skip_next_whois = 1; @@ -614,30 +612,30 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu) /* let the translators tweak this if need be */ fmt = _("<tt><b>%-11s</b></tt> %s"); - snprintf (unknown, sizeof (unknown), "<i>%s</i>", _("Unknown")); + g_snprintf (unknown, sizeof (unknown), "<i>%s</i>", _("Unknown")); if (user->realname) { real = strip_color (user->realname, -1, STRIP_ALL|STRIP_ESCMARKUP); - snprintf (buf, sizeof (buf), fmt, _("Real Name:"), real); + g_snprintf (buf, sizeof (buf), fmt, _("Real Name:"), real); g_free (real); } else { - snprintf (buf, sizeof (buf), fmt, _("Real Name:"), unknown); + g_snprintf (buf, sizeof (buf), fmt, _("Real Name:"), unknown); } item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), user->realname ? user->realname : unknown); - snprintf (buf, sizeof (buf), fmt, _("User:"), + g_snprintf (buf, sizeof (buf), fmt, _("User:"), user->hostname ? user->hostname : unknown); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), user->hostname ? user->hostname : unknown); - snprintf (buf, sizeof (buf), fmt, _("Account:"), + g_snprintf (buf, sizeof (buf), fmt, _("Account:"), user->account ? user->account : unknown); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", @@ -647,13 +645,13 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu) users_country = country (user->hostname); if (users_country) { - snprintf (buf, sizeof (buf), fmt, _ ("Country:"), users_country); + g_snprintf (buf, sizeof (buf), fmt, _ ("Country:"), users_country); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), users_country); } - snprintf (buf, sizeof (buf), fmt, _("Server:"), + g_snprintf (buf, sizeof (buf), fmt, _("Server:"), user->servername ? user->servername : unknown); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", @@ -664,12 +662,12 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu) { char min[96]; - snprintf (min, sizeof (min), _("%u minutes ago"), + g_snprintf (min, sizeof (min), _("%u minutes ago"), (unsigned int) ((time (0) - user->lasttalk) / 60)); - snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), min); + g_snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), min); } else { - snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), unknown); + g_snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), unknown); } menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); @@ -679,7 +677,7 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu) if (away) { char *msg = strip_color (away->message ? away->message : unknown, -1, STRIP_ALL|STRIP_ESCMARKUP); - snprintf (buf, sizeof (buf), fmt, _("Away Msg:"), msg); + g_snprintf (buf, sizeof (buf), fmt, _("Away Msg:"), msg); g_free (msg); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", @@ -728,16 +726,15 @@ menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel) struct User *user; GtkWidget *submenu, *menu = gtk_menu_new (); - if (str_copy) - free (str_copy); - str_copy = strdup (nick); + g_free (str_copy); + str_copy = g_strdup (nick); submenu_list = 0; /* first time through, might not be 0 */ /* more than 1 nick selected? */ if (num_sel > 1) { - snprintf (buf, sizeof (buf), _("%d nicks selected."), num_sel); + g_snprintf (buf, sizeof (buf), _("%d nicks selected."), num_sel); menu_quick_item (0, buf, menu, 0, 0, 0); menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0); } else @@ -938,7 +935,7 @@ open_url_cb (GtkWidget *item, char *url) char buf[512]; /* pass this to /URL so it can handle irc:// */ - snprintf (buf, sizeof (buf), "URL %s", url); + g_snprintf (buf, sizeof (buf), "URL %s", url); handle_command (current_sess, buf, FALSE); } @@ -948,20 +945,19 @@ menu_urlmenu (GdkEventButton *event, char *url) GtkWidget *menu; char *tmp, *chop; - if (str_copy) - free (str_copy); - str_copy = strdup (url); + g_free (str_copy); + str_copy = g_strdup (url); menu = gtk_menu_new (); /* more than 51 chars? Chop it */ if (g_utf8_strlen (str_copy, -1) >= 52) { - tmp = strdup (str_copy); + tmp = g_strdup (str_copy); chop = g_utf8_offset_to_pointer (tmp, 48); chop[0] = chop[1] = chop[2] = '.'; chop[3] = 0; menu_quick_item (0, tmp, menu, XCMENU_SHADED, 0, 0); - free (tmp); + g_free (tmp); } else { menu_quick_item (0, str_copy, menu, XCMENU_SHADED, 0, 0); @@ -988,7 +984,7 @@ menu_chan_cycle (GtkWidget * menu, char *chan) if (current_sess) { - snprintf (tbuf, sizeof tbuf, "CYCLE %s", chan); + g_snprintf (tbuf, sizeof tbuf, "CYCLE %s", chan); handle_command (current_sess, tbuf, FALSE); } } @@ -1000,7 +996,7 @@ menu_chan_part (GtkWidget * menu, char *chan) if (current_sess) { - snprintf (tbuf, sizeof tbuf, "part %s", chan); + g_snprintf (tbuf, sizeof tbuf, "part %s", chan); handle_command (current_sess, tbuf, FALSE); } } @@ -1012,7 +1008,7 @@ menu_chan_join (GtkWidget * menu, char *chan) if (current_sess) { - snprintf (tbuf, sizeof tbuf, "join %s", chan); + g_snprintf (tbuf, sizeof tbuf, "join %s", chan); handle_command (current_sess, tbuf, FALSE); } } @@ -1026,9 +1022,8 @@ menu_chanmenu (struct session *sess, GdkEventButton * event, char *chan) if (find_channel (sess->server, chan)) is_joined = TRUE; - if (str_copy) - free (str_copy); - str_copy = strdup (chan); + g_free (str_copy); + str_copy = g_strdup (chan); menu = gtk_menu_new (); @@ -1074,9 +1069,8 @@ menu_addfavoritemenu (server *serv, GtkWidget *menu, char *channel, gboolean ist if (channel != str_copy) { - if (str_copy) - free (str_copy); - str_copy = strdup (channel); + g_free (str_copy); + str_copy = g_strdup (channel); } if (istree) @@ -1717,7 +1711,7 @@ menu_about (GtkWidget *wid, gpointer sess) "You should have received a copy of the GNU General Public License\n" \ "along with this program. If not, see <http://www.gnu.org/licenses/>"; - g_snprintf (comment, sizeof(comment), "Compiled: "__DATE__"\n" + g_snprintf (comment, sizeof(comment), "" #ifdef WIN32 "Portable Mode: %s\n" "Build Type: x%d\n" diff --git a/src/fe-gtk/notifications/notification-backend.h b/src/fe-gtk/notifications/notification-backend.h new file mode 100644 index 00000000..b60ced4e --- /dev/null +++ b/src/fe-gtk/notifications/notification-backend.h @@ -0,0 +1,27 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * 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_PLUGIN_NOTIFICATION_BACKEND_H +#define HEXCHAT_PLUGIN_NOTIFICATION_BACKEND_H + +int notification_backend_supported (void); +void notification_backend_show (const char *title, const char *text); +int notification_backend_init (void); +void notification_backend_deinit (void); + +#endif diff --git a/src/fe-gtk/notifications/notification-dummy.c b/src/fe-gtk/notifications/notification-dummy.c new file mode 100644 index 00000000..022443bf --- /dev/null +++ b/src/fe-gtk/notifications/notification-dummy.c @@ -0,0 +1,39 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * 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 + */ + +void +notification_backend_show (const char *title, const char *text) +{ +} + +int +notification_backend_init (void) +{ + return 0; +} + +void +notification_backend_deinit (void) +{ +} + +int +notification_backend_supported (void) +{ + return 0; +} diff --git a/src/fe-gtk/notifications/notification-libnotify.c b/src/fe-gtk/notifications/notification-libnotify.c new file mode 100644 index 00000000..94f9679d --- /dev/null +++ b/src/fe-gtk/notifications/notification-libnotify.c @@ -0,0 +1,72 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * 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 "config.h" +#include <glib.h> +#include <libnotify/notify.h> + +static gboolean strip_markup = FALSE; + +void +notification_backend_show (const char *title, const char *text) +{ + NotifyNotification *notification; + + if (strip_markup) + text = g_markup_escape_text (text, -1); + + notification = notify_notification_new (title, text, "hexchat"); + notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("hexchat")); + + notify_notification_show (notification, NULL); + + g_object_unref (notification); + if (strip_markup) + g_free ((char*)text); +} + +int +notification_backend_init (void) +{ + GList* server_caps; + + if (!NOTIFY_CHECK_VERSION (0, 7, 0)) + return 0; + + if (!notify_init (PACKAGE_NAME)) + return 0; + + server_caps = notify_get_server_caps (); + if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)g_strcmp0)) + strip_markup = TRUE; + g_list_free_full (server_caps, g_free); + + return 1; +} + +void +notification_backend_deinit (void) +{ + notify_uninit (); +} + +int +notification_backend_supported (void) +{ + return notify_is_initted (); +} diff --git a/src/fe-gtk/notifications/notification-osx.m b/src/fe-gtk/notifications/notification-osx.m new file mode 100644 index 00000000..c9ad72d0 --- /dev/null +++ b/src/fe-gtk/notifications/notification-osx.m @@ -0,0 +1,54 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * 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 + */ + +#import <Cocoa/Cocoa.h> +#include <gtkosxapplication.h> + +void +notification_backend_show (const char *title, const char *text) +{ + NSString *str_title = [[NSString alloc] initWithUTF8String:title]; + NSString *str_text = [[NSString alloc] initWithUTF8String:text]; + + NSUserNotification *userNotification = [NSUserNotification new]; + userNotification.title = str_title; + userNotification.informativeText = str_text; + + NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; + [center scheduleNotification:userNotification]; + + [str_title release]; + [str_text release]; +} + +int +notification_backend_init (void) +{ + return 1; +} + +void +notification_backend_deinit (void) +{ +} + +int +notification_backend_supported (void) +{ + return gtkosx_application_get_bundle_id () != NULL; +} diff --git a/src/fe-gtk/notifications/notification-windows.c b/src/fe-gtk/notifications/notification-windows.c new file mode 100644 index 00000000..3fade306 --- /dev/null +++ b/src/fe-gtk/notifications/notification-windows.c @@ -0,0 +1,87 @@ +/* HexChat + * Copyright (C) 2015 Arnav Singh. + * + * 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 <gmodule.h> + +#include "hexchat.h" +#include "plugin.h" + +#include <Windows.h> + +void (*winrt_notification_backend_show) (const char *title, const char *text) = NULL; +int (*winrt_notification_backend_init) (void) = NULL; +void (*winrt_notification_backend_deinit) (void) = NULL; +int (*winrt_notification_backend_supported) (void) = NULL; + +void +notification_backend_show (const char *title, const char *text) +{ + if (winrt_notification_backend_show == NULL) + { + return; + } + + winrt_notification_backend_show (title, text); +} + +int +notification_backend_init (void) +{ + UINT original_error_mode; + GModule *module; + + /* Temporarily suppress the "DLL could not be loaded" dialog box before trying to load hcnotifications-winrt.dll */ + original_error_mode = GetErrorMode (); + SetErrorMode(SEM_FAILCRITICALERRORS); + module = module_load (HEXCHATLIBDIR "\\hcnotifications-winrt.dll"); + SetErrorMode (original_error_mode); + + if (module == NULL) + { + return 0; + } + + g_module_symbol (module, "notification_backend_show", (gpointer *) &winrt_notification_backend_show); + g_module_symbol (module, "notification_backend_init", (gpointer *) &winrt_notification_backend_init); + g_module_symbol (module, "notification_backend_deinit", (gpointer *) &winrt_notification_backend_deinit); + g_module_symbol (module, "notification_backend_supported", (gpointer *) &winrt_notification_backend_supported); + + return winrt_notification_backend_init (); +} + +void +notification_backend_deinit (void) +{ + if (winrt_notification_backend_deinit == NULL) + { + return; + } + + winrt_notification_backend_deinit (); +} + +int +notification_backend_supported (void) +{ + if (winrt_notification_backend_supported == NULL) + { + return 0; + } + + return winrt_notification_backend_supported (); +} diff --git a/src/fe-gtk/notifications/notification-winrt.cpp b/src/fe-gtk/notifications/notification-winrt.cpp new file mode 100644 index 00000000..663f9c08 --- /dev/null +++ b/src/fe-gtk/notifications/notification-winrt.cpp @@ -0,0 +1,100 @@ +/* HexChat + * Copyright (c) 2014 Leetsoftwerx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <string> +#include <codecvt> + +#include <roapi.h> +#include <windows.ui.notifications.h> + +using namespace Windows::UI::Notifications; +using namespace Windows::Data::Xml::Dom; + +static ToastNotifier ^ notifier = nullptr; + +static std::wstring +widen(const std::string & to_widen) +{ + std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter; + return converter.from_bytes(to_widen); +} + +extern "C" +{ + __declspec (dllexport) void + notification_backend_show (const char *title, const char *text) + { + try + { + auto toastTemplate = ToastNotificationManager::GetTemplateContent (ToastTemplateType::ToastText02); + auto node_list = toastTemplate->GetElementsByTagName ("text"); + UINT node_count = node_list->Length; + + auto wtitle = widen (title); + node_list->GetAt (0)->AppendChild ( + toastTemplate->CreateTextNode (Platform::StringReference (wtitle.c_str (), wtitle.size ()))); + + auto wtext = widen (text); + node_list->GetAt (1)->AppendChild ( + toastTemplate->CreateTextNode (Platform::StringReference (wtext.c_str (), wtext.size ()))); + + // Mute sound, we already play our own + auto node = toastTemplate->SelectSingleNode ("/toast"); + auto audio_elem = toastTemplate->CreateElement ("audio"); + audio_elem->SetAttribute ("silent", "true"); + static_cast<XmlElement^>(node)->AppendChild (audio_elem); + + notifier->Show (ref new ToastNotification (toastTemplate)); + } + catch (Platform::Exception ^ ex) + { + } + catch (...) + { + } + } + + __declspec (dllexport) int + notification_backend_init (void) + { + if (!notifier) + notifier = ToastNotificationManager::CreateToastNotifier ("HexChat.Desktop.Notify"); + + if (FAILED (Windows::Foundation::Initialize (RO_INIT_SINGLETHREADED))) + return 0; + + return 1; + } + + __declspec (dllexport) void + notification_backend_deinit (void) + { + notifier = nullptr; + Windows::Foundation::Uninitialize (); + } + + __declspec (dllexport) int + notification_backend_supported (void) + { + return 1; + } +} diff --git a/src/fe-gtk/notifications/notifications-winrt.vcxproj b/src/fe-gtk/notifications/notifications-winrt.vcxproj new file mode 100644 index 00000000..dcd2a2b7 --- /dev/null +++ b/src/fe-gtk/notifications/notifications-winrt.vcxproj @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClCompile Include="notification-winrt.cpp"> + <CompileAsWinRT>true</CompileAsWinRT> + </ClCompile> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{C53145CC-D021-40C9-B97C-0249AB9A43C9}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>notifications-winrt</RootNamespace> + <ProjectName>notifications-winrt</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <PlatformToolset>v120</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\..\win32\hexchat.props" /> + <PropertyGroup> + <TargetName>hcnotifications-winrt</TargetName> + <OutDir>$(HexChatRel)plugins\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;NDEBUG;_WINDOWS;_USRDLL;NOTIFICATIONS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalUsingDirectories>$(VCInstallDir)vcpackages;$(FrameworkSdkDir)References\CommonConfiguration\Neutral;%(AdditionalUsingDirectories)</AdditionalUsingDirectories> + </ClCompile> + <Link> + <AdditionalDependencies>$(DepLibs);mincore.lib;runtimeobject.lib;%(AdditionalDependencies)</AdditionalDependencies> + <MinimumRequiredVersion>6.03</MinimumRequiredVersion> + <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;NDEBUG;_WINDOWS;_USRDLL;NOTIFICATIONS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalUsingDirectories>$(VCInstallDir)vcpackages;$(FrameworkSdkDir)References\CommonConfiguration\Neutral;%(AdditionalUsingDirectories)</AdditionalUsingDirectories> + </ClCompile> + <Link> + <AdditionalDependencies>$(DepLibs);mincore.lib;runtimeobject.lib;%(AdditionalDependencies)</AdditionalDependencies> + <MinimumRequiredVersion>6.03</MinimumRequiredVersion> + <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project> diff --git a/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters b/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters new file mode 100644 index 00000000..06f4e558 --- /dev/null +++ b/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="notification-winrt.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/src/fe-gtk/notifygui.c b/src/fe-gtk/notifygui.c index 5aa60d0a..ed16f44f 100644 --- a/src/fe-gtk/notifygui.c +++ b/src/fe-gtk/notifygui.c @@ -190,11 +190,11 @@ notify_gui_update (void) { lastseenminutes = (int)(time (0) - lastseen) / 60; if (lastseenminutes < 60) - snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), lastseenminutes); + g_snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), lastseenminutes); else if (lastseenminutes < 120) - snprintf (agobuf, sizeof (agobuf), _("An hour ago")); + g_snprintf (agobuf, sizeof (agobuf), _("An hour ago")); else - snprintf (agobuf, sizeof (agobuf), _("%d hours ago"), lastseenminutes / 60); + g_snprintf (agobuf, sizeof (agobuf), _("%d hours ago"), lastseenminutes / 60); seen = agobuf; } if (!valid) /* create new tree row if required */ @@ -219,7 +219,7 @@ notify_gui_update (void) name = ""; server = server_get_network (servnot->server, TRUE); - snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), (int)(time (0) - lastseen) / 60); + g_snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), (int)(time (0) - lastseen) / 60); seen = agobuf; if (!valid) /* create new tree row if required */ @@ -380,7 +380,7 @@ fe_notify_ask (char *nick, char *networks) gtk_table_attach_defaults (GTK_TABLE (table), wid, 1, 2, 2, 3); label = gtk_label_new (NULL); - snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", _("Comma separated list of networks is accepted.")); + g_snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", _("Comma separated list of networks is accepted.")); gtk_label_set_markup (GTK_LABEL (label), buf); gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 3, 4); diff --git a/src/fe-gtk/palette.c b/src/fe-gtk/palette.c index 435ba84b..17689756 100644 --- a/src/fe-gtk/palette.c +++ b/src/fe-gtk/palette.c @@ -106,45 +106,39 @@ palette_alloc (GtkWidget * widget) void palette_load (void) { - int i, j, l, fh; + int i, j, fh; char prefname[256]; struct stat st; char *cfg; - int red, green, blue; + guint16 red, green, blue; fh = hexchat_open_file ("colors.conf", O_RDONLY, 0, 0); if (fh != -1) { fstat (fh, &st); - cfg = malloc (st.st_size + 1); - if (cfg) + cfg = g_malloc0 (st.st_size + 1); + read (fh, cfg, st.st_size); + + /* mIRC colors 0-31 are here */ + for (i = 0; i < 32; i++) + { + g_snprintf (prefname, sizeof prefname, "color_%d", i); + cfg_get_color (cfg, prefname, &red, &green, &blue); + colors[i].red = red; + colors[i].green = green; + colors[i].blue = blue; + } + + /* our special colors are mapped at 256+ */ + for (i = 256, j = 32; j < MAX_COL+1; i++, j++) { - cfg[0] = '\0'; - l = read (fh, cfg, st.st_size); - if (l >= 0) - cfg[l] = '\0'; - - /* mIRC colors 0-31 are here */ - for (i = 0; i < 32; i++) - { - snprintf (prefname, sizeof prefname, "color_%d", i); - cfg_get_color (cfg, prefname, &red, &green, &blue); - colors[i].red = red; - colors[i].green = green; - colors[i].blue = blue; - } - - /* our special colors are mapped at 256+ */ - for (i = 256, j = 32; j < MAX_COL+1; i++, j++) - { - snprintf (prefname, sizeof prefname, "color_%d", i); - cfg_get_color (cfg, prefname, &red, &green, &blue); - colors[j].red = red; - colors[j].green = green; - colors[j].blue = blue; - } - free (cfg); + g_snprintf (prefname, sizeof prefname, "color_%d", i); + cfg_get_color (cfg, prefname, &red, &green, &blue); + colors[j].red = red; + colors[j].green = green; + colors[j].blue = blue; } + g_free (cfg); close (fh); } } @@ -161,14 +155,14 @@ palette_save (void) /* mIRC colors 0-31 are here */ for (i = 0; i < 32; i++) { - snprintf (prefname, sizeof prefname, "color_%d", i); + g_snprintf (prefname, sizeof prefname, "color_%d", i); cfg_put_color (fh, colors[i].red, colors[i].green, colors[i].blue, prefname); } /* our special colors are mapped at 256+ */ for (i = 256, j = 32; j < MAX_COL+1; i++, j++) { - snprintf (prefname, sizeof prefname, "color_%d", i); + g_snprintf (prefname, sizeof prefname, "color_%d", i); cfg_put_color (fh, colors[j].red, colors[j].green, colors[j].blue, prefname); } diff --git a/src/fe-gtk/pixmaps.c b/src/fe-gtk/pixmaps.c index cbec6f71..053afaaf 100644 --- a/src/fe-gtk/pixmaps.c +++ b/src/fe-gtk/pixmaps.c @@ -87,10 +87,9 @@ pixmap_load_from_file (char *filename) static GdkPixbuf * load_pixmap (const char *filename) { - gchar *path; GdkPixbuf *pixbuf; - path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "icons" G_DIR_SEPARATOR_S "%s.png", get_xdir (), filename); + gchar *path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "icons" G_DIR_SEPARATOR_S "%s.png", get_xdir (), filename); pixbuf = gdk_pixbuf_new_from_file (path, 0); g_free (path); diff --git a/src/fe-gtk/plugin-notification.c b/src/fe-gtk/plugin-notification.c new file mode 100644 index 00000000..04a64213 --- /dev/null +++ b/src/fe-gtk/plugin-notification.c @@ -0,0 +1,215 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * 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 "config.h" +#include <glib.h> + +#include "../common/hexchat-plugin.h" +#include "../common/inbound.h" /* For alert_match_word() */ +#include "notifications/notification-backend.h" + +static hexchat_plugin *ph; + +static gboolean +should_alert (void) +{ + int omit_away, omit_focused, omit_tray; + + if (hexchat_get_prefs (ph, "gui_focus_omitalerts", NULL, &omit_focused) == 3 && omit_focused) + { + const char *status = hexchat_get_info (ph, "win_status"); + + if (status && !g_strcmp0 (status, "active")) + return FALSE; + } + + if (hexchat_get_prefs (ph, "away_omit_alerts", NULL, &omit_away) == 3 && omit_away) + { + if (hexchat_get_info (ph, "away")) + return FALSE; + } + + if (hexchat_get_prefs (ph, "gui_tray_quiet", NULL, &omit_tray) == 3 && omit_tray) + { + int tray_enabled; + + if (hexchat_get_prefs (ph, "gui_tray", NULL, &tray_enabled) == 3 && tray_enabled) + { + const char *status = hexchat_get_info (ph, "win_status"); + + if (status && g_strcmp0 (status, "hidden") != 0) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +is_ignored (char *nick) +{ + const char *no_hilight; + + if (hexchat_get_prefs (ph, "irc_no_hilight", &no_hilight, NULL) == 1 && no_hilight) + { + return alert_match_word (nick, (char*)no_hilight); + } + return FALSE; +} + +static void +show_notification (const char *title, const char *text) +{ + char *stripped_title, *stripped_text; + + /* Strip all colors */ + stripped_title = hexchat_strip (ph, title, -1, 7); + stripped_text = hexchat_strip (ph, text, -1, 7); + + notification_backend_show (stripped_title, stripped_text); + + hexchat_free (ph, stripped_title); + hexchat_free (ph, stripped_text); +} + +static void +show_notificationf (const char *text, const char *format, ...) +{ + va_list args; + char *buf; + + va_start (args, format); + buf = g_strdup_vprintf (format, args); + va_end (args); + + show_notification (buf, text); + g_free (buf); +} + +static int +incoming_hilight_cb (char *word[], gpointer userdata) +{ + int hilight; + + if (hexchat_get_prefs (ph, "input_balloon_hilight", NULL, &hilight) == 3 && hilight && should_alert()) + { + show_notificationf (word[2], _("Highlighted message from: %s (%s)"), word[1], hexchat_get_info (ph, "channel")); + } + return HEXCHAT_EAT_NONE; +} + +static int +incoming_message_cb (char *word[], gpointer userdata) +{ + int message; + + if (hexchat_get_prefs (ph, "input_balloon_chans", NULL, &message) == 3 && message && should_alert ()) + { + show_notificationf (word[2], _("Channel message from: %s (%s)"), word[1], hexchat_get_info (ph, "channel")); + } + return HEXCHAT_EAT_NONE; +} + +static int +incoming_priv_cb (char *word[], gpointer userdata) +{ + int priv; + + if (hexchat_get_prefs (ph, "input_balloon_priv", NULL, &priv) == 3 && priv && should_alert ()) + { + const char *network = hexchat_get_info (ph, "network"); + if (!network) + network = hexchat_get_info (ph, "server"); + + if (userdata != NULL) /* Special event */ + { + if (GPOINTER_TO_INT (userdata) == 3) + { + if (!is_ignored (word[2])) + show_notificationf (word[1], _("File offer from: %s (%s)"), word[2], network); + } + else if (GPOINTER_TO_INT (userdata) == 2) + { + if (!is_ignored (word[2])) + show_notificationf (word[1], _("Invited to channel by: %s (%s)"), word[2], network); + } + else + { + if (!is_ignored (word[1])) + show_notificationf (word[2], _("Notice from: %s (%s)"), word[1], network); + } + } + else + show_notificationf (word[2], _("Private message from: %s (%s)"), word[1], network); + } + return HEXCHAT_EAT_NONE; +} + +static int +tray_cmd_cb (char *word[], char *word_eol[], gpointer userdata) +{ + if (word[2] && !g_ascii_strcasecmp (word[2], "-b") && word[3] && word[4]) + { + if (should_alert ()) + show_notification (word[3], word_eol[4]); + return HEXCHAT_EAT_ALL; + } + + return HEXCHAT_EAT_NONE; +} + +int +notification_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) +{ + if (!notification_backend_init ()) + return 0; + + ph = plugin_handle; + *plugin_name = ""; + *plugin_desc = ""; + *plugin_version = ""; + + hexchat_hook_print (ph, "Channel Msg Hilight", HEXCHAT_PRI_LOWEST, incoming_hilight_cb, NULL); + hexchat_hook_print (ph, "Channel Action Hilight", HEXCHAT_PRI_LOWEST, incoming_hilight_cb, NULL); + + hexchat_hook_print (ph, "Channel Message", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL); + hexchat_hook_print (ph, "Channel Action", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL); + hexchat_hook_print (ph, "Channel Notice", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL); + + hexchat_hook_print (ph, "Private Message", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + hexchat_hook_print (ph, "Private Message to Dialog", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + hexchat_hook_print (ph, "Private Action", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + hexchat_hook_print (ph, "Private Action to Dialog", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL); + + /* Special events treated as priv */ + hexchat_hook_print (ph, "Notice", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (1)); + hexchat_hook_print (ph, "Invited", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (2)); + hexchat_hook_print (ph, "DCC Offer", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (3)); + + hexchat_hook_command (ph, "TRAY", HEXCHAT_PRI_HIGH, tray_cmd_cb, NULL, NULL); + + return 1; +} + + +int +notification_plugin_deinit (void) +{ + notification_backend_deinit (); + return 1; +} diff --git a/src/fe-gtk/plugin-notification.h b/src/fe-gtk/plugin-notification.h new file mode 100644 index 00000000..07ad1609 --- /dev/null +++ b/src/fe-gtk/plugin-notification.h @@ -0,0 +1,25 @@ +/* HexChat + * Copyright (C) 2015 Patrick Griffis. + * + * 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_PLUGIN_NOTIFICATION_H +#define HEXCHAT_PLUGIN_NOTIFICATION_H + +int notification_plugin_init (void *, char **, char **, char **, char *); +int notification_plugin_deinit (void *); + +#endif diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c index b3e34c0a..077a7c63 100644 --- a/src/fe-gtk/plugin-tray.c +++ b/src/fe-gtk/plugin-tray.c @@ -34,18 +34,6 @@ #include <unistd.h> #endif -#ifdef USE_LIBNOTIFY -#include <libnotify/notify.h> -#ifndef NOTIFY_CHECK_VERSION -#define NOTIFY_CHECK_VERSION(x,y,z) 0 -#endif -#if NOTIFY_CHECK_VERSION(0,7,0) -#define XC_NOTIFY_NEW(a,b,c,d) notify_notification_new(a,b,c) -#else -#define XC_NOTIFY_NEW(a,b,c,d) notify_notification_new(a,b,c,d) -#endif -#endif - typedef enum /* current icon status */ { TS_NONE, @@ -154,82 +142,6 @@ fe_tray_set_tooltip (const char *text) gtk_status_icon_set_tooltip_text (sticon, text); } -void -fe_tray_set_balloon (const char *title, const char *text) -{ -#ifndef WIN32 -#if 0 - const char *argv[8]; - const char *path; - char time[16]; -#endif - WinStatus ws; - - /* no balloons if the window is focused */ - ws = tray_get_window_status (); - if ((prefs.hex_away_omit_alerts && hexchat_get_info(ph, "away")) || - (prefs.hex_gui_focus_omitalerts && ws == WS_FOCUSED)) - return; - - /* bit 1 of flags means "no balloons unless hidden/iconified" */ - if (ws != WS_HIDDEN && prefs.hex_gui_tray_quiet) - return; - - /* FIXME: this should close the current balloon */ - if (!text) - return; - -#ifdef USE_LIBNOTIFY - static int notify_text_strip_flags = STRIP_ALL; - NotifyNotification *notification; - char *notify_text, *notify_title; - - if (!notify_is_initted()) - { - notify_init(PACKAGE_NAME); - - GList* server_caps = notify_get_server_caps (); - if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)strcmp)) - { - notify_text_strip_flags |= STRIP_ESCMARKUP; - } - g_list_free_full (server_caps, g_free); - } - - notify_text = strip_color (text, -1, notify_text_strip_flags); - notify_title = strip_color (title, -1, STRIP_ALL); - - notification = XC_NOTIFY_NEW (notify_title, notify_text, HEXCHATSHAREDIR "/icons/hicolor/scalable/apps/hexchat.svg", NULL); - -#if NOTIFY_CHECK_VERSION(0,7,0) - notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("hexchat")); -#endif - - g_free ((char *)notify_title); - g_free ((char *)notify_text); - - notify_notification_set_timeout (notification, prefs.hex_input_balloon_time*1000); - notify_notification_show (notification, NULL); - - g_object_unref (notification); -#endif -#endif -} - -static void -tray_set_balloonf (const char *text, const char *format, ...) -{ - va_list args; - char *buf; - - va_start (args, format); - buf = g_strdup_vprintf (format, args); - va_end (args); - - fe_tray_set_balloon (buf, text); - g_free (buf); -} - static void tray_set_tipf (const char *format, ...) { @@ -575,26 +487,32 @@ tray_menu_destroy (GtkWidget *menu, gpointer userdata) } #ifdef WIN32 -static void +static gboolean tray_menu_enter_cb (GtkWidget *menu) { tray_menu_inactivetime = 0; + return FALSE; } -static void +static gboolean tray_menu_left_cb (GtkWidget *menu) { tray_menu_inactivetime = g_get_real_time (); + return FALSE; } -static void +static gboolean tray_check_hide (GtkWidget *menu) { if (tray_menu_inactivetime && g_get_real_time () - tray_menu_inactivetime >= 2000000) { tray_menu_destroy (menu, NULL); + return G_SOURCE_REMOVE; } + + return G_SOURCE_CONTINUE; } +#endif static void tray_menu_settings (GtkWidget * wid, gpointer none) @@ -602,7 +520,6 @@ tray_menu_settings (GtkWidget * wid, gpointer none) extern void setup_open (void); setup_open (); } -#endif static void tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) @@ -651,10 +568,9 @@ tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) gtk_widget_set_sensitive (item, FALSE); menu_add_plugin_items (menu, "\x5$TRAY", NULL); -#ifdef WIN32 + tray_make_item (menu, NULL, tray_menu_quit_cb, NULL); mg_create_icon_item (_("_Preferences"), GTK_STOCK_PREFERENCES, menu, tray_menu_settings, NULL); -#endif tray_make_item (menu, NULL, tray_menu_quit_cb, NULL); mg_create_icon_item (_("_Quit"), GTK_STOCK_QUIT, menu, tray_menu_quit_cb, NULL); @@ -669,7 +585,7 @@ tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) g_signal_connect (G_OBJECT (menu), "enter-notify-event", G_CALLBACK (tray_menu_enter_cb), NULL); - tray_menu_timer = g_timeout_add(500, (GSourceFunc) tray_check_hide, menu); + tray_menu_timer = g_timeout_add (500, tray_check_hide, menu); #endif gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, @@ -718,10 +634,6 @@ tray_hilight_cb (char *word[], void *userdata) tray_hilight_count, word[1], hexchat_get_info (ph, "channel")); } - if (prefs.hex_input_balloon_hilight) - tray_set_balloonf (word[2], _("Highlighted message from: %s (%s)"), - word[1], hexchat_get_info (ph, "channel")); - return HEXCHAT_EAT_NONE; } @@ -743,10 +655,6 @@ tray_message_cb (char *word[], void *userdata) tray_set_tipf (_(DISPLAY_NAME": %u channel messages."), tray_pub_count); } - if (prefs.hex_input_balloon_chans) - tray_set_balloonf (word[2], _("Channel message from: %s (%s)"), - word[1], hexchat_get_info (ph, "channel")); - return HEXCHAT_EAT_NONE; } @@ -774,10 +682,6 @@ tray_priv (char *from, char *text) tray_set_tipf (_(DISPLAY_NAME": %u private messages, latest from: %s (%s)"), tray_priv_count, from, network); } - - if (prefs.hex_input_balloon_priv) - tray_set_balloonf (text, _("Private message from: %s (%s)"), - from, network); } static int @@ -822,10 +726,6 @@ tray_dcc_cb (char *word[], void *userdata) tray_file_count, word[1], network); } - if (prefs.hex_input_balloon_priv && (!prefs.hex_away_omit_alerts || tray_find_away_status () != 1)) - tray_set_balloonf ("", _("File offer from: %s (%s)"), - word[1], network); - return HEXCHAT_EAT_NONE; } @@ -904,8 +804,6 @@ tray_plugin_deinit (hexchat_plugin *plugin_handle) { #ifdef WIN32 tray_cleanup (); -#elif defined(USE_LIBNOTIFY) - notify_uninit (); #endif return 1; } diff --git a/src/fe-gtk/plugingui.c b/src/fe-gtk/plugingui.c index 9b3186a6..83e05727 100644 --- a/src/fe-gtk/plugingui.c +++ b/src/fe-gtk/plugingui.c @@ -142,23 +142,21 @@ plugingui_load_cb (session *sess, char *file) { if (file) { - char *buf = malloc (strlen (file) + 9); + char *buf; if (strchr (file, ' ')) - sprintf (buf, "LOAD \"%s\"", file); + buf = g_strdup_printf ("LOAD \"%s\"", file); else - sprintf (buf, "LOAD %s", file); + buf = g_strdup_printf ("LOAD %s", file); handle_command (sess, buf, FALSE); - free (buf); + g_free (buf); } } void plugingui_load (void) { - char *sub_dir; - - sub_dir = g_build_filename (get_xdir(), "addons", NULL); + char *sub_dir = g_build_filename (get_xdir(), "addons", NULL); gtkutil_file_req (_("Select a Plugin or Script to load"), plugingui_load_cb, current_sess, sub_dir, "*."G_MODULE_SUFFIX";*.lua;*.pl;*.py;*.tcl;*.js", FRF_FILTERISINITIAL|FRF_EXTENSIONS); @@ -175,7 +173,7 @@ plugingui_loadbutton_cb (GtkWidget * wid, gpointer unused) static void plugingui_unload (GtkWidget * wid, gpointer unused) { - char *modname, *file, *buf; + char *modname, *file; GtkTreeView *view; GtkTreeIter iter; @@ -188,16 +186,17 @@ plugingui_unload (GtkWidget * wid, gpointer unused) { if (plugin_kill (modname, FALSE) == 2) fe_message (_("That plugin is refusing to unload.\n"), FE_MSG_ERROR); - } else + } + else { + char *buf; /* let python.so or perl.so handle it */ - buf = malloc (strlen (file) + 10); if (strchr (file, ' ')) - sprintf (buf, "UNLOAD \"%s\"", file); + buf = g_strdup_printf ("UNLOAD \"%s\"", file); else - sprintf (buf, "UNLOAD %s", file); + buf = g_strdup_printf ("UNLOAD %s", file); handle_command (current_sess, buf, FALSE); - free (buf); + g_free (buf); } g_free (modname); @@ -211,14 +210,14 @@ plugingui_reloadbutton_cb (GtkWidget *wid, GtkTreeView *view) if (file) { - char *buf = malloc (strlen (file) + 9); + char *buf; if (strchr (file, ' ')) - sprintf (buf, "RELOAD \"%s\"", file); + buf = g_strdup_printf ("RELOAD \"%s\"", file); else - sprintf (buf, "RELOAD %s", file); + buf = g_strdup_printf ("RELOAD %s", file); handle_command (current_sess, buf, FALSE); - free (buf); + g_free (buf); g_free (file); } } diff --git a/src/fe-gtk/rawlog.c b/src/fe-gtk/rawlog.c index f2527492..1d4bf9fd 100644 --- a/src/fe-gtk/rawlog.c +++ b/src/fe-gtk/rawlog.c @@ -109,7 +109,7 @@ open_rawlog (struct server *serv) return; } - snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Raw Log (%s)"), serv->servername); + g_snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Raw Log (%s)"), serv->servername); serv->gui->rawlog_window = mg_create_generic_tab ("RawLog", tbuf, FALSE, TRUE, close_rawlog, serv, 640, 320, &vbox, serv); @@ -146,7 +146,7 @@ fe_add_rawlog (server *serv, char *text, int len, int outbound) { char **split_text; char *new_text; - int i; + size_t i; if (!serv->gui->rawlog_window) return; @@ -163,7 +163,7 @@ fe_add_rawlog (server *serv, char *text, int len, int outbound) else new_text = g_strconcat ("\0033>>\017 ", split_text[i], NULL); - gtk_xtext_append (GTK_XTEXT (serv->gui->rawlog_textlist)->buffer, new_text, strlen (new_text)); + gtk_xtext_append (GTK_XTEXT (serv->gui->rawlog_textlist)->buffer, new_text, strlen (new_text), 0); g_free (new_text); } diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c index f43a225a..f7909f72 100644 --- a/src/fe-gtk/servlistgui.c +++ b/src/fe-gtk/servlistgui.c @@ -90,7 +90,7 @@ static GtkWidget *servlist_open_edit (GtkWidget *parent, ircnet *net); static const char *pages[]= { IRC_DEFAULT_CHARSET, - "IRC (Latin/Unicode Hybrid)", + "CP1252 (Windows-1252)", "ISO-8859-15 (Western Europe)", "ISO-8859-2 (Central Europe)", "ISO-8859-7 (Greek)", @@ -497,7 +497,7 @@ servlist_addnet_cb (GtkWidget *item, GtkTreeView *treeview) ircnet *net; net = servlist_net_add (_("New Network"), "", TRUE); - net->encoding = strdup (IRC_DEFAULT_CHARSET); + net->encoding = g_strdup (IRC_DEFAULT_CHARSET); servlist_server_add (net, "newserver/6667"); store = (GtkListStore *)gtk_tree_view_get_model (treeview); @@ -668,13 +668,12 @@ servlist_favor (GtkWidget *button, gpointer none) static void servlist_update_from_entry (char **str, GtkWidget *entry) { - if (*str) - free (*str); + g_free (*str); if (gtk_entry_get_text (GTK_ENTRY (entry))[0] == 0) *str = NULL; else - *str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + *str = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); } static void @@ -960,10 +959,10 @@ servlist_savegui (void) if (!rfc_casecmp (nick1, nick2)) return 2; - strcpy (prefs.hex_irc_nick1, nick1); - strcpy (prefs.hex_irc_nick2, nick2); - strcpy (prefs.hex_irc_nick3, gtk_entry_get_text (GTK_ENTRY (entry_nick3))); - strcpy (prefs.hex_irc_user_name, gtk_entry_get_text (GTK_ENTRY (entry_guser))); + safe_strcpy (prefs.hex_irc_nick1, nick1, sizeof(prefs.hex_irc_nick1)); + safe_strcpy (prefs.hex_irc_nick2, nick2, sizeof(prefs.hex_irc_nick2)); + safe_strcpy (prefs.hex_irc_nick3, gtk_entry_get_text (GTK_ENTRY (entry_nick3)), sizeof(prefs.hex_irc_nick3)); + safe_strcpy (prefs.hex_irc_user_name, gtk_entry_get_text (GTK_ENTRY (entry_guser)), sizeof(prefs.hex_irc_user_name)); sp = strchr (prefs.hex_irc_user_name, ' '); if (sp) sp[0] = 0; /* spaces will break the login */ @@ -1203,9 +1202,9 @@ servlist_celledit_cb (GtkCellRendererText *cell, gchar *arg1, gchar *arg2, } netname = net->name; - net->name = strdup (arg2); + net->name = g_strdup (arg2); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, net->name, -1); - free (netname); + g_free (netname); } gtk_tree_path_free (path); @@ -1311,7 +1310,7 @@ servlist_sanitize_hostname (char *host) { char *ret, *c, *e; - ret = strdup (host); + ret = g_strdup (host); c = strchr (ret, ':'); e = strrchr (ret, ':'); @@ -1371,7 +1370,7 @@ servlist_editserver_cb (GtkCellRendererText *cell, gchar *name, gchar *newval, g servname = serv->hostname; serv->hostname = servlist_sanitize_hostname (newval); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, serv->hostname, -1); - free (servname); + g_free (servname); } } @@ -1409,7 +1408,7 @@ servlist_editcommand_cb (GtkCellRendererText *cell, gchar *name, gchar *newval, cmd = entry->command; entry->command = servlist_sanitize_command (newval); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, entry->command, -1); - free (cmd); + g_free (cmd); } } @@ -1508,9 +1507,8 @@ servlist_combo_cb (GtkEntry *entry, gpointer userdata) if (!selected_net) return; - if (selected_net->encoding) - free (selected_net->encoding); - selected_net->encoding = strdup (gtk_entry_get_text (entry)); + g_free (selected_net->encoding); + selected_net->encoding = g_strdup (gtk_entry_get_text (entry)); } /* Fills up the network's authentication type so that it's guaranteed to be either NULL or a valid value. */ @@ -1594,7 +1592,6 @@ servlist_create_charsetcombo (void) int i; cb = gtk_combo_box_text_new_with_entry (); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb), "System default"); i = 0; while (pages[i]) { @@ -1602,7 +1599,7 @@ servlist_create_charsetcombo (void) i++; } - gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN(cb))), selected_net->encoding ? selected_net->encoding : "System default"); + gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN(cb))), selected_net->encoding ? selected_net->encoding : pages[0]); g_signal_connect (G_OBJECT (gtk_bin_get_child (GTK_BIN (cb))), "changed", G_CALLBACK (servlist_combo_cb), NULL); @@ -1660,7 +1657,7 @@ bold_label (char *text) char buf[128]; GtkWidget *label; - snprintf (buf, sizeof (buf), "<b>%s</b>", text); + g_snprintf (buf, sizeof (buf), "<b>%s</b>", text); label = gtk_label_new (buf); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); @@ -1702,7 +1699,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net) editwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (editwindow), 4); - snprintf (buf, sizeof (buf), _(DISPLAY_NAME": Edit %s"), net->name); + g_snprintf (buf, sizeof (buf), _(DISPLAY_NAME": Edit %s"), net->name); gtk_window_set_title (GTK_WINDOW (editwindow), buf); gtk_window_set_default_size (GTK_WINDOW (editwindow), netedit_win_width, netedit_win_height); gtk_window_set_transient_for (GTK_WINDOW (editwindow), GTK_WINDOW (parent)); diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index e4372dc9..dc469591 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -36,6 +36,7 @@ #include "pixmaps.h" #include "menu.h" #include "plugin-tray.h" +#include "notifications/notification-backend.h" #ifdef WIN32 #include "../common/fe.h" @@ -314,6 +315,7 @@ static const setting tabs_settings[] = {ST_TOGGLE, N_("Show icons in the channel tree"), P_OFFINTNL(hex_gui_tab_icons), 0, 0, 0}, {ST_TOGGLE, N_("Show dotted lines in the channel tree"), P_OFFINTNL(hex_gui_tab_dots), 0, 0, 0}, {ST_TOGGLE, N_("Scroll mouse-wheel to change tabs"), P_OFFINTNL (hex_gui_tab_scrollchans), 0, 0, 0}, + {ST_TOGGLE, N_("Middle click to close tab"), P_OFFINTNL(hex_gui_tab_middleclose), 0, 0, 0}, {ST_TOGGLE, N_("Smaller text"), P_OFFINTNL(hex_gui_tab_small), 0, 0, 0}, {ST_MENU, N_("Focus new tabs:"), P_OFFINTNL(hex_gui_tab_newtofront), 0, focusnewtabsmenu, 0}, {ST_MENU, N_("Placement of notices:"), P_OFFINTNL(hex_irc_notice_pos), 0, noticeposmenu, 0}, @@ -396,9 +398,47 @@ static const setting alert_settings[] = {ST_HEADER, N_("Alerts"),0,0,0}, {ST_ALERTHEAD}, -#if !defined (WIN32) && !defined (__APPLE__) - {ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0}, + + + {ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0}, + {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0}, + {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0}, +#ifdef WIN32 + {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play the \"Instant Message Notification\" system sound upon the selected events"), (void *)beeplist, 0}, +#else +#ifdef USE_LIBCANBERRA + {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play \"message-new-instant\" from the freedesktop.org sound theme upon the selected events"), (void *)beeplist, 0}, +#else + {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play a GTK beep upon the selected events"), (void *)beeplist, 0}, #endif +#endif + + {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL(hex_away_omit_alerts), 0, 0, 0}, + {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0}, + + {ST_HEADER, N_("Tray Behavior"), 0, 0, 0}, + {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4}, + {ST_TOGGLE, N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0}, + {ST_TOGGLE, N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0}, + {ST_TOGGLE, N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0}, + {ST_TOGGLE, N_("Only show notifications when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0}, + + {ST_HEADER, N_("Highlighted Messages"),0,0,0}, + {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1}, + + {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight}, + {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight}, + {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight}, + {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")}, + + {ST_END, 0, 0, 0, 0, 0} +}; + +static const setting alert_settings_nonotifications[] = +{ + {ST_HEADER, N_("Alerts"),0,0,0}, + + {ST_ALERTHEAD}, {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0}, #ifdef HAVE_GTK_MAC {ST_3OGGLE, N_("Bounce dock icon on:"), 0, 0, (void *)taskbarlist, 0}, @@ -421,17 +461,10 @@ static const setting alert_settings[] = {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0}, {ST_HEADER, N_("Tray Behavior"), 0, 0, 0}, -#ifdef WIN32 - {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 3}, -#else {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4}, -#endif {ST_TOGGLE, N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0}, {ST_TOGGLE, N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0}, {ST_TOGGLE, N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0}, -#ifndef WIN32 - {ST_TOGGLE, N_("Only show tray balloons when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0}, -#endif {ST_HEADER, N_("Highlighted Messages"),0,0,0}, {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1}, @@ -449,7 +482,7 @@ static const setting alert_settings_unity[] = {ST_HEADER, N_("Alerts"),0,0,0}, {ST_ALERTHEAD}, - {ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0}, + {ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0}, {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0}, {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0}, @@ -467,6 +500,28 @@ static const setting alert_settings_unity[] = {ST_END, 0, 0, 0, 0, 0} }; +static const setting alert_settings_unityandnonotifications[] = +{ + {ST_HEADER, N_("Alerts"), 0, 0, 0}, + + {ST_ALERTHEAD}, + {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0}, + {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0}, + + {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL (hex_away_omit_alerts), 0, 0, 0}, + {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL (hex_gui_focus_omitalerts), 0, 0, 0}, + + {ST_HEADER, N_("Highlighted Messages"), 0, 0, 0}, + {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1}, + + {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL (hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight}, + {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL (hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight}, + {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL (hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight}, + {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")}, + + {ST_END, 0, 0, 0, 0, 0} +}; + static const setting general_settings[] = { {ST_HEADER, N_("Default Messages"),0,0,0}, @@ -559,9 +614,6 @@ static const char *const proxytypes[] = N_("Socks4"), N_("Socks5"), N_("HTTP"), -#ifdef USE_MSPROXY - N_("MS Proxy (ISA)"), -#endif #ifdef USE_LIBPROXY N_("Auto"), #endif @@ -598,11 +650,7 @@ static const setting network_settings[] = {ST_MENU, N_("Use proxy for:"), P_OFFINTNL(hex_net_proxy_use), 0, proxyuse, 0}, {ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0}, -#ifdef USE_MSPROXY - {ST_TOGGLE, N_("Use Authentication (MS Proxy, HTTP or Socks5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0}, -#else {ST_TOGGLE, N_("Use Authentication (HTTP or Socks5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0}, -#endif {ST_ENTRY, N_("Username:"), P_OFFSETNL(hex_net_proxy_user), 0, 0, sizeof prefs.hex_net_proxy_user}, {ST_ENTRY, N_("Password:"), P_OFFSETNL(hex_net_proxy_pass), 0, GINT_TO_POINTER(1), sizeof prefs.hex_net_proxy_pass}, @@ -630,7 +678,7 @@ setup_headlabel (GtkWidget *tab, int row, int col, char *text) char buf[128]; char *sp; - snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text); + g_snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text); sp = strchr (buf + 17, ' '); if (sp) *sp = '\n'; @@ -752,7 +800,7 @@ setup_create_italic_label (char *text) char buf[256]; label = gtk_label_new (NULL); - snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text); + g_snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text); gtk_label_set_markup (GTK_LABEL (label), buf); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); @@ -1121,8 +1169,8 @@ setup_entry_cb (GtkEntry *entry, setting *set) { int size; int pos; - int len = gtk_entry_get_text_length (entry); unsigned char *p = (unsigned char*)gtk_entry_get_text (entry); + int len = strlen (p); /* need to truncate? */ if (len >= set->extra) @@ -1220,9 +1268,9 @@ setup_create_header (GtkWidget *table, int row, char *labeltext) char buf[128]; if (row == 0) - snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext)); + g_snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext)); else - snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext)); + g_snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext)); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), buf); @@ -1683,9 +1731,8 @@ setup_snd_changed_cb (GtkEntry *ent, GtkTreeView *tree) return; /* get the new sound file */ - if (sound_files[n]) - free (sound_files[n]); - sound_files[n] = strdup (gtk_entry_get_text (GTK_ENTRY (ent))); + g_free (sound_files[n]); + sound_files[n] = g_strdup (gtk_entry_get_text (GTK_ENTRY (ent))); /* update the TreeView list */ store = (GtkListStore *)gtk_tree_view_get_model (tree); @@ -1790,7 +1837,7 @@ setup_add_page (const char *title, GtkWidget *book, GtkWidget *tab) /* label */ label = gtk_label_new (NULL); - snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title)); + g_snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title)); gtk_label_set_markup (GTK_LABEL (label), buf); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_misc_set_padding (GTK_MISC (label), 2, 1); @@ -1839,10 +1886,18 @@ setup_create_pages (GtkWidget *box) setup_add_page (cata[8], book, setup_create_page (general_settings)); - if (unity_mode ()) + if (unity_mode () && !notification_backend_supported ()) + { + setup_add_page (cata[9], book, setup_create_page (alert_settings_unityandnonotifications)); + } + else if (unity_mode ()) { setup_add_page (cata[9], book, setup_create_page (alert_settings_unity)); } + else if (!notification_backend_supported ()) + { + setup_add_page (cata[9], book, setup_create_page (alert_settings_nonotifications)); + } else { setup_add_page (cata[9], book, setup_create_page (alert_settings)); @@ -2121,6 +2176,8 @@ setup_apply (struct hexchatprefs *pr) noapply = TRUE; if (DIFF (hex_gui_ulist_style)) noapply = TRUE; + if (DIFF (hex_gui_ulist_sort)) + noapply = TRUE; if (DIFF (hex_gui_tab_dots)) do_layout = TRUE; @@ -2137,6 +2194,13 @@ setup_apply (struct hexchatprefs *pr) " menu first."), FE_MSG_WARN | FE_MSG_MARKUP); + /* format cannot be blank, there is already a setting for this */ + if (pr->hex_stamp_text_format[0] == 0) + { + pr->hex_stamp_text = 0; + strcpy (pr->hex_stamp_text_format, prefs.hex_stamp_text_format); + } + memcpy (&prefs, pr, sizeof (prefs)); #ifdef WIN32 diff --git a/src/fe-gtk/sexy-iso-codes.c b/src/fe-gtk/sexy-iso-codes.c index e6acb726..06c8cd07 100644 --- a/src/fe-gtk/sexy-iso-codes.c +++ b/src/fe-gtk/sexy-iso-codes.c @@ -19,10 +19,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" + #include "sexy-iso-codes.h" #include <libintl.h> #include <string.h> -#include "../../config.h" #define ISO_639_DOMAIN "iso_639" #define ISO_3166_DOMAIN "iso_3166" diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c index bac1e2b5..f57c7f41 100644 --- a/src/fe-gtk/sexy-spell-entry.c +++ b/src/fe-gtk/sexy-spell-entry.c @@ -31,7 +31,12 @@ #include <sys/types.h> #include <sys/stat.h> #include "sexy-iso-codes.h" + +#ifdef WIN32 +#include "marshal.h" +#else #include "../common/marshal.h" +#endif #ifdef WIN32 #include "../common/typedef.h" @@ -136,6 +141,8 @@ enum }; static guint signals[LAST_SIGNAL] = {0}; +static PangoAttrList *empty_attrs_list = NULL; + static gboolean spell_accumulator(GSignalInvocationHint *hint, GValue *return_accu, const GValue *handler_return, gpointer data) { @@ -243,6 +250,11 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass) _hexchat_marshal_BOOLEAN__STRING, G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + + if (empty_attrs_list == NULL) + { + empty_attrs_list = pango_attr_list_new (); + } } static void @@ -292,7 +304,7 @@ insert_hiddenchar (SexySpellEntry *entry, guint start, guint end) * is 'hidden' */ #if 0 PangoAttribute *hattr; - PangoRectangle *rect = g_malloc (sizeof (PangoRectangle)); + PangoRectangle *rect = g_new (PangoRectangle, 1); rect->x = 0; rect->y = 0; @@ -758,12 +770,9 @@ sexy_spell_entry_finalize(GObject *obj) pango_attr_list_unref(entry->priv->attr_list); if (entry->priv->dict_hash) g_hash_table_destroy(entry->priv->dict_hash); - if (entry->priv->words) - g_strfreev(entry->priv->words); - if (entry->priv->word_starts) - g_free(entry->priv->word_starts); - if (entry->priv->word_ends) - g_free(entry->priv->word_ends); + g_strfreev(entry->priv->words); + g_free(entry->priv->word_starts); + g_free(entry->priv->word_ends); if (have_enchant) { if (entry->priv->broker) { @@ -1038,7 +1047,7 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry) { /* Check for attributes */ text = gtk_entry_get_text (GTK_ENTRY (entry)); - text_len = gtk_entry_get_text_length (GTK_ENTRY (entry)); + text_len = strlen (text); check_attributes (entry, text, text_len); } @@ -1078,7 +1087,14 @@ sexy_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event) layout = gtk_entry_get_layout(gtk_entry); - pango_layout_set_attributes(layout, entry->priv->attr_list); + if (gtk_entry->preedit_length == 0) + { + pango_layout_set_attributes(layout, entry->priv->attr_list); + } + else + { + pango_layout_set_attributes(layout, empty_attrs_list); + } return GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event); } diff --git a/src/fe-gtk/textgui.c b/src/fe-gtk/textgui.c index 9956e9c6..b0f2f392 100644 --- a/src/fe-gtk/textgui.c +++ b/src/fe-gtk/textgui.c @@ -81,14 +81,14 @@ PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, ti timet = time (0); stamp_size = get_stamp_str (prefs.hex_stamp_text_format, timet, &stamp); - new_text = malloc (len + stamp_size + 1); + new_text = g_malloc (len + stamp_size + 1); memcpy (new_text, stamp, stamp_size); g_free (stamp); memcpy (new_text + stamp_size, text, len); - gtk_xtext_append (xtbuf, new_text, len + stamp_size); - free (new_text); + gtk_xtext_append (xtbuf, new_text, len + stamp_size, timet); + g_free (new_text); } else - gtk_xtext_append (xtbuf, text, len); + gtk_xtext_append (xtbuf, text, len, timet); return; } @@ -173,13 +173,12 @@ pevent_edited (GtkCellRendererText *render, gchar *pathstr, gchar *new_text, gpo } if (m > (te[sig].num_args & 0x7f)) { - free (out); - out = malloc (4096); - snprintf (out, 4096, - _("This signal is only passed %d args, $%d is invalid"), - te[sig].num_args & 0x7f, m); + g_free (out); + out = g_strdup_printf ( + _("This signal is only passed %d args, $%d is invalid"), + te[sig].num_args & 0x7f, m); fe_message (out, FE_MSG_WARN); - free (out); + g_free (out); return; } @@ -188,23 +187,20 @@ pevent_edited (GtkCellRendererText *render, gchar *pathstr, gchar *new_text, gpo gtk_list_store_set (GTK_LIST_STORE (model), &iter, TEXT_COLUMN, new_text, -1); gtk_tree_path_free (path); - if (pntevts_text[sig]) - free (pntevts_text[sig]); - if (pntevts[sig]) - free (pntevts[sig]); + g_free (pntevts_text[sig]); + g_free (pntevts[sig]); - pntevts_text[sig] = malloc (len + 1); - memcpy (pntevts_text[sig], text, len + 1); + pntevts_text[sig] = g_strdup (text); pntevts[sig] = out; - out = malloc (len + 2); + out = g_malloc (len + 2); memcpy (out, text, len + 1); out[len] = '\n'; out[len + 1] = 0; check_special_chars (out, TRUE); PrintTextRaw (xtext->buffer, out, 0, 0); - free (out); + g_free (out); /* Scroll to bottom */ gtk_adjustment_set_value (xtext->adj, gtk_adjustment_get_upper (xtext->adj)); @@ -328,14 +324,14 @@ pevent_test_cb (GtkWidget * wid, GtkWidget * twid) text = _(pntevts_text[n]); len = strlen (text); - out = malloc (len + 2); + out = g_malloc (len + 2); memcpy (out, text, len + 1); out[len] = '\n'; out[len + 1] = 0; check_special_chars (out, TRUE); PrintTextRaw (GTK_XTEXT (twid)->buffer, out, 0, 0); - free (out); + g_free (out); } } diff --git a/src/fe-gtk/userlistgui.c b/src/fe-gtk/userlistgui.c index 19564ece..d06975ca 100644 --- a/src/fe-gtk/userlistgui.c +++ b/src/fe-gtk/userlistgui.c @@ -42,11 +42,11 @@ enum { - COL_PIX=0, // GdkPixbuf * - COL_NICK=1, // char * - COL_HOST=2, // char * - COL_USER=3, // struct User * - COL_GDKCOLOR=4 // GdkColor * + COL_PIX=0, /* GdkPixbuf * */ + COL_NICK=1, /* char * */ + COL_HOST=2, /* char * */ + COL_USER=3, /* struct User * */ + COL_GDKCOLOR=4 /* GdkColor * */ }; @@ -105,7 +105,7 @@ fe_userlist_numbers (session *sess) { if (sess->total) { - snprintf (tbuf, sizeof (tbuf), _("%d ops, %d total"), sess->ops, sess->total); + g_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 @@ -188,7 +188,7 @@ userlist_selection_list (GtkWidget *widget, int *num_ret) if (num_sel < 1) return NULL; - nicks = malloc (sizeof (char *) * (num_sel + 1)); + nicks = g_new (char *, num_sel + 1); i = 0; gtk_tree_model_get_iter_first (model, &iter); @@ -286,7 +286,7 @@ fe_userlist_remove (session *sess, struct User *user) int sel; iter = find_row (GTK_TREE_VIEW (sess->gui->user_tree), - sess->res->user_model, user, &sel); + GTK_TREE_MODEL(sess->res->user_model), user, &sel); if (!iter) return 0; @@ -316,7 +316,7 @@ fe_userlist_rehash (session *sess, struct User *user) int nick_color = 0; iter = find_row (GTK_TREE_VIEW (sess->gui->user_tree), - sess->res->user_model, user, &sel); + GTK_TREE_MODEL(sess->res->user_model), user, &sel); if (!iter) return; @@ -332,9 +332,9 @@ fe_userlist_rehash (session *sess, struct User *user) } void -fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) +fe_userlist_insert (session *sess, struct User *newuser, gboolean sel) { - GtkTreeModel *model = sess->res->user_model; + GtkTreeModel *model = GTK_TREE_MODEL(sess->res->user_model); GdkPixbuf *pix = get_user_icon (sess->server, newuser); GtkTreeIter iter; char *nick; @@ -348,16 +348,16 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) nick = newuser->nick; if (!prefs.hex_gui_ulist_icons) { - nick = malloc (strlen (newuser->nick) + 2); + nick = g_malloc (strlen (newuser->nick) + 2); nick[0] = newuser->prefix[0]; - if (!nick[0] || nick[0] == ' ') + if (nick[0] == '\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, + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, 0, COL_PIX, pix, COL_NICK, nick, COL_HOST, newuser->hostname, @@ -367,7 +367,7 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) if (!prefs.hex_gui_ulist_icons) { - free (nick); + g_free (nick); } /* is it me? */ @@ -377,14 +377,6 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) 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) @@ -396,12 +388,6 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel) } 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); @@ -459,11 +445,67 @@ userlist_dnd_leave (GtkTreeView *widget, GdkDragContext *context, guint ttime) return TRUE; } -void * -userlist_create_model (void) +static int +userlist_alpha_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer userdata) +{ + struct User *user_a, *user_b; + + gtk_tree_model_get (model, iter_a, COL_USER, &user_a, -1); + gtk_tree_model_get (model, iter_b, COL_USER, &user_b, -1); + + return nick_cmp_alpha (user_a, user_b, ((session*)userdata)->server); +} + +static int +userlist_ops_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer userdata) { - return gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, + struct User *user_a, *user_b; + + gtk_tree_model_get (model, iter_a, COL_USER, &user_a, -1); + gtk_tree_model_get (model, iter_b, COL_USER, &user_b, -1); + + return nick_cmp_az_ops (((session*)userdata)->server, user_a, user_b); +} + +GtkListStore * +userlist_create_model (session *sess) +{ + GtkListStore *store; + GtkTreeIterCompareFunc cmp_func; + GtkSortType sort_type; + + store = gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR); + + switch (prefs.hex_gui_ulist_sort) + { + case 0: + cmp_func = userlist_ops_cmp; + sort_type = GTK_SORT_ASCENDING; + break; + case 1: + cmp_func = userlist_alpha_cmp; + sort_type = GTK_SORT_ASCENDING; + break; + case 2: + cmp_func = userlist_ops_cmp; + sort_type = GTK_SORT_DESCENDING; + break; + case 3: + cmp_func = userlist_alpha_cmp; + sort_type = GTK_SORT_DESCENDING; + break; + default: + /* No sorting */ + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(store), NULL, NULL, NULL); + return store; + } + + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(store), cmp_func, sess, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store), + GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, sort_type); + + return store; } static void @@ -525,7 +567,7 @@ userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata) i--; g_free (nicks[i]); } - free (nicks); + g_free (nicks); } return TRUE; } @@ -542,13 +584,13 @@ userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata) i--; g_free (nicks[i]); } - free (nicks); + g_free (nicks); return TRUE; } if (nicks) { g_free (nicks[0]); - free (nicks); + g_free (nicks); } sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); @@ -567,7 +609,7 @@ userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata) i--; g_free (nicks[i]); } - free (nicks); + g_free (nicks); } } else { @@ -668,7 +710,7 @@ void userlist_show (session *sess) { gtk_tree_view_set_model (GTK_TREE_VIEW (sess->gui->user_tree), - sess->res->user_model); + GTK_TREE_MODEL(sess->res->user_model)); } void diff --git a/src/fe-gtk/userlistgui.h b/src/fe-gtk/userlistgui.h index 993fe8f0..e24f2ebc 100644 --- a/src/fe-gtk/userlistgui.h +++ b/src/fe-gtk/userlistgui.h @@ -23,7 +23,7 @@ void userlist_set_value (GtkWidget *treeview, gfloat val); gfloat userlist_get_value (GtkWidget *treeview); GtkWidget *userlist_create (GtkWidget *box); -void *userlist_create_model (void); +GtkListStore *userlist_create_model (session *sess); void userlist_show (session *sess); void userlist_select (session *sess, char *name); char **userlist_selection_list (GtkWidget *widget, int *num_ret); diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index 6a499f52..6692b360 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -31,13 +31,19 @@ #include <stdlib.h> #include <time.h> -#include "../../config.h" +#include "config.h" #include "../common/hexchat.h" #include "../common/fe.h" #include "../common/util.h" #include "../common/hexchatc.h" #include "../common/url.h" + +#ifdef WIN32 +#include "marshal.h" +#else #include "../common/marshal.h" +#endif + #include "fe-gtk.h" #include "xtext.h" #include "fkeys.h" @@ -484,7 +490,10 @@ gtk_xtext_adjustment_set (xtext_buffer *buf, int fire_signal) adj->page_increment = adj->page_size; if (adj->value > adj->upper - adj->page_size) + { + buf->scrollbar_down = TRUE; adj->value = adj->upper - adj->page_size; + } if (adj->value < 0) adj->value = 0; @@ -829,7 +838,6 @@ find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent) int off, len, wid, mbl, mbw; /* Skip to the first chunk of stuff for the subline */ - list = ent->slp; if (subline > 0) { suboff = GPOINTER_TO_INT (g_slist_nth_data (ent->sublines, subline - 1)); @@ -846,6 +854,8 @@ find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent) list = ent->slp; } /* Step to the first character of the subline */ + if (list == NULL) + return 0; meta = list->data; off = meta->off; len = meta->len; @@ -934,12 +944,12 @@ gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline, } static textentry * -gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, - int *out_of_bounds, int *ret_subline) +gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, int *out_of_bounds) { textentry *ent; int line; int subline; + int outofbounds; /* Adjust y value for negative rounding, double to int */ if (y < 0) @@ -948,13 +958,12 @@ gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, line = (y + xtext->pixel_offset) / xtext->fontsize; ent = gtk_xtext_nth (xtext, line + (int)xtext->adj->value, &subline); if (!ent) - return 0; + return NULL; if (off) - *off = gtk_xtext_find_x (xtext, x, ent, subline, line, out_of_bounds); - - if (ret_subline) - *ret_subline = subline; + *off = gtk_xtext_find_x (xtext, x, ent, subline, line, &outofbounds); + if (out_of_bounds) + *out_of_bounds = outofbounds; return ent; } @@ -1049,14 +1058,14 @@ gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area) return; } - ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL, NULL); + ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL); if (!ent_start) { xtext_draw_bg (xtext, area->x, area->y, area->width, area->height); goto xit; } ent_end = gtk_xtext_find_char (xtext, area->x + area->width, - area->y + area->height, NULL, NULL, NULL); + area->y + area->height, NULL, NULL); if (!ent_end) ent_end = xtext->buffer->text_last; @@ -1244,13 +1253,14 @@ lamejump: } } /* marking upward? */ - else if (xtext->buffer->last_ent_end == end_ent && + else if (xtext->buffer->last_ent_start != NULL && + xtext->buffer->last_ent_end == end_ent && xtext->buffer->last_offset_end == end_offset) { ent = end_ent; while (ent) { - if (ent == start_ent) + if (ent == start_ent && xtext->buffer->last_ent_start) { gtk_xtext_selection_up (xtext, xtext->buffer->last_ent_start, ent, start_offset); /*gtk_xtext_render_ents (xtext, xtext->buffer->last_ent_start, ent);*/ @@ -1299,99 +1309,104 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren textentry *ent; textentry *ent_end; textentry *ent_start; - int offset_start; - int offset_end; - int subline_start; - int subline_end; - int oob; - int marking_up = FALSE; - int len_start; - int len_end; + int offset_start = 0; + int offset_end = 0; + textentry *low_ent, *high_ent; + int low_x, low_y, low_offs; + int high_x, high_y, high_offs, high_len; - ent_start = gtk_xtext_find_char (xtext, xtext->select_start_x, xtext->select_start_y, &offset_start, &oob, &subline_start); - ent_end = gtk_xtext_find_char (xtext, xtext->select_end_x, xtext->select_end_y, &offset_end, &oob, &subline_end); + if (xtext->buffer->text_first == NULL) + return; - if ((!ent_start || !ent_end) && !xtext->buffer->text_last && xtext->adj->value != xtext->buffer->old_value) - { - gtk_xtext_render_page (xtext); + ent_start = gtk_xtext_find_char (xtext, xtext->select_start_x, xtext->select_start_y, &offset_start, NULL); + ent_end = gtk_xtext_find_char (xtext, xtext->select_end_x, xtext->select_end_y, &offset_end, NULL); + if (ent_start == NULL && ent_end == NULL) return; - } - if (!ent_start) + if ((ent_start != ent_end && xtext->select_start_y > xtext->select_end_y) || /* different entries */ + (ent_start == ent_end && offset_start > offset_end)) /* same entry, different character offsets */ { - ent_start = xtext->buffer->text_last; - offset_start = ent_start->str_len; + /* marking up */ + low_ent = ent_end; + low_x = xtext->select_end_x; + low_y = xtext->select_end_y; + low_offs = offset_end; + high_ent = ent_start; + high_x = xtext->select_start_x; + high_y = xtext->select_start_y; + high_offs = offset_start; } - - if (!ent_end) + else { - ent_end = xtext->buffer->text_last; - offset_end = ent_end->str_len; + /* marking down */ + low_ent = ent_start; + low_x = xtext->select_start_x; + low_y = xtext->select_start_y; + low_offs = offset_start; + high_ent = ent_end; + high_x = xtext->select_end_x; + high_y = xtext->select_end_y; + high_offs = offset_end; } - - if ((ent_start != ent_end && xtext->select_start_y > xtext->select_end_y) || /* different entries */ - (ent_start == ent_end && subline_start > subline_end) || /* different lines */ - (ent_start == ent_end && subline_start == subline_end && xtext->select_start_x > xtext->select_end_x)) /* marking to the left */ + if (low_ent == NULL) + { + low_ent = xtext->buffer->text_first; + low_offs = 0; + } + if (high_ent == NULL) { - marking_up = TRUE; + high_ent = xtext->buffer->text_last; + high_offs = high_ent->str_len; } /* word selection */ if (xtext->word_select) { /* a word selection cannot be started if the cursor is out of bounds in gtk_xtext_button_press */ - gtk_xtext_get_word (xtext, xtext->select_start_x, xtext->select_start_y, NULL, &offset_start, &len_start, NULL); + gtk_xtext_get_word (xtext, low_x, low_y, NULL, &low_offs, NULL, NULL); /* in case the cursor is out of bounds we keep offset_end from gtk_xtext_find_char and fix the length */ - if (gtk_xtext_get_word (xtext, xtext->select_end_x, xtext->select_end_y, NULL, &offset_end, &len_end, NULL) == NULL) - len_end = offset_end == ent_end->str_len? 0: -1; /* -1 for the space, 0 if at the end */ - - if (!marking_up) - offset_end += len_end; - else - offset_start += len_start; + if (gtk_xtext_get_word (xtext, high_x, high_y, NULL, &high_offs, &high_len, NULL) == NULL) + high_len = high_offs == high_ent->str_len? 0: -1; /* -1 for the space, 0 if at the end */ + high_offs += high_len; + if (low_y < 0) + low_offs = xtext->buffer->last_offset_start; + if (high_y > xtext->buffer->window_height) + high_offs = xtext->buffer->last_offset_end; } /* line/ent selection */ else if (xtext->line_select) { - offset_start = marking_up? ent_start->str_len: 0; - offset_end = marking_up? 0: ent_end->str_len; + low_offs = 0; + high_offs = high_ent->str_len; } - - if (marking_up) + /* character selection */ + else { - int temp; - - /* ensure ent_start is above ent_end */ - if (ent_start != ent_end) - { - ent = ent_start; - ent_start = ent_end; - ent_end = ent; - } - - /* switch offsets as well */ - temp = offset_start; - offset_start = offset_end; - offset_end = temp; + if (low_y < 0) + low_offs = xtext->buffer->last_offset_start; + if (high_y > xtext->buffer->window_height) + high_offs = xtext->buffer->last_offset_end; } /* set all the old mark_ fields to -1 */ gtk_xtext_selection_clear (xtext->buffer); - /* set the default values */ - ent_start->mark_end = ent_start->str_len; - ent_end->mark_start = 0; + low_ent->mark_start = low_offs; + low_ent->mark_end = high_offs; - /* set the calculated values (this overwrites the default values if we're on the same ent) */ - ent_start->mark_start = offset_start; - ent_end->mark_end = offset_end; - - /* set all the mark_ fields of the ents within the selection */ - if (ent_start != ent_end) + if (low_ent != high_ent) { - ent = ent_start->next; - while (ent && ent != ent_end) + low_ent->mark_end = low_ent->str_len; + if (high_offs != 0) + { + high_ent->mark_start = 0; + high_ent->mark_end = high_offs; + } + + /* set all the mark_ fields of the ents within the selection */ + ent = low_ent->next; + while (ent && ent != high_ent) { ent->mark_start = 0; ent->mark_end = ent->str_len; @@ -1400,7 +1415,7 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren } if (render) - gtk_xtext_selection_render (xtext, ent_start, ent_end); + gtk_xtext_selection_render (xtext, low_ent, high_ent); } static int @@ -1532,7 +1547,7 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int out_of_bounds = 0; int len_to_offset = 0; - ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds, NULL); + ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds); if (ent == NULL || out_of_bounds || offset < 0 || offset >= ent->str_len) return NULL; @@ -1585,11 +1600,11 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, /* make sure we're not before the start of the match */ if (len_to_offset < start) - return 0; + return NULL; /* and not after it */ if (len_to_offset - start >= end - start) - return 0; + return NULL; } return word; @@ -1646,7 +1661,8 @@ gtk_xtext_check_mark_stamp (GtkXText *xtext, GdkModifierType mask) { gboolean redraw = FALSE; - if (mask & STATE_SHIFT || prefs.hex_text_autocopy_stamp) + if ((mask & STATE_SHIFT || prefs.hex_text_autocopy_stamp) + && (!prefs.hex_stamp_text || prefs.hex_text_indent)) { if (!xtext->mark_stamp) { @@ -1707,7 +1723,7 @@ gtk_xtext_get_word_adjust (GtkXText *xtext, int x, int y, textentry **word_ent, } } } - g_slist_free_full (slp, free); + g_slist_free_full (slp, g_free); return word_type; } @@ -1853,7 +1869,7 @@ gtk_xtext_set_clip_owner (GtkWidget * xtext, GdkEventButton * event) gtk_selection_owner_set (xtext, GDK_SELECTION_SECONDARY, event ? event->time : GDK_CURRENT_TIME); } - free (str); + g_free (str); } } @@ -2107,7 +2123,7 @@ gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret) return NULL; /* now allocate mem and copy buffer */ - pos = txt = malloc (len); + pos = txt = g_malloc (len); ent = buf->last_ent_start; while (ent) { @@ -2147,10 +2163,11 @@ gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret) /*stripped = gtk_xtext_conv_color (txt, strlen (txt), &len);*/ stripped = txt; len = strlen (txt); - } else + } + else { stripped = gtk_xtext_strip_color (txt, strlen (txt), NULL, &len, NULL, FALSE); - free (txt); + g_free (txt); } *len_ret = len; @@ -2205,7 +2222,7 @@ gtk_xtext_selection_get (GtkWidget * widget, g_free (new_text); } - free (stripped); + g_free (stripped); } static gboolean @@ -2360,7 +2377,7 @@ xtext_do_chunk(chunk_t *c) if (c->len1 == 0) return; - meta = malloc (sizeof *meta); + meta = g_new (offlen_t, 1); meta->off = c->off1; meta->len = c->len1; meta->emph = c->emph; @@ -2383,7 +2400,7 @@ gtk_xtext_strip_color (unsigned char *text, int len, unsigned char *outbuf, int mbl; /* multi-byte length */ if (outbuf == NULL) - new_str = malloc (len + 2); + new_str = g_malloc (len + 2); else new_str = outbuf; @@ -2459,7 +2476,7 @@ bad_utf8: /* Normal ending sequence, and give up if bad utf8 */ if (slpp) *slpp = c.slp; else - g_slist_free_full (c.slp, free); + g_slist_free_full (c.slp, g_free); return new_str; } @@ -2475,7 +2492,7 @@ gtk_xtext_text_width_ent (GtkXText *xtext, textentry *ent) if (ent->slp) { - g_slist_free_full (ent->slp, free); + g_slist_free_full (ent->slp, g_free); ent->slp = NULL; } @@ -2507,7 +2524,7 @@ gtk_xtext_text_width (GtkXText *xtext, unsigned char *text, int len) &new_len, &slp, !xtext->ignore_hidden); width = backend_get_text_width_slp (xtext, new_buf, slp); - g_slist_free_full (slp, free); + g_slist_free_full (slp, g_free); return width; } @@ -3254,7 +3271,7 @@ gtk_xtext_render_stamp (GtkXText * xtext, textentry * ent, { textentry tmp_ent; int jo, ji, hs; - int xsize, y; + int xsize, y, emphasis; /* trashing ent here, so make a backup first */ memcpy (&tmp_ent, ent, sizeof (tmp_ent)); @@ -3264,7 +3281,7 @@ gtk_xtext_render_stamp (GtkXText * xtext, textentry * ent, xtext->jump_out_offset = 0; xtext->jump_in_offset = 0; xtext->hilight_start = 0xffff; /* temp disable */ - int emphasis = 0; + emphasis = 0; if (xtext->mark_stamp) { @@ -3530,7 +3547,7 @@ gtk_xtext_save (GtkXText * xtext, int fh) &newlen, NULL, FALSE); write (fh, buf, newlen); write (fh, "\n", 1); - free (buf); + g_free (buf); ent = ent->next; } } @@ -3641,7 +3658,7 @@ gtk_xtext_nth (GtkXText *xtext, int line, int *subline) break; lines -= g_slist_length (ent->sublines); } - return 0; + return NULL; } } /* -- end of optimization -- */ @@ -3656,7 +3673,7 @@ gtk_xtext_nth (GtkXText *xtext, int line, int *subline) } ent = ent->next; } - return 0; + return NULL; } /* render enta (or an inclusive range enta->entb) */ @@ -3895,10 +3912,10 @@ gtk_xtext_kill_ent (xtext_buffer *buffer, textentry *ent) gtk_xtext_search_textentry_del (buffer, ent); } - g_slist_free_full (ent->slp, free); + g_slist_free_full (ent->slp, g_free); g_slist_free (ent->sublines); - free (ent); + g_free (ent); return visible; } @@ -4033,7 +4050,7 @@ gtk_xtext_clear (xtext_buffer *buf, int lines) while (buf->text_first) { next = buf->text_first->next; - free (buf->text_first); + g_free (buf->text_first); buf->text_first = next; } buf->text_last = NULL; @@ -4191,7 +4208,6 @@ gtk_xtext_search_textentry (xtext_buffer *buf, textentry *ent) hay = match? g_strdup (str): g_utf8_casefold (str, lstr); lhay = strlen (hay); - off = 0; for (pos = hay, len = lhay; len; off += buf->search_lnee, pos = hay + off, len = lhay - off) @@ -4210,7 +4226,7 @@ gtk_xtext_search_textentry (xtext_buffer *buf, textentry *ent) } /* Common processing --- */ - g_slist_free_full (slp, free); + g_slist_free_full (slp, g_free); return gl; } @@ -4639,7 +4655,7 @@ gtk_xtext_append_indent (xtext_buffer *buf, if (right_text[right_len-1] == '\n') right_len--; - ent = malloc (left_len + right_len + 2 + sizeof (textentry)); + ent = g_malloc (left_len + right_len + 2 + sizeof (textentry)); str = (unsigned char *) ent + sizeof (textentry); memcpy (str, left_text, left_len); @@ -4660,7 +4676,9 @@ gtk_xtext_append_indent (xtext_buffer *buf, space = 0; /* do we need to auto adjust the separator position? */ - if (buf->xtext->auto_indent && ent->indent < MARGIN + space) + if (buf->xtext->auto_indent && + buf->indent < buf->xtext->max_auto_indent && + ent->indent < MARGIN + space) { tempindent = MARGIN + space + buf->xtext->space_width + left_width; @@ -4681,7 +4699,7 @@ gtk_xtext_append_indent (xtext_buffer *buf, } void -gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len) +gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp) { textentry *ent; @@ -4694,7 +4712,7 @@ gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len) if (len >= sizeof (buf->xtext->scratch_buffer)) len = sizeof (buf->xtext->scratch_buffer) - 1; - ent = malloc (len + 1 + sizeof (textentry)); + ent = g_malloc (len + 1 + sizeof (textentry)); ent->str = (unsigned char *) ent + sizeof (textentry); ent->str_len = len; if (len) @@ -4703,7 +4721,7 @@ gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len) ent->indent = 0; ent->left_len = -1; - gtk_xtext_append_entry (buf, ent, 0); + gtk_xtext_append_entry (buf, ent, stamp); } gboolean @@ -4738,11 +4756,14 @@ gtk_xtext_lastlog (xtext_buffer *out, xtext_buffer *search_area) } else { - gtk_xtext_append (out, ent->str, ent->str_len); + gtk_xtext_append (out, ent->str, ent->str_len, 0); } - out->text_last->stamp = ent->stamp; - gtk_xtext_search_textentry_add (out, out->text_last, gl, TRUE); + if (out->text_last) + { + out->text_last->stamp = ent->stamp; + gtk_xtext_search_textentry_add (out, out->text_last, gl, TRUE); + } } ent = ent->next; } @@ -4936,6 +4957,7 @@ gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render) if (buf->window_width != w) { buf->window_width = w; + buf->window_height = h; gtk_xtext_calc_lines (buf, FALSE); if (buf->scrollbar_down) gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - @@ -4959,8 +4981,7 @@ gtk_xtext_buffer_new (GtkXText *xtext) { xtext_buffer *buf; - buf = malloc (sizeof (xtext_buffer)); - memset (buf, 0, sizeof (xtext_buffer)); + buf = g_new0 (xtext_buffer, 1); buf->old_value = -1; buf->xtext = xtext; buf->scrollbar_down = TRUE; @@ -4990,9 +5011,9 @@ gtk_xtext_buffer_free (xtext_buffer *buf) while (ent) { next = ent->next; - free (ent); + g_free (ent); ent = next; } - free (buf); + g_free (buf); } diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h index 73f5b52d..d6853f9f 100644 --- a/src/fe-gtk/xtext.h +++ b/src/fe-gtk/xtext.h @@ -252,7 +252,7 @@ struct _GtkXTextClass }; GtkWidget *gtk_xtext_new (GdkColor palette[], int separator); -void gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len); +void gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp); void gtk_xtext_append_indent (xtext_buffer *buf, unsigned char *left_text, int left_len, unsigned char *right_text, int right_len, |