Project

General

Profile

runtime_v3.6jwt.cc

Jim Turner, March 06, 2015 20:07

 
1
/*
2
 * runtime.c
3
 * Copyright 2010-2014 John Lindgren
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions, and the following disclaimer.
10
 *
11
 * 2. Redistributions in binary form must reproduce the above copyright notice,
12
 *    this list of conditions, and the following disclaimer in the documentation
13
 *    provided with the distribution.
14
 *
15
 * This software is provided "as is" and without any warranty, express or
16
 * implied. In no event shall the authors be liable for any damages arising from
17
 * the use of this software.
18
 */
19

    
20
#include "runtime.h"
21

    
22
#include <errno.h>
23
#include <locale.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <sys/stat.h>
27
#include <unistd.h>
28

    
29
#include <new>
30

    
31
#ifdef _WIN32
32
#include <windows.h>
33
#endif
34
#ifdef __APPLE__
35
#include <mach-o/dyld.h>
36
#endif
37

    
38
#include <glib.h>
39
#include <libintl.h>
40

    
41
#include "audstrings.h"
42
#include "drct.h"
43
#include "hook.h"
44
#include "internal.h"
45
#include "mainloop.h"
46
#include "playlist-internal.h"
47
#include "plugins-internal.h"
48
#include "scanner.h"
49

    
50
#define AUTOSAVE_INTERVAL 300000 /* milliseconds, autosave every 5 minutes */
51

    
52
#ifdef WORDS_BIGENDIAN
53
#define UTF16_NATIVE "UTF-16BE"
54
#else
55
#define UTF16_NATIVE "UTF-16LE"
56
#endif
57

    
58
#ifdef S_IRGRP
59
#define DIRMODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
60
#else
61
#define DIRMODE (S_IRWXU)
62
#endif
63

    
64
size_t misc_bytes_allocated;
65

    
66
static bool headless_mode;
67
static bool MuteInLieuOfPause;   /* JWT */
68

    
69
#if defined(USE_QT) && ! defined(USE_GTK)
70
static MainloopType mainloop_type = MainloopType::Qt;
71
#else
72
static MainloopType mainloop_type = MainloopType::GLib;
73
#endif
74

    
75
static aud::array<AudPath, String> aud_paths;
76

    
77
EXPORT void aud_set_headless_mode (bool headless)
78
{
79
    headless_mode = headless;
80
}
81

    
82
EXPORT bool aud_get_headless_mode ()
83
{
84
    return headless_mode;
85
}
86

    
87
EXPORT void aud_set_mainloop_type (MainloopType type)
88
{
89
    mainloop_type = type;
90
}
91

    
92
EXPORT MainloopType aud_get_mainloop_type ()
93
{
94
    return mainloop_type;
95
}
96

    
97
EXPORT void aud_set_pausemute_mode (bool pausemute_mode)  /* JWT */
98
{
99
    MuteInLieuOfPause = pausemute_mode;
100
}
101

    
102
EXPORT bool aud_get_pausemute_mode ()
103
{
104
    return MuteInLieuOfPause;
105
}
106

    
107
static StringBuf get_path_to_self ()
108
{
109
#ifdef HAVE_PROC_SELF_EXE
110

    
111
    StringBuf buf (-1);
112
    int len = readlink ("/proc/self/exe", buf, buf.len ());
113

    
114
    if (len < 0)
115
    {
116
        AUDERR ("Failed to read /proc/self/exe: %s\n", strerror (errno));
117
        return StringBuf ();
118
    }
119

    
120
    if (len == buf.len ())
121
        throw std::bad_alloc ();
122

    
123
    buf.resize (len);
124
    return buf;
125

    
126
#elif defined _WIN32
127

    
128
    StringBuf buf (-1);
129
    wchar_t * bufw = (wchar_t *) (char *) buf;
130
    int sizew = buf.len () / sizeof (wchar_t);
131
    int lenw = GetModuleFileNameW (nullptr, bufw, sizew);
132

    
133
    if (! lenw)
134
    {
135
        AUDERR ("GetModuleFileName failed.\n");
136
        return StringBuf ();
137
    }
138

    
139
    if (lenw == sizew)
140
        throw std::bad_alloc ();
141

    
142
    buf.resize (lenw * sizeof (wchar_t));
143
    buf.steal (str_convert (buf, buf.len (), UTF16_NATIVE, "UTF-8"));
144
    return buf;
145

    
146
#elif defined __APPLE__
147

    
148
    StringBuf buf (-1);
149
    uint32_t size = buf.len ();
150

    
151
    if (_NSGetExecutablePath (buf, & size) < 0)
152
        throw std::bad_alloc ();
153

    
154
    buf.resize (strlen (buf));
155
    return buf;
156

    
157
#else
158

    
159
    return StringBuf ();
160

    
161
#endif
162
}
163

    
164
static String relocate_path (const char * path, const char * from, const char * to)
165
{
166
    int oldlen = strlen (from);
167
    int newlen = strlen (to);
168

    
169
    if (oldlen && from[oldlen - 1] == G_DIR_SEPARATOR)
170
        oldlen --;
171
    if (newlen && to[newlen - 1] == G_DIR_SEPARATOR)
172
        newlen --;
173

    
174
#ifdef _WIN32
175
    if (strcmp_nocase (path, from, oldlen) || (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR))
176
#else
177
    if (strncmp (path, from, oldlen) || (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR))
178
#endif
179
        return String (path);
180

    
181
    return String (str_printf ("%.*s%s", newlen, to, path + oldlen));
182
}
183

    
184
static void set_default_paths ()
185
{
186
    aud_paths[AudPath::BinDir] = String (HARDCODE_BINDIR);
187
    aud_paths[AudPath::DataDir] = String (HARDCODE_DATADIR);
188
    aud_paths[AudPath::PluginDir] = String (HARDCODE_PLUGINDIR);
189
    aud_paths[AudPath::LocaleDir] = String (HARDCODE_LOCALEDIR);
190
    aud_paths[AudPath::DesktopFile] = String (HARDCODE_DESKTOPFILE);
191
    aud_paths[AudPath::IconFile] = String (HARDCODE_ICONFILE);
192
}
193

    
194
static void relocate_all_paths ()
195
{
196
    StringBuf bindir = filename_normalize (str_copy (HARDCODE_BINDIR));
197
    StringBuf datadir = filename_normalize (str_copy (HARDCODE_DATADIR));
198
    StringBuf plugindir = filename_normalize (str_copy (HARDCODE_PLUGINDIR));
199
    StringBuf localedir = filename_normalize (str_copy (HARDCODE_LOCALEDIR));
200
    StringBuf desktopfile = filename_normalize (str_copy (HARDCODE_DESKTOPFILE));
201
    StringBuf iconfile = filename_normalize (str_copy (HARDCODE_ICONFILE));
202

    
203
    StringBuf from = str_copy (bindir);
204

    
205
    /* get path to current executable */
206
    StringBuf to = get_path_to_self ();
207

    
208
    if (! to)
209
    {
210
        set_default_paths ();
211
        return;
212
    }
213

    
214
    to.steal (filename_normalize (std::move (to)));
215

    
216
    const char * base = last_path_element (to);
217

    
218
    if (! base)
219
    {
220
        set_default_paths ();
221
        return;
222
    }
223

    
224
    cut_path_element (to, base - to);
225

    
226
    /* trim trailing path elements common to old and new paths */
227
    /* at the end, the old and new installation prefixes are left */
228
    const char * a, * b;
229
    while ((a = last_path_element (from)) &&
230
     (b = last_path_element (to)) &&
231
#ifdef _WIN32
232
     ! strcmp_nocase (a, b))
233
#else
234
     ! strcmp (a, b))
