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