| |
1 /* |
| |
2 * Pidgin - Internet Messenger |
| |
3 * Copyright (C) Pidgin Developers <devel@pidgin.im> |
| |
4 * |
| |
5 * Pidgin is the legal property of its developers, whose names are too numerous |
| |
6 * to list here. Please refer to the COPYRIGHT file distributed with this |
| |
7 * source distribution. |
| |
8 * |
| |
9 * This program is free software; you can redistribute it and/or modify |
| |
10 * it under the terms of the GNU General Public License as published by |
| |
11 * the Free Software Foundation; either version 2 of the License, or |
| |
12 * (at your option) any later version. |
| |
13 * |
| |
14 * This program is distributed in the hope that it will be useful, |
| |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
17 * GNU General Public License for more details. |
| |
18 * |
| |
19 * You should have received a copy of the GNU General Public License |
| |
20 * along with this program; if not, see <https://www.gnu.org/licenses/>. |
| |
21 */ |
| |
22 |
| |
23 #ifdef HAVE_CONFIG_H |
| |
24 # include <config.h> |
| |
25 #endif |
| |
26 |
| |
27 #include <glib.h> |
| |
28 #include <glib/gi18n-lib.h> |
| |
29 #include <glib/gstdio.h> |
| |
30 |
| |
31 #include <gplugin.h> |
| |
32 #include <purple.h> |
| |
33 |
| |
34 #include "pidginapplication.h" |
| |
35 |
| |
36 #include "gtkaccount.h" |
| |
37 #include "gtkblist.h" |
| |
38 #include "pidgincore.h" |
| |
39 #include "pidgindebug.h" |
| |
40 |
| |
41 struct _PidginApplication { |
| |
42 GtkApplication parent; |
| |
43 }; |
| |
44 |
| |
45 /****************************************************************************** |
| |
46 * Globals |
| |
47 *****************************************************************************/ |
| |
48 static gchar *opt_config_dir_arg = NULL; |
| |
49 static gboolean opt_nologin = FALSE; |
| |
50 |
| |
51 static GOptionEntry option_entries[] = { |
| |
52 { |
| |
53 "config", 'c', 0, G_OPTION_ARG_FILENAME, &opt_config_dir_arg, |
| |
54 N_("use DIR for config files"), N_("DIR") |
| |
55 }, { |
| |
56 "nologin", 'n', 0, G_OPTION_ARG_NONE, &opt_nologin, |
| |
57 N_("don't automatically login"), NULL |
| |
58 }, |
| |
59 { |
| |
60 "version", 'v', 0, G_OPTION_ARG_NONE, NULL, |
| |
61 N_("display the current version and exit"), NULL |
| |
62 }, { |
| |
63 NULL |
| |
64 } |
| |
65 }; |
| |
66 |
| |
67 G_DEFINE_TYPE(PidginApplication, pidgin_application, GTK_TYPE_APPLICATION) |
| |
68 |
| |
69 /****************************************************************************** |
| |
70 * GApplication Implementation |
| |
71 *****************************************************************************/ |
| |
72 static void |
| |
73 pidgin_application_startup(GApplication *application) { |
| |
74 GtkCssProvider *provider = NULL; |
| |
75 GError *error = NULL; |
| |
76 GList *active_accounts = NULL; |
| |
77 gchar *search_path = NULL; |
| |
78 |
| |
79 G_APPLICATION_CLASS(pidgin_application_parent_class)->startup(application); |
| |
80 |
| |
81 /* set a user-specified config directory */ |
| |
82 if (opt_config_dir_arg != NULL) { |
| |
83 if (g_path_is_absolute(opt_config_dir_arg)) { |
| |
84 purple_util_set_user_dir(opt_config_dir_arg); |
| |
85 } else { |
| |
86 /* Make an absolute (if not canonical) path */ |
| |
87 gchar *cwd = g_get_current_dir(); |
| |
88 gchar *path = g_build_filename(cwd, opt_config_dir_arg, NULL); |
| |
89 |
| |
90 purple_util_set_user_dir(path); |
| |
91 |
| |
92 g_free(cwd); |
| |
93 g_free(path); |
| |
94 } |
| |
95 } |
| |
96 |
| |
97 provider = gtk_css_provider_new(); |
| |
98 |
| |
99 search_path = g_build_filename(purple_config_dir(), "gtk-3.0.css", NULL); |
| |
100 gtk_css_provider_load_from_path(provider, search_path, &error); |
| |
101 if(error != NULL) { |
| |
102 purple_debug_error("gtk", "Unable to load custom gtk-3.0.css: %s\n", |
| |
103 error->message); |
| |
104 g_clear_error(&error); |
| |
105 } else { |
| |
106 GdkScreen *screen = gdk_screen_get_default(); |
| |
107 gtk_style_context_add_provider_for_screen(screen, |
| |
108 GTK_STYLE_PROVIDER(provider), |
| |
109 GTK_STYLE_PROVIDER_PRIORITY_USER); |
| |
110 } |
| |
111 |
| |
112 g_free(search_path); |
| |
113 |
| |
114 #ifdef _WIN32 |
| |
115 winpidgin_init(); |
| |
116 #endif |
| |
117 |
| |
118 purple_core_set_ui_ops(pidgin_core_get_ui_ops()); |
| |
119 |
| |
120 if(!purple_core_init(PIDGIN_UI)) { |
| |
121 fprintf(stderr, |
| |
122 _("Initialization of the libpurple core failed. Aborting!\n" |
| |
123 "Please report this!\n")); |
| |
124 g_abort(); |
| |
125 } |
| |
126 |
| |
127 if(g_getenv("PURPLE_PLUGINS_SKIP")) { |
| |
128 purple_debug_info("gtk", |
| |
129 "PURPLE_PLUGINS_SKIP environment variable " |
| |
130 "set, skipping normal Pidgin plugin paths"); |
| |
131 } else { |
| |
132 search_path = g_build_filename(purple_data_dir(), "plugins", NULL); |
| |
133 |
| |
134 if(!g_file_test(search_path, G_FILE_TEST_IS_DIR)) { |
| |
135 g_mkdir(search_path, S_IRUSR | S_IWUSR | S_IXUSR); |
| |
136 } |
| |
137 |
| |
138 purple_plugins_add_search_path(search_path); |
| |
139 g_free(search_path); |
| |
140 |
| |
141 purple_plugins_add_search_path(PIDGIN_LIBDIR); |
| |
142 } |
| |
143 |
| |
144 purple_plugins_refresh(); |
| |
145 |
| |
146 /* load plugins we had when we quit */ |
| |
147 purple_plugins_load_saved(PIDGIN_PREFS_ROOT "/plugins/loaded"); |
| |
148 |
| |
149 /* gk 20201008: this needs to be moved to the buddy list initialization. */ |
| |
150 pidgin_blist_setup_sort_methods(); |
| |
151 |
| |
152 gtk_window_set_default_icon_name("pidgin"); |
| |
153 |
| |
154 g_free(opt_config_dir_arg); |
| |
155 opt_config_dir_arg = NULL; |
| |
156 |
| |
157 /* |
| |
158 * We want to show the blist early in the init process so the |
| |
159 * user feels warm and fuzzy. |
| |
160 */ |
| |
161 purple_blist_show(); |
| |
162 |
| |
163 if(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/enabled")) { |
| |
164 pidgin_debug_window_show(); |
| |
165 } |
| |
166 |
| |
167 if(opt_nologin) { |
| |
168 /* Set all accounts to "offline" */ |
| |
169 PurpleSavedStatus *saved_status; |
| |
170 |
| |
171 /* If we've used this type+message before, lookup the transient status */ |
| |
172 saved_status = purple_savedstatus_find_transient_by_type_and_message( |
| |
173 PURPLE_STATUS_OFFLINE, NULL); |
| |
174 |
| |
175 /* If this type+message is unique then create a new transient saved status */ |
| |
176 if(saved_status == NULL) { |
| |
177 saved_status = purple_savedstatus_new(NULL, PURPLE_STATUS_OFFLINE); |
| |
178 } |
| |
179 |
| |
180 /* Set the status for each account */ |
| |
181 purple_savedstatus_activate(saved_status); |
| |
182 } else { |
| |
183 /* Everything is good to go--sign on already */ |
| |
184 if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) { |
| |
185 purple_savedstatus_activate(purple_savedstatus_get_startup()); |
| |
186 } |
| |
187 |
| |
188 purple_accounts_restore_current_statuses(); |
| |
189 } |
| |
190 |
| |
191 if((active_accounts = purple_accounts_get_all_active()) == NULL) { |
| |
192 pidgin_accounts_window_show(); |
| |
193 } else { |
| |
194 g_list_free(active_accounts); |
| |
195 } |
| |
196 |
| |
197 /* GTK clears the notification for us when opening the first window, but we |
| |
198 * may have launched with only a status icon, so clear it just in case. |
| |
199 */ |
| |
200 gdk_notify_startup_complete(); |
| |
201 |
| |
202 #ifdef _WIN32 |
| |
203 winpidgin_post_init(); |
| |
204 #endif |
| |
205 |
| |
206 /* TODO: Use GtkApplicationWindow or add a window instead */ |
| |
207 g_application_hold(application); |
| |
208 } |
| |
209 |
| |
210 static void |
| |
211 pidgin_application_activate(GApplication *application) { |
| |
212 PidginBuddyList *blist = pidgin_blist_get_default_gtk_blist(); |
| |
213 |
| |
214 if(blist != NULL && blist->window != NULL) { |
| |
215 gtk_window_present(GTK_WINDOW(blist->window)); |
| |
216 } |
| |
217 } |
| |
218 |
| |
219 static gint |
| |
220 pidgin_application_command_line(GApplication *application, |
| |
221 GApplicationCommandLine *cmdline) |
| |
222 { |
| |
223 gchar **argv = NULL; |
| |
224 gint argc = 0, i = 0; |
| |
225 |
| |
226 argv = g_application_command_line_get_arguments(cmdline, &argc); |
| |
227 |
| |
228 if(argc == 1) { |
| |
229 /* No arguments, just activate */ |
| |
230 g_application_activate(application); |
| |
231 } |
| |
232 |
| |
233 /* Start at 1 to skip the executable name */ |
| |
234 for (i = 1; i < argc; i++) { |
| |
235 purple_got_protocol_handler_uri(argv[i]); |
| |
236 } |
| |
237 |
| |
238 g_strfreev(argv); |
| |
239 |
| |
240 return 0; |
| |
241 } |
| |
242 |
| |
243 static gint |
| |
244 pidgin_application_handle_local_options(GApplication *application, |
| |
245 GVariantDict *options) |
| |
246 { |
| |
247 if (g_variant_dict_contains(options, "version")) { |
| |
248 printf("%s %s (libpurple %s)\n", PIDGIN_NAME, DISPLAY_VERSION, |
| |
249 purple_core_get_version()); |
| |
250 |
| |
251 return 0; |
| |
252 } |
| |
253 |
| |
254 return -1; |
| |
255 } |
| |
256 |
| |
257 /****************************************************************************** |
| |
258 * GObject Implementation |
| |
259 *****************************************************************************/ |
| |
260 static void |
| |
261 pidgin_application_init(PidginApplication *application) { |
| |
262 GApplication *gapp = G_APPLICATION(application); |
| |
263 |
| |
264 g_application_add_main_option_entries(gapp, option_entries); |
| |
265 g_application_add_option_group(gapp, purple_get_option_group()); |
| |
266 g_application_add_option_group(gapp, gplugin_get_option_group()); |
| |
267 } |
| |
268 |
| |
269 static void |
| |
270 pidgin_application_class_init(PidginApplicationClass *klass) { |
| |
271 GApplicationClass *app_class = G_APPLICATION_CLASS(klass); |
| |
272 |
| |
273 app_class->startup = pidgin_application_startup; |
| |
274 app_class->activate = pidgin_application_activate; |
| |
275 app_class->command_line = pidgin_application_command_line; |
| |
276 app_class->handle_local_options = pidgin_application_handle_local_options; |
| |
277 } |
| |
278 |
| |
279 /****************************************************************************** |
| |
280 * Public API |
| |
281 *****************************************************************************/ |
| |
282 GApplication * |
| |
283 pidgin_application_new(void) { |
| |
284 return g_object_new( |
| |
285 PIDGIN_TYPE_APPLICATION, |
| |
286 "flags", G_APPLICATION_CAN_OVERRIDE_APP_ID | |
| |
287 G_APPLICATION_HANDLES_COMMAND_LINE, |
| |
288 "register-session", TRUE, |
| |
289 NULL); |
| |
290 } |