235
#endif
236
    {
237
        cut_path_element (from, a - from);
238
        cut_path_element (to, b - to);
239
    }
240

    
241
    /* replace old prefix with new one in each path */
242
    aud_paths[AudPath::BinDir] = relocate_path (bindir, from, to);
243
    aud_paths[AudPath::DataDir] = relocate_path (datadir, from, to);
244
    aud_paths[AudPath::PluginDir] = relocate_path (plugindir, from, to);
245
    aud_paths[AudPath::LocaleDir] = relocate_path (localedir, from, to);
246
    aud_paths[AudPath::DesktopFile] = relocate_path (desktopfile, from, to);
247
    aud_paths[AudPath::IconFile] = relocate_path (iconfile, from, to);
248
}
249

    
250
EXPORT void aud_init_paths ()
251
{
252
    relocate_all_paths ();
253

    
254
    const char * xdg_config_home = g_get_user_config_dir ();
255

    
256
    aud_paths[AudPath::UserDir] = String (filename_build ({xdg_config_home, "audacious"}));
257
    aud_paths[AudPath::PlaylistDir] = String (filename_build
258
     ({aud_paths[AudPath::UserDir], "playlists"}));
259

    
260
    /* create ~/.config/audacious/playlists */
261
    if (g_mkdir_with_parents (aud_paths[AudPath::PlaylistDir], DIRMODE) < 0)
262
        AUDERR ("Failed to create %s: %s\n",
263
         (const char *) aud_paths[AudPath::PlaylistDir], strerror (errno));
264

    
265
#ifdef _WIN32
266
    /* set some UNIX-style environment variables */
267
    g_setenv ("HOME", g_get_home_dir (), true);
268
    g_setenv ("XDG_CONFIG_HOME", xdg_config_home, true);
269
    g_setenv ("XDG_DATA_HOME", g_get_user_data_dir (), true);
270
    g_setenv ("XDG_CACHE_HOME", g_get_user_cache_dir (), true);
271
#endif
272
}
273

    
274
EXPORT void aud_cleanup_paths ()
275
{
276
    for (String & path : aud_paths)
277
        path = String ();
278
}
279

    
280
EXPORT const char * aud_get_path (AudPath id)
281
{
282
    return aud_paths[id];
283
}
284

    
285
EXPORT void aud_init_i18n ()
286
{
287
    const char * localedir = aud_get_path (AudPath::LocaleDir);
288

    
289
    setlocale (LC_ALL, "");
290
    bindtextdomain (PACKAGE, localedir);
291
    bind_textdomain_codeset (PACKAGE, "UTF-8");
292
    bindtextdomain (PACKAGE "-plugins", localedir);
293
    bind_textdomain_codeset (PACKAGE "-plugins", "UTF-8");
294
    textdomain (PACKAGE);
295
}
296

    
297
EXPORT void aud_init ()
298
{
299
    g_thread_pool_set_max_idle_time (100);
300

    
301
    config_load ();
302

    
303
    art_init ();
304
    chardet_init ();
305
    eq_init ();
306
    playlist_init ();
307

    
308
    start_plugins_one ();
309

    
310
    scanner_init ();
311
    playlist_enable_scan (true);
312

    
313
    load_playlists ();
314
}
315

    
316
static void do_autosave (void *)
317
{
318
    hook_call ("config save", nullptr);
319
    save_playlists (false);
320
    config_save ();
321
}
322

    
323
EXPORT void aud_run ()
324
{
325
    start_plugins_two ();
326

    
327
    static QueuedFunc autosave;
328
    autosave.start (AUTOSAVE_INTERVAL, do_autosave, nullptr);
329

    
330
    /* calls "config save" before returning */
331
    interface_run ();
332

    
333
    autosave.stop ();
334

    
335
    stop_plugins_two ();
336
}
337

    
338
EXPORT void aud_cleanup ()
339
{
340
    save_playlists (true);
341

    
342
    aud_playlist_play (-1);
343
    playback_stop (true);
344

    
345
    adder_cleanup ();
346
    playlist_enable_scan (false);
347
    scanner_cleanup ();
348

    
349
    stop_plugins_one ();
350

    
351
    art_cleanup ();
352
    chardet_cleanup ();
353
    eq_cleanup ();
354
    playlist_end ();
355

    
356
    event_queue_cancel_all ();
357
    hook_cleanup ();
358

    
359
    config_save ();
360
    config_cleanup ();
361
}
362

    
363
EXPORT void aud_leak_check ()
364
{
365
    string_leak_check ();
366

    
367
    if (misc_bytes_allocated)
368
        AUDWARN ("Bytes allocated at exit: %zd\n", misc_bytes_allocated);
369
}