~audio-recorder/audio-recorder/trunk

22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
1
/*
1424 by Osmo Antero
Version 3.0.0
2
 * Copyright (c) 2011- Osmo Antero.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Library General Public
6
 * License as published by the Free Software Foundation; either
239 by Osmo Antero
Moving to GPL3 license. All src/*.c should now comply to GPL3.
7
 * version 3 of the License (GPL3), or any later version.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
463 by Osmo Antero
Updated README and INSTALL files.
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
239 by Osmo Antero
Moving to GPL3 license. All src/*.c should now comply to GPL3.
12
 * See the GNU Library General Public License 3 for more details.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
13
 *
14
 * You should have received a copy of the GNU Library General Public
239 by Osmo Antero
Moving to GPL3 license. All src/*.c should now comply to GPL3.
15
 * License 3 along with this program; if not, see /usr/share/common-licenses/GPL file
1012.1.5 by David Rabel
GPL boilerplate updated in source files.
16
 * or <http://www.gnu.org/licenses/>.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
17
*/
18
#include <string.h>
19
#include <stdlib.h>
20
21
#include <glib.h>
22
#include <glib/gstdio.h>
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
23
#include <gio/gdesktopappinfo.h>
1 by Osmo Antero Maatta
Initial import 17.jan.2011
24
#include <time.h>
25
26
#include "support.h" // _(x)
27
#include "utility.h"
28
#include "log.h"
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
29
#include "dconf.h"
1 by Osmo Antero Maatta
Initial import 17.jan.2011
30
31
// Some utility functions
32
339 by Osmo Antero
Replaced fized size icons 16x16,...,64x64 with scalable svg images. The off-icon on the systray is now white-gray.
33
gboolean run_tool_for_file(gchar *file, gchar *alternative_tool, GError **error) {
34
    // Run suitable program/tool for the given file.
67 by Osmo Antero
Menu item 'Show recordings' displays saved recordings in a file browser.
35
36
    if (error) {
37
        *error = NULL;
38
    }
39
40
    // Create place for 2 arguments + NULL
41
    gchar **argv = g_new(gchar*, 3);
42
43
    // Try: xdg-open
44
    gchar *tool = find_command_path("xdg-open");
45
46
    if ((!tool) && alternative_tool) {
47
        // Try: alternative_tool
48
        tool = find_command_path(alternative_tool);
49
    }
50
51
    LOG_DEBUG("Running:%s \"%s\"\n", tool, file);
52
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
53
    // The tool command
67 by Osmo Antero
Menu item 'Show recordings' displays saved recordings in a file browser.
54
    argv[0] = g_strdup(tool);
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
55
    // File or URL
67 by Osmo Antero
Menu item 'Show recordings' displays saved recordings in a file browser.
56
    argv[1] = g_strdup(file);
57
    argv[2] = NULL;
58
59
    // Now create a process and run the command.
60
    // It will return immediately because it's asynchronous.
61
    exec_command_async(argv, error);
62
63
    gboolean ret = TRUE;
64
65
    if (error && *error) {
66
        // Error
67
        ret = FALSE;
68
    }
69
70
    g_free(tool);
71
    g_strfreev(argv);
72
73
    return ret;
74
}
75
1 by Osmo Antero Maatta
Initial import 17.jan.2011
76
gboolean is_file_writable(gchar *filename) {
77
    // Test if filename is writable
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
78
    GFileOutputStream *fstream;
79
    GError *error = NULL;
1423 by Osmo Antero
Fix problem with duplicate messages from media players.
80
81
    if (!filename) return FALSE;
82
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
83
    GFile *file = g_file_new_for_path(filename);
1423 by Osmo Antero
Fix problem with duplicate messages from media players.
84
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
85
    gboolean del = FALSE;
86
87
    if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
88
        fstream = g_file_append_to(file, G_FILE_CREATE_NONE, NULL, &error);
89
    } else {
90
        fstream = g_file_create(file, G_FILE_CREATE_NONE, NULL, &error);
91
        del = (!error);
92
    }
93
94
    gboolean ret = TRUE;
95
96
    if (error || !fstream) {
97
        ret = FALSE;
98
    }
99
100
    if (error)
101
        g_error_free(error);
463 by Osmo Antero
Updated README and INSTALL files.
102
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
103
    g_object_unref(fstream);
104
    g_object_unref(file);
105
106
    if (del)
107
        g_remove(filename);
108
109
    return ret;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
110
}
111
112
gchar *check_null(gchar *s) {
113
    // Return safe (not null) string
114
    static gchar *not_null = "\0";
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
115
    if (!s)
1 by Osmo Antero Maatta
Initial import 17.jan.2011
116
        return not_null;
117
    else
118
        return s;
119
}
120
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
121
guint str_length(const gchar *s, guint maxlen) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
122
    // Return length of s
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
123
    if (!s) return 0;
124
    return g_utf8_strlen(s, maxlen);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
125
}
126
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
127
guint str_length0(const gchar *s) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
128
    return str_length(s, MAX_PATH_LEN);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
