--- a/pidgin/gtkconv.c Thu Jul 18 03:45:06 2019 +0000 +++ b/pidgin/gtkconv.c Fri Jul 19 01:53:24 2019 -0500 @@ -70,6 +70,7 @@ #include "pidgingdkpixbuf.h" #include "pidgininvitedialog.h" #include "pidginlog.h" +#include "pidginmessage.h" #include "pidginstock.h" #include "pidgintooltip.h" @@ -156,14 +157,6 @@ #define PIDGIN_DRAG_BLIST_NODE (1337) #define PIDGIN_DRAG_IM_CONTACT (31337) -static const GtkTargetEntry dnd_targets[] = -{ - {"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, PIDGIN_DRAG_BLIST_NODE}, - {"application/x-im-contact", 0, PIDGIN_DRAG_IM_CONTACT} -}; - -static GtkTargetList *webkit_dnd_targets = NULL; - static GtkWidget *invite_dialog = NULL; static GtkWidget *warn_close_dialog = NULL; @@ -185,7 +178,6 @@ static void generate_send_to_items(PidginConvWindow *win); /* Prototypes. <-- because Paco-Paco hates this comment. */ -static void load_conv_theme(PidginConversation *gtkconv); static gboolean infopane_entry_activate(PidginConversation *gtkconv); static void got_typing_keypress(PidginConversation *gtkconv, gboolean first); static void gray_stuff_out(PidginConversation *gtkconv); @@ -401,7 +393,6 @@ PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); if (PIDGIN_CONVERSATION(conv)) { - load_conv_theme(gtkconv); gtkconv->last_flags = 0; } } @@ -598,7 +589,7 @@ account = purple_conversation_get_account(conv); - buffer = talkatu_editor_get_buffer(gtkconv->editor); + buffer = talkatu_editor_get_buffer(TALKATU_EDITOR(gtkconv->editor)); if (check_for_and_do_command(conv)) { talkatu_buffer_clear(TALKATU_BUFFER(buffer)); @@ -783,7 +774,8 @@ savelog_writefile_cb(void *user_data, const char *filename) { PurpleConversation *conv = (PurpleConversation *)user_data; - PidginWebView *webview; + PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); + GtkTextBuffer *buffer = NULL; FILE *fp; const char *name; gchar *text; @@ -795,21 +787,18 @@ return; } - webview = PIDGIN_WEBVIEW(PIDGIN_CONVERSATION(conv)->webview); name = purple_conversation_get_name(conv); + fprintf(fp, "<html>\n"); - fprintf(fp, "<head>\n"); fprintf(fp, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf(fp, "<title>%s</title>\n", name); - text = pidgin_webview_get_head_html(webview); - fprintf(fp, "%s", text); - g_free(text); fprintf(fp, "</head>\n"); fprintf(fp, "<body>\n"); fprintf(fp, _("<h1>Conversation with %s</h1>\n"), name); - text = pidgin_webview_get_body_html(webview); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->history)); + text = talkatu_markup_get_html(buffer, NULL); fprintf(fp, "%s", text); g_free(text); fprintf(fp, "\n</body>\n"); @@ -1323,47 +1312,6 @@ return g_strconcat("-pidgin-user:", who, NULL); } -static WebKitDOMNode * -get_mark_for_user(PidginConversation *gtkconv, const char *who) -{ - WebKitDOMDocument *doc; - WebKitDOMNodeList *nodes; - WebKitDOMNode *node = NULL; - gulong len; - char *tmp; - - doc = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(gtkconv->webview)); - - tmp = get_class_for_user(who); - nodes = webkit_dom_document_get_elements_by_class_name(doc, tmp); - g_free(tmp); - - if (nodes != NULL) { - len = webkit_dom_node_list_get_length(nodes); - if (len > 0) - node = webkit_dom_node_list_item(nodes, len - 1); - } - - g_object_unref(nodes); - - return node; -} - -static void -menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv) -{ - WebKitDOMNode *node; - const char *who; - - who = g_object_get_data(G_OBJECT(w), "user_data"); - node = get_mark_for_user(gtkconv, who); - - if (node != NULL) - webkit_dom_element_scroll_into_view(WEBKIT_DOM_ELEMENT(node), TRUE); - else - g_return_if_reached(); -} - static GtkWidget * create_chat_menu(PurpleChatConversation *chat, const char *who, PurpleConnection *gc) { @@ -1478,12 +1426,6 @@ g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } - button = pidgin_new_menu_item(menu, _("Last Said"), GTK_STOCK_INDEX, - G_CALLBACK(menu_last_said_cb), PIDGIN_CONVERSATION(conv)); - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); - if (!get_mark_for_user(PIDGIN_CONVERSATION(conv), who)) - gtk_widget_set_sensitive(button, FALSE); - if (buddy != NULL) { if (purple_account_is_connected(account)) @@ -1577,13 +1519,6 @@ if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) { chat_do_im(gtkconv, who); - } else if (event->button == GDK_BUTTON_MIDDLE && event->type == GDK_BUTTON_PRESS) { - /* Move to user's anchor */ - WebKitDOMNode *node = get_mark_for_user(gtkconv, who); - - if (node != NULL) - webkit_dom_element_scroll_into_view(WEBKIT_DOM_ELEMENT(node), TRUE); - } else if (gdk_event_triggers_context_menu((GdkEvent *)event)) { GtkWidget *menu = create_chat_menu (PURPLE_CHAT_CONVERSATION(conv), who, gc); gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); @@ -1659,8 +1594,8 @@ GtkWidget *from; GtkWidget *to; } transitions[] = { - {gtkconv->entry, gtkconv->webview}, - {gtkconv->webview, chat ? gtkconv->u.chat->list : gtkconv->entry}, + {gtkconv->entry, gtkconv->history}, + {gtkconv->history, chat ? gtkconv->u.chat->list : gtkconv->entry}, {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry}, {NULL, NULL} }, *ptr; @@ -1961,17 +1896,18 @@ } break; - case GDK_KEY_Page_Up: - case GDK_KEY_KP_Page_Up: - pidgin_webview_page_up(PIDGIN_WEBVIEW(gtkconv->webview)); - return TRUE; - break; - - case GDK_KEY_Page_Down: - case GDK_KEY_KP_Page_Down: - pidgin_webview_page_down(PIDGIN_WEBVIEW(gtkconv->webview)); - return TRUE; - break; + # warning fixme!! + // case GDK_KEY_Page_Up: + // case GDK_KEY_KP_Page_Up: + // pidgin_webview_page_up(PIDGIN_WEBVIEW(gtkconv->webview)); + // return TRUE; + // break; + + // case GDK_KEY_Page_Down: + // case GDK_KEY_KP_Page_Down: + // pidgin_webview_page_down(PIDGIN_WEBVIEW(gtkconv->webview)); + // return TRUE; + // break; case GDK_KEY_KP_Enter: case GDK_KEY_Return: @@ -2000,27 +1936,6 @@ } /* - * NOTE: - * This guy just kills a single right click from being propagated any - * further. I have no idea *why* we need this, but we do ... It - * prevents right clicks on the GtkTextView in a convo dialog from - * going all the way down to the notebook. I suspect a bug in - * GtkTextView, but I'm not ready to point any fingers yet. - */ -static gboolean -entry_stop_rclick_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - if (event->button == GDK_BUTTON_SECONDARY && event->type == GDK_BUTTON_PRESS) { - /* Right single click */ - g_signal_stop_emission_by_name(G_OBJECT(widget), "button_press_event"); - - return TRUE; - } - - return FALSE; -} - -/* * If someone tries to type into the conversation backlog of a * conversation window then we yank focus from the conversation backlog * and give it to the text entry box so that people can type @@ -2094,7 +2009,7 @@ pidgin_webview_switch_active_conversation( PIDGIN_WEBVIEW(gtkconv->entry), conv); pidgin_webview_switch_active_conversation( - PIDGIN_WEBVIEW(gtkconv->webview), conv); + PIDGIN_WEBVIEW(gtkconv->history), conv); purple_conversation_set_logging(conv, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(gtkconv->win->menu->logging))); @@ -3002,11 +2917,11 @@ if (PURPLE_IS_CHAT_CONVERSATION(conv)) { chat = purple_blist_find_chat(account, purple_conversation_get_name(conv)); - if ((chat == NULL) && (gtkconv->webview != NULL)) { - chat = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat"); - } - - if ((chat == NULL) && (gtkconv->webview != NULL)) { + if ((chat == NULL) && (gtkconv->history != NULL)) { + chat = g_object_get_data(G_OBJECT(gtkconv->history), "transient_chat"); + } + + if ((chat == NULL) && (gtkconv->history != NULL)) { GHashTable *components; PurpleAccount *account = purple_conversation_get_account(conv); PurpleProtocol *protocol = @@ -3023,7 +2938,7 @@ } chat = purple_chat_new(account, NULL, components); purple_blist_node_set_transient((PurpleBlistNode *)chat, TRUE); - g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_chat", + g_object_set_data_full(G_OBJECT(gtkconv->history), "transient_chat", chat, (GDestroyNotify)purple_blist_remove_chat); } } else { @@ -3031,13 +2946,13 @@ return FALSE; buddy = purple_blist_find_buddy(account, purple_conversation_get_name(conv)); - if (!buddy && gtkconv->webview) { - buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy"); + if (!buddy && gtkconv->history) { + buddy = g_object_get_data(G_OBJECT(gtkconv->history), "transient_buddy"); if (!buddy) { buddy = purple_buddy_new(account, purple_conversation_get_name(conv), NULL); purple_blist_node_set_transient((PurpleBlistNode *)buddy, TRUE); - g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_buddy", + g_object_set_data_full(G_OBJECT(gtkconv->history), "transient_buddy", buddy, (GDestroyNotify)g_object_unref); } } @@ -4622,7 +4537,8 @@ static gboolean resize_webview_cb(PidginConversation *gtkconv) { - PidginWebView *webview; +#if 0 + GtkStyleContext *ctx = NULL; gint min_lines; gint max_height; gint min_height; @@ -4632,23 +4548,19 @@ gint toolbar_size; gint old_w; gint old_h; - GtkAllocation webview_allocation; + GtkAllocation history_allocation; GtkAllocation entry_allocation; - webview = PIDGIN_WEBVIEW(gtkconv->entry); - - /* Get text height from the DOM */ - height = pidgin_webview_get_DOM_height(webview); - /* Find the height of the conversation window to calculate the maximum possible entry * size (1/2 of the window) */ - gtk_widget_get_allocation(gtkconv->webview, &webview_allocation); + gtk_widget_get_allocation(gtkconv->history, &history_allocation); gtk_widget_get_allocation(gtkconv->entry, &entry_allocation); total_height = webview_allocation.height + entry_allocation.height; max_height = total_height / 2; /* Get size of the characters to calculate initial minimum space for the entry */ + ctx = gtk_widget_get_style_context(gtkconv->history); font_size = pidgin_webview_get_font_size(webview); /* Allow to have a minimum of "min_lines" height as defined in the preference */ @@ -4675,6 +4587,7 @@ purple_debug_info("pidgin", "resizing to %d, %d lines\n", height, min_lines); } +#endif return FALSE; } @@ -4869,7 +4782,7 @@ if (PURPLE_IS_CHAT_CONVERSATION(conv)) { node = (PurpleBlistNode*)(purple_blist_find_chat(purple_conversation_get_account(conv), purple_conversation_get_name(conv))); if (!node) - node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat"); + node = g_object_get_data(G_OBJECT(gtkconv->history), "transient_chat"); } else { node = (PurpleBlistNode*)(purple_blist_find_buddy(purple_conversation_get_account(conv), purple_conversation_get_name(conv))); #if 0 @@ -4884,326 +4797,10 @@ return FALSE; } -/* Quick Find {{{ */ -static gboolean -pidgin_conv_end_quickfind(PidginConversation *gtkconv) -{ - GtkStyleContext *context = gtk_widget_get_style_context(gtkconv->quickfind_entry); - gtk_style_context_remove_class(context, "not-found"); - - webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(gtkconv->webview)); - gtk_widget_hide(gtkconv->quickfind_container); - - gtk_widget_grab_focus(gtkconv->entry); - return TRUE; -} - -static gboolean -quickfind_process_input(GtkWidget *entry, GdkEventKey *event, PidginConversation *gtkconv) -{ - switch (event->keyval) { - case GDK_KEY_Return: - case GDK_KEY_KP_Enter: - if (webkit_web_view_search_text(WEBKIT_WEB_VIEW(gtkconv->webview), gtk_entry_get_text(GTK_ENTRY(entry)), FALSE, TRUE, TRUE)) { - GtkStyleContext *context = gtk_widget_get_style_context(gtkconv->quickfind_entry); - gtk_style_context_remove_class(context, "not-found"); - } else { - GtkStyleContext *context = gtk_widget_get_style_context(gtkconv->quickfind_entry); - gtk_style_context_add_class(context, "not-found"); - } - break; - case GDK_KEY_Escape: - pidgin_conv_end_quickfind(gtkconv); - break; - default: - return FALSE; - } - return TRUE; -} - -static void -pidgin_conv_setup_quickfind(PidginConversation *gtkconv, GtkWidget *container) -{ - GtkWidget *widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label, *entry, *close; - GtkStyleContext *context; - GtkCssProvider *filter_css; - const gchar filter_style[] = - ".not-found {" - "color: @error_fg_color;" - "text-shadow: 0 1px @error_text_shadow;" - "background-image: none;" - "background-color: @error_bg_color;" - "}"; - - gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0); - - close = pidgin_create_small_button(gtk_label_new("×")); - gtk_box_pack_start(GTK_BOX(widget), close, FALSE, FALSE, 0); - gtk_widget_set_tooltip_text(close, _("Close Find bar")); - - label = gtk_label_new(_("Find:")); - gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 10); - - entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(widget), entry, TRUE, TRUE, 0); - filter_css = gtk_css_provider_new(); - gtk_css_provider_load_from_data(filter_css, filter_style, -1, NULL); - context = gtk_widget_get_style_context(entry); - gtk_style_context_add_provider(context, - GTK_STYLE_PROVIDER(filter_css), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - - gtkconv->quickfind_entry = entry; - gtkconv->quickfind_container = widget; - - /* Hook to signals and stuff */ - g_signal_connect(G_OBJECT(entry), "key-press-event", - G_CALLBACK(quickfind_process_input), gtkconv); - g_signal_connect_swapped(G_OBJECT(close), "button-press-event", - G_CALLBACK(pidgin_conv_end_quickfind), gtkconv); -} - -/* }}} */ - -static char * -replace_header_tokens(PurpleConversation *conv, const char *text) -{ - PurpleAccount *account = purple_conversation_get_account(conv); - GString *str; - const char *cur = text; - const char *prev = cur; - time_t mtime; - struct tm *tm = NULL; - - if (text == NULL || *text == '\0') - return NULL; - - str = g_string_new(NULL); - while ((cur = strchr(cur, '%'))) { - char *freeval = NULL; - const char *replace = NULL; - const char *fin = NULL; - - if (g_str_has_prefix(cur, "%chatName%")) { - replace = purple_conversation_get_name(conv); - - } else if (g_str_has_prefix(cur, "%sourceName%")) { - replace = purple_account_get_private_alias(account); - if (replace == NULL) - replace = purple_account_get_username(account); - - } else if (g_str_has_prefix(cur, "%destinationName%")) { - PurpleBuddy *buddy = purple_blist_find_buddy(account, purple_conversation_get_name(conv)); - if (buddy) { - replace = purple_buddy_get_alias(buddy); - } else { - replace = purple_conversation_get_name(conv); - } - - } else if (g_str_has_prefix(cur, "%incomingIconPath%")) { - PurpleBuddyIcon *icon = purple_im_conversation_get_icon(PURPLE_IM_CONVERSATION(conv)); - if (icon) - replace = purple_buddy_icon_get_full_path(icon); - - } else if (g_str_has_prefix(cur, "%outgoingIconPath%")) { - replace = purple_account_get_buddy_icon_path(account); - - } else if (g_str_has_prefix(cur, "%timeOpened")) { - const char *tmp = cur + strlen("%timeOpened"); - - if (*tmp == '{') { - const char *end; - tmp++; - end = strstr(tmp, "}%"); - if (!end) /* Invalid string */ - continue; - if (!tm) { - mtime = time(NULL); - tm = localtime(&mtime); - } - replace = freeval = purple_uts35_to_str(tmp, end - tmp, tm); - fin = end + 1; - } else { - if (!tm) { - mtime = time(NULL); - tm = localtime(&mtime); - } - - replace = purple_utf8_strftime("%X", tm); - } - - } else if (g_str_has_prefix(cur, "%dateOpened%")) { - if (!tm) { - mtime = time(NULL); - tm = localtime(&mtime); - } - - replace = purple_date_format_short(tm); - - } else { - cur++; - continue; - } - - /* Here we have a replacement to make */ - g_string_append_len(str, prev, cur - prev); - if (replace) - g_string_append(str, replace); - - /* And update the pointers */ - if (fin) { - prev = cur = fin + 1; - } else { - prev = cur = strchr(cur + 1, '%') + 1; - } - g_free(freeval); - freeval = NULL; - } - - /* And wrap it up */ - g_string_append(str, prev); - return g_string_free(str, FALSE); -} - -static char * -replace_template_tokens(PidginConvTheme *theme, const char *header, const char *footer) -{ - GString *str; - const char *text; - char **ms; - char *path; - - text = pidgin_conversation_theme_get_template(theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_MAIN); - if (text == NULL) - return NULL; - - ms = g_strsplit(text, "%@", 6); - if (ms[0] == NULL || ms[1] == NULL || ms[2] == NULL || ms[3] == NULL || ms[4] == NULL || ms[5] == NULL) { - g_strfreev(ms); - return NULL; - } - - str = g_string_new(NULL); - - g_string_append(str, ms[0]); - g_string_append(str, "file://"); - path = pidgin_conversation_theme_get_template_path(theme); - g_string_append(str, path); - g_free(path); - - g_string_append(str, ms[1]); - - text = pidgin_conversation_theme_get_template(theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_BASESTYLE_CSS); - g_string_append(str, text); - - g_string_append(str, ms[2]); - - g_string_append(str, "file://"); - path = pidgin_conversation_theme_get_css_path(theme); - g_string_append(str, path); - g_free(path); - - g_string_append(str, ms[3]); - if (header) - g_string_append(str, header); - g_string_append(str, ms[4]); - if (footer) - g_string_append(str, footer); - g_string_append(str, ms[5]); - - g_strfreev(ms); - - return g_string_free(str, FALSE); -} - -static void -set_theme_webkit_settings(WebKitWebView *webview, PidginConvTheme *theme) -{ - WebKitWebSettings *settings; - const GValue *val; - - g_object_get(G_OBJECT(webview), "settings", &settings, NULL); - - val = pidgin_conversation_theme_lookup(theme, "DefaultFontFamily", TRUE); - if (val && G_VALUE_HOLDS_STRING(val)) - { - const gchar *font_family = g_value_get_string(val); -#ifdef _WIN32 - /* XXX: a hack for not converting backslash to yen sign. - * See gtkwebview.c: pidgin_webview_new. - */ - if (g_ascii_strcasecmp(font_family, "sans-serif") == 0) - font_family = NULL; -#endif - if (font_family) - g_object_set(G_OBJECT(settings), "default-font-family", font_family, NULL); - } - - val = pidgin_conversation_theme_lookup(theme, "DefaultFontSize", TRUE); - if (val && G_VALUE_HOLDS_INT(val)) - g_object_set(G_OBJECT(settings), "default-font-size", GINT_TO_POINTER(g_value_get_int(val)), NULL); - - val = pidgin_conversation_theme_lookup(theme, "DefaultBackgroundIsTransparent", TRUE); - if (val && G_VALUE_HOLDS_BOOLEAN(val)) - /* this does not work :( */ - webkit_web_view_set_transparent(webview, g_value_get_boolean(val)); -} - -static void -conv_variant_changed_cb(GObject *gobject, GParamSpec *pspec, gpointer user_data) -{ - PidginConversation *gtkconv = user_data; - char *path, *js; - - path = pidgin_conversation_theme_get_css_path(PIDGIN_CONV_THEME(gobject)); - js = g_strdup_printf("setStylesheet(\"mainStyle\", \"file://%s\");", path); - g_free(path); - pidgin_webview_safe_execute_script(PIDGIN_WEBVIEW(gtkconv->webview), js); - g_free(js); -} - -static void -load_conv_theme(PidginConversation *gtkconv) -{ - char *header, *footer; - char *template; - char *basedir, *baseuri; - - header = replace_header_tokens(gtkconv->active_conv, - pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_HEADER)); - footer = replace_header_tokens(gtkconv->active_conv, - pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_FOOTER)); - template = replace_template_tokens(gtkconv->theme, header, footer); - g_free(header); - g_free(footer); - - if (template == NULL) - return; - - set_theme_webkit_settings(WEBKIT_WEB_VIEW(gtkconv->webview), gtkconv->theme); - - basedir = pidgin_conversation_theme_get_template_path(gtkconv->theme); - baseuri = g_strdup_printf("file://%s", basedir); - webkit_web_view_load_string(WEBKIT_WEB_VIEW(gtkconv->webview), template, - "text/html", "UTF-8", baseuri); - - if (PURPLE_IS_CHAT_CONVERSATION(gtkconv->active_conv)) - pidgin_webview_safe_execute_script(PIDGIN_WEBVIEW(gtkconv->webview), - "document.getElementById('Chat').className = 'groupchat'"); - - g_signal_connect(G_OBJECT(gtkconv->theme), "notify::variant", - G_CALLBACK(conv_variant_changed_cb), gtkconv); - - g_free(basedir); - g_free(baseuri); - g_free(template); -} - static GtkWidget * setup_common_pane(PidginConversation *gtkconv) { - GtkWidget *vbox, *frame, *webview_sw, *event_box, *view; + GtkWidget *vbox, *sw, *event_box, *view; GtkCellRenderer *rend; GtkTreePath *path; PurpleConversation *conv = gtkconv->active_conv; @@ -5299,12 +4896,19 @@ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", CONV_EMBLEM_COLUMN, NULL); g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL); - /* Setup the webkit widget */ - frame = pidgin_create_webview(FALSE, >kconv->webview, &webview_sw); - g_object_set(G_OBJECT(gtkconv->webview), "expand", TRUE, NULL); - _pidgin_widget_set_accessible_name(frame, "Conversation Pane"); - - load_conv_theme(gtkconv); + /* Setup the history widget */ + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy( + GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, + GTK_POLICY_ALWAYS + ); + + gtkconv->history_buffer = talkatu_history_buffer_new(); + gtkconv->history = talkatu_history_new(); + gtk_text_view_set_buffer(GTK_TEXT_VIEW(gtkconv->history), gtkconv->history_buffer); + gtk_container_add(GTK_CONTAINER(sw), gtkconv->history); if (chat) { GtkWidget *hpaned; @@ -5316,27 +4920,22 @@ hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0); gtk_widget_show(hpaned); - gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE); + gtk_paned_pack1(GTK_PANED(hpaned), sw, TRUE, TRUE); /* Now add the userlist */ setup_chat_userlist(gtkconv, hpaned); } else { - gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); - } - gtk_widget_show_all(frame); - - gtk_widget_set_name(gtkconv->webview, "pidgin_conv_webview"); - g_object_set_data(G_OBJECT(gtkconv->webview), "gtkconv", gtkconv); - - g_signal_connect_after(G_OBJECT(gtkconv->webview), "button_press_event", - G_CALLBACK(entry_stop_rclick_cb), NULL); - g_signal_connect(G_OBJECT(gtkconv->webview), "key_press_event", + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + } + gtk_widget_show_all(sw); + + g_object_set_data(G_OBJECT(gtkconv->history), "gtkconv", gtkconv); + + g_signal_connect(G_OBJECT(gtkconv->history), "key_press_event", G_CALLBACK(refocus_entry_cb), gtkconv); - g_signal_connect(G_OBJECT(gtkconv->webview), "key_release_event", + g_signal_connect(G_OBJECT(gtkconv->history), "key_release_event", G_CALLBACK(refocus_entry_cb), gtkconv); - pidgin_conv_setup_quickfind(gtkconv, vbox); - gtkconv->lower_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0); gtk_widget_show(gtkconv->lower_hbox); @@ -5366,131 +4965,6 @@ return vbox; } -static void -conv_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, - GtkSelectionData *sd, guint info, guint t, - PidginConversation *gtkconv) -{ - PurpleConversation *conv = gtkconv->active_conv; - PidginConvWindow *win = gtkconv->win; - PurpleIMConversation *im; - PurpleAccount *convaccount = purple_conversation_get_account(conv); - PurpleConnection *gc = purple_account_get_connection(convaccount); - PurpleProtocol *protocol = gc ? purple_connection_get_protocol(gc) : NULL; - const guchar *data = gtk_selection_data_get_data(sd); - - if (info == PIDGIN_DRAG_BLIST_NODE) - { - PurpleBlistNode *n = NULL; - PurpleBuddy *b; - PidginConversation *gtkconv = NULL; - PurpleAccount *buddyaccount; - const char *buddyname; - PurpleBlistNode **data_val = (gpointer)data; - - n = *data_val; - - if (PURPLE_IS_CONTACT(n)) - b = purple_contact_get_priority_buddy((PurpleContact*)n); - else if (PURPLE_IS_BUDDY(n)) - b = (PurpleBuddy*)n; - else - return; - - buddyaccount = purple_buddy_get_account(b); - buddyname = purple_buddy_get_name(b); - /* - * If a buddy is dragged to a chat window of the same protocol, - * invite him to the chat. - */ - if (PURPLE_IS_CHAT_CONVERSATION(conv) && - protocol && PURPLE_PROTOCOL_IMPLEMENTS(protocol, CHAT_IFACE, invite) && - purple_strequal(purple_account_get_protocol_id(convaccount), - purple_account_get_protocol_id(buddyaccount))) { - purple_chat_conversation_invite_user(PURPLE_CHAT_CONVERSATION(conv), buddyname, NULL, TRUE); - } else { - /* - * If we already have an open conversation with this buddy, then - * just move the conv to this window. Otherwise, create a new - * conv and add it to this window. - */ - im = purple_conversations_find_im_with_account(buddyname, buddyaccount); - if (im != NULL) { - PidginConvWindow *oldwin; - gtkconv = PIDGIN_CONVERSATION(PURPLE_CONVERSATION(im)); - oldwin = gtkconv->win; - if (oldwin != win) { - pidgin_conv_window_remove_gtkconv(oldwin, gtkconv); - pidgin_conv_window_add_gtkconv(win, gtkconv); - } - } else { - im = purple_im_conversation_new(buddyaccount, buddyname); - gtkconv = PIDGIN_CONVERSATION(PURPLE_CONVERSATION(im)); - if (gtkconv->win != win) { - pidgin_conv_window_remove_gtkconv(gtkconv->win, gtkconv); - pidgin_conv_window_add_gtkconv(win, gtkconv); - } - } - - /* Make this conversation the active conversation */ - pidgin_conv_window_switch_gtkconv(win, gtkconv); - } - - gtk_drag_finish(dc, TRUE, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); - } - else if (info == PIDGIN_DRAG_IM_CONTACT) - { - char *protocol_id = NULL; - char *username = NULL; - PurpleAccount *account; - PidginConversation *gtkconv; - - if (pidgin_parse_x_im_contact((const char *) data, FALSE, &account, - &protocol_id, &username, NULL)) - { - if (account == NULL) - { - purple_notify_error(win, NULL, - _("You are not currently signed on with an account that " - "can add that buddy."), NULL, NULL); - } else { - /* - * If a buddy is dragged to a chat window of the same protocol, - * invite him to the chat. - */ - if (PURPLE_IS_CHAT_CONVERSATION(conv) && - protocol && PURPLE_PROTOCOL_IMPLEMENTS(protocol, CHAT_IFACE, invite) && - purple_strequal(purple_account_get_protocol_id(convaccount), protocol_id)) { - purple_chat_conversation_invite_user(PURPLE_CHAT_CONVERSATION(conv), username, NULL, TRUE); - } else { - im = purple_im_conversation_new(account, username); - gtkconv = PIDGIN_CONVERSATION(PURPLE_CONVERSATION(im)); - if (gtkconv->win != win) { - pidgin_conv_window_remove_gtkconv(gtkconv->win, gtkconv); - pidgin_conv_window_add_gtkconv(win, gtkconv); - } - } - } - } - - g_free(username); - g_free(protocol_id); - - gtk_drag_finish(dc, TRUE, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); - } - else if (info == WEBKIT_WEB_VIEW_TARGET_INFO_URI_LIST) { - if (PURPLE_IS_IM_CONVERSATION(conv)) - pidgin_dnd_file_manage(sd, convaccount, purple_conversation_get_name(conv)); - gtk_drag_finish(dc, TRUE, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); - } - else - gtk_drag_finish(dc, FALSE, FALSE, t); -} - - static PidginConversation * pidgin_conv_find_gtkconv(PurpleConversation * conv) { @@ -5550,43 +5024,6 @@ return FALSE; } -static void set_typing_font(GtkWidget *widget, PidginConversation *gtkconv) -{ -/* TODO WEBKIT */ -#if 0 - static PangoFontDescription *font_desc = NULL; - static GdkRGBA *color = NULL; - static gboolean enable = TRUE; - - if (font_desc == NULL) { - char *string = NULL; - gtk_widget_style_get(widget, - "typing-notification-font", &string, - "typing-notification-color", &color, - "typing-notification-enable", &enable, - NULL); - font_desc = pango_font_description_from_string(string); - g_free(string); - if (color == NULL) { - GdkRGBA def = {0x8888/65535.0, 0x8888/65535.0, 0x8888/65535.0, 1.0}; - color = gdk_rgba_copy(&def); - } - } - - gtk_text_buffer_create_tag(GTK_IMHTML(widget)->text_buffer, "TYPING-NOTIFICATION", - "foreground-rgba", color, - "font-desc", font_desc, - NULL); - - if (!enable) { - g_object_set_data(G_OBJECT(widget), "disable-typing-notification", GINT_TO_POINTER(TRUE)); - /* or may be 'gtkconv->disable_typing = TRUE;' instead? */ - } - - g_signal_handlers_disconnect_by_func(G_OBJECT(widget), set_typing_font, gtkconv); -#endif /* if 0 */ -} - /************************************************************************** * Conversation UI operations **************************************************************************/ @@ -5644,45 +5081,8 @@ return; } - /* Setup drag-and-drop */ - gtk_drag_dest_set(pane, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, - NULL, 0, GDK_ACTION_COPY); - targets = gtk_target_list_new(dnd_targets, G_N_ELEMENTS(dnd_targets)); - gtk_target_list_add(targets, gdk_atom_intern("text/uri-list", FALSE), 0, - WEBKIT_WEB_VIEW_TARGET_INFO_URI_LIST); - gtk_drag_dest_set_target_list(pane, targets); - - if (webkit_dnd_targets) { - targets = webkit_dnd_targets; - } else { - GtkTargetEntry *entries; - gint count; - - targets = webkit_web_view_get_paste_target_list(WEBKIT_WEB_VIEW(gtkconv->webview)); - entries = gtk_target_table_new_from_list(targets, &count); - targets = gtk_target_list_new(entries, count); - gtk_target_table_free(entries, count); - - gtk_target_list_add_table(targets, dnd_targets, G_N_ELEMENTS(dnd_targets)); - webkit_dnd_targets = targets; - } - - gtk_drag_dest_set(gtkconv->webview, 0, NULL, 0, GDK_ACTION_COPY); - gtk_drag_dest_set_target_list(gtkconv->webview, targets); - g_signal_connect(G_OBJECT(pane), "button_press_event", G_CALLBACK(ignore_middle_click), NULL); - g_signal_connect(G_OBJECT(pane), "drag-data-received", - G_CALLBACK(conv_dnd_recv), gtkconv); -#if 0 - /* FIXME: WebKit confuses the dnd source when this is enabled */ - g_signal_connect(G_OBJECT(gtkconv->webview), "drag-data-received", - G_CALLBACK(conv_dnd_recv), gtkconv); - g_signal_connect(G_OBJECT(gtkconv->entry), "drag-data-received", - G_CALLBACK(conv_dnd_recv), gtkconv); -#endif - - g_signal_connect(gtkconv->webview, "style-updated", G_CALLBACK(set_typing_font), gtkconv); /* Setup the container for the tab. */ gtkconv->tab_cont = tab_cont = gtk_box_new(GTK_ORIENTATION_VERTICAL, PIDGIN_HIG_BOX_SPACE); @@ -5705,9 +5105,6 @@ purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar") ); - pidgin_webview_switch_active_conversation( - PIDGIN_WEBVIEW(gtkconv->webview), conv); - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons")) gtk_widget_show(gtkconv->infopane_hbox); else @@ -5726,7 +5123,7 @@ if (generated_nick_colors == NULL) { GdkColor color; GdkRGBA rgba; - color = gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]; + color = gtk_widget_get_style(gtkconv->history)->base[GTK_STATE_NORMAL]; rgba.red = color.red / 65535.0; rgba.green = color.green / 65535.0; rgba.blue = color.blue / 65535.0; @@ -5846,9 +5243,6 @@ } g_array_unref(gtkconv->nick_colors); - - g_object_disconnect(G_OBJECT(gtkconv->theme), "any_signal::notify", - conv_variant_changed_cb, gtkconv, NULL); g_object_unref(gtkconv->theme); g_free(gtkconv); @@ -6231,39 +5625,20 @@ static void pidgin_conv_write_conv(PurpleConversation *conv, PurpleMessage *pmsg) { + PidginMessage *pidgin_msg = NULL; + PurpleMessageFlags flags; PidginConversation *gtkconv; PurpleConnection *gc; PurpleAccount *account; -#if 0 - int gtk_font_options = 0; - int gtk_font_options_all = 0; - char buf2[BUF_LONG]; - gboolean show_date; - char *mdate; - char *str; - char *with_font_tag; - char *sml_attrib = NULL; - size_t length; -#endif char *displaying; gboolean plugin_return; -#if 0 - gboolean is_rtl_message = FALSE; -#endif - - const char *message_html; - char *msg_tokenized; - char *escape; - char *script; - char *smileyed; - PurpleMessageFlags flags, old_flags; - const char *func = "appendMessage"; g_return_if_fail(conv != NULL); gtkconv = PIDGIN_CONVERSATION(conv); g_return_if_fail(gtkconv != NULL); flags = purple_message_get_flags(pmsg); +#if 0 if (gtkconv->attach_timer) { /* We are currently in the process of filling up the buffer with the message * history of the conversation. So we do not need to add the message here. @@ -6280,17 +5655,20 @@ if (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) pidgin_conv_switch_active_conversation(conv); } +#endif account = purple_conversation_get_account(conv); g_return_if_fail(account != NULL); gc = purple_account_get_connection(account); g_return_if_fail(gc != NULL || !(flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV))); +#if 0 /* Make sure URLs are clickable */ if(flags & PURPLE_MESSAGE_NO_LINKIFY) displaying = g_strdup(purple_message_get_contents(pmsg)); else displaying = purple_markup_linkify(purple_message_get_contents(pmsg)); +#endif plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1( pidgin_conversations_get_handle(), @@ -6298,13 +5676,17 @@ conv, pmsg)); if (plugin_return) { - g_free(displaying); +// g_free(displaying); return; } + + pidgin_msg = pidgin_message_new(pmsg); + talkatu_history_buffer_write_message( + TALKATU_HISTORY_BUFFER(gtkconv->history_buffer), + TALKATU_MESSAGE(pidgin_msg) + ); + #if 0 - length = strlen(displaying) + 1; -#endif - old_flags = gtkconv->last_flags; if ((flags & PURPLE_MESSAGE_SEND) && (old_flags & PURPLE_MESSAGE_SEND)) { message_html = pidgin_conversation_theme_get_template(gtkconv->theme, @@ -6366,6 +5748,7 @@ g_free(msg_tokenized); g_free(escape); +#endif #if 0 /* if the buffer is not empty add a <br> */ if (!pidgin_webview_is_empty(PIDGIN_WEBVIEW(gtkconv->webview))) @@ -6616,7 +5999,9 @@ purple_signal_emit(pidgin_conversations_get_handle(), (PURPLE_IS_IM_CONVERSATION(conv) ? "displayed-im-msg" : "displayed-chat-msg"), conv, pmsg); +#if 0 g_free(displaying); +#endif update_typing_message(gtkconv, NULL); } @@ -6831,14 +6216,6 @@ return FALSE; } -static void -pidgin_conv_send_confirm(PurpleConversation *conv, const char *message) -{ - PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); - - pidgin_webview_append_html(PIDGIN_WEBVIEW(gtkconv->webview), message); -} - /* * Makes sure all the menu items and all the buttons are hidden/shown and * sensitive/insensitive. This is called after changing tabs and when an @@ -7322,7 +6699,7 @@ pidgin_conv_chat_update_user, /* chat_update_user */ pidgin_conv_present_conversation, /* present */ pidgin_conv_has_focus, /* has_focus */ - pidgin_conv_send_confirm, /* send_confirm */ + NULL, /* send_confirm */ NULL, NULL, NULL, @@ -8064,7 +7441,6 @@ add_message_history_to_gtkconv(gpointer data) { PidginConversation *gtkconv = data; - PidginWebView *webview = PIDGIN_WEBVIEW(gtkconv->webview); int count = 0; int timer = gtkconv->attach_timer; time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->editor), "attach-start-time")); @@ -8074,8 +7450,10 @@ while (gtkconv->attach_current && count < ADD_MESSAGE_HISTORY_AT_ONCE) { PurpleMessage *msg = gtkconv->attach_current->data; if (!im && when && (guint64)when < purple_message_get_time(msg)) { +#if 0 pidgin_webview_append_html(webview, "<BR><HR>"); pidgin_webview_scroll_to_end(webview, TRUE); +#endif g_object_set_data(G_OBJECT(gtkconv->editor), "attach-start-time", NULL); } /* XXX: should it be gtkconv->active_conv? */ @@ -8112,8 +7490,10 @@ /* XXX: see above - should it be active_conv? */ pidgin_conv_write_conv(gtkconv->active_conv, msg); } +#if 0 pidgin_webview_append_html(webview, "<BR><HR>"); pidgin_webview_scroll_to_end(webview, TRUE); +#endif g_object_set_data(G_OBJECT(gtkconv->editor), "attach-start-time", NULL); }