From: Florian Zeitz Date: Sun, 23 Dec 2012 01:18:27 +0000 (+0100) Subject: Add some simple chat UI X-Git-Url: http://cgit.babelmonkeys.de/?p=jubjub.git;a=commitdiff_plain;h=d5df5e6b07d60d4ac8f43213e719d3331a8b5eb6 Add some simple chat UI --- diff --git a/data/gtk/chat.ui b/data/gtk/chat.ui new file mode 100644 index 0000000..8c352cd --- /dev/null +++ b/data/gtk/chat.ui @@ -0,0 +1,207 @@ + + + + + False + 400 + 200 + + + True + False + vertical + + + True + False + + + True + False + _Datei + True + + + True + False + + + gtk-new + True + False + True + True + + + + + gtk-open + True + False + True + True + + + + + gtk-save + True + False + True + True + + + + + gtk-save-as + True + False + True + True + + + + + True + False + + + + + gtk-quit + True + False + True + True + + + + + + + + + True + False + _Bearbeiten + True + + + True + False + + + gtk-cut + True + False + True + True + + + + + gtk-copy + True + False + True + True + + + + + gtk-paste + True + False + True + True + + + + + gtk-delete + True + False + True + True + + + + + + + + + True + False + _Ansicht + True + + + + + True + False + _Hilfe + True + + + True + False + + + gtk-about + True + False + True + True + + + + + + + + + False + True + 0 + + + + + True + True + never + in + + + True + True + False + word + False + + + + + True + True + 1 + + + + + True + True + ● + + + False + True + 2 + + + + + + diff --git a/src/gui/gtk/JubGtkChatUI.h b/src/gui/gtk/JubGtkChatUI.h new file mode 100644 index 0000000..5c0addb --- /dev/null +++ b/src/gui/gtk/JubGtkChatUI.h @@ -0,0 +1,20 @@ +#import +#import +#include + +typedef void (^jub_send_block_t)(OFString *); + +@interface JubGtkChatUI: OFObject +{ + GtkWidget *chat_window; + GtkTextBuffer *chat_buffer; + jub_send_block_t sendBlock; + BOOL bufferEmpty; +} + +- initWithTitle: (OFString*)title + sendBlock: (jub_send_block_t)sendBlock_; + +- (void)addMessage: (OFString*)text + sender: (OFString*)sender; +@end diff --git a/src/gui/gtk/JubGtkChatUI.m b/src/gui/gtk/JubGtkChatUI.m new file mode 100644 index 0000000..1dd1155 --- /dev/null +++ b/src/gui/gtk/JubGtkChatUI.m @@ -0,0 +1,143 @@ +#import "JubGtkChatUI.h" + +struct show_chat_params { + GtkWidget *window; + OFString *title; +}; + +static gboolean show_chat(gpointer data) +{ + struct show_chat_params *params = data; + + gtk_window_set_title(GTK_WINDOW(params->window), + [params->title UTF8String]); + gtk_widget_show(params->window); + + g_object_unref(params->window); + [params->title release]; + free(params); + + return FALSE; +} + +struct add_text_params { + OFString *name; + OFString *text; + GtkTextBuffer *buffer; + BOOL first; +}; + +static gboolean add_text(gpointer data) +{ + GtkTextIter endIter; + struct add_text_params *params = data; + + if (OF_LIKELY(!params->first)) + gtk_text_buffer_insert_at_cursor(params->buffer, "\n", 1); + + gtk_text_buffer_get_end_iter(params->buffer, &endIter); + gtk_text_buffer_insert_with_tags_by_name(params->buffer, &endIter, + [params->name UTF8String], [params->name UTF8StringLength], "bold", + NULL); + gtk_text_buffer_get_end_iter(params->buffer, &endIter); + gtk_text_buffer_insert_with_tags_by_name(params->buffer, &endIter, + ": ", 2, "bold", NULL); + + gtk_text_buffer_insert_at_cursor(params->buffer, + [params->text UTF8String], [params->text UTF8StringLength]); + + [params->name release]; + [params->text release]; + g_object_unref(params->buffer); + free(params); + + return FALSE; +} + +static gboolean call_send_block(GtkEntry *entry, GdkEventKey *event, + gpointer data) +{ + if (event->keyval != GDK_KEY_Return) return TRUE; + + jub_send_block_t block = data; + OFString *text = + [[OFString alloc] initWithUTF8String: gtk_entry_get_text(entry)]; + gtk_entry_set_text(entry, ""); + block(text); + [text release]; + + return TRUE; +} + +static gboolean add_tags(gpointer data) { + gtk_text_buffer_create_tag(data, "bold", "weight", + PANGO_WEIGHT_BOLD, NULL); + + return FALSE; +} + +@implementation JubGtkChatUI +- initWithTitle: (OFString*)title + sendBlock: (jub_send_block_t)sendBlock_ +{ + self = [super init]; + + @try { + GtkTextView *chat_view; + GtkEntry *chat_entry; + GtkBuilder *builder = gtk_builder_new(); + + sendBlock = [sendBlock_ copy]; + bufferEmpty = YES; + + gtk_builder_add_from_file(builder, "data/gtk/chat.ui", NULL); + + chat_window = GTK_WIDGET( + gtk_builder_get_object(builder, "ChatWindow")); + + chat_view = GTK_TEXT_VIEW( + gtk_builder_get_object(builder, "ChatTextView")); + + chat_entry = GTK_ENTRY( + gtk_builder_get_object(builder, "ChatEntry")); + + g_signal_connect(chat_entry, "key_release_event", + G_CALLBACK(call_send_block), sendBlock); + + chat_buffer = gtk_text_view_get_buffer(chat_view); + g_idle_add(add_tags, chat_buffer); + + struct show_chat_params *params = malloc(sizeof(*params)); + params->window = g_object_ref(chat_window); + params->title = [title retain]; + g_idle_add(show_chat, params); + + g_object_unref(builder); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + gtk_widget_destroy(chat_window); + [sendBlock release]; + + [super dealloc]; +} + +- (void)addMessage: (OFString*)text + sender: (OFString*)sender; +{ + struct add_text_params *params = malloc(sizeof(*params)); + params->name = [sender retain]; + params->text = [text retain]; + params->buffer = g_object_ref(chat_buffer); + params->first = bufferEmpty; + g_idle_add(add_text, params); + if (OF_UNLIKELY(bufferEmpty)) bufferEmpty = NO; +} +@end diff --git a/src/gui/gtk/JubGtkRosterUI.h b/src/gui/gtk/JubGtkRosterUI.h index 3244ad5..9bb0878 100644 --- a/src/gui/gtk/JubGtkRosterUI.h +++ b/src/gui/gtk/JubGtkRosterUI.h @@ -8,6 +8,7 @@ GtkTreeModelFilter *roster_filter; OFMapTable *groupMap; OFMutableDictionary *contactMap; + OFMutableDictionary *chatMap; OFCountedSet *presences; GtkBuilder *builder; } diff --git a/src/gui/gtk/JubGtkRosterUI.m b/src/gui/gtk/JubGtkRosterUI.m index acdffb6..9a2da29 100644 --- a/src/gui/gtk/JubGtkRosterUI.m +++ b/src/gui/gtk/JubGtkRosterUI.m @@ -1,5 +1,6 @@ #import "JubGtkRosterUI.h" #import "JubGObjectMap.h" +#import "JubGtkChatUI.h" static gboolean filter_roster_by_presence(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) @@ -38,6 +39,7 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, initWithKeyFunctions: keyFunctions valueFunctions: rowRefFunctions]; contactMap = [[OFMutableDictionary alloc] init]; + chatMap = [[OFMutableDictionary alloc] init]; presences = [[OFCountedSet alloc] init]; builder = g_object_ref(builder_); @@ -94,6 +96,34 @@ static gboolean refilter_roster(gpointer data) g_idle_add(refilter_roster, roster_filter); } +// FIXME: This needs to move somewhere else +- (void)connection: (XMPPConnection*)connection + didReceiveMessage: (XMPPMessage*)message +{ + JubGtkChatUI *chat = [chatMap objectForKey: [message.from bareJID]]; + if (chat == nil) { + OFString * title = [@"Chat with " stringByAppendingString: + [message.from bareJID]]; + chat = [JubGtkChatUI alloc]; + [[chat initWithTitle: title + sendBlock: ^(OFString *text) { + XMPPMessage *msg = + [XMPPMessage messageWithType: @"chat"]; + msg.to = message.from; + msg.body = text; + [connection sendStanza: msg]; + + [chat addMessage: msg.body + sender: [message.to bareJID]]; + }] autorelease]; + + [chatMap setObject: chat + forKey: [message.from bareJID]]; + } + [chat addMessage: message.body + sender: [message.from bareJID]]; +} + /* Roster Delegate methods */ struct add_roster_item_param { OFString *group; diff --git a/src/gui/gtk/Makefile b/src/gui/gtk/Makefile index 25bb2e5..275ebf9 100644 --- a/src/gui/gtk/Makefile +++ b/src/gui/gtk/Makefile @@ -1,5 +1,6 @@ STATIC_LIB_NOINST = gtk.a SRCS = JubGtkUI.m \ + JubGtkChatUI.m \ JubGtkRosterUI.m include ../../../buildsys.mk