129
}
130
131
void str_copy(gchar *dest, gchar *src, guint len) {
132
    // Strncpy src to dest
101 by Osmo Antero
New media-player interface that's based on the MediaPlayer2 standard. See src/dbus-mpris2.c.
133
    if (!dest) return;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
134
135
    if (!src) {
136
        *dest = '\0';
137
    } else {
138
        strncpy(dest, src, len);
139
    }
140
}
141
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
142
void str_trim(gchar *s) {
143
    // Remove leading and trailing whitespaces from a string. Edit in place.
144
    if (s) {
145
        g_strstrip(s);
146
    }
147
}
148
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
149
void str_cut_nicely(gchar *s, glong to_len, glong min_len) {
56 by Osmo Antero
Version 0.5
150
    // Cut string nicely to given to_len.
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
151
    glong l = g_utf8_strlen(s, -1);
152
    if (l <= to_len) return;
153
154
    glong i = to_len - 1;
155
156
    // Find space
157
    while (i >= 0) {
158
        if ( *(s + i) == ' ') break;
159
        i--;
160
    }
161
162
    if (i >= min_len) {
163
        *(s + i) = '\0';
164
    } else {
165
        *(s + to_len -1) = '\0';
166
    }
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
167
}
168
1 by Osmo Antero Maatta
Initial import 17.jan.2011
169
void split_filename2(gchar *path, gchar **filepath,  gchar **filebase) {
170
    // Split path to filepath + filename
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
171
    gchar *fileext;
172
    split_filename3(path, filepath,  filebase, &fileext);
173
    if (fileext) {
174
        /* TODO: Not very optimal code this... path is much longer than (filebase + '.' + fileext)
1 by Osmo Antero Maatta
Initial import 17.jan.2011
175
        */
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
176
        gchar *result = g_strdup(path);
177
        g_sprintf(result, "%s.%s", *filebase, fileext);
178
        g_free(fileext);
179
        g_free(*filebase);
180
        *filebase = result;
181
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
182
}
183
184
void split_filename3(gchar *path, gchar **filepath,  gchar **filebase, gchar **fileext) {
185
    // Split path to filepath + filename + fileext
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
186
    static gchar buf[MAX_PATH_LEN];
187
188
    *filepath = NULL;
189
    *filebase = NULL;
190
    *fileext = NULL;
191
192
    if (!path || str_length(path, MAX_PATH_LEN) < 1) return;
193
194
    glong pos_ext = -1;
195
    glong pos_base = -1;
196
197
    glong path_len = str_length(path, MAX_PATH_LEN);
198
199
    gchar *pos = g_utf8_offset_to_pointer(path, path_len - 1);
200
    while (pos >= path) {
201
        gunichar unichar = g_utf8_get_char(pos);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
202
203
        /* Find last '.' */
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
204
        if (unichar == '.' && pos_ext < 0)
205
            pos_ext = g_utf8_pointer_to_offset(path, pos);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
206
207
        /* Find last '/' */
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
208
        else if (unichar == '/' && pos_base < 0) {
209
            pos_base = g_utf8_pointer_to_offset(path, pos);
210
            break;
211
        }
212
        pos = g_utf8_prev_char(pos);
213
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
214
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
215
    glong len;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
216
217
    // Take the file name (basename) before file extension
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
218
    if (pos_base > -1) {
219
        if (pos_ext > -1)
220
            len = pos_ext - pos_base -1;
221
        else
222
            len = path_len - pos_base -1;
223
    } else {
224
        if (pos_ext > -1)
225
            len = pos_ext;
226
        else
227
            len = path_len;
228
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
229
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
230
    if (len > 0) {
231
        memset(buf, '\0', MAX_PATH_LEN);
232
        gchar *pos = g_utf8_offset_to_pointer(path, pos_base+1);
233
        g_utf8_strncpy(buf, pos, (gsize)len);
234
        *filebase = g_strdup(buf);
235
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
236
237
    // Take the unused path before basename and file extension
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
238
    if (pos_base > -1) {
239
        memset(buf, '\0', MAX_PATH_LEN);
240
        g_utf8_strncpy(buf, path, (gsize)pos_base+1);
241
        *filepath = g_strdup(buf);
242
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
243
244
    // Take file extension without "."
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
245
    if (pos_ext > -1) {
246
        len = path_len - pos_ext - 1;
247
        if (len > 0 ) {
248
            memset(buf, '\0', MAX_PATH_LEN);
249
            gchar *pos = g_utf8_offset_to_pointer(path, pos_ext+1);
250
            g_utf8_strncpy(buf, pos, (gsize)len);
251
            *fileext = g_strdup(buf);
252
        }
253
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
254
255
    /* The caller should g_free() all returned values:
256
       g_free(filepath)
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
257
       g_free(filebase)
258
       g_free(fileext)
1 by Osmo Antero Maatta
Initial import 17.jan.2011
259
    */
260
}
261
262
gboolean paths_are_equal(gchar *path1, gchar *path2) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
263
    // Check if paths are equal.
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
264
    // TODO: It would be smarter to test inodes.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
265
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
266
    // Add trailing /
267
    gchar *p1 = g_build_filename(path1, "/", NULL);
268
    gchar *p2 = g_build_filename(path2, "/", NULL);
269
270
    gboolean ret = !g_strcmp0(p1, p2);
271
272
    g_free(p1);
273
    g_free(p2);
274
275
    return ret;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
276
}
277
278
gchar *format_file_size(guint64 fsize) {
279
    // Format file size string
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
280
    gint div = 1;
281
    gchar *label;
282
283
    if (fsize > 1E9) {
284
        div = 1E9;
285
        label = "GB";
286
    } else if (fsize > 1E6) {
287
        div = 1E6;
288
        label = "MB";
289
    } else if (fsize > 1E3) {
290
        div = 1E3;
291
        label = "KB";
292
    } else {
293
        div = 1;
86 by Osmo Antero Maatta
Some GUI improvements
294
        label = ""; // "bytes"
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
295
    }
296
297
    gchar *txt = g_strdup_printf("%02.1F %s", ((gdouble)fsize / (gdouble)div), label);
298
299
    // The caller should g_free() this value
300
    return txt;
301
}
1 by Osmo Antero Maatta
Initial import 17.jan.2011
302
303
gchar *substitute_time_and_date_pattern(gchar *pattern) {
304
    // Substitue time+date pattern
305
223 by Osmo Antero
Changed default filename pattern to %Y-%m-%d-%H:%M:%S
306
    // Typical pattern is: "%Y-%m-%d-%H:%M:%S"
1012.1.4 by David Rabel
Replaced http by https wherever it was reasonable. Also replaced some broken links and link that where only redirecting.
307
    // See: https://linux.die.net/man/3/strftime
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
308
    time_t t;
309
    struct tm *tmp;
310
    t = time(NULL);
311
    tmp = localtime(&t);
312
    if (tmp == NULL) {
313
        return NULL;
314
    }
315
316
    static gchar buf[128];
317
318
    strftime(buf, 128, pattern, tmp);
319
320
    // Caller should g_free() this value
321
    return g_strdup(buf);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
322
}
323
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
324
void seconds_to_h_m_s(guint seconds, guint *hh, guint *mm, guint *ss) {
325
    // Split seconds to hours, minutes and seconds.
326
    *hh = seconds / 3600;
327
    seconds -= (*hh * 3600);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
328
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
329
    *mm = seconds / 60;
330
    seconds -= (*mm * 60);
331
332
    *ss = seconds;
333
}
334
1 by Osmo Antero Maatta
Initial import 17.jan.2011
335
guint64 get_file_size(gchar *filename) {
195 by osmoma at gmail
Moving to Gstreamer 1.0, temporary commit.
336
    // Get file size.
1012.1.4 by David Rabel
Replaced http by https wherever it was reasonable. Also replaced some broken links and link that where only redirecting.
337
    // Ref: https://developer.gnome.org/glib/2.34/glib-File-Utilities.html#g-stat
195 by osmoma at gmail
Moving to Gstreamer 1.0, temporary commit.
338
    GStatBuf fstat;
339
    if (!g_stat(filename, &fstat)) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
340
        return (guint64)fstat.st_size;
341
    }
342
    return 0L;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
343
}
344
345
gint messagebox_error(const gchar *message, GtkWidget *window) {
346
    // Show dialog box with error message and wait for user's response.
347
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
348
    GtkWidget *dialog;
349
    GtkResponseType answer;
350
351
    dialog = gtk_message_dialog_new((window ? GTK_WINDOW(window) : NULL),
352
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
353
                                    GTK_MESSAGE_ERROR,
354
                                    GTK_BUTTONS_CLOSE,
355
                                    message, NULL);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
356
357
    gchar *prog_name = get_program_name();
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
358
    gtk_window_set_title(GTK_WINDOW(dialog), prog_name);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
359
    g_free(prog_name);
360
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
361
    answer = gtk_dialog_run(GTK_DIALOG(dialog));
56 by Osmo Antero
Version 0.5
362
    if (answer == -1) {}
1 by Osmo Antero Maatta
Initial import 17.jan.2011
363
    // answer not used
364
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
365
    gtk_widget_destroy(dialog);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
366
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
367
    return TRUE;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
368
}
369
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
370
gboolean exec_command_sync(char *command, gint *status, gchar **serr, gchar **sout) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
371
    // Start, spawn a child process and run the given command.
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
372
    // The started process is synchronous thefore this function will wait until the child terminates.
373
    // This functions returns TRUE if the child completed without errors, otherwise FALSE.
374
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
375
    *sout = NULL;
376
    *serr = NULL;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
377
    *status = 0; /* ok */
378
379
    GError *error = NULL;
380
    gint ret = TRUE; /* ok */
381
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
382
    if (!g_spawn_command_line_sync(command, sout, serr, status, &error)) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
383
        // Got an error
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
384
1 by Osmo Antero Maatta
Initial import 17.jan.2011
385
        // Add error->message to stderr
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
386
        if (error) {
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
387
            if (*serr) {
388
                gchar *tmp = g_strdup_printf("%s\n%s", *serr, error->message);
389
                g_free(*serr);
390
                *serr = tmp;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
391
            } else {
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
392
                *serr = g_strdup(error->message);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
393
            }
394
        }
395
396
        ret = FALSE;
397
    }
398
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
399
    if (*sout)
400
        str_trim(*sout);/* Modify in place */
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
401
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
402
    if (str_length(*sout, 1024) < 1) {
403
        g_free(*sout);
404
        *sout = NULL;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
405
    }
406
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
407
    if (*serr)
408
        str_trim(*serr);/* Modify in place */
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
409
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
410
    if (str_length(*serr, 1024) < 1) {
411
        g_free(*serr);
412
        *serr = NULL;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
413
    }
414
415
    if (error)
416
        g_error_free(error);
417
418
    return ret;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
419
}
420
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
421
gboolean exec_shell_command(gchar *command, gchar **serr, gchar **sout) {
422
    // Execute shell command. Return result in serr and sout.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
423
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
424
    gint status = -1;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
425
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
426
    *serr = *sout = NULL;
427
428
    gboolean ret = exec_command_sync(command, &status, serr, sout);
429
430
    if ((!ret) || *serr) {
431
        gchar *msg = g_strdup_printf("exec_shell_command (%s) failed. %s\n", command, *serr);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
432
        LOG_ERROR(msg);
433
        g_free(msg);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
434
        ret = FALSE;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
435
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
436
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
437
    return ret;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
438
}
439
440
gchar *find_command_path(gchar *command) {
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
441
    // Use "which" to locate absolute path of the given program.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
442
    // An example:
443
    // find_command_path("gimp") will return "/usr/bin/gimp".
444
1428 by Osmo Antero
Version 3.0.4.
445
    if (!command) {
446
        return NULL;
447
    }
448
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
449
    gchar *line = g_strdup_printf("which %s", command);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
450
451
    gint status;
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
452
    gchar *serr = NULL;
453
    gchar *sout = NULL;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
454
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
455
    if (!exec_command_sync(line, &status, &serr, &sout)) {
456
        gchar *msg = g_strdup_printf("Cannot execute command '%s'.\n%s.\n", line, serr);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
457
        LOG_ERROR("%s", msg);
458
        g_free(msg);
459
    }
460
461
    g_free(line);
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
462
    g_free(serr);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
463
464
    // The caller should g_free() this value after usage
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
465
    return sout;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
466
}
467
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
468
GPid exec_command_async(gchar **argv, GError **error) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
469
    // Start, spawn a child process and run the command given by argv list.
470
    // The process is asynchronous and returns immediately back to the caller.
471
    // This function returns PID of the child process. Returns GError.
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
472
    GPid child_pid;
473
474
    if (error) *error = NULL;
475
463 by Osmo Antero
Updated README and INSTALL files.
476
    if (!g_spawn_async(NULL/*inherit parent*/, argv, NULL/*inherit parent*/,
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
477
                       G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH,
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
478
                       NULL/*no setup function*/, NULL/*no user data*/, &child_pid, error)) {
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
479
19 by Osmo Antero Maatta
Added instructions for translators
480
        // Translators: This is an error message.
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
481
        LOG_ERROR(_("Exec error. Cannot start process %s.\n%s.\n"), argv[0], (*error)->message);
482
        child_pid = -1;
483
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
484
485
    // Return pid
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
486
    return child_pid;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
487
}
488
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
489
gboolean run_simple_command(gchar *cmd, gchar *args) {
490
    // Run a simple command with args
491
492
    // Find a path?
493
    gchar *path = find_command_path(cmd);
494
    gchar *c = NULL;
495
    if (path) {
496
        c = g_strdup_printf("%s %s", path, args);
497
    } else {
498
        c = g_strdup_printf("%s %s", cmd, args);
499
    }
500
501
    gchar *sout = NULL;
502
    gchar *serr = NULL;
503
228 by Osmo Antero
Small fix in utility.c (run_simple_command()).
504
    gboolean ret = exec_shell_command(c, &serr, &sout);
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
505
506
    g_free(path);
507
    g_free(c);
508
    g_free(sout);
509
    g_free(serr);
510
511
    return ret;
512
}
513
1 by Osmo Antero Maatta
Initial import 17.jan.2011
514
GPid get_PID(gchar *app_name) {
515
    // Return process PID for the given app_name
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
516
    gchar *serr = NULL;
517
    gchar *sout = NULL;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
518
519
    gchar *cmd = g_strdup_printf("ps -o %%p --no-heading -C %s", app_name);
520
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
521
    exec_shell_command(cmd, &serr, &sout);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
522
    g_free(cmd);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
523
524
    GPid p = -1L;
525
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
526
    if (sout)
527
        p = atol(sout);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
528
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
529
    g_free(sout);
530
    g_free(serr);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
531
1 by Osmo Antero Maatta
Initial import 17.jan.2011
532
    return p;
533
}
534
535
gboolean check_PID(GPid pid) {
536
    // Check if process id (pid) is alive and running
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
537
    gchar *serr = NULL;
538
    gchar *sout = NULL;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
539
540
    gchar *cmd = g_strdup_printf("ps --pid %d -o pid h", pid);
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
541
    exec_shell_command(cmd, &serr, &sout);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
542
    g_free(cmd);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
543
544
    gint64 p = -1L;
545
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
546
    if (sout)
547
        p = atol(sout);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
548
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
549
    g_free(sout);
550
    g_free(serr);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
551
1 by Osmo Antero Maatta
Initial import 17.jan.2011
552
    return p == pid && p > 0;
553
}
554
555
gchar *get_nth_arg(gchar *str, guint n, gboolean ret_rest) {
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
556
    // Return n'th token of the  str. The tokens must be separated by spaces " ".
1 by Osmo Antero Maatta
Initial import 17.jan.2011
557
    // Eg. get_nth_arg("AA BB CC DD EE", 3, FALSE) will return "CC".
558
    //     get_nth_arg("AA BB CC DD EE", 3, TRUE) will return "CC DD EE".
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
559
    // The first token # is 1, second is 2, etc.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
560
    gchar *p1 = NULL;
561
    gchar *p2 = NULL;
562
    if (!str) return NULL;
563
564
    guint i = 0;
565
    p1 = str;
566
    while (1) {
567
        if (p1) {
568
            p2 = g_strstr_len(p1+1, -1, " ");
569
        }
570
571
        i = i + 1;
572
        if (i >= n) break;
573
574
        if (p2) {
575
            p1 = p2+1;
576
        } else {
577
            break;
578
        }
579
    }
580
581
    // n'th argument was seen?
582
    if (i < n) {
583
        // No.
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
584
        return NULL;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
585
    }
586
587
    gchar *s = NULL;
588
    if (p1 && ret_rest) {
589
        s = g_strdup(p1);
590
    } else if (p1 && p2) {
591
        s = g_strndup(p1, p2 - p1);
592
    } else if (p1) {
593
        s = g_strdup(p1);
594
    } else {
595
        s = g_strdup(str);
596
    }
597
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
598
    str_trim(s);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
599
600
    // The caller should g_free() this value
601
    return s;
602
}
603
604
gchar *get_last_arg(gchar *str) {
605
    // Find and return last token after space
606
    gchar *s = NULL;
607
608
    // Find last space
609
    gchar *p = g_strrstr(str, " ");
610
    if (p) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
611
        s = g_strdup(p+1);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
612
    } else {
613
        s = g_strdup(str);
614
    }
615
616
    // The caller should g_free() this value
617
    return s;
618
}
619
620
void purify_filename(gchar *filename, gboolean purify_all) {
470.2.7 by Osmo Antero
Fixed bug with long filenames.
621
    // Purify filename, remove unwished characters.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
622
    // Edit filename in place.
623
624
    gchar *delims = NULL;
625
    if (purify_all) {
626
        // Remove also '/' and '.'
470.2.7 by Osmo Antero
Fixed bug with long filenames.
627
        delims = "@&$^?()|~{}[]\\=+<>;\"'`,*./";
1 by Osmo Antero Maatta
Initial import 17.jan.2011
628
    } else {
470.2.7 by Osmo Antero
Fixed bug with long filenames.
629
        delims = "@&$^?()|~{}[]\\=+<>;\"'`,*";
1 by Osmo Antero Maatta
Initial import 17.jan.2011
630
    }
631
632
    // Replace illegals with space
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
633
    if (filename) {
634
        g_strdelimit(filename, delims, ' ');
635
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
636
}
637
638
gchar *read_file_content(gchar *filename, GError **error) {
639
    // Read and return file content
640
    gchar *text = NULL;
641
    gsize len = 0;
642
643
    if (error) {
644
        *error = NULL;
645
    }
646
1012.1.4 by David Rabel
Replaced http by https wherever it was reasonable. Also replaced some broken links and link that where only redirecting.
647
    // Ref: https://developer.gnome.org/glib/unstable/glib-File-Utilities.html#g-file-get-contents
1 by Osmo Antero Maatta
Initial import 17.jan.2011
648
    g_file_get_contents(filename, &text, &len, error);
649
    if (*error) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
650
        g_free(text);
651
        text = NULL;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
652
    }
653
654
    // Caller should check and free the error value.
655
    // Caller should g_free() this value.
656
    return text;
657
}
658
659
gboolean save_file_content(gchar *filename, gchar *text, GError **error) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
660
    // Save file content
1 by Osmo Antero Maatta
Initial import 17.jan.2011
661
    gboolean ret = TRUE;
662
663
    if (error) {
664
        *error = NULL;
665
    }
666
1012.1.4 by David Rabel
Replaced http by https wherever it was reasonable. Also replaced some broken links and link that where only redirecting.
667
    // Ref: https://developer.gnome.org/glib/unstable/glib-File-Utilities.html#g-file-set-contents
1 by Osmo Antero Maatta
Initial import 17.jan.2011
668
    ret = g_file_set_contents(filename, text, -1, error);
669
670
    // Caller should check and free the error value.
671
    return ret;
672
}
673
674
gchar *get_home_dir() {
675
    // Return user's $HOME directory
676
677
    // Read $HOME environment variable
678
    const char *home_dir = g_getenv("HOME");
679
    if (!home_dir) {
680
        // Get home from passwd file
681
        home_dir = g_get_home_dir();
682
    }
683
684
    // Caller should g_free() this value
685
    return g_strdup(home_dir);
686
}
687
688
GList *get_directory_listing(gchar *path, gchar *file_pattern) {
689
    // Get directory listing and return a GList of filenames that matches the given file_pattern.
690
    GError *error = NULL;
691
1012.1.4 by David Rabel
Replaced http by https wherever it was reasonable. Also replaced some broken links and link that where only redirecting.
692
    // Ref: https://developer.gnome.org/glib/unstable/glib-File-Utilities.html
1 by Osmo Antero Maatta
Initial import 17.jan.2011
693
    GDir *dir = g_dir_open(path, 0, &error);
694
    if (error) {
695
        LOG_ERROR("Cannot read directory %s. %s\n", path, error->message);
696
        g_error_free(error);
697
        return NULL;
698
    }
699
700
    GList *list = NULL;
701
702
    // Create file pattern
703
    GPatternSpec *patt = g_pattern_spec_new(file_pattern);
704
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
705
    // Loop for all filenames
1 by Osmo Antero Maatta
Initial import 17.jan.2011
706
    const gchar *filename = g_dir_read_name(dir);
707
    while (filename) {
708
        // Filename matches the pattern?
709
        gboolean ret = g_pattern_match_string(patt, filename);
710
        if (ret) {
711
            // Make path + filename
712
            gchar *p_ = g_build_filename(path, filename, NULL);
713
714
            // Yes, add filename to the list.
715
            list = g_list_append(list, p_);
716
717
            // Note: p_ will be freed when the list is destroyed.
718
        }
719
        // Next filename
720
        filename = g_dir_read_name(dir);
721
    }
722
723
    g_dir_close(dir);
724
    g_pattern_spec_free(patt);
725
726
    // Caller should free this list with:
727
    //  g_list_free_full(list, g_free);
728
    //  list = NULL;
729
    return list;
730
}
731
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
732
// Some support functions
733
300 by Osmo Antero
Testing version 1.0 of audio-recorder.
734
gchar *get_filename_pattern() {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
735
    // Return pattern that will be base for a new, unique filename (includes filename + date+time pattern)
736
737
    gchar *filename_pattern = NULL;
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
738
    conf_get_string_value("filename-pattern", &filename_pattern);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
739
    str_trim(filename_pattern);
740
741
    // Pattern cannot have "/" character (edit in place)
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
742
    if (filename_pattern) {
743
        g_strdelimit(filename_pattern, "/", '-');
744
    }
745
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
746
    // The pattern is ok?
747
    if (str_length(filename_pattern, 1024) < 2) {
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
748
        // Set default pattern
749
        g_free(filename_pattern);
750
224 by Osmo Antero
Changed default filename pattern to _(%Y-%m-%d-%H:%M:%S), it's translatable.
751
        // Translators: This is a default filename pattern. You can keept this as it is.
752
        filename_pattern = g_strdup(_("%Y-%m-%d-%H:%M:%S"));
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
753
        conf_save_string_value("filename-pattern", filename_pattern);
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
754
    }
755
756
    // The caller should g_free() this value
757
    return filename_pattern;
758
}
759
760
gchar *get_audio_folder() {
761
    // Return directory where we store audio files.
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
762
    // Normally: /home/username/Audio
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
763
764
    gchar *folder_name = NULL;
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
765
    conf_get_string_value("folder-name", &folder_name);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
766
    str_trim(folder_name);
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
767
768
    // Has folder name?
769
    if (str_length(folder_name, 1024) < 1) {
770
        g_free(folder_name);
771
        // Set default to "/home/username/Audio"
772
773
        // Get $HOME
774
        gchar *home = get_home_dir();
775
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
776
        // If user has a $HOME/Music folder, then use the English word.
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
777
        gchar *path = g_strdup_printf("%s/%s", home, "Music");
778
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
779
        if (g_file_test(path, G_FILE_TEST_IS_DIR))
780
            folder_name = g_strdup_printf("%s/%s", home, "Audio");
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
781
        else
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
782
            // Translators: This is a directory name like "/home/username/Audio".
19 by Osmo Antero Maatta
Added instructions for translators
783
            // We store all recordings in this directory.
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
784
            folder_name = g_strdup_printf("%s/%s", home, _("Audio"));
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
785
786
        // Save default
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
787
        conf_save_string_value("folder-name", folder_name);
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
788
789
        g_free(home);
790
        g_free(path);
791
    }
792
793
    // The caller should g_free() this value
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
794
    return folder_name;
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
795
}
1 by Osmo Antero Maatta
Initial import 17.jan.2011
796
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
797
GdkPixbuf *get_pixbuf_from_file(gchar *filename, gint width, gint height) {
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
798
    if (!filename) return NULL;
799
800
    GError *error = NULL;
801
    GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error);
802
    if (error) {
803
        g_warning("Could not load image from %s. %s\n", filename, error->message);
804
        g_error_free(error);
805
        pixbuf = NULL;
806
    }
807
808
    if (!pixbuf) return NULL;
809
810
    gint w = gdk_pixbuf_get_width(pixbuf);
811
    gint h = gdk_pixbuf_get_height(pixbuf);
812
    if ((w > width && width > 0) || (h > height && height > 0)) {
813
        GdkPixbuf *img = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_HYPER);
814
        g_object_unref(pixbuf);
815
        pixbuf = img;
816
    }
