2 * Dictix / DixMain - dix-main.vala
4 * Copyright (C) Martin Blanchard 2011 <tinram@gmx.fr>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
35 public bool now_recording
;
36 public bool now_playing
;
37 public bool transport_is_paused
;
40 /* Last just-recorded record pointer, use once to set TreeView state */
41 public TreeIter last_record
;
43 /* Timer value use for notification while recording */
44 public int notification_timer
;
46 /* Usefull directories and files */
47 public string data_dir
;
48 public string ui_file
;
49 public string menu_file
;
52 public Recorder recorder
;
54 public Transcoder transcoder
;
56 /* Record list, iter atributes are thoses:
58 - 1: timeval, (uint64);
63 - 6: duration (int64).
65 - 8: sample-rate (int).
66 - 9: bit-rate (int). */
67 public ListStore records
;
70 public GLib
.Settings settings
;
74 public class Main
: Gtk
.Application
{
76 private Cancellable guardian
;
78 private short destroy_count
;
80 public Main (string id
, ApplicationFlags flags
) {
81 GLib
.Object (application_id
: id
, flags
: flags
);
89 public void on_record_started_cb () {
90 if (Global
.state
== State
.READY
) {
91 Global
.now_recording
= true;
95 public void on_playback_started_cb () {
96 if (Global
.state
== State
.READY
) {
97 Global
.now_playing
= true;
98 Global
.transport_is_paused
= false;
102 public void on_record_stopped_cb (string uri
) {
103 if (Global
.state
== State
.READY
) {
104 Global
.now_recording
= false;
107 Global
.last_record
= add_record (uri
);
111 if (destroy_count
> 0) {
113 if (destroy_count
== 0) {
119 public void on_playback_stopped_cb (bool eos
) {
120 if (Global
.state
== State
.READY
) {
121 Global
.now_playing
= false;
124 Global
.transport_is_paused
= true;
126 Global
.transport_is_paused
= false;
130 if (destroy_count
> 0) {
132 if (destroy_count
== 0) {
138 public void on_destroy_cb () {
141 if (Global
.now_recording
== true) {
143 Global
.recorder
.stop_recording ();
145 if (Global
.now_playing
== true) {
147 Global
.player
.stop ();
150 if (destroy_count
== 0) {
151 /* We are nither recording nor playing */
156 private void just_quit () {
157 switch (Global
.state
) {
159 if (guardian
!= null) {
170 /* timeval = uint64.MAX is just a hack to keep new records at the beginning of the list... */
171 private TreeIter
add_record (string uri
, uint64 timeval
= uint64.MAX
) {
172 TagReader reader
= null;
182 reader
= new
TagReader (uri
);
183 Global
.records
.prepend (out iter
);
185 if (reader
!= null) {
188 title
= reader
.get_title ();
189 codec
= reader
.get_codec ();
191 size
= reader
.get_size ();
192 duration
= reader
.get_duration ();
193 channels
= reader
.get_channels ();
194 sample_rate
= reader
.get_sample_rate ();
195 bit_rate
= reader
.get_bit_rate ();
197 title
= _("Unknow record");
200 Global
.records
.set (iter
,
201 Column
.URI
, uri
.dup (),
202 Column
.TIMEVAL
, timeval
,
207 Column
.DURATION
, duration
,
208 Column
.CHANNELS
, channels
,
209 Column
.SAMPLE_RATE
, sample_rate
,
210 Column
.BIT_RATE
, bit_rate
);
215 private async
void list_data_directory () {
216 FileEnumerator enumeration
= null;
217 File directory
= null;
221 directory
= File
.new_for_path (Global
.data_dir
);
223 guardian
= new
Cancellable ();
224 enumeration
= yield directory
.enumerate_children_async (FILE_ATTRIBUTE_STANDARD_NAME
+
226 FILE_ATTRIBUTE_TIME_MODIFIED
,
227 FileQueryInfoFlags
.NONE
,
230 /* FIXME: Why is G_FILE_ATTRIBUTE_TIME_CREATED always == 0 ?? */
232 List
<FileInfo
> files
= null;
234 files
= yield enumeration
.next_files_async (10, Priority
.DEFAULT
);
236 foreach (var info
in files
) {
237 if (info
.get_name ().has_suffix (".flac") == true) {
238 string filename
= null;
241 filename
= Path
.build_filename (Global
.data_dir
, info
.get_name ());
242 uri
= Filename
.to_uri (filename
, null);
243 timeval
= info
.get_attribute_uint64 (FILE_ATTRIBUTE_TIME_MODIFIED
);
246 add_record (uri
, timeval
);
251 /* No more files, just give last record creation time to the Recorder for naming stuff: */
252 if (Global
.records
.get_iter_first (out iter
) == true) {
253 Global
.records
.get (iter
, Column
.TIMEVAL
, out timeval
);
255 Global
.recorder
.set ("last-record-timeval", timeval
);
259 Global
.state
= State
.READY
;
264 } catch (Error error
) {
265 warning (error
.message
);
269 public void on_activate_cb () {
270 if (this
.get_windows () != null) {
271 /* An other instance alredy exists, just show it */
274 Builder builder
= null;
275 UIManager manager
= null;
277 Global
.state
= State
.WORKING
;
278 Global
.now_recording
= false;
279 Global
.now_playing
= false;
280 Global
.transport_is_paused
= false;
281 Global
.seeking
= false;
282 Global
.notification_timer
= NotificationDelay
.INVALID
;
284 Environment
.set_variable ("PULSE_PROP_media.role", "production", true);
286 Global
.records
= new
ListStore (Column
.NB
,
287 typeof (string), /* uri */
288 typeof (uint64), /* timeval */
289 typeof (string), /* icon */
290 typeof (string), /* title */
291 typeof (string), /* codec */
292 typeof (uint64), /* size */
293 typeof (int64), /* duration */
294 typeof (int), /* channels */
295 typeof (int), /* sample-rate */
296 typeof (int)); /* bit-rate */
297 Global
.records
.set_sort_column_id (Column
.TIMEVAL
, SortType
.DESCENDING
);
299 Environment
.set_application_name (Config
.PACKAGE_NAME
);
301 Global
.settings
= new GLib
.Settings (Config
.PACKAGE_SCHEMA
);
303 Global
.recorder
= new
Recorder (Global
.data_dir
);
304 if (Global
.recorder
== null) {
305 warning (_("Impossible to allocate core recorder object !"));
309 Global
.recorder
.record_started
.connect (on_record_started_cb
);
310 Global
.recorder
.record_stopped
.connect (on_record_stopped_cb
);
312 Global
.player
= new
Player ();
313 if (Global
.player
== null) {
314 warning (_("Impossible to allocate core player object !"));
318 Global
.player
.playback_started
.connect (on_playback_started_cb
);
319 Global
.player
.playback_stopped
.connect (on_playback_stopped_cb
);
321 Global
.transcoder
= new
Transcoder ();
322 if (Global
.transcoder
== null) {
323 warning (_("Impossible to allocate core transcoder object !"));
328 builder
= new
Builder ();
330 builder
.add_from_file (Global
.ui_file
);
331 } catch (Error error
) {
332 warning (error
.message
);
337 manager
= new
UIManager ();
339 manager
.add_ui_from_file (Global
.menu_file
);
340 } catch (Error error
) {
341 warning (error
.message
);
346 ui
= new
Ui (builder
, manager
);
347 ui
.destroy
.connect (this
.on_destroy_cb
);
349 list_data_directory
.begin ();
351 ui
.set_application (this
);
357 public int main (string[] args
) {
359 File directory
= null;
363 Intl
.bindtextdomain (Config
.GETTEXT_PACKAGE
, Config
.PACKAGE_LOCALEDIR
);
364 Intl
.bind_textdomain_codeset (Config
.GETTEXT_PACKAGE
, "UTF-8");
365 Intl
.textdomain (Config
.GETTEXT_PACKAGE
);
367 Global
.data_dir
= Path
.build_filename (Environment
.get_user_data_dir (), Config
.PACKAGE
);
368 // Global.ui_file = Path.build_filename (Config.PACKAGE_DATADIR, Config.PACKAGE, "main.ui");
369 // Global.menu_file = Path.build_filename (Config.PACKAGE_DATADIR, Config.PACKAGE, "menu.ui");
370 Global
.ui_file
= Path
.build_filename (".", "data", "main.ui");
371 Global
.menu_file
= Path
.build_filename (".", "data", "menu.ui");
373 directory
= File
.new_for_path (Global
.data_dir
);
374 if (directory
.query_exists () == false) {
375 /* Our xdg data dir doesn't exists, let's create it */
377 directory
.make_directory ();
378 } catch (Error error
) {
379 warning (error
.message
);
387 Notify
.init (Config
.PACKAGE_NAME
);
389 app
= new
Main ("org.gnome." + Config
.PACKAGE_NAME
, ApplicationFlags
.FLAGS_NONE
);
390 app
.activate
.connect (app
.on_activate_cb
);
392 int status
= app
.run (args
);