1 /* Copyright (C) 2016-2017 Shengyu Zhang <i@silverrainz.me>
2  *
3  * This file is part of Srain.
4  *
5  * Srain is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /* @file sui.c
20  * @brief Srain UI module interfaces
21  * @author Shengyu Zhang <i@silverrainz.me>
22  * @version 0.06.2
23  * @date 2016-06-29
24  */
25 
26 #include <gtk/gtk.h>
27 #include <string.h>
28 
29 #include "core/core.h"
30 #include "sui/sui.h"
31 
32 #include "srain.h"
33 #include "i18n.h"
34 #include "log.h"
35 #include "meta.h"
36 #include "ret.h"
37 
38 #include "sui_common.h"
39 #include "sui_app.h"
40 #include "sui_window.h"
41 #include "sui_buffer.h"
42 #include "sui_server_buffer.h"
43 #include "sui_chat_buffer.h"
44 #include "sui_channel_buffer.h"
45 #include "sui_dialog_buffer.h"
46 #include "sui_message.h"
47 #include "sui_misc_message.h"
48 #include "sui_send_message.h"
49 #include "sui_recv_message.h"
50 
sui_proc_pending_event()51 void sui_proc_pending_event(){
52     while (gtk_events_pending()) gtk_main_iteration();
53 }
54 
sui_new_application(const char * id,void * ctx,SuiApplicationEvents * events,SuiApplicationConfig * cfg)55 SuiApplication* sui_new_application(const char *id, void *ctx,
56         SuiApplicationEvents *events, SuiApplicationConfig *cfg) {
57     return sui_application_new(id, ctx, events, cfg);
58 }
59 
sui_free_application(SuiApplication * app)60 void sui_free_application(SuiApplication *app){
61     sui_application_exit(app);
62 }
63 
sui_run_application(SuiApplication * app,int argc,char * argv[])64 void sui_run_application(SuiApplication *app, int argc, char *argv[]){
65     sui_application_run(app, argc, argv);
66 }
67 
sui_new_window(SuiApplication * app,SuiWindowEvents * events)68 SuiWindow* sui_new_window(SuiApplication *app, SuiWindowEvents *events){
69     SuiWindow *win;
70     SuiWindowConfig *cfg;
71     SuiApplicationConfig *app_cfg;
72 
73     cfg = sui_window_config_new();
74     app_cfg = sui_application_get_config(app);
75     *cfg = app_cfg->window; // Copy window config
76 
77     win = sui_window_new(app, events, cfg);
78     gtk_window_present(GTK_WINDOW(win));
79 
80     return win;
81 }
82 
sui_free_window(SuiWindow * win)83 void sui_free_window(SuiWindow *win){
84     g_return_if_fail(win);
85     // TODO
86 }
87 
sui_new_buffer(void * ctx,SuiBufferEvents * events,SuiBufferConfig * cfg)88 SuiBuffer* sui_new_buffer(void *ctx, SuiBufferEvents *events, SuiBufferConfig *cfg){
89     SuiBuffer *buf;
90     SrnChat *chat;
91 
92     // FIXME: dont use core's type here?
93     chat = ctx;
94     switch (chat->type) {
95         case SRN_CHAT_TYPE_SERVER:
96             buf = SUI_BUFFER(sui_server_buffer_new(ctx, events, cfg));
97             break;
98         case SRN_CHAT_TYPE_CHANNEL:
99             buf = SUI_BUFFER(sui_channel_buffer_new(ctx, events, cfg));
100             break;
101         case SRN_CHAT_TYPE_DIALOG:
102             buf = SUI_BUFFER(sui_dialog_buffer_new(ctx, events, cfg));
103             break;
104         default:
105             g_return_val_if_reached(NULL);
106     }
107     // FIXME: Wrong usage of sui_common_get_cur_window()
108     sui_window_add_buffer(sui_common_get_cur_window(), buf);
109 
110     return buf;
111 }
112 
sui_free_buffer(SuiBuffer * buf)113 void sui_free_buffer(SuiBuffer *buf){
114     g_return_if_fail(SUI_IS_BUFFER(buf));
115     // FIXME: Wrong usage of sui_common_get_cur_window()
116     sui_window_rm_buffer(sui_common_get_cur_window(), buf);
117 }
118 
sui_activate_buffer(SuiBuffer * buf)119 void sui_activate_buffer(SuiBuffer *buf){
120     g_return_if_fail(SUI_IS_BUFFER(buf));
121     sui_window_set_cur_buffer(sui_common_get_cur_window(), buf);
122 }
123 
sui_buffer_add_message(SuiBuffer * buf,SuiMessage * msg)124 void sui_buffer_add_message(SuiBuffer *buf, SuiMessage *msg){
125     GType type;
126     SuiWindow *win;
127     SuiSideBar *sidebar;
128     SuiSideBarItem *item;
129     SuiMessageList *list;
130 
131     g_return_if_fail(SUI_IS_BUFFER(buf));
132     g_return_if_fail(SUI_IS_MESSAGE(msg));
133 
134     /* Add message */
135     sui_message_set_buffer(msg, buf);
136     sui_message_update(msg);
137     list = sui_buffer_get_message_list(buf);
138     type = G_OBJECT_TYPE(msg);
139     if (type == SUI_TYPE_MISC_MESSAGE){
140         sui_message_list_add_message(list, msg, GTK_ALIGN_CENTER);
141     } else if (type == SUI_TYPE_SEND_MESSAGE){
142         sui_message_list_add_message(list, msg, GTK_ALIGN_END);
143     } else if (type == SUI_TYPE_RECV_MESSAGE){
144         sui_message_list_add_message(list, msg, GTK_ALIGN_START);
145     } else {
146         g_warn_if_reached();
147     }
148 
149     /* Update side bar */
150     win = SUI_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(buf)));
151     g_return_if_fail(SUI_IS_WINDOW(win));
152 
153     sidebar = sui_window_get_side_bar(win);
154     item = sui_side_bar_get_item(sidebar, buf);
155     sui_message_update_side_bar_item(msg, item);
156 
157     if (buf == sui_common_get_cur_buffer()){
158         // Don't show counter while buffer is active
159         sui_side_bar_item_clear_count(item);
160     }
161 }
162 
sui_free_message(SuiMessage * msg)163 void sui_free_message(SuiMessage *msg){
164     // TODO
165 }
166 
167 /**
168  * @brief ``sui_notify_message`` sends a notification about the ``msg`` as
169  * appropriate.
170  *
171  * @param msg
172  */
sui_notify_message(SuiMessage * msg)173 void sui_notify_message(SuiMessage *msg){
174     bool in_app; // Whether a in-app notification
175     SuiApplication *app;
176     SuiWindow *win;
177     SuiBuffer *buf;
178     SuiBufferConfig *buf_cfg;
179     SuiNotification *notif;
180 
181     g_return_if_fail(SUI_IS_MESSAGE(msg));
182     in_app = FALSE;
183     app = sui_application_get_instance();
184     g_return_if_fail(SUI_IS_APPLICATION(app));
185     win = sui_application_get_cur_window(app);
186     g_return_if_fail(SUI_IS_WINDOW(win));
187     buf = sui_message_get_buffer(msg);
188     g_return_if_fail(SUI_IS_BUFFER(buf));
189     buf_cfg = sui_buffer_get_config(buf);
190 
191     if (!buf_cfg->notify){
192         DBG_FR("Notification is disabled");
193         return;
194     }
195     if (sui_window_is_active(win)){
196         DBG_FR("Window is active");
197         if (sui_window_get_cur_buffer(win) == buf){
198             DBG_FR("Buffer is active");
199             return;
200         }
201         in_app = TRUE;
202     }
203 
204     notif = sui_message_new_notification(msg);
205     if (in_app) {
206         // TODO: In-app notification support
207     } else {
208         sui_application_highlight_tray_icon(app, TRUE);
209         sui_application_send_notification(app, notif);
210     }
211 
212     sui_notification_free(notif);
213 }
214 
sui_new_misc_message(void * ctx,SuiMiscMessageStyle style)215 SuiMessage *sui_new_misc_message(void *ctx, SuiMiscMessageStyle style){
216     return SUI_MESSAGE(sui_misc_message_new(ctx, style));
217 }
218 
sui_new_send_message(void * ctx)219 SuiMessage *sui_new_send_message(void *ctx){
220     return SUI_MESSAGE(sui_send_message_new(ctx));
221 }
222 
sui_new_recv_message(void * ctx)223 SuiMessage *sui_new_recv_message(void *ctx){
224     return SUI_MESSAGE(sui_recv_message_new(ctx));
225 }
226 
sui_new_user(void * ctx)227 SuiUser* sui_new_user(void *ctx){
228     return sui_user_new(ctx);
229 }
230 
sui_free_user(SuiUser * user)231 void sui_free_user(SuiUser *user){
232     sui_user_free(user);
233 }
234 
sui_update_user(SuiBuffer * buf,SuiUser * user)235 void sui_update_user(SuiBuffer *buf, SuiUser *user){
236     g_return_if_fail(SUI_IS_CHAT_BUFFER(buf));
237     g_return_if_fail(user);
238 
239     sui_user_list_update_user(
240             sui_chat_buffer_get_user_list(SUI_CHAT_BUFFER(buf)), user);
241 }
242 
sui_add_user(SuiBuffer * buf,SuiUser * user)243 void sui_add_user(SuiBuffer *buf, SuiUser *user){
244     SuiChatBuffer *chat_buf;
245     SuiUserList *list;
246 
247     g_return_if_fail(SUI_IS_CHAT_BUFFER(buf));
248     g_return_if_fail(user);
249 
250     chat_buf = SUI_CHAT_BUFFER(buf);
251     list = sui_chat_buffer_get_user_list(chat_buf);
252 
253     sui_user_list_add_user(list, user);
254 }
255 
sui_rm_user(SuiBuffer * buf,SuiUser * user)256 void sui_rm_user(SuiBuffer *buf, SuiUser *user){
257     SuiChatBuffer *chat_buf;
258     SuiUserList *list;
259 
260     g_return_if_fail(SUI_IS_CHAT_BUFFER(buf));
261     g_return_if_fail(user);
262 
263     chat_buf = SUI_CHAT_BUFFER(buf);
264     list = sui_chat_buffer_get_user_list(chat_buf);
265 
266     sui_user_list_rm_user(list, user);
267 }
268 
sui_set_topic(SuiBuffer * buf,const char * topic)269 void sui_set_topic(SuiBuffer *buf, const char *topic){
270     SuiBuffer *buffer;
271 
272     g_return_if_fail(buf);
273     g_return_if_fail(SUI_IS_BUFFER(buf));
274     g_return_if_fail(topic);
275 
276     buffer = buf;
277 
278     sui_buffer_set_topic(buffer, topic);
279 }
280 
sui_set_topic_setter(SuiBuffer * buf,const char * setter)281 void sui_set_topic_setter(SuiBuffer *buf, const char *setter){
282     SuiBuffer *buffer;
283 
284     g_return_if_fail(buf);
285     g_return_if_fail(SUI_IS_BUFFER(buf));
286     g_return_if_fail(setter);
287 
288     buffer = buf;
289 
290     sui_buffer_set_topic_setter(buffer, setter);
291 }
292 
sui_message_box(const char * title,const char * msg)293 void sui_message_box(const char *title, const char *msg){
294     GtkMessageDialog *dia;
295     char *markuped_msg;
296 
297     gtk_init(0, NULL); // FIXME: config
298 
299     dia = GTK_MESSAGE_DIALOG(
300             gtk_message_dialog_new(GTK_WINDOW(sui_common_get_cur_window()),
301                 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
302                 GTK_MESSAGE_INFO,
303                 GTK_BUTTONS_OK,
304                 NULL
305                 )
306             );
307 
308     gtk_window_set_title(GTK_WINDOW(dia), title);
309     // TODO: accpet markuped message
310     markuped_msg = g_markup_escape_text(msg, -1);
311     gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dia), markuped_msg);
312     g_free(markuped_msg);
313 
314     /* Without this, message dialog cannot be displayed on the center of screen */
315     sui_proc_pending_event();
316 
317     gtk_dialog_run(GTK_DIALOG(dia));
318     gtk_widget_destroy(GTK_WIDGET(dia));
319 }
320 
sui_chan_list_start(SuiBuffer * buf)321 void sui_chan_list_start(SuiBuffer *buf){
322     SuiServerBuffer *srv_buf;
323     SuiJoinPanel *panel;
324 
325     g_return_if_fail(SUI_IS_SERVER_BUFFER(buf));
326     srv_buf = SUI_SERVER_BUFFER(buf);
327     panel = sui_server_buffer_get_join_panel(srv_buf);
328     g_return_if_fail(!sui_join_panel_get_is_adding(panel));
329 
330     sui_join_panel_set_is_adding(panel, TRUE);
331     sui_server_buffer_clear_channel(srv_buf);
332 }
333 
sui_chan_list_add(SuiBuffer * buf,const char * chan,int users,const char * topic)334 void sui_chan_list_add(SuiBuffer *buf, const char *chan, int users,
335         const char *topic){
336     SuiServerBuffer *srv_buf;
337     SuiJoinPanel *panel;
338 
339     g_return_if_fail(SUI_IS_SERVER_BUFFER(buf));
340     g_return_if_fail(chan);
341     g_return_if_fail(topic);
342     srv_buf = SUI_SERVER_BUFFER(buf);
343     panel = sui_server_buffer_get_join_panel(srv_buf);
344     g_return_if_fail(sui_join_panel_get_is_adding(panel));
345 
346     sui_server_buffer_add_channel(srv_buf, chan, users, topic);
347     sui_proc_pending_event();
348 }
349 
sui_chan_list_end(SuiBuffer * buf)350 void sui_chan_list_end(SuiBuffer *buf){
351     SuiServerBuffer *srv_buf;
352     SuiJoinPanel *panel;
353 
354     g_return_if_fail(SUI_IS_SERVER_BUFFER(buf));
355     srv_buf = SUI_SERVER_BUFFER(buf);
356     panel = sui_server_buffer_get_join_panel(srv_buf);
357     g_return_if_fail(sui_join_panel_get_is_adding(panel));
358 
359     sui_join_panel_set_is_adding(panel, FALSE);
360 }
361