817
818
    return pixbuf;
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
819
}
820
821
/*
822
gchar *g_strlist_to_string(GList *lst, gchar *delim) {
823
	GString *str = g_string_new(NULL);
824
825
	GList *n = g_list_first(lst);
826
	while (n) {
827
		gchar *txt = (gchar*)n->data;
828
		g_string_append_printf(str, "%s%s", txt, delim);
829
		n = g_list_next(n);
830
	}
831
832
	gchar *s = g_string_free(str, FALSE);
833
834
	// The caller should g_free() this value
835
	return s;
836
}
837
*/
838
839
void str_list_free(GList *list) {
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
840
    // Free GList of strings.
841
    g_list_foreach(list, (GFunc)g_free, NULL);
842
    g_list_free(list);
843
    list = NULL;
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
844
}
845
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
846
GList *str_list_copy(GList *list) {
847
    GList *new_list = NULL;
848
    GList *item = g_list_first(list);
849
    while (item) {
850
        gchar *s = g_strdup((gchar*)item->data);
851
        new_list = g_list_append(new_list, s);
463 by Osmo Antero
Updated README and INSTALL files.
852
        item = g_list_next(item);
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
853
    }
854
    return new_list;
855
}
856
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
857
void str_list_print(gchar *prefix, GList *lst) {
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
858
    // Print GList of strings.
859
860
    if (g_list_length(lst) < 1) {
861
        LOG_MSG("%s: <the list is empty>\n", prefix);
862
    }
863
864
    GList *n = g_list_first(lst);
865
    while (n) {
866
        gchar *txt = (gchar*)n->data;
867
        LOG_MSG("%s: %s\n", prefix, txt);
868
        n = g_list_next(n);
869
    }
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
870
}
871
872
gboolean str_lists_equal(GList *l1, GList *l2) {
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
873
    // Compare 2 string lists (GLists).
874
    // Return TRUE if lists are equal.
875
876
    if (g_list_length(l1) != g_list_length(l2)) {
877
        return FALSE;
878
    }
879
880
    guint i = 0;
881
    for (i=0; i < g_list_length(l1); i++) {
882
        gchar *s1 = (gchar*)g_list_nth_data(l1, i);
883
        gchar *s2 = (gchar*)g_list_nth_data(l2, i);
884
885
        if (g_strcmp0(s1, s2)) {
886
            return FALSE;
887
        }
888
    }
889
    return TRUE;
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
890
}
891
62 by Osmo Antero
The recorder now obeys commands from Banshee Player.
892
gchar *g_strrstr0(gchar *haystack, gchar *needle) {
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
893
    // Same as g_strrstr() but this tests for NULL values (and avoids annoying warnings).
894
    if (!(haystack && needle)) return NULL;
895
    return g_strrstr(haystack, needle);
62 by Osmo Antero
The recorder now obeys commands from Banshee Player.
896
}
897
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
898
gchar *read_value_from_keyfile(gchar *key_file, gchar *group_name, gchar *key_name) {
899
    // Open key_file and return value for the given key.
900
    // Sample call:
901
    // gchar *key_file = "/usr/share/applications/banshee.desktop";
902
    // gchar *icon_name = read_value_from_keyfile(key_file, "Desktop Entry", "Icon");
903
    gchar *value = NULL;
904
    GError *error = NULL;
463 by Osmo Antero
Updated README and INSTALL files.
905
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
906
    if (!key_file) {
463 by Osmo Antero
Updated README and INSTALL files.
907
        return NULL;
908
    }
909
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
910
    // Load key_file
911
    GKeyFile *g_key = g_key_file_new();
912
    g_key_file_load_from_file(g_key, key_file, G_KEY_FILE_NONE, &error);
463 by Osmo Antero
Updated README and INSTALL files.
913
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
914
    if (error) {
915
        goto LBL_1;
463 by Osmo Antero
Updated README and INSTALL files.
916
    }
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
917
918
    // Read value
919
    value = g_key_file_get_value(g_key, group_name, key_name, &error);
920
463 by Osmo Antero
Updated README and INSTALL files.
921
LBL_1:
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
922
    if (error) {
923
        g_error_free(error);
463 by Osmo Antero
Updated README and INSTALL files.
924
    }
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
925
463 by Osmo Antero
Updated README and INSTALL files.
926
    g_key_file_free(g_key);
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
927
928
    // Caller should g_free() this value
929
    return value;
930
}
931
472.1.1 by Osmo Antero
dbus-mpris.c: MPRIS2 'Metdata' is not necessary if 'PlaybackStatus'=='Playing'. Missing 'Metadata' is actually an error but the recorder can survive without it.
932
GdkPixbuf *load_icon_pixbuf(gchar *icon_name, guint _size) {
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
933
    // Load icon pixbuf from current icon theme.
934
    GdkPixbuf *pixbuf = NULL;
935
936
    if (!icon_name) {
937
        return NULL;
463 by Osmo Antero
Updated README and INSTALL files.
938
    }
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
939
1430 by Osmo Antero
Version 3.0.4. Nitpicking with media-players' executables and desktop files
940
    // Normally icon name should equal exec name (without path) in .desktip files 
941
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
942
    // Current icon theme
943
    GtkIconTheme *theme = gtk_icon_theme_get_default();
944
945
    // Load icon from its theme
472.1.1 by Osmo Antero
dbus-mpris.c: MPRIS2 'Metdata' is not necessary if 'PlaybackStatus'=='Playing'. Missing 'Metadata' is actually an error but the recorder can survive without it.
946
    pixbuf = gtk_icon_theme_load_icon(theme, icon_name, _size, 0, NULL);
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
947
948
    // Got it?
1430 by Osmo Antero
Version 3.0.4. Nitpicking with media-players' executables and desktop files
949
    if (!GDK_IS_PIXBUF(pixbuf)) {
950
		// Some media players set entire path for the icon in .desktop file (this is probably a mistake)
951
        // Like: /snap/imsplayer/34/usr/share/imsplayer/icons/imsplayer-128.png
952
953
        // Load directly from a file
954
        pixbuf = get_pixbuf_from_file(icon_name, _size, _size);
955
    }
472.1.1 by Osmo Antero
dbus-mpris.c: MPRIS2 'Metdata' is not necessary if 'PlaybackStatus'=='Playing'. Missing 'Metadata' is actually an error but the recorder can survive without it.
956
957
    // Some icons are large. Force to _size.
958
    if (GDK_IS_PIXBUF(pixbuf)) {
959
        GdkPixbuf *img = gdk_pixbuf_scale_simple(pixbuf, _size, _size, GDK_INTERP_HYPER);
960
        g_object_unref(pixbuf);
961
        pixbuf = img;
962
    }
963
463 by Osmo Antero
Updated README and INSTALL files.
964
    // Caller should g_object_unref() this value
104 by Osmo Antero
Removed fixed icon images. Getting now icon pixmaps from current icon theme.
965
    return pixbuf;
966
}
967
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
968
void kill_program_by_name(gchar *app_name, GPid preserve_pid) {
969
    // Kill all app_name processes. But do not kill preserve_pid.
463 by Osmo Antero
Updated README and INSTALL files.
970
    // Use this to kill programs that do not respond to client requests (dbus request).
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
971
    gchar *serr = NULL;
972
    gchar *sout = NULL;
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
973
974
    // Get list of PIDs for app_name
975
    gchar *cmd = g_strdup_printf("ps -o %%p --no-heading -C %s", app_name);
976
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
977
    exec_shell_command(cmd, &serr, &sout);
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
978
    g_free(cmd);
979
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
980
    if (!sout) {
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
981
        goto LBL_1;
982
    }
983
984
    // For each PID in the list...
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
985
    gchar **args = g_strsplit(sout, "\n", -1);
463 by Osmo Antero
Updated README and INSTALL files.
986
    guint i=0;
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
987
    while (args && args[i]) {
988
        GPid pid = atol(args[i]);
989
        if (pid != preserve_pid && pid > 1) {
990
            // $ kill -9 PID
991
            kill(pid, SIGKILL);
992
        }
993
        i++;
994
    }
995
996
    // Free args
463 by Osmo Antero
Updated README and INSTALL files.
997
    g_strfreev(args);
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
998
    args=NULL;
999
463 by Osmo Antero
Updated README and INSTALL files.
1000
LBL_1:
227 by Osmo Antero
Small fix in main.c (run_simple_command()).
1001
    g_free(sout);
1002
    g_free(serr);
226.1.1 by Osmo Antero
Main.c uses now fork() and execvp() to detach the instance from command-line when started with --command=start argument. Spawns a child process, then execvp(new audio-recorder).
1003
}
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
1004
430 by Osmo Antero
Cosmetics: select and set active media-format in Additional-settings -> Recording commands.
1005
void kill_frozen_instances(gchar *program_path, GPid preserve_pid) {
1006
    // Terminate possibly frozen instances of audio-recorder.
1007
    gchar *app_path = NULL;
1008
    gchar *app_base = NULL;
1009
    split_filename2(program_path, &app_path, &app_base);
1010
1011
    kill_program_by_name(app_base, preserve_pid);
1012
1013
    g_free(app_path);
1014
    g_free(app_base);
1015
}
1016
1423 by Osmo Antero
Fix problem with duplicate messages from media players.
1017
gboolean str_startwith(const gchar *s, const gchar *what, gboolean case_insensitive) {
1018
    // Check if utf8 string 's' starts with 'what'  
1019
    size_t len1 = g_utf8_strlen(s, MAX_PATH_LEN);
1020
    size_t len2 = g_utf8_strlen(what, MAX_PATH_LEN);
1021
1022
    if (len2 > len1) {
1023
        return FALSE;    
1024
    }
1025
1026
    gint ret = 0;
1027
    gchar *s_tmp = NULL;
1028
    gchar *what_tmp = NULL;
1029
1030
    if (case_insensitive) {
1031
        s_tmp = g_utf8_casefold(s, len2);
1032
        what_tmp = g_utf8_casefold(what, len2);
1033
    } else {
1034
        s_tmp = g_strndup(s, len2);
1035
        what_tmp = g_strndup(what, len2);
1036
    }
1037
1038
    // gchar *g_utf8_substring (const gchar *str, glong start_pos, glong end_pos);
1039
1040
    ret = g_utf8_collate(s_tmp, what_tmp);
1041
1042
    g_free(s_tmp);
1043
    g_free(what_tmp);
1044
1045
    return (ret == 0);
1046
}
1047
1427 by Osmo Antero
Version 3.0.2
1048
gint str_compare(const gchar *s1, const gchar *s2, gboolean case_insensitive) {
1440.1.1 by Osmo Antero
Fixing bug #1838710 in str_compare() function. Thanks to Chipschap and Roy.
1049
1050
    if (s1 == NULL && s2 == NULL) {
1051
        // Assume equals
1052
        return 0;
1053
    } else if (s1 == NULL) {
1054
        // s1 < s2
1055
        return -1;
1056
    } else if (s2 == NULL) {
1057
        // s1 > s2
1058
        return 1;
1059
    }
1060
1061
    // Here both are valid (not NULL) strings
1442 by Osmo Antero
A small typo in the str_compare() function.
1062
    if (*s1 == '\0' && *s2 == '\0') {
1427 by Osmo Antero
Version 3.0.2
1063
        // Equals
1064
        return 0;   
1065
    } 
1066
1067
    gint ret = 0;
1068
1069
    if (case_insensitive) { 
1070
        gchar *ss1 = g_utf8_casefold(s1, g_utf8_strlen(s1, MAX_PATH_LEN - 4));
1071
        gchar *ss2 = g_utf8_casefold(s2, g_utf8_strlen(s2, MAX_PATH_LEN - 4));
1072
    
1073
        ret = g_utf8_collate(ss1, ss2);
1074
        g_free(ss1);
1075
        g_free(ss2);
1076
1077
    } else {
1078
1079
        ret = g_utf8_collate(s1, s2);
1080
    }
1081
1082
    return ret;
1083
}
1084
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
1085
/*
292 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1086
gchar *get_command_and_name(gchar *desktop_file, gchar **command) {
1087
    // Load program.desktop file and return application name and executable command (with args).
1088
    gchar *app_name = NULL;
1089
    *command = NULL;
1090
463 by Osmo Antero
Updated README and INSTALL files.
1091
    gchar *s = NULL;
292 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1092
    // Ends with ".desktop"?
1093
    if (g_str_has_suffix(desktop_file, ".desktop")) {
1094
        s = g_strdup(desktop_file);
1095
    } else {
463 by Osmo Antero
Updated README and INSTALL files.
1096
        // Add ".desktop"
292 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1097
        s = g_strdup_printf("%s.desktop", desktop_file);
1098
    }
1099
1100
    // Load GDesktopAppInfo from propgram.desktop file
1101
    GDesktopAppInfo *app_info = g_desktop_app_info_new(s);
1102
    g_free(s);
1103
1104
    if (!app_info) {
1105
        return NULL;
463 by Osmo Antero
Updated README and INSTALL files.
1106
    }
292 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1107
1012.1.4 by David Rabel
Replaced http by https wherever it was reasonable. Also replaced some broken links and link that where only redirecting.
1108
    // Ref:https://developer.gnome.org/gio/2.26/GAppInfo.html
1109
    // and its implementation:https://developer.gnome.org/gio/2.30/gio-Desktop-file-based-GAppInfo.html
293 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1110
1111
    // Read application name
292 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1112
    app_name = (gchar*)g_app_info_get_name(G_APP_INFO(app_info));
1113
    if (!app_name) {
1114
        app_name = (gchar*)g_app_info_get_display_name(G_APP_INFO(app_info));
1115
    }
1116
1117
    app_name = g_strdup(app_name);
1118
293 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1119
    // Read command with arguments
292 by Osmo Antero
Changes in src/dbus-mpris.c. Players' «Identity» property is no longer needed. Reading now all necessary info from players' .desktop file.
1120
    *command = g_strdup((gchar*)g_app_info_get_commandline(G_APP_INFO(app_info)));
1121
1122
    g_object_unref(app_info);
1123
1124
    // Caller should g_free() both returned app_name and command.
1125
    return app_name;
1126
}
295 by Osmo Antero
Using now players' .desktop file to get program name and executable (improved code).
1127
*/
430 by Osmo Antero
Cosmetics: select and set active media-format in Additional-settings -> Recording commands.
1128
1129