Merge branch 'master' into gregoa
authorgregor herrmann <gregoa@debian.org>
Sun, 28 Mar 2010 09:21:41 +0000 (11:21 +0200)
committergregor herrmann <gregoa@debian.org>
Sun, 28 Mar 2010 09:21:41 +0000 (11:21 +0200)
62 files changed:
CMakeLists.txt
README
debian/control
debian/zavai.install
hooks/CMakeLists.txt [new file with mode: 0644]
hooks/gsm
src/CMakeLists.txt
src/app_alarm.vala
src/app_calendar.vala
src/app_debug.vala
src/app_keyboard.vala
src/app_log.vala [new file with mode: 0644]
src/app_main.vala
src/app_power.vala
src/at.vala [new file with mode: 0644]
src/audio.vala [new file with mode: 0644]
src/bluetooth.vala [new file with mode: 0644]
src/calendar.vala
src/clock.vala [new file with mode: 0644]
src/config.vala [new file with mode: 0644]
src/core.vala [new file with mode: 0644]
src/dbus-extra.vapi [new file with mode: 0644]
src/devkit-power-gobject.vapi [new file with mode: 0644]
src/gps.vala [new file with mode: 0644]
src/gsm.vala [new file with mode: 0644]
src/input.vala [new file with mode: 0644]
src/libgps.vapi [new file with mode: 0644]
src/libomhacks.vapi [new file with mode: 0644]
src/linux-input.vapi [new file with mode: 0644]
src/log.vala [new file with mode: 0644]
src/lua5.1.vapi [new symlink]
src/power.vala [new file with mode: 0644]
src/registry.vala [new file with mode: 0644]
src/uevent.vala [new file with mode: 0644]
src/wifi.vala [new file with mode: 0644]
src/x11.vapi [new file with mode: 0644]
src/zavai-calendar.vala [deleted file]
src/zavai.vala
test/CMakeLists.txt
test/test-gsm-receive.vala
zavai/CMakeLists.txt [deleted file]
zavai/at.vala [deleted file]
zavai/audio.vala [deleted file]
zavai/bluetooth.vala [deleted file]
zavai/clock.vala [deleted file]
zavai/config.vala [deleted file]
zavai/core.vala [deleted file]
zavai/dbus-extra.vapi [deleted file]
zavai/devkit-power-gobject.vapi [deleted file]
zavai/gps.vala [deleted file]
zavai/gsm.vala [deleted file]
zavai/input.vala [deleted file]
zavai/libgps.vapi [deleted file]
zavai/libomhacks.vapi [deleted file]
zavai/linux-input.vapi [deleted file]
zavai/log.vala [deleted file]
zavai/lua5.1.vapi [deleted symlink]
zavai/power.vala [deleted file]
zavai/registry.vala [deleted file]
zavai/uevent.vala [deleted file]
zavai/wifi.vala [deleted file]
zavai/x11.vapi [deleted file]

index 468379e0ec7124fb9a52dd4c54fb8b9694874a62..f00ba196e77eab7e745c6cf4f393a7477aa0681c 100644 (file)
@@ -1,10 +1,9 @@
 cmake_minimum_required(VERSION 2.6)
 project(zavai)
 set(zavai_version "0.1")
+add_subdirectory(hooks)
 add_subdirectory(gtkfisheyelist)
 add_subdirectory(polygen)
 add_subdirectory(player)
-add_subdirectory(test)
-add_subdirectory(zavai)
 add_subdirectory(src)
-#add_subdirectory(hooks)
+add_subdirectory(test)
diff --git a/README b/README
index 0d17b4ca8aa52d078adcf9c6e41062bdbcb613d7..c3dad671fe1a81ad13c05a155a2d0b5a194db125 100644 (file)
--- a/README
+++ b/README
@@ -176,32 +176,52 @@ TODO list / wish list
  * FSO API "documentation":
  http://git.freesmartphone.org/?p=specs.git;a=blob_plain;f=html/index.html;hb=HEAD
 
+using vala-dbus-binding-tool:
+  mdbus -s org.freesmartphone.ogsmd /org/freesmartphone/GSM/Device org.freedesktop.DBus.Introspectable.Introspect > /tmp/api.xml
+  vi /tmp/api.xml
+  convert to xml: 
+    remove quotes at begin and end
+    :$s/\n/^M/g
+  mkdir /tmp/foo
+  vala-dbus-binding-tool --directory=/tmp/foo --api-path=/tmp/api.xml
+
+  Async and D-Bus:
+  http://git.gnome.org/browse/vala/tree/tests/dbus/async.test
+
  * Features to add:
  - if GPS time is more than 1 minute and less than 1 hour different than the
    system time, automatically sync it
    if GPS time is more than 1 hour different than the system time, show a
    "SYNC" button that will sync it if pressed
+ - stacked notifier, with stacked modal dialogs
+   (notify sms received during phone ringing during alarm)
+    - aux acks the topmost dialog
+    - custom ringtone per every notifier (stops ringtone of modifier below,
+      saving the time offset of playing so it can be reloaded and resumed)
  - log
+    - flash aux when there are unacknowledged log entries
     - write data to disk as log happens (to have at least partial logs if power
       is cut)
     - more detailed GPX data (dop, elev..)
     - message (structured) (json?)
-    - flash aux when there are unacknowledged log entries
  - turn on/off gsm
-    + start frameworkd as a subprocess, configured to only do phone
-    + go through the dbus motions of turning on this and that, and entering PIN
-      hardcoded in zavai config
-    + GSM status on main screen (with messages while coming online, and
-      operator, power and so on)
-    - log incoming messages
-    - log and refuse incoming calls
+    - play ringtone when someone calls (not useful to pick up, but just to
+      notify a call is there)
+      (but stop ringtone if aux pressed in the meantime, to avoid annoying
+      people)
+    - log incoming SMS messages
+      (first as a standalone app quick to compile)
+    - pick up phone call
+       - phone call applet (pushed when picking up)
+          - buttons for dtmf
+         - button for hold
+         - button for hangup
+       - icon in main screen (to go back to applet if going around zavai during
+        phone call)
    to "move" the GSM device to my laptop:
     socat FILE:/dev/ttySAC0 TCP-LISTEN:12345,bind=192.168.0.202
     socat TCP:192.168.0.202:12345 PTY,link=/tmp/gps,raw,echo=0
  - alarm
-    + play sound at alarm trigger
-    - leave expired alarm on screen until acknowledged
-      (alarm status icon that also brings to alarm menu)
     - remember alarm names (on request, maybe with an add feature) and how
       often they are triggered, and show them most frequent first
     - show active alarms and allow to delete them
@@ -237,7 +257,6 @@ TODO list / wish list
     - ical on libical-dev
     - vcard+index file
     - lua functions to read things
- - zavai-calendar as a separate app
  - zavai-contacts as a separate app
  - calendar
     - next30: don't update if not shown currently on the notebook
index d8b1bcd78e5830db062e55d5e40edc01f4525be8..56890a0ba73681f4303d6f78fbf7b31711d7f8dd 100644 (file)
@@ -8,7 +8,8 @@ Homepage: http://git.debian.org/?p=users/enrico/zavai.git
 
 Package: zavai
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, xvkbd, transset-df
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: xvkbd, transset-df
 Suggests: polygen, polygen-data
 Description: a UI for openmoko
  A useless thing of no value
index 2465e9f8cc849a863553c369bc5d03a61fa90c9b..7133ea055930e54846a8095f671f2fa11f311bb7 100644 (file)
@@ -1,6 +1,4 @@
 conf/zavai.conf etc/dbus-1/system.d
 icons usr/share/zavai
-hooks/display usr/share/doc/zavai/examples
-hooks/keyboard usr/share/doc/zavai/examples
-hooks/keyboard.fil usr/share/doc/zavai/examples
+hooks/*.fil usr/share/doc/zavai/examples
 debian/zavai_forever usr/bin
diff --git a/hooks/CMakeLists.txt b/hooks/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4bab2f6
--- /dev/null
@@ -0,0 +1,4 @@
+project(hooks)
+
+install(PROGRAMS bluetooth display gps gsm keyboard wifi
+       DESTINATION share/zavai/hooks)
index dacad069440163e079990347a3a12b8e528d2415..849ad4cd3a036792b0b73dff724adab1bdcd5cb0 100755 (executable)
--- a/hooks/gsm
+++ b/hooks/gsm
@@ -1,5 +1,20 @@
 #!/bin/sh
 
+make_default_conf() {
+       cat > ~/.frameworkd.conf << EOT
+[frameworkd]
+log_to=file
+log_destination=/tmp/frameworkd.log
+
+[ogsmd]
+log_level=INFO
+modemtype = ti_calypso
+ti_calypso_deep_sleep = adaptive
+ti_calypso_dsp_mode = aec+nr
+ti_calypso_muxer = fso-abyss
+EOT
+}
+
 case "$1" in
        # At the start of zavai
        status)
@@ -14,6 +29,9 @@ case "$1" in
        run)
                if [ -x /usr/bin/frameworkd ]
                then
+                       # Make default config if missing
+                       test -e ~/.frameworkd.conf || make_default_conf
+
                        # Start frameworkd for GSM services only
                        exec /usr/bin/frameworkd -s ogsmd > /tmp/zavai-frameworkd.log 2>&1
                else
index 06cacbd24af4981a1bdd7369afb890176ec5f950..e89883298fca434756391d8adea9c0a2529feb1e 100644 (file)
@@ -6,7 +6,7 @@ set(zavai_version 0.1)
 set(packages gtk+-2.0 dbus-glib-1>=0.80 libwnck-1.0>=2.26.0 lua5.1 libomhacks x11 gdk-x11-2.0 libgps gstreamer-0.10)
 add_packages(ZAVAI ${packages})
 
-set(VALA_PACKAGES ${packages} posix linux-input dbus-extra gtkfisheyelist libzavai)
+set(VALA_PACKAGES ${packages} posix linux-input dbus-extra gtkfisheyelist)
 set(VFLAGS --vapidir=${zavai_SOURCE_DIR} --vapidir=${gtkfisheyelist_BINARY_DIR})
 add_definitions(-Wall)
 # -Werror 
@@ -22,24 +22,12 @@ else()
   message("-- Not using devkit-power-gobject")
 endif ()
 
-set(VFLAGS ${VFLAGS} --vapidir=${zavai_BINARY_DIR} --vapidir=${libzavai_SOURCE_DIR} --vapidir=${libzavai_BINARY_DIR})
+add_definitions(-DWNCK_I_KNOW_THIS_IS_UNSTABLE -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE -I${gtkfisheyelist_BINARY_DIR} -I${zavai_BINARY_DIR})
+link_libraries(gtkfisheyelist-static)
 
-file(GLOB libvala [a-y]*.vala widgets/*.vala)
-add_vala_library(libzavaiui ${libvala})
-add_library(libzavaiui STATIC ${libzavaiui_CSOURCES})
-
-add_definitions(-DWNCK_I_KNOW_THIS_IS_UNSTABLE -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE -I${gtkfisheyelist_BINARY_DIR} -I${zavai_BINARY_DIR} -I${libzavai_BINARY_DIR})
-set(VALA_PACKAGES ${VALA_PACKAGES} libzavai libzavaiui)
-link_libraries(gtkfisheyelist-static libzavai libzavaiui)
-
-file(GLOB zavala zavai.vala)
+file(GLOB zavala *.vala)
 add_vala_program(zavai ${zavala})
 add_executable(zavai ${zavai_CSOURCES})
 
-file(GLOB zacvala zavai-calendar.vala)
-add_vala_program(zavai-calendar ${zacvala})
-add_executable(zavai-calendar ${zavai-calendar_CSOURCES})
-
 install(TARGETS zavai RUNTIME DESTINATION bin)
-install(TARGETS zavai-calendar RUNTIME DESTINATION bin)
 install(FILES sat-monitor DESTINATION bin)
index 8baa9d6f5c86300876c0c047dc996e3f1550d028..c3bfd7cfd4013021b707f8748ec294dc19e9c6b5 100644 (file)
@@ -24,11 +24,13 @@ namespace zavai {
 namespace ui {
 namespace alarm {
 
+/*
 // Compute a-b in microseconds
 static long timediff(Posix.timeval* a, Posix.timeval* b)
 {
     return (a->tv_sec - b->tv_sec) * 1000000 + (a->tv_usec - b->tv_usec);
 }
+*/
 
 public class AlarmNotifier : zavai.Resource, Gtk.Window
 {
@@ -128,7 +130,7 @@ public class AlarmNotifier : zavai.Resource, Gtk.Window
 
     public void on_done(clock.AlarmTriggerInfo info)
     {
-        if (current == null || current.id != info.id) return;
+        if (current == null || current != info) return;
         visible = false;
         abort_timeout();
         current = null;
index bc87f3fa42878ac0a4bfc79989d39392a66c0040..e35c2cd687da2d8915d00b4fa7fc358ba04fd848 100644 (file)
@@ -43,7 +43,7 @@ public class Calendar : Applet
     }
 }
 
-Calendar calendar;
+public Calendar calendar;
 
 public void init()
 {
index 221e2c9b7daa4d9a852af13fdcc2d7b8444d1a42..4290242ef5640bca23412144e01700bf07663d3b 100644 (file)
@@ -97,6 +97,14 @@ public void init()
     menu_debug.add_applet(useless);
     menu_debug.add_service_toggle(useless_service, "Start useless service", "Stop useless service");
 
+    var b = new BigButton();
+    b.set_label("Fire an alarm");
+    b.clicked += (b) => {
+        zavai.clock.AlarmTriggerInfo alarm = new zavai.clock.AlarmTriggerInfo("Test alarm");
+        zavai.clock.alarm_trigger_queue.enqueue_trigger(alarm);
+    };
+    menu_debug.add_widget(b);
+
     var power_menu_service = new PowerMenuService();
     zavai.registry.register(power_menu_service);
     menu_debug.add_service_toggle(power_menu_service, "Toggle power menu", "Toggle power menu");
index c70b16f7f7ce814d450ecdb5b65243f648dad854..18efc2b70f47b8ea72b0616bfec5a8819f0e9ef9 100644 (file)
@@ -42,7 +42,10 @@ public class Keyboard : Service
 
     protected override void start()
     {
-        string[] args = { zavai.config.homedir + "/keyboard", null };
+        string script = zavai.config.find_script("keyboard");
+        if (script == null) return;
+
+        string[] args = { script, null };
         int opid;
         try {
             Gdk.spawn_on_screen(
diff --git a/src/app_log.vala b/src/app_log.vala
new file mode 100644 (file)
index 0000000..6092a77
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * app_log - zavai log applet
+ *
+ * Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+namespace zavai {
+namespace ui {
+namespace logview {
+
+public class Log : Applet
+{
+    protected Gtk.ScrolledWindow scroll_list;
+    protected Gtk.ListStore model;
+    protected Gtk.TreeView list;
+    protected Gtk.CellRendererText rend_name;
+    protected Gtk.Frame details_frame;
+    protected Gtk.ScrolledWindow details_scroll;
+    protected Gtk.TextBuffer details;
+    protected Gtk.TextView details_view;
+    protected BigButton read_unread;
+    protected Gtk.TreeIter cur_iter;
+    protected zavai.log.Log cur_log;
+
+    public Log()
+    {
+        _label = "Log";
+
+        model = new Gtk.ListStore(3, typeof(string), typeof(string), typeof(bool));
+        model.set_sort_column_id(1, Gtk.SortType.DESCENDING);
+
+        rend_name = new Gtk.CellRendererText();
+
+        list = new Gtk.TreeView.with_model(model);
+        list.insert_column_with_attributes (-1, "Name", rend_name, "text", 1, "strikethrough", 2, null);
+        //list.insert_column_with_attributes (-1, "Notes", new Gtk.CellRendererText(), "text", 1);
+
+        scroll_list = new Gtk.ScrolledWindow(null, null);
+        scroll_list.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+        scroll_list.add(list);
+
+        details_frame = new Gtk.Frame("Entry details");
+        details = new Gtk.TextBuffer(null);
+        details_view = new Gtk.TextView.with_buffer(details);
+        details_view.wrap_mode = Gtk.WrapMode.WORD;
+        details_view.cursor_visible = false;
+        details_view.editable = false;
+        details_scroll = new Gtk.ScrolledWindow(null, null);
+        details_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+        details_scroll.add(details_view);
+        details_frame.add(details_scroll);
+
+        pack_start(scroll_list, true, true, 0);
+        pack_start(details_frame, true, true, 0);
+
+        list.cursor_changed += on_row_selected;
+
+        read_unread = new BigButton();
+        update_read_unread(false);
+        read_unread.set_sensitive(false);
+        read_unread.clicked += on_read_unread;
+        button_box.pack_start(read_unread, true, true, 0);
+    }
+
+    private void render_details(zavai.log.Log l)
+    {
+        details.text = "";
+        details.insert_at_cursor("%s: %s\n".printf(l.tag, l.title), -1);
+
+        for (weak List<zavai.log.LogEntry> i = l.entries; i != null; i = i.next)
+        {
+            // We are displaying it to the user, so use local timezone
+            var t = Time.local(i.data.ts);
+            string formatted = t.format("%Y-%m-%d %H:%M:%S");
+            details.insert_at_cursor("%s: %s\n".printf(formatted, i.data.msg), -1);
+            // public double lat;
+            // public double lon;
+        }
+    }
+
+    private void on_row_selected(Gtk.TreeView tv)
+    {
+        Gtk.TreePath path;
+        list.get_cursor(out path, null);
+
+        if (!model.get_iter(out cur_iter, path)) return;
+
+        Value vdir, vname;
+        model.get_value(cur_iter, 0, out vdir);
+        model.get_value(cur_iter, 1, out vname);
+
+        string pathname = vdir.get_string() + "/" + vname.get_string();
+        cur_log = zavai.log.log.load(pathname);
+        render_details(cur_log);
+
+        read_unread.set_sensitive(true);
+        update_read_unread(cur_log.acked);
+
+        // model.set(iter, 0, d); // set new dir
+        //selected((int)year, (int)month, (int)day);
+    }
+
+    private void on_read_unread(Gtk.Button b)
+    {
+        if (cur_log.acked)
+        {
+            cur_log.acked = false;
+        } else {
+            cur_log.acked = true;
+        }
+        model.set(cur_iter, 2, cur_log.acked, -1);
+
+        update_read_unread(cur_log.acked);
+
+        Value vname;
+        model.get_value(cur_iter, 1, out vname);
+        zavai.log.log.set_acknowledged(vname.get_string(), cur_log.acked);
+    }
+
+    private void update_read_unread(bool acked)
+    {
+        if (acked)
+            read_unread.set_label("Mark as unread");
+        else
+            read_unread.set_label("Mark as read");
+    }
+
+    public void refresh()
+    {
+        model.clear();
+
+        zavai.log.log.list_entries((d, f) => {
+            Gtk.TreeIter iter;
+            model.insert_with_values(out iter, -1, 0, d, 1, f, 2, false, -1);
+            return true;
+        });
+    }
+
+    public override void start()
+    {
+        refresh();
+    }
+    public override void stop()
+    {
+    }
+}
+
+public Log log;
+
+public void init()
+{
+    log = new Log();
+    zavai.menu_misc.add_applet(log);
+}
+
+}
+}
+}
index b7752cb423f34168eb3d16d0cf642987c8e5c6fe..b14b7e51f853c3cd3bcd3f4469d368e23b6dc784 100644 (file)
@@ -43,6 +43,7 @@ public class Clock : Gtk.VBox
     protected zavai.clock.SourceType last_time_type;
     protected time_t last_deadline;
     protected string last_deadline_label;
+    protected Log log;
 
     construct
     {
@@ -66,6 +67,9 @@ public class Clock : Gtk.VBox
         l_deadline.set_justify(Gtk.Justification.CENTER);
         pack_start(l_deadline, false, false, 0);
 
+        log = new Log();
+        pack_start(log, false, false, 0);
+
         zavai.clock.clock.minute_changed += on_minute_changed;
         zavai.clock.clock.schedule_changed += on_schedule_changed;
         on_schedule_changed(zavai.clock.clock.next_alarm());
@@ -131,6 +135,7 @@ public class Status : Applet
     public Gtk.HBox status_icons;
     public Clock clock;
     public Gtk.Label gsm_status;
+    public Gtk.Label gsm_info;
     public AppletPushLink menu;
 
     public Status(string label)
@@ -139,15 +144,24 @@ public class Status : Applet
         status_icons = new Gtk.HBox(false, 0);
         clock = new Clock();
         gsm_status = new Gtk.Label("");
+        gsm_info = new Gtk.Label("");
         menu = new AppletPushLink(zavai.menu_main);
 
         pack_start(status_icons, false, false, 0);
         pack_start(clock, false, false, 0);
         pack_start(gsm_status, false, false, 0);
+        pack_start(gsm_info, false, false, 0);
         // pack_start(music.player, false, false, 0);
         pack_end(menu, false, false, 0);
 
         zavai.gsm.gsm.status_changed += (msg) => { gsm_status.set_text(msg); };
+        zavai.gsm.gsm.info_changed += () => {
+stderr.printf("NEW INFO %s %s %d\n", zavai.gsm.gsm.info_provider, zavai.gsm.gsm.info_registration, zavai.gsm.gsm.info_signal_strength);
+            string text = "%s (%s)".printf(zavai.gsm.gsm.info_provider, zavai.gsm.gsm.info_registration);
+            if (zavai.gsm.gsm.info_signal_strength != -1)
+                text = "%s %d%%".printf(text, zavai.gsm.gsm.info_signal_strength);
+            gsm_info.set_text(text);
+        };
     }
 }
 
@@ -397,6 +411,46 @@ public class AddRelativeDeadline : AddDeadline
     }
 }
 
+public class Log : Gtk.VBox
+{
+    protected Gtk.Label l_info;
+    protected Gtk.Button l_info_button;
+
+    construct
+    {
+        l_info = new Gtk.Label("");
+        // l_info.modify_font(Pango.FontDescription.from_string("Sans 60"));
+        pack_start(l_info, false, false, 0);
+
+        l_info_button = new Gtk.Button();
+        l_info_button.set_image(l_info);
+        l_info_button.relief = Gtk.ReliefStyle.NONE;
+        l_info_button.clicked += (b) => {
+            zavai.app.push_applet(zavai.ui.logview.log);
+        };
+        pack_start(l_info_button, false, false, 0);
+
+        zavai.log.log.entries_changed += refresh;
+
+        refresh();
+    }
+
+    public void refresh()
+    {
+        int count = 0;
+        zavai.log.log.list_entries((d, f) => {
+            ++count;
+            return true;
+        });
+        if (count == 0)
+            l_info.set_text("");
+        else
+            l_info.set_text("%d log entries".printf(count));
+        l_info_button.set_sensitive(count != 0);
+        //zavai.log.Log l = zavai.log.log.load(args[2]);
+    }
+}
+
 /*
 public class AddDailyDeadline : Applet
 {
index 8fedf3f4e5545ccd44a9e1d5238375f8e2f3c7c6..2e666030553b66e15c05369e4ffe03d9c6c8ccec 100644 (file)
@@ -485,7 +485,7 @@ public class Backlight: zavai.Service
     public void wiggle()
     {
         try {
-            zavai.config.run_script(zavai.config.homedir + "/display wiggle");
+            zavai.config.find_and_run_script("display", "wiggle");
         } catch (Error e) {
             zavai.log.error("Requesting/releasing resource Display: " + e.message);
         }
@@ -496,7 +496,7 @@ public class Backlight: zavai.Service
         if (!started)
         {
             try {
-                zavai.config.run_script(zavai.config.homedir + "/display lock_off");
+                zavai.config.find_and_run_script("display", "lock_off");
             } catch (GLib.Error e) {
                 zavai.log.error(e.message);
             }
@@ -506,7 +506,7 @@ public class Backlight: zavai.Service
     public void unlock_screen()
     {
         try {
-            zavai.config.run_script(zavai.config.homedir + "/display defaults");
+            zavai.config.find_and_run_script("display", "defaults");
         } catch (GLib.Error e) {
             zavai.log.error(e.message);
         }
@@ -516,7 +516,7 @@ public class Backlight: zavai.Service
     {
         if (started) return;
         try {
-            zavai.config.run_script(zavai.config.homedir + "/display lock_on");
+            zavai.config.find_and_run_script("display", "lock_on");
             zavai.log.info("Acquired display");
             base.start();
         } catch (GLib.Error e) {
@@ -529,7 +529,7 @@ public class Backlight: zavai.Service
     {
         if (!started) return;
         try {
-            zavai.config.run_script(zavai.config.homedir + "/display defaults");
+            zavai.config.find_and_run_script("display", "defaults");
             zavai.log.info("Released display");
             base.stop();
         } catch (GLib.Error e) {
diff --git a/src/at.vala b/src/at.vala
new file mode 100644 (file)
index 0000000..33cdf27
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * at - at interface
+ *
+ * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace at {
+
+public struct Event
+{
+       int id;
+       time_t deadline;
+}
+
+// Return the earliest ID in the queue, or -1 if none are found
+// Queue is null for all queues, otherwise a queue name
+public static Event earliestID(string? queue = null)
+{
+       Event res = { -1, 0 };
+
+       string argv[4];
+       argv[0] = "/usr/bin/atq";
+       if (queue == null)
+               argv[1] = null;
+       else
+       {
+               argv[1] = "-q";
+               argv[2] = queue;
+               argv[3] = null;
+       }
+
+       Pid pid;
+       int stdout;
+
+       try
+       {
+               if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdout, null))
+                       return res;
+       } catch (SpawnError e) {
+               stderr.printf("Cannot run 'at -q': %s\n", e.message);
+               return res;
+       }
+
+       FileStream fs = FileStream.fdopen(stdout, "r");
+       if (fs == null)
+               return res;
+
+       char buf[200];
+       string? line;
+       while ((line = fs.gets(buf)) != null)
+       {
+               if (!line[0].isdigit()) continue;
+               weak string rest;
+               ulong id = line.to_ulong(out rest, 10);
+               Time t = Time();
+               rest = t.strptime(rest.offset(1), "%a %b %d %H:%M:%S %Y");
+               if (rest == null) continue;
+               if (rest.size() < 2) continue;
+               //stderr.printf("PARSE QUEUE rest %s\n", rest);
+               // Skip the queue of tasks currently being executed
+               //if (rest[1] == '=') continue;
+               // Skip entries not in the wanted queue
+               if (queue != null && rest[1] != queue[0]) continue;
+               time_t tt = t.mktime();
+               if (res.deadline == 0 || tt < res.deadline) {
+                       res.id = (int)id;
+                       res.deadline = tt;
+               }
+       }
+       Process.close_pid(pid);
+       return res;
+}
+
+public delegate bool jobParser(int fd);
+
+// Get the contents of a job given its id
+public static bool jobContents(int id, jobParser parser)
+{
+       string argv[4];
+       argv[0] = "/usr/bin/at";
+       argv[1] = "-c";
+       argv[2] = id.to_string();
+       argv[3] = null;
+
+       Pid pid;
+       int stdoutfd;
+
+       try
+       {
+               if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdoutfd, null))
+                       return false;
+       } catch (SpawnError e) {
+               stderr.printf("Cannot run 'at -c': %s\n", e.message);
+               return false;
+       }
+
+       bool res = parser(stdoutfd);
+
+       Process.close_pid(pid);
+
+       return res;
+}
+
+/*
+TODO: schedule alarms via at
+
+Uses the 'z' queue.
+
+atq -q z  can be used to list the jobs (for example, at startup, or after a job has run)
+at -c id  can be used to query a job, parsing its contents (which can have
+          comments or variables being set)
+zavai --notify ...  can be used to notify the job (and start zavai if it's not running)
+
+Alarm needs to be able to serialize itself to an at invocation and to
+deserialize itself from the output of at -c
+
+Alarm needs to deserialize also a job with no special markers whatsoever: a
+generic at job.
+*/
+
+
+/*
+public class Alarm : Object
+{
+       // TODO: make a factory method to construct from an "at -c" output
+
+       // TODO: make a method that provides an at invocation
+
+       public signal void trigger(Alarm a);
+
+       public time_t deadline;
+       public string label;
+
+       public Alarm(time_t deadline, string label)
+       {
+               this.deadline = deadline;
+               this.label = label;
+       }
+}
+*/
+
+       // Schedule a task that notifies a string
+       // TODO public void schedule_label(const Alarm a);
+
+       // Return the next item in the queue due to be run
+       // TODO public Alarm? next_scheduled();
+
+}
diff --git a/src/audio.vala b/src/audio.vala
new file mode 100644 (file)
index 0000000..1c39420
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * audio - audio resource for zavai
+ *
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace audio {
+
+public class Audio: zavai.Service
+{
+    protected Omhacks.Led vibrator;
+    protected bool has_vibrator;
+
+    /*
+       protected dynamic DBus.Object audiodev;
+       protected dynamic DBus.Object vibdev;
+   */
+
+    public Audio()
+    {
+        Object(name: "audio");
+
+        has_vibrator = (vibrator.init("neo1973:vibrator") == 0);
+
+/*
+        audiodev = zavai.registry.sbus.get_object(
+                "org.freesmartphone.odeviced",
+                "/org/freesmartphone/Device/Audio",
+                "org.freesmartphone.Device.Audio");
+        vibdev = zavai.registry.sbus.get_object(
+                "org.freesmartphone.odeviced",
+                "/org/freesmartphone/Device/LED/neo1973_vibrator",
+                "org.freesmartphone.Device.LED");
+*/
+        clock.alarm_trigger_queue.triggered += on_alarm_trigger;
+        clock.alarm_trigger_queue.acked += on_alarm_done;
+        clock.alarm_trigger_queue.canceled += on_alarm_done;
+    }
+
+    public void on_alarm_trigger(clock.AlarmTriggerInfo info)
+    {
+        zavai.log.debug("Make noise for alarm");
+        if (has_vibrator)
+        {
+            vibrator.brightness = 256;
+            // FIXME: is there a better way? I hope there is a better way. Please
+            // tell me there is a better way.
+            var trig = "timer";
+            for (int i = 0; ; ++i)
+            {
+                vibrator.trigger[i] = (char)trig[i];
+                if (trig[i] == 0) break;
+            }
+            vibrator.delay_on = 200;
+            vibrator.delay_off = 300;
+            vibrator.set();
+        }
+        soundplayer.play(config.ringtone_alarm, true);
+    }
+
+    public void on_alarm_done(clock.AlarmTriggerInfo info)
+    {
+        zavai.log.debug("Stop noise for alarm");
+        if (has_vibrator)
+        {
+            var trig = "none";
+            for (int i = 0; ; ++i)
+            {
+                vibrator.trigger[i] = (char)trig[i];
+                if (trig[i] == 0) break;
+            }
+            vibrator.brightness = 0;
+            vibrator.set();
+        }
+        soundplayer.stop();
+    }
+
+/*
+    public void notify_alarm(zavai.clock.Alarm a)
+    {
+        // Wiggle screen to turn on backlight
+        zavai.ui.power.backlight.wiggle();
+        try {
+            // Method does not exist in this frameworkd
+            vibdev.BlinkSeconds(5, 500, 200);
+        } catch (Error e) {
+            zavai.log.error("Cannot blink vibrator: " + e.message);
+        }
+        // TODO: play music?
+    }
+*/
+}
+
+public class Player: zavai.Resource, Object
+{
+    protected Gst.Element player;
+    protected bool playing;
+    protected Player slave;
+    protected Player master;
+    protected bool loop;
+    protected string uri;
+    public signal void state_changed(Gst.State new_state);
+
+    public Player()
+    {
+        slave = null;
+        master = null;
+        player = Gst.ElementFactory.make("playbin", null);
+        playing = false;
+        loop = false;
+        var bus = player.get_bus();
+        bus.add_signal_watch();
+        bus.message += on_message;
+    }
+
+    public void set_slave(Player player)
+    {
+        slave = player;
+        slave.master = this;
+    }
+
+    public void play(string uri, bool loop = false)
+    {
+stderr.printf("Playing %s\n", uri);
+        this.uri = uri;
+
+        if (slave != null && slave.playing)
+            slave.pause();
+
+        player.set_property("uri", uri);
+        player.set_state(master != null && master.playing ? Gst.State.PAUSED : Gst.State.PLAYING);
+        playing = true;
+        this.loop = loop;
+    }
+
+    public Gst.State get_state()
+    {
+        Gst.State state;
+        Gst.State pending;
+
+        player.get_state(out state, out pending, (Gst.ClockType)Gst.CLOCK_TIME_NONE);
+
+        return state;
+    }
+
+    public void pause()
+    {
+        player.set_state(Gst.State.PAUSED);
+        state_changed(Gst.State.PAUSED);
+    }
+
+    public void resume()
+    {
+        player.set_state(Gst.State.PLAYING);
+        state_changed(Gst.State.PLAYING);
+    }
+
+    public void restart()
+    {
+        player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
+        player.set_state(Gst.State.PLAYING);
+        state_changed(Gst.State.PLAYING);
+    }
+
+    public void stop()
+    {
+        playing = false;
+        player.set_state(Gst.State.NULL);
+        state_changed(Gst.State.NULL);
+
+        // Resume slave after we are done
+        if (slave != null && slave.playing)
+            slave.resume();
+    }
+
+    protected void on_message(Gst.Message message)
+    {
+        if (message.type == Gst.MessageType.EOS)
+        {
+            if (loop)
+                restart();
+            else
+                stop();
+        }
+    }
+
+    public void shutdown()
+    {
+        stop();
+    }
+}
+
+public Audio audio = null;
+public Player musicplayer = null;
+public Player soundplayer = null;
+
+public void init()
+{
+    audio = new Audio();
+    musicplayer = new Player();
+    soundplayer = new Player();
+    soundplayer.set_slave(musicplayer);
+    zavai.registry.register(musicplayer);
+    zavai.registry.register(soundplayer);
+}
+
+}
+}
diff --git a/src/bluetooth.vala b/src/bluetooth.vala
new file mode 100644 (file)
index 0000000..0103d0f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * bluetooth - bluetooth resource for zavai
+ *
+ * Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace bluetooth {
+
+public class Bluetooth: zavai.ScriptService
+{
+    public Bluetooth()
+    {
+        Object(name: "bluetooth");
+        started = script_status();
+    }
+
+    /// Start Bluetooth
+    public override void start()
+    {
+        if (started) return;
+        if (!script_start()) return;
+        zavai.log.info("bluetooth turned on");
+        base.start();
+    }
+
+    // Release usage of GPS
+    public override void stop()
+    {
+        if (!started) return;
+        script_stop();
+        base.stop();
+    }
+}
+
+public Bluetooth bluetooth = null;
+
+public void init()
+{
+    bluetooth = new Bluetooth();
+
+}
+
+}
+}
index 7b0ab09bf866a28f2990209520aa9f110d426643..5e258873a91bb624ef36b8efdb3372cc312526b1 100644 (file)
@@ -152,12 +152,13 @@ public class Next30 : Gtk.ScrolledWindow
                var buffer = new char[64];
                date.strftime(buffer, "%d %a");
                Gtk.TreeIter iter;
-               model.append (out iter);
-               model.set(iter, 0, (string)buffer);
-               model.set(iter, 1, notes);
-               model.set(iter, 2, date.get_year());
-               model.set(iter, 3, date.get_month());
-               model.set(iter, 4, date.get_day());
+        model.insert_with_values(out iter, -1,
+            0, (string)buffer,
+            1, notes,
+            2, date.get_year(),
+            3, date.get_month(),
+            4, date.get_day(),
+            -1);
        }
 
        public void update(Date start)
diff --git a/src/clock.vala b/src/clock.vala
new file mode 100644 (file)
index 0000000..fd5e6f0
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * clock - clock resource for zavai
+ *
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace clock {
+
+public enum SourceType
+{
+    SYSTEM,
+    GPS
+}
+
+/*
+TODO: schedule alarms via at
+
+Uses the 'z' queue.
+
+atq -q z  can be used to list the jobs (for example, at startup, or after a job has run)
+at -c id  can be used to query a job, parsing its contents (which can have
+          comments or variables being set)
+zavai --notify ...  can be used to notify the job (and start zavai if it's not running)
+
+Alarm needs to be able to serialize itself to an at invocation and to
+deserialize itself from the output of at -c
+
+Alarm needs to deserialize also a job with no special markers whatsoever: a
+generic at job.
+
+
+
+refresh_alarms()
+{
+    oldtime = next_alarm ? next_alarm.time : 0
+    next_alarm = the first alarm from atq
+    if (oldtime != next_alarm.time)
+    {
+        remove existing triggers
+          (triggers can be skipped if we don't need to support non-zavai alarms)
+        schedule a trigger calling refresh_alarms() at next_alarm.time + 30 seconds
+          (triggers can be skipped if we don't need to support non-zavai alarms)
+    }
+}
+
+at clock constructor: refresh_alarms()
+inotifywait -e close /usr/bin/at -> refresh_alarms()  (shows when someone has just used at)
+  (can be skipped if we don't need to support non-zavai alarms)
+at alarm triggered through zavai: refresh_alarms()
+
+
+*/
+
+
+public class Alarm : Object
+{
+    public at.Event ev;
+    public string label;
+
+    // Schedule with at
+    public static void schedule(string timespec, string label) throws Error
+    {
+        string argv[5];
+        argv[0] = "/usr/bin/at";
+        argv[1] = "-q";
+        argv[2] = "z";
+        argv[3] = timespec;
+        argv[4] = null;
+
+        Pid pid;
+        int stdinfd;
+
+        if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, out stdinfd, null, null))
+            return;
+
+        {
+            FileStream fs = FileStream.fdopen(stdinfd, "w");
+            string display = GLib.Environment.get_variable("DISPLAY");
+            if (display != null)
+                fs.printf("DISPLAY=\"%s\"; export DISPLAY\n", display);
+            fs.printf("# Zavai variables start here\n");
+            fs.printf("ZAVAI_LABEL=\"%s\"\n", label.escape(""));
+            fs.printf("# Zavai commands starts here\n");
+            fs.printf("%s notify \"$ZAVAI_LABEL\"", zavai.config.argv0);
+        }
+        
+        Process.close_pid(pid);
+    }
+
+    // Get the label of the job with the given at ID
+    public static string? getLabel(int atID)
+    {
+        string label = null;
+        at.jobContents(atID, fd => {
+            FileStream fs = FileStream.fdopen(fd, "r");
+            while (true)
+            {
+                string? line = fs.read_line();
+                if (line == null) break;
+                if (line.has_prefix("ZAVAI_LABEL=\""))
+                {
+                    size_t size = line.size();
+                    if (size < 15) continue;
+                    label = line.substring(13, (long)(size - 14));
+                    label = label.compress();
+                    break;
+                }
+            }
+            return true;
+        });
+        return label;
+    }
+}
+
+[DBus (name = "org.enricozini.zavai.Alarm")]
+public class ZavaiClock : Object {
+    public void Notify (string label) {
+        clock.notify_alarm(label);
+    }
+}
+
+public class AlarmTriggerInfo
+{
+    public zavai.log.Log log;
+    public string label;
+    public bool acked;
+    public bool canceled;
+
+    public AlarmTriggerInfo(string label)
+    {
+        this.label = label;
+        acked = false;
+        canceled = false;
+    }
+}
+
+public class AlarmTriggerQueue : zavai.Service
+{
+    protected List<AlarmTriggerInfo> queue;
+
+    public signal void triggered(AlarmTriggerInfo info);
+    public signal void acked(AlarmTriggerInfo info);
+    public signal void canceled(AlarmTriggerInfo info);
+
+    public AlarmTriggerQueue()
+    {
+        queue = new List<AlarmTriggerInfo>();
+    }
+
+    public void enqueue_trigger(AlarmTriggerInfo info)
+    {
+        // Reuse IDs from the associated logger object
+        info.log = zavai.log.log.start("alarm", "Alarm " + info.label);
+        queue.append(info);
+        if (queue.data == info)
+            triggered(queue.data);
+    }
+
+    protected void done_with_first()
+    {
+        var first = queue.data;
+        queue.remove_link(queue);
+        if (queue != null)
+            triggered(queue.data);
+    }
+
+    public void ack(AlarmTriggerInfo info)
+    {
+        if (queue == null || info != queue.data) return;
+        if (!info.acked && !info.canceled)
+        {
+            info.acked = true;
+            acked(info);
+            info.log.add("alarm acknowledged");
+            zavai.log.log.end(info.log);
+        }
+        done_with_first();
+    }
+
+    public void cancel(AlarmTriggerInfo info)
+    {
+        if (queue == null || info != queue.data) return;
+        if (!info.acked && !info.canceled)
+        {
+            info.canceled = true;
+            canceled(info);
+            info.log.add("alarm canceled");
+            zavai.log.log.end(info.log);
+        }
+        done_with_first();
+    }
+}
+
+public class Clock: zavai.Service
+{
+    protected time_t last_gps_time;
+    protected time_t last_gps_time_system_time;
+    protected time_t last_system_time;
+    protected uint system_time_timeout;
+    protected time_t last_minute;
+    protected time_t chosen_time;
+    protected SourceType chosen_type;
+    protected ZavaiClock dbusClock;
+
+    protected dynamic DBus.Object otimed_alarm;
+    protected dynamic DBus.Object rtc;
+    protected SList<Alarm> alarms;
+
+    // Ticks once a minute
+    public signal void minute_changed(long time, SourceType source);
+    public signal void schedule_changed(Alarm? next);
+
+    public Clock()
+    {
+        Object(name: "clock");
+        alarms = null;
+        dbusClock = new ZavaiClock();
+        last_minute = 0;
+        last_gps_time = 0;
+        last_gps_time_system_time = 0;
+        last_system_time = time_t();
+        chosen_time = last_system_time;
+
+        // FSO alarm system
+        otimed_alarm = zavai.registry.sbus.get_object(
+                "org.freesmartphone.otimed",
+                "/org/freesmartphone/Time/Alarm",
+                "org.freesmartphone.Time.Alarm");
+
+        rtc = zavai.registry.sbus.get_object(
+                "org.freesmartphone.odeviced",
+                "/org/freesmartphone/Device/RTC/0",
+                "org.freesmartphone.Device.RealtimeClock");
+
+        zavai.registry.sbus.register_object("/org/enricozini/Zavai/Clock", dbusClock);
+    }
+
+    public void notify_alarm(string label)
+    {
+        stderr.printf("Notifying %s\n", label);
+        AlarmTriggerInfo info = new AlarmTriggerInfo(label);
+        alarm_trigger_queue.enqueue_trigger(info);
+        schedule_changed(next_alarm());
+    }
+
+    public Alarm? next_alarm()
+    {
+        at.Event ev;
+        ev = at.earliestID("z");
+        if (ev.deadline == 0)
+            return null;
+        string label = Alarm.getLabel(ev.id);
+        Alarm res = new Alarm();
+        res.ev = ev;
+        res.label = label;
+        return res;
+    }
+
+    public void schedule(string timespec, string label) throws Error
+    {
+        Alarm.schedule(timespec, label);
+        schedule_changed(next_alarm());
+    }
+
+    private void on_gps_time(uint t)
+    {
+        if (t == 0)
+        {
+            last_gps_time_system_time = 0;
+            update_time();
+        } else {
+            last_gps_time = (time_t)t;
+            last_gps_time_system_time = time_t();
+            update_time();
+        }
+    }
+
+    private bool on_system_time()
+    {
+        last_system_time = time_t();
+        update_time();
+        return true;
+    }
+
+    private void update_time()
+    {
+        if (last_gps_time_system_time + 10 > last_system_time)
+        {
+            chosen_time = last_gps_time;
+            chosen_type = SourceType.GPS;
+        }
+        else
+        {
+            chosen_time = last_system_time;
+            chosen_type = SourceType.SYSTEM;
+        }
+        if (chosen_time / 60 != last_minute)
+        {
+            last_minute = chosen_time / 60;
+            minute_changed(chosen_time, chosen_type);
+        }
+    }
+
+    /// Request GPS resource
+    public override void start()
+    {
+        if (started) return;
+
+        system_time_timeout = Timeout.add(5000, on_system_time);
+        zavai.gps.gps.time_changed += on_gps_time;
+        last_system_time = time_t();
+        update_time();
+
+        base.start();
+    }
+
+    public override void stop()
+    {
+        if (!started) return;
+
+        Source.remove(system_time_timeout);
+        zavai.gps.gps.time_changed -= on_gps_time;
+
+        base.stop();
+    }
+}
+
+public Clock clock = null;
+public AlarmTriggerQueue alarm_trigger_queue = null;
+
+public void init()
+{
+    clock = new Clock();
+    alarm_trigger_queue = new AlarmTriggerQueue();
+}
+
+}
+}
diff --git a/src/config.vala b/src/config.vala
new file mode 100644 (file)
index 0000000..c2a0e56
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * config - zavai configuration
+ *
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+namespace zavai {
+
+public class Config
+{
+    protected Lua.LuaVM lua;
+    protected weak string get_string(string name)
+    {
+        lua.get_global(name);
+        weak string res = lua.to_string(-1);
+        lua.pop(1);
+        return res;
+    }
+    protected string set_string(string name, string? val)
+    {
+        if (val == null)
+            lua.push_nil();
+        else
+            lua.push_string(val);
+        lua.set_global(name);
+        return val;
+    }
+    protected weak int get_int(string name)
+    {
+        lua.get_global(name);
+        int res = lua.to_integer(-1);
+        lua.pop(1);
+        return res;
+    }
+    protected int set_int(string name, int val)
+    {
+        lua.push_integer(val);
+        lua.set_global(name);
+        return val;
+    }
+
+    private string _version;
+    public string version
+    {
+        get { return _version; }
+        set { _version = set_string("version", value); }
+    }
+
+    // "phone" or "laptop"
+    private string _profile;
+    public string profile
+    {
+        get { return _profile; }
+        set { _profile = set_string("profile", value); }
+    }
+
+    private string _homedir;
+    public string homedir
+    {
+        get { return _homedir; }
+        set { _homedir = set_string("homedir", value); }
+    }
+
+    private string _icondir;
+    public string icondir
+    {
+        get { return _icondir; }
+        set { _icondir = set_string("icondir", value); }
+    }
+
+    private int _min_button_height;
+    public int min_button_height
+    {
+        get { return _min_button_height; }
+        set { _min_button_height = set_int("min_button_height", value); }
+    }
+
+    private string _gpsd_host;
+    public string gpsd_host
+    {
+        get { return _gpsd_host; }
+        set { _gpsd_host = set_string("gpsd_host", value); }
+    }
+
+    private string _gpsd_port;
+    public string gpsd_port
+    {
+        get { return _gpsd_port; }
+        set { _gpsd_port = set_string("gpsd_port", value); }
+    }
+
+    private string _gprs_apn;
+    public string gprs_apn
+    {
+        get { return _gprs_apn; }
+        set { _gprs_apn = set_string("gprs_apn", value); }
+    }
+
+    private string _gprs_user;
+    public string gprs_user
+    {
+        get { return _gprs_user; }
+        set { _gprs_user = set_string("gprs_user", value); }
+    }
+
+    private string _gprs_pass;
+    public string gprs_pass
+    {
+        get { return _gprs_pass; }
+        set { _gprs_pass = set_string("gprs_pass", value); }
+    }
+
+    private string _sim_pin;
+    public string sim_pin
+    {
+        get { return _sim_pin; }
+        set { _sim_pin = set_string("sim_pin", value); }
+    }
+
+    private int _power_button_keycode;
+    public int power_button_keycode
+    {
+        get { return _power_button_keycode; }
+        set { _power_button_keycode = set_int("power_button_keycode", value); }
+    }
+
+    private int _aux_button_keycode;
+    public int aux_button_keycode
+    {
+        get { return _aux_button_keycode; }
+        set { _aux_button_keycode = set_int("aux_button_keycode", value); }
+    }
+
+    private string _ringtone_alarm;
+    public string ringtone_alarm
+    {
+        get { return _ringtone_alarm; }
+        set { _ringtone_alarm = set_string("ringtone_alarm", value); }
+    }
+
+    public int backlight_max
+    {
+        get;
+        set;
+    }
+
+    private string _argv0;
+    public string argv0 {
+        get { return _argv0; }
+        set {
+            if (value.chr(-1, '/') != null)
+            {
+                if (Path.is_absolute(value))
+                {
+                    _argv0 = value;
+                } else {
+                    _argv0 = Path.build_filename(Environment.get_current_dir(), value, null);
+                }
+            } else {
+                _argv0 = Environment.find_program_in_path(value);
+            }
+            zavai.log.debug("ARGV0: " + _argv0);
+        }
+    }
+
+    /// Reread config values from the Lua VM, to be run after running Lua code
+    protected void refresh_from_lua()
+    {
+        _version = get_string("version");
+        _profile = get_string("profile");
+        _homedir = get_string("homedir");
+        _icondir = get_string("icondir");
+        _min_button_height = get_int("min_button_height");
+        _gpsd_host = get_string("gpsd_host");
+        _gpsd_port = get_string("gpsd_port");
+        _gprs_apn = get_string("gprs_apn");
+        _gprs_user = get_string("gprs_user");
+        _gprs_pass = get_string("gprs_pass");
+        _sim_pin = get_string("sim_pin");
+        _power_button_keycode = get_int("power_button_keycode");
+        _aux_button_keycode = get_int("aux_button_keycode");
+        _ringtone_alarm = get_string("ringtone_alarm");
+    }
+
+    public Config()
+    {
+        lua = new Lua.LuaVM();
+        lua.open_libs();
+
+        // Set defaults
+        version = "0.1";
+        profile = "phone";
+        homedir = GLib.Environment.get_home_dir() + "/.zavai";
+        icondir = GLib.Environment.get_variable("ZAVAI_ICONDIR");
+        if (icondir == null)
+                icondir = "/usr/share/zavai/icons";
+        min_button_height = 80;
+        gpsd_host = "localhost";
+        gpsd_port = "gpsd";
+        gprs_apn = "general.t-mobile.uk";
+        gprs_user = "x";
+        gprs_pass = "x";
+        sim_pin = "1234";
+        backlight_max = 15;
+        power_button_keycode = 124;
+        aux_button_keycode = 177;
+        ringtone_alarm = "file:///usr/share/sounds/yue-fso/lec1.ogg";
+
+        // Read config
+        if (lua.do_file(homedir + "/config"))
+        {
+            zavai.log.error("Failed to parse " + homedir + "/config: " + lua.to_string(-1));
+        }
+        refresh_from_lua();
+    }
+
+    /**
+     * Find a zavai script.
+     * 
+     * ~/.zavai/NAME is searched first, then /usr/share/zavai/hooks/
+     *
+     * If the script is not found, NULL is returned
+     */
+    public string? find_script(string name)
+    {
+        string candidate = homedir + "/" + name;
+        if (FileUtils.test(candidate, FileTest.EXISTS))
+            return candidate;
+        candidate = "/usr/share/zavai/hooks/" + name;
+        if (FileUtils.test(candidate, FileTest.EXISTS))
+            return candidate;
+        return null;
+    }
+
+    public void find_and_run_script(string script, string args) throws SpawnError
+    {
+        string cmd = find_script(script);
+        if (cmd == null)
+            throw new SpawnError.NOENT("hook '" + cmd + "' not found");
+        run_script(cmd + " " + args);
+    }
+
+    public void run_script(string command) throws SpawnError
+    {
+        zavai.log.info("Run program: " + command);
+        string[] args = command.split(" ");
+        Pid pid;
+        Process.spawn_async(
+            Environment.get_home_dir(),
+            args,
+            null,
+            SpawnFlags.SEARCH_PATH,
+            null,
+            out pid);
+    }
+
+    public int run_script_sync(string command, out string std_out, out string std_err) throws SpawnError
+    {
+        int status = -1;
+        zavai.log.info("Run program: " + command);
+        string[] args = command.split(" ");
+        bool res = Process.spawn_sync(Environment.get_home_dir(), args, null, SpawnFlags.SEARCH_PATH, null, out std_out, out std_err, out status);
+        return status;
+    }
+}
+
+public Config config = null;
+
+}
diff --git a/src/core.vala b/src/core.vala
new file mode 100644 (file)
index 0000000..ade1231
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * app - zavai main window
+ *
+ * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+
+public interface Resource : Object {
+    /**
+     * Shut down this resource.
+     *
+     * Normally one does nothing here, but it is important to give resources a
+     * chance to do cleanup when the program quits.
+     * 
+     * This can be used for tasks like closing the tags on a GPX track,
+     * releasing a FSO resource, restoring mixer settings and so on.
+     */
+    public abstract void shutdown();
+}
+
+public abstract class Service : Object, Resource {
+    public string name { get; construct; }
+
+    bool _started;
+    public bool started {
+        get { return _started; }
+        set { _started = value; }
+    }
+
+    public signal void toggled(bool new_state);
+
+    protected class Request
+    {
+        public string requestor;
+        public int count;
+        public Request(string requestor)
+        {
+            this.requestor = requestor;
+            count = 1;
+        }
+    }
+
+    protected List<Request> requests;
+
+    construct
+    {
+        started = false;
+        requests = null;
+        zavai.registry.register(this);
+    }
+
+    public void shutdown()
+    {
+        stop();
+    }
+
+    /// Activate the service
+    protected virtual void start()
+    {
+        if (!started)
+        {
+            zavai.log.info("Service " + name + " started\n");
+            started = true;
+            toggled(started);
+        }
+    }
+
+    /// Deactivate the service
+    protected virtual void stop()
+    {
+        if (started)
+        {
+            zavai.log.info("Service " + name + " stopped\n");
+            started = false;
+            toggled(started);
+        }
+    }
+
+    /**
+      Request a resource using the given ID.
+     *
+     * If it is the first time the resource is requested, start it and
+     * return true. Else, take note of the request and return false.
+     *
+     * If a resource is requested multiple times with the same ID, it will
+     * need to be released multiple times with that ID.
+     */
+    public bool request(string id)
+    {
+        bool res = (requests == null);
+        bool got = false;
+        for (weak List<Request> i = requests; i != null; i = i.next)
+            if (i.data.requestor == id)
+            {
+                ++i.data.count;
+                got = true;
+                break;
+            }
+        if (!got)
+            requests.prepend(new Request(id));
+        if (res) start();
+        return res;
+    }
+
+    /**
+     * Release a resource using the given ID.
+     *
+     * If after the call nothing is requesting the resource, stop it and
+     * return true. Else, take note of the release and return false.
+     *
+     * If a resource is requested multiple times with the same ID, it will
+     * need to be released multiple times with that ID.
+     */
+    public bool release(string id)
+    {
+        weak List<Request> el = null;
+        for (weak List<Request> i = requests; i != null; i = i.next)
+            if (i.data.requestor == id)
+            {
+                el = i;
+                break;
+            }
+
+        if (el == null)
+            return false;
+
+        requests.delete_link(el);
+
+        if (requests != null)
+            return false;
+
+        stop();
+        return true;
+    }
+}
+
+public abstract class ScriptService : Service
+{
+    protected string script;
+
+    protected bool script_start()
+    {
+        try {
+            zavai.config.find_and_run_script(name, "start");
+            return true;
+        } catch (Error e) {
+            zavai.log.error("Running " + name + " start: " + e.message);
+            return false;
+        }
+    }
+
+    protected bool script_stop()
+    {
+        try {
+            zavai.config.find_and_run_script(name, "stop");
+            return true;
+        } catch (Error e) {
+            zavai.log.error("Running " + name + " stop: " + e.message);
+            return false;
+        }
+    }
+
+    protected bool script_status()
+    {
+        string std_out;
+        string std_err;
+        string script = zavai.config.find_script(name);
+        if (script == null)
+        {
+            zavai.log.error("Hook " + name + " does not exist");
+            return false;
+        }
+        string command = script + " status";
+        try {
+            int res = zavai.config.run_script_sync(command, out std_out, out std_err);
+            if (res != 0)
+            {
+                zavai.log.error("Running " + command + ": " + std_err);
+                return false;
+            }
+        } catch (SpawnError e) {
+            zavai.log.error("Running " + command + ": " + e.message);
+            return false;
+        }
+
+        std_out._strip();
+
+        return (std_out == "on");
+    }
+}
+
+public abstract class ScriptMonitorService : Service
+{
+    protected Pid child_pid;
+    protected int child_watch_id;
+
+    ScriptMonitorService()
+    {
+        child_pid = 0;
+        child_watch_id = 0;
+    }
+
+    protected bool script_start()
+    {
+        string script = zavai.config.find_script(name);
+        zavai.log.info("Run program: " + script + " pre");
+        try {
+            // Then run our own script
+            zavai.config.run_script(script + " pre");
+        } catch (Error e) {
+            zavai.log.error("Running " + script + " pre: " + e.message);
+            return false;
+        }
+
+        zavai.log.info("Run program: " + script + " run");
+        string[] args = { script, "run" };
+        try {
+            Process.spawn_async(
+                Environment.get_home_dir(),
+                args,
+                null,
+                SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
+                null,
+                out child_pid);
+        } catch (SpawnError e) {
+            zavai.log.error("Running " + script + " run: " + e.message);
+            return false;
+        }
+
+        // Add a child watch source to know when it ends
+        ChildWatch.add(child_pid, on_child);
+
+        return true;
+    }
+
+    protected bool script_stop()
+    {
+        Posix.kill((Posix.pid_t)child_pid, Posix.SIGTERM);
+        return true;
+    }
+
+    protected void on_child(Pid pid, int status)
+    {
+        zavai.log.info("Exited");
+stderr.printf("STATUS %d\n", status);
+        Process.close_pid(pid);
+
+        try {
+            // Then run our own script
+            zavai.config.find_and_run_script(name, "post");
+        } catch (Error e) {
+            zavai.log.error("Running " + name + " post: " + e.message);
+            return;
+        }
+
+        cleanup_after_script_stop();
+
+        base.stop();
+    }
+
+    protected virtual void cleanup_after_script_stop()
+    {
+    }
+
+    /*
+    protected bool script_status()
+    {
+    }
+    */
+}
+
+}
diff --git a/src/dbus-extra.vapi b/src/dbus-extra.vapi
new file mode 100644 (file)
index 0000000..5213899
--- /dev/null
@@ -0,0 +1,5 @@
+namespace DBus {
+       [CCode (cname = "dbus_bus_get_unique_name")]
+       public unowned string bus_get_unique_name (DBus.RawConnection conn);
+}
+
diff --git a/src/devkit-power-gobject.vapi b/src/devkit-power-gobject.vapi
new file mode 100644 (file)
index 0000000..139abc2
--- /dev/null
@@ -0,0 +1,232 @@
+/* devkit-power-gobject.vapi generated by vapigen, do not modify. */
+
+[CCode (cprefix = "Dkp", lower_case_cprefix = "dkp_")]
+namespace Dkp {
+       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class Client : GLib.Object {
+               [CCode (has_construct_function = false)]
+               public Client ();
+               public unowned GLib.PtrArray enumerate_devices () throws GLib.Error;
+               [CCode (cname = "dkp_client_can_hibernate")]
+               public bool get_can_hibernate ();
+               [CCode (cname = "dkp_client_can_suspend")]
+               public bool get_can_suspend ();
+               public unowned string get_daemon_version ();
+               [CCode (cname = "dkp_client_lid_is_closed")]
+               public bool get_lid_is_closed ();
+               [CCode (cname = "dkp_client_on_battery")]
+               public bool get_on_battery ();
+               [CCode (cname = "dkp_client_on_low_battery")]
+               public bool get_on_low_battery ();
+               public bool hibernate () throws GLib.Error;
+               public bool suspend () throws GLib.Error;
+               [NoAccessorMethod]
+               public bool can_hibernate { get; }
+               [NoAccessorMethod]
+               public bool can_suspend { get; }
+               public string daemon_version { get; }
+               [NoAccessorMethod]
+               public bool lid_is_closed { get; }
+               [NoAccessorMethod]
+               public bool lid_is_present { get; }
+               [NoAccessorMethod]
+               public bool on_battery { get; }
+               [NoAccessorMethod]
+               public bool on_low_battery { get; }
+               public virtual signal void changed ();
+               public virtual signal void device_added (void* device);
+               public virtual signal void device_changed (void* device);
+               public virtual signal void device_removed (void* device);
+       }
+       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class Device : GLib.Object {
+               [CCode (has_construct_function = false)]
+               public Device ();
+               public unowned GLib.PtrArray get_history (string type, uint timespec, uint resolution) throws GLib.Error;
+               public unowned string get_object_path ();
+               public unowned GLib.PtrArray get_statistics (string type) throws GLib.Error;
+               public bool print ();
+               public bool refresh () throws GLib.Error;
+               public bool set_object_path (string object_path) throws GLib.Error;
+               public static Dkp.DeviceState state_from_text (string state);
+               public static unowned string state_to_text (Dkp.DeviceState state_enum);
+               public static Dkp.DeviceTechnology technology_from_text (string technology);
+               public static unowned string technology_to_text (Dkp.DeviceTechnology technology_enum);
+               public static Dkp.DeviceType type_from_text (string type);
+               public static unowned string type_to_text (Dkp.DeviceType type_enum);
+               [NoAccessorMethod]
+               public double capacity { get; set; }
+               [NoAccessorMethod]
+               public double energy { get; set; }
+               [NoAccessorMethod]
+               public double energy_empty { get; set; }
+               [NoAccessorMethod]
+               public double energy_full { get; set; }
+               [NoAccessorMethod]
+               public double energy_full_design { get; set; }
+               [NoAccessorMethod]
+               public double energy_rate { get; set; }
+               [NoAccessorMethod]
+               public bool has_history { get; set; }
+               [NoAccessorMethod]
+               public bool has_statistics { get; set; }
+               [NoAccessorMethod]
+               public bool is_present { get; set; }
+               [NoAccessorMethod]
+               public bool is_rechargeable { get; set; }
+               [NoAccessorMethod]
+               public string model { owned get; set; }
+               [NoAccessorMethod]
+               public string native_path { owned get; set; }
+               [NoAccessorMethod]
+               public bool online { get; set; }
+               [NoAccessorMethod]
+               public double percentage { get; set; }
+               [NoAccessorMethod]
+               public bool power_supply { get; set; }
+               [NoAccessorMethod]
+               public bool recall_notice { get; set; }
+               [NoAccessorMethod]
+               public string recall_url { owned get; set; }
+               [NoAccessorMethod]
+               public string recall_vendor { owned get; set; }
+               [NoAccessorMethod]
+               public string serial { owned get; set; }
+               [NoAccessorMethod]
+               public uint state { get; set; }
+               [NoAccessorMethod]
+               public uint technology { get; set; }
+               [NoAccessorMethod]
+               public int64 time_to_empty { get; set; }
+               [NoAccessorMethod]
+               public int64 time_to_full { get; set; }
+               [NoAccessorMethod]
+               public uint type { get; set; }
+               [NoAccessorMethod]
+               public uint64 update_time { get; set; }
+               [NoAccessorMethod]
+               public string vendor { owned get; set; }
+               [NoAccessorMethod]
+               public double voltage { get; set; }
+               public virtual signal void changed (void* obj);
+       }
+       [Compact]
+       [CCode (copy_function = "dkp_history_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class HistoryObj {
+               public Dkp.DeviceState state;
+               public uint time;
+               public double value;
+               [CCode (has_construct_function = false)]
+               public HistoryObj ();
+               public bool clear ();
+               public unowned Dkp.HistoryObj copy ();
+               public static unowned Dkp.HistoryObj create (double value, Dkp.DeviceState state);
+               public bool equal (Dkp.HistoryObj obj2);
+               public static unowned Dkp.HistoryObj from_string (string text);
+               public bool print ();
+               public unowned string to_string ();
+       }
+       [Compact]
+       [CCode (copy_function = "dkp_qos_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class QosObj {
+               public weak string cmdline;
+               public uint cookie;
+               public bool persistent;
+               public uint pid;
+               public weak string sender;
+               public uint64 timespec;
+               public Dkp.QosType type;
+               public uint uid;
+               public int value;
+               [CCode (has_construct_function = false)]
+               public QosObj ();
+               public unowned Dkp.QosObj copy ();
+               public bool equal (Dkp.QosObj obj2);
+               public bool print ();
+       }
+       [Compact]
+       [CCode (copy_function = "dkp_stats_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class StatsObj {
+               public double accuracy;
+               public double value;
+               [CCode (has_construct_function = false)]
+               public StatsObj ();
+               public unowned Dkp.StatsObj copy ();
+               public static unowned Dkp.StatsObj create (double value, double accuracy);
+               public static unowned Dkp.StatsObj from_string (string text);
+               public unowned string to_string ();
+       }
+       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class Wakeups : GLib.Object {
+               [CCode (has_construct_function = false)]
+               public Wakeups ();
+               public unowned GLib.PtrArray get_data () throws GLib.Error;
+               public uint get_total () throws GLib.Error;
+               public bool has_capability ();
+               public virtual signal void data_changed ();
+               public virtual signal void total_changed (uint value);
+       }
+       [Compact]
+       [CCode (copy_function = "dkp_wakeups_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public class WakeupsObj {
+               public weak string cmdline;
+               public weak string details;
+               public uint id;
+               public bool is_userspace;
+               public uint old;
+               public float value;
+               [CCode (has_construct_function = false)]
+               public WakeupsObj ();
+               public unowned Dkp.WakeupsObj copy ();
+               public bool equal (Dkp.WakeupsObj obj2);
+               public bool print ();
+       }
+       [CCode (cprefix = "DKP_DEVICE_STATE_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public enum DeviceState {
+               UNKNOWN,
+               CHARGING,
+               DISCHARGING,
+               EMPTY,
+               FULLY_CHARGED,
+               PENDING_CHARGE,
+               PENDING_DISCHARGE,
+               LAST
+       }
+       [CCode (cprefix = "DKP_DEVICE_TECHNOLOGY_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public enum DeviceTechnology {
+               UNKNOWN,
+               LITHIUM_ION,
+               LITHIUM_POLYMER,
+               LITHIUM_IRON_PHOSPHATE,
+               LEAD_ACID,
+               NICKEL_CADMIUM,
+               NICKEL_METAL_HYDRIDE,
+               LAST
+       }
+       [CCode (cprefix = "DKP_DEVICE_TYPE_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public enum DeviceType {
+               UNKNOWN,
+               LINE_POWER,
+               BATTERY,
+               UPS,
+               MONITOR,
+               MOUSE,
+               KEYBOARD,
+               PDA,
+               PHONE,
+               LAST
+       }
+       [CCode (cprefix = "DKP_QOS_TYPE_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public enum QosType {
+               UNKNOWN,
+               NETWORK,
+               CPU_DMA,
+               LAST
+       }
+       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public const int COMPILE_VERSION;
+       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public static Dkp.QosType qos_type_from_text (string type);
+       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
+       public static unowned string qos_type_to_text (Dkp.QosType type);
+}
diff --git a/src/gps.vala b/src/gps.vala
new file mode 100644 (file)
index 0000000..17e7642
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * gps - gps resource for zavai
+ *
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace gps {
+
+// For a list of dbus services, look in /etc/dbus-1/system.d/
+public class GPS: zavai.ScriptService
+{
+    protected libgps.data_t data;
+    protected IOChannel gpsfd = null;
+    protected uint gpsfd_watch = 0;
+
+    protected int old_fix_status = libgps.STATUS_NO_FIX;
+    protected uint old_time = 0;
+    protected double old_lat = 1000;
+    protected double old_lon = 1000;
+
+    public signal void fix_status_changed(int status);
+    public signal void time_changed(uint time);
+    public signal void pos_changed();
+
+    public GPS()
+    {
+        Object(name: "gps");
+        data = libgps.data_t();
+        started = script_status();
+    }
+
+    public int fix_status() { return old_fix_status; }
+    public double time() { return old_time; }
+    public weak libgps.data_t info() { return data; }
+
+    protected bool on_input_data(IOChannel source, IOCondition condition)
+    {
+        while (libgps.waiting(ref data))
+        {
+            int res = libgps.poll(ref data);
+            if (res != 0)
+                zavai.log.error(libgps.errstr(res));
+
+            if (data.status != old_fix_status)
+            {
+                fix_status_changed(data.status);
+                old_fix_status = data.status;
+            }
+
+            uint cur_time = (uint)data.fix.time;
+            if (data.status != libgps.STATUS_NO_FIX && old_time != cur_time)
+            {
+                time_changed(cur_time);
+                old_time = cur_time;
+            }
+
+            double lat = (data.status == libgps.STATUS_NO_FIX ? 1000 : data.fix.latitude);
+            double lon = (data.status == libgps.STATUS_NO_FIX ? 1000 : data.fix.longitude);
+            if (lat != old_lat || lon != old_lon)
+                pos_changed();
+
+            /*
+            stderr.printf("GPSMSG %d %d\n", (int)data.set, data.status);
+            stderr.printf("SATUSED %d\n", data.satellites_used);
+            stderr.printf("SWT %f\n", data.skyview_time);
+            stderr.printf("SATVIS %d\n", data.satellites_visible);
+            for (int i = 0; i < data.satellites_visible; ++i)
+            {
+                stderr.printf("PRN %d ELE %d AZI %d SS %f\n",
+                    data.PRN[i], data.elevation[i], data.azimuth[i], data.ss[i]);
+            }
+            */
+        }
+        return true;
+    }
+
+    /// Request GPS resource
+    public override void start()
+    {
+        if (started) return;
+
+        if (!script_start()) return;
+
+        zavai.log.info("Connecting to gpsd at " + config.gpsd_host + ":" + config.gpsd_port);
+        int res = libgps.open_r(config.gpsd_host, config.gpsd_port, ref data);
+        if (res != 0)
+        {
+            zavai.log.error(libgps.errstr(res));
+            return;
+        }
+
+        res = libgps.stream(ref data, libgps.WATCH_ENABLE, null);
+        if (res != 0)
+        {
+            zavai.log.error(libgps.errstr(res));
+            return;
+        }
+
+        //res = libgps.send(ref data, "?SKY;");
+        //res = libgps.send(ref data, "?WATCH;");
+        //if (res != 0) zavai.log.error(libgps.errstr(res));
+
+        gpsfd = new IOChannel.unix_new(data.gps_fd);
+        try {
+            gpsfd.set_encoding(null);
+        } catch (Error e) {
+            zavai.log.error("Setting encoding to null on gpsd io channel: " + e.message);
+        }
+        //gpsfd.set_buffered(false);
+        gpsfd_watch = gpsfd.add_watch(IOCondition.IN, on_input_data);
+
+        zavai.log.info("GPS turned on");
+        base.start();
+    }
+
+    // Release usage of GPS
+    public override void stop()
+    {
+        if (!started) return;
+
+        Source.remove(gpsfd_watch);
+
+        int res = libgps.close(ref data);
+        if (res != 0)
+            zavai.log.error(libgps.errstr(res));
+
+        script_stop();
+
+        if (old_fix_status != libgps.STATUS_NO_FIX)
+        {
+            old_fix_status = libgps.STATUS_NO_FIX;
+            fix_status_changed(old_fix_status);
+        }
+
+        if (old_time != 0)
+        {
+            old_time = 0;
+            time_changed(old_time);
+        }
+
+        base.stop();
+    }
+}
+
+// #    def start_recording(self):
+// #        if self.gps_monitor:
+// #            self.gps_monitor.stop()
+// #            self.gps_monitor = None
+// #
+// #        if not self.audio:
+// #            return
+// #
+// #        # Sync system time
+// #        gpstime = self.gps.gps_time.GetTime()
+// #        subprocess.call(["date", "-s", "@%d" % gpstime])
+// #        subprocess.call(["hwclock", "--systohc"])
+// #
+// #        # Compute basename for output files
+// #        self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
+// #        self.basename = os.path.join(AUDIODIR, self.basename)
+// #
+// #        # Start recording the GPX track
+// #        self.gpx = GPX(self.basename)
+// #        self.gps.track_position(self.on_position_changed)
+// #
+// #        # Start recording in background forking arecord
+// #        self.audio.set_basename(self.basename)
+// #        self.audio.start_recording()
+// #
+
+// Write GPX track and waypoint files
+public class GPX : Service
+{
+    protected uint wpt_seq = 0;
+    protected zavai.log.Log log = null;
+
+    public GPX()
+    {
+        Object(name: "gps.gpx");
+    }
+
+    public override void start()
+    {
+        if (!started)
+        {
+            log = zavai.log.log.start("track", "GPS track");
+            base.start();
+        }
+    }
+
+    public override void stop()
+    {
+        if (started)
+        {
+            zavai.log.log.end(log);
+            log = null;
+            base.stop();
+        }
+    }
+
+    // Mark a waypoint
+    public void waypoint(string? name = null)
+    {
+        if (log == null) return;
+
+        string wptname;
+        if (name == null)
+        {
+            wptname = "wpt_%u".printf(wpt_seq);
+            wpt_seq += 1;
+        } else {
+            wptname = name;
+        }
+
+        log.add(wptname);
+    }
+}
+
+public zavai.gps.GPS gps = null;
+public zavai.gps.GPX gpx = null;
+
+public void init()
+{
+    gps = new GPS();
+    gpx = new GPX();
+
+}
+
+}
+}
diff --git a/src/gsm.vala b/src/gsm.vala
new file mode 100644 (file)
index 0000000..e554503
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * gsm - gsm resource for zavai
+ *
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace gsm {
+
+[DBus (name = "org.freesmartphone.GSM.Device")]
+public interface FSO_GSM_Device : Object {
+    public abstract async int test_int (int i, out int j) throws DBus.Error;
+    public abstract async string test_string (string s, out string t) throws DBus.Error;
+    public abstract async void set_sim_buffers_sms(bool sim_buffers_sms) throws DBus.Error;
+    public abstract async void set_r_t_c() throws DBus.Error;
+    public abstract async void cancel_command() throws DBus.Error;
+    public abstract async void set_antenna_power(bool power) throws DBus.Error;
+    public abstract async GLib.HashTable<string, GLib.Value?> get_info() throws DBus.Error;
+    public abstract async void set_microphone_muted(bool muted) throws DBus.Error;
+    public signal void keypad_event(string name, bool pressed);
+    public abstract async int get_speaker_volume() throws DBus.Error;
+    public abstract async int get_r_t_c() throws DBus.Error;
+    public abstract async void set_speaker_volume(int modem_volume) throws DBus.Error;
+    public abstract async GLib.HashTable<string, GLib.Value?> get_features() throws DBus.Error;
+    public abstract async bool get_microphone_muted() throws DBus.Error;
+    public abstract async bool get_antenna_power() throws DBus.Error;
+    public abstract async void get_power_status(out string param0, out int param1) throws DBus.Error;
+    public abstract async bool get_sim_buffers_sms() throws DBus.Error;
+}
+
+[DBus (name = "org.freesmartphone.GSM.SIM")]
+public interface FSO_GSM_SIM : GLib.Object {
+    //public abstract async SIMParam0Struct[] retrieve_phonebook(string category) throws DBus.Error;
+    public abstract async void send_auth_code(string code) throws DBus.Error;
+    public abstract async string get_issuer() throws DBus.Error;
+    public abstract async void change_auth_code(string old_pin, string new_pin) throws DBus.Error;
+    public signal void auth_status(string status);
+    public abstract async string send_generic_sim_command(string command) throws DBus.Error;
+    public abstract async string[] list_phonebooks() throws DBus.Error;
+    public abstract async void set_service_center_number(string number) throws DBus.Error;
+    public abstract async GLib.HashTable<string, string> get_provider_list() throws DBus.Error;
+    //public abstract async SIMParam0Struct2[] get_home_zones() throws DBus.Error;
+    public signal void ready_status(bool status);
+    public abstract async void retrieve_entry(string category, int index, out string param0, out string param1) throws DBus.Error;
+    public abstract async void delete_message(int index) throws DBus.Error;
+    public abstract async void send_restricted_sim_command(int command, int fileid, int p1, int p2, int p3, string data, out int param0, out int param1, out string param2) throws DBus.Error;
+    public abstract async GLib.HashTable<string, GLib.Value?> get_messagebook_info() throws DBus.Error;
+    public abstract async bool get_sim_ready() throws DBus.Error;
+    public abstract async GLib.HashTable<string, GLib.Value?> get_phonebook_info(string category) throws DBus.Error;
+    public signal void memory_full();
+    public abstract async GLib.HashTable<string, GLib.Value?> get_sim_info() throws DBus.Error;
+    public abstract async void set_auth_code_required(bool required, string pin) throws DBus.Error;
+    public abstract async string get_auth_status() throws DBus.Error;
+    public abstract async void send_stored_message(int index, out int param0, out string param1) throws DBus.Error;
+    public abstract async int store_message(string number, string contents, GLib.HashTable<string, GLib.Value?> properties) throws DBus.Error;
+    public abstract async bool get_auth_code_required() throws DBus.Error;
+    public signal void incoming_stored_message(int index);
+    public abstract async void retrieve_message(int index, out string param0, out string param1, out string param2, out GLib.HashTable<string, GLib.Value?> param3) throws DBus.Error;
+    public abstract async void store_entry(string category, int index, string name, string number) throws DBus.Error;
+    public abstract async void unlock(string puk, string new_pin) throws DBus.Error;
+    public abstract async string get_service_center_number() throws DBus.Error;
+    //public abstract async SIMParam0Struct23[] retrieve_messagebook(string category) throws DBus.Error;
+    public abstract async void delete_entry(string category, int index) throws DBus.Error;
+}
+
+[DBus (name = "org.freesmartphone.GSM.Network")]
+public interface FSO_GSM_Network : GLib.Object {
+    public signal void status(GLib.HashTable<string, GLib.Value?> status);
+    public signal void signal_strength(int strength);
+    //public abstract async NetworkParam0Struct[] list_providers() throws DBus.Error;
+    public abstract async GLib.HashTable<string, GLib.Value?> get_call_forwarding(string reason) throws DBus.Error;
+    public signal void time_zone_report(int timezone);
+    public abstract async void unregister() throws DBus.Error;
+    public abstract async void set_calling_identification(string status) throws DBus.Error;
+    public abstract async void register_() throws DBus.Error;
+    public abstract async void send_ussd_request(string request) throws DBus.Error;
+    public abstract async void disable_call_forwarding(string reason, string class_) throws DBus.Error;
+    public signal void incoming_ussd(string mode, string message_);
+    public abstract async int get_signal_strength() throws DBus.Error;
+    public abstract async void enable_call_forwarding(string reason, string class_, string number, int timeout) throws DBus.Error;
+    public abstract async string get_calling_identification() throws DBus.Error;
+    public abstract async void register_with_provider(string operator_code) throws DBus.Error;
+    public signal void cipher_status(string gsm, string gprs);
+    public abstract async GLib.HashTable<string, GLib.Value?> get_status() throws DBus.Error;
+    public abstract async void get_country_code(out string param0, out string param1) throws DBus.Error;
+}
+
+[DBus (name = "org.freesmartphone.GSM.Call")]
+public interface FSO_GSM_Call : GLib.Object {
+    public abstract async void activate(int index) throws DBus.Error;
+    public abstract async void emergency(string number) throws DBus.Error;
+    public abstract async void hold_active() throws DBus.Error;
+    public abstract async void release_held() throws DBus.Error;
+    public abstract async void send_dtmf(string tones) throws DBus.Error;
+    public abstract async void release_all() throws DBus.Error;
+    public abstract async int initiate(string number, string type_) throws DBus.Error;
+    // public abstract async CallParam0Struct[] list_calls() throws DBus.Error;
+    public abstract async void transfer(string number) throws DBus.Error;
+    public abstract async void release(int index) throws DBus.Error;
+    public signal void call_status(int index, string status, GLib.HashTable<string, GLib.Value?> properties);
+    public abstract async void activate_conference(int index) throws DBus.Error;
+}
+
+public class GSM: zavai.ScriptMonitorService
+{
+    protected dynamic DBus.Object dbus;
+    public FSO_GSM_Device device;
+    public FSO_GSM_Network network;
+    public FSO_GSM_SIM sim;
+    public FSO_GSM_Call call;
+
+    protected class CallInfo
+    {
+        public int gsm_id;
+        public zavai.log.Log log;
+    }
+    protected List<CallInfo> calls;
+
+    public string info_provider;
+    public string info_registration;
+    public int info_signal_strength;
+
+    public signal void status_changed(string message);
+    public signal void info_changed();
+
+    protected void dump_table(HashTable<string, Value?> vals)
+    {
+        vals.for_each((pk, pv) => {
+            string k = (string)pk;
+            Value? v = (Value?)pv;
+            stderr.printf("K: %s V: %s\n", k, v == null ? "(null)" : v.strdup_contents());
+        });
+    }
+
+    protected void acquire_new_status(HashTable<string, Value?> status)
+    {
+        // NETWORK STATUS
+        // K: provider V: "vodafone UK"
+        // K: mode V: "automatic"
+        // K: registration V: "roaming"
+        // K: cid V: "157F"
+        // K: lac V: "0031"
+        // K: act V: "GSM"
+        // K: code V: "23415"
+        bool changed = false;
+
+        var vprovider = status.lookup("provider");
+        if (vprovider != null)
+        {
+            if (info_provider != vprovider.get_string())
+            {
+                info_provider = vprovider.get_string();
+                changed = true;
+            }
+        }
+
+        var vregistration = status.lookup("registration");
+        if (vregistration != null)
+        {
+            if (info_registration != vregistration.get_string())
+            {
+                info_registration = vregistration.get_string();
+                changed = true;
+            }
+        }
+
+        if (changed)
+        {
+stderr.printf("NOTIFY CHANGED\n");
+            info_changed();
+        }
+    }
+
+    protected void acquire_new_signal_strength(int strength)
+    {
+        if (info_signal_strength != strength)
+        {
+            info_signal_strength = strength;
+stderr.printf("ACQUIRE SIG %d\n", info_signal_strength);
+            info_changed();
+        }
+    }
+
+    public GSM()
+    {
+        Object(name: "gsm");
+
+        calls = new List<CallInfo>();
+
+        device = (FSO_GSM_Device)zavai.registry.sbus.get_object(
+                "org.freesmartphone.ogsmd", 
+                "/org/freesmartphone/GSM/Device",
+                "org.freesmartphone.GSM.Device");
+        network = (FSO_GSM_Network)zavai.registry.sbus.get_object(
+            "org.freesmartphone.ogsmd", 
+            "/org/freesmartphone/GSM/Device",
+            "org.freesmartphone.GSM.Network");
+        sim = (FSO_GSM_SIM)zavai.registry.sbus.get_object(
+                "org.freesmartphone.ogsmd", 
+                "/org/freesmartphone/GSM/Device",
+                "org.freesmartphone.GSM.SIM");
+        call = (FSO_GSM_Call)zavai.registry.sbus.get_object(
+            "org.freesmartphone.ogsmd", 
+            "/org/freesmartphone/GSM/Device",
+            "org.freesmartphone.GSM.Call");
+        dbus = zavai.registry.sbus.get_object(
+                "org.freedesktop.DBus",
+                "/org/freedesktop/DBus",
+                "org.freedesktop.DBus");
+        dbus.NameOwnerChanged += on_name_owner_changed;
+
+        info_provider = "(unknown)";
+        info_signal_strength = -1;
+
+        network.status += (status) => {
+            stderr.printf("NETWORK STATUS\n");
+            dump_table(status);
+            acquire_new_status(status);
+        };
+
+        network.signal_strength += (strength) => {
+            stderr.printf("SIGNAL STRENGTH %d\n", strength);
+            acquire_new_signal_strength(strength);
+        };
+
+        call.call_status += on_call_status;
+    }
+
+    /// Request GPS resource
+    public override void start()
+    {
+        if (started) return;
+
+        status_changed("Starting");
+
+        script_start();
+
+        base.start();
+    }
+
+    protected void on_name_owner_changed(DBus.Object sender, string name, string oldOwner, string newOwner)
+    {
+        zavai.log.debug("NOC " + name + " from " + oldOwner + " to " + newOwner);
+        if (name == "org.freesmartphone.ogsmd" && newOwner != "")
+        {
+            status_changed("ogpsd came online");
+            start_gsm.begin();
+        }
+    }
+
+    // Release usage of GPS
+    public override void stop()
+    {
+        if (!started) return;
+
+        script_stop();
+
+        status_changed("");
+        info_provider = "";
+        info_signal_strength = -1;
+        info_changed();
+    }
+
+    protected override void cleanup_after_script_stop()
+    {
+        call = null;
+    }
+
+    public async void start_gsm()
+    {
+        status_changed("Turning on antenna");
+        while (true)
+        {
+            try {
+                yield device.set_antenna_power(true);
+                break;
+            } catch (Error e) {
+                zavai.log.warning("SetAntennaPower: " + e.message);
+                if (e.message.str("current status is 'enabling'") != null
+                 || e.message.str("current status is 'unknown'") != null)
+                {
+                    status_changed("Waiting for ogsmd to settle");
+                    zavai.log.info("trying again after 2 seconds");
+                    Timeout.add(2 * 1000, () => {
+                        start_gsm.callback();
+                        return false;
+                    });
+                    yield;
+                } else {
+                    status_changed("Checking if PIN is required");
+                    string status = yield sim.get_auth_status();
+                    zavai.log.info("on_auth_status: " + status);
+                    if (status == "READY")
+                        status_changed("PIN ok");
+                    else if (status == "SIM PIN")
+                    {
+                        status_changed("Sending PIN");
+                        yield sim.send_auth_code(zavai.config.sim_pin);
+                        status_changed("PIN OK");
+                    }
+                    else
+                        zavai.log.debug("Unknown status: " + status);
+                }
+            }
+        }
+        zavai.log.warning("on_antenna_power ok");
+        status_changed("Registering with network");
+        yield network.register_();
+        status_changed("Registered with network");
+
+        acquire_new_status(yield network.get_status());
+        acquire_new_signal_strength(yield network.get_signal_strength());
+    }
+
+    protected CallInfo? lookup_call(int gsm_id)
+    {
+        for (weak List<CallInfo> i = calls; i != null; i = i.next)
+            if (i.data.gsm_id == gsm_id)
+                return i.data;
+        return null;
+    }
+
+    public void on_call_status(int index, string status, HashTable<string, Value?> properties)
+    {
+        stderr.printf("CALL STATUS %d %s\n", index, status);
+        dump_table(properties);
+
+        CallInfo? info = lookup_call(index);
+        if (info == null)
+        {
+            Value? v = properties.lookup("peer");
+            string title;
+            if (v != null)
+                title = "%s call from %s".printf(status, v.get_string());
+            else
+                title = "%s call".printf(status);
+
+            info = new CallInfo();
+            info.gsm_id = index;
+            info.log = zavai.log.log.start("call", title);
+            calls.append(info);
+        }
+
+        // Log a summary of all info
+        string call_info = "status: %s\n".printf(status);
+        properties.for_each((pk, pv) => {
+            string k = (string)pk;
+            Value? v = (Value?)pv;
+            call_info = call_info + "%s: %s\n".printf(k, v == null ? "(null)" : v.strdup_contents());
+        });
+        info.log.add(call_info);
+
+        // Remove entry when it's the last possible status
+        if (status == "release")
+        {
+            zavai.log.log.end(info.log);
+            for (weak List<CallInfo> i = calls; i != null; i = i.next)
+                if (i.data.gsm_id == index)
+                {
+                    calls.delete_link(i);
+                    break;
+                }
+        }
+
+        /*
+        dbg("cbCallStatus %d, %s, %s" % (id, status, formatDict(properties)))
+        self.status = status
+        if status == "incoming":
+            if "peer" in properties and properties["peer"] == "+358942832031":
+                self.gsm_call_iface.ReleaseAll()
+                os.system("kapula-debug-call-handler &")
+            else:
+                os.system("alsactl restore -f /etc/alsa-scenarios/stereoout-maxvolume.state")
+                os.system("vibrator-start")
+                os.system("ringtone-start")
+                os.system("ledctrl --on-time 400 --off-time 200 gta02-aux:red");
+        if status == "release":
+            os.system("ringtone-stop")
+            os.system("vibrator-stop")
+            os.system("ledctrl --off gta02-aux:red");
+        */
+    }
+}
+
+public class GPRS: zavai.Service
+{
+    public dynamic DBus.Object device;
+
+    public GPRS()
+    {
+        Object(name: "gsm.gprs");
+
+        device = zavai.registry.sbus.get_object(
+            "org.freesmartphone.ogsmd", 
+            "/org/freesmartphone/GSM/Device",
+            "org.freesmartphone.GSM.PDP");
+    }
+
+    /// Request GPS resource
+    public override void start()
+    {
+        if (started) return;
+        try {
+            //gsm.request(name);
+            device.ActivateContext(
+                zavai.config.gprs_apn,
+                zavai.config.gprs_user,
+                zavai.config.gprs_pass);
+            zavai.log.info("Started GPRS");
+            base.start();
+        } catch (GLib.Error e) {
+            zavai.log.error(e.message);
+        }
+        base.start();
+    }
+
+    // Release usage of GPS
+    public override void stop()
+    {
+        if (!started) return;
+        try {
+            //gsm.release(name);
+            device.DeactivateContext();
+            zavai.log.info("Stopped GPRS");
+            base.stop();
+        } catch (GLib.Error e) {
+            zavai.log.error(e.message);
+        }
+        base.stop();
+    }
+}
+
+public zavai.gsm.GSM gsm = null;
+public zavai.gsm.GPRS gprs = null;
+
+public void init()
+{
+    gsm = new GSM();
+    gprs = new GPRS();
+}
+
+}
+}
diff --git a/src/input.vala b/src/input.vala
new file mode 100644 (file)
index 0000000..ffa0add
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * devinput - zavai /dev/input device handling
+ *
+ * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+namespace zavai {
+namespace input {
+
+public class DevInput : zavai.Service
+{
+    public string device { get; construct; }
+
+    public signal bool event(LinuxInput.Event* ev);
+
+    protected IOChannel fd = null;
+    protected uint fd_watch = 0;
+
+    public DevInput(string name, string device)
+    {
+        Object(name: "input.power_button", device: "/dev/input/event0");
+    }
+
+    protected void close_fd()
+    {
+        if (fd != null)
+        {
+            try {
+                fd.shutdown(false);
+            } catch (IOChannelError e) {
+                zavai.log.error("When closing " + device + ": " + e.message);
+            }
+
+            fd = null;
+        }
+    }
+
+    protected bool on_input_data(IOChannel source, IOCondition condition)
+    {
+        if (condition != IOCondition.IN) return true;
+
+        //stderr.printf("GOT INPUT ON %s %d\n", device, source.unix_get_fd());
+        char[] buf = new char[sizeof(LinuxInput.Event)];
+        size_t count_read;
+        try {
+            source.read_chars(buf, out count_read);
+        } catch (Error e) {
+            zavai.log.error("Reading from " + device + ": " + e.message);
+            return true;
+        }
+        //stderr.printf("READ %zu chars\n", count_read);
+
+        LinuxInput.Event* ie = (LinuxInput.Event*)buf;
+        //stderr.printf("INPUT EVENT time %lu.%lu type %hu code %hu val %d\n", (ulong)ie->time.tv_sec, ie->time.tv_usec, ie->type, ie->code, ie->val);
+
+        /*
+        ts1, ts2, type, code, value = struct.unpack("LLHHI", buf)
+        #print ts1, ts2, type, code, value
+        if type == 1 and code == 119:
+            if value:
+                #print "BUTTON RELEASE"
+                pass
+            else:
+                if self.last_button_press + 1 < ts1:
+                    self.last_button_press = ts1
+                    if self.button_press_handler is not None:
+                        self.button_press_handler()
+                    #print "BUTTON PRESS"
+        elif type == 5 and code == 2:
+            if value:
+                info("Headset plugged in")
+                self.mixer_for_headset(self)
+            else:
+                info("Headset plugged out")
+                self.mixer_for_handset(self)
+        */
+        return event(ie);
+    }
+
+    /// Start reading from the device
+    public override void start()
+    {
+        if (started) return;
+
+        if (fd != null)
+            close_fd();
+
+        // Open the device and listed to it using the GObject main loop
+        zavai.log.info("Opening device " + device);
+        fd = new IOChannel.file(device, "r");
+        try {
+            fd.set_encoding(null);
+        } catch (Error e) {
+            zavai.log.error("Setting encoding to null on " + device + ": " + e.message);
+        }
+        fd.set_buffered(false);
+        fd_watch = fd.add_watch(IOCondition.IN, on_input_data);
+
+        base.start();
+    }
+
+    // Stop reading from the device
+    public override void stop()
+    {
+        if (!started) return;
+
+        if (fd != null)
+        {
+            Source.remove(fd_watch);
+            close_fd();
+        }
+
+        base.stop();
+    }
+}
+
+public class HotKeys : zavai.Service
+{
+    protected List<int> grabbed;
+    public signal bool hotkey(uint keycode, ulong time, bool pressed);
+
+    public HotKeys()
+    {
+        Object(name: "input.hotkeys");
+
+        grabbed = new List<int>();
+    }
+
+    // Hotkey handlink takes inspiration from
+    // http://old.nabble.com/-PATCH--Initial-non-working-implementation-of-wxWindow::%28Un%29RegisterHotKey-on-wxGTK-td14557263.html
+    private static Gdk.FilterReturn on_hotkey(Gdk.XEvent* xevent, Gdk.Event? event, void* data)
+    {
+        // Global events don't get their data translated to gdk, as there is no
+        // GdkWindow to work with, therefore we need to use the xevent, because
+        // GdkEvent* is always GDK_NOTHING
+        X.Event* xev = (X.Event*)xevent;
+
+        switch (xev->type)
+        {
+            case X.EventType.KeyPress:
+                return zavai.input.hotkeys.my_on_hotkey(xev, true);
+            case X.EventType.KeyRelease:
+                return zavai.input.hotkeys.my_on_hotkey(xev, false);
+            default:
+                return Gdk.FilterReturn.CONTINUE;
+        }
+    }
+
+    //public Gdk.FilterReturn on_hotkey(Gdk.XEvent xevent, Gdk.Event? event)
+    private Gdk.FilterReturn my_on_hotkey(X.Event* xev, bool pressed)
+    {
+        // From http://tronche.com/gui/x/xlib/input/pointer-grabbing.html:
+        //
+        // A timestamp is a time value, expressed in milliseconds. It typically is the
+        // time since the last server reset. Timestamp values wrap around (after about
+        // 49.7 days). The server, given its current time is represented by timestamp
+        // T, always interprets timestamps from clients by treating half of the
+        // timestamp space as being later in time than T. One timestamp value, named
+        // CurrentTime, is never generated by the server. This value is reserved for
+        // use in requests to represent the current server time. 
+
+        if (grabbed.index((int)xev->xkey.keycode) == -1)
+            return Gdk.FilterReturn.CONTINUE;
+
+        if (hotkey(xev->xkey.keycode, xev->xkey.time, pressed))
+            return Gdk.FilterReturn.REMOVE;
+        return Gdk.FilterReturn.CONTINUE;
+    }
+
+    public void grab(int keycode, int modifiers, bool owner_events)
+    {
+        // We need to grab the keys we want to listen to
+        int res = Gdk.x11_get_default_xdisplay().grab_key(keycode, modifiers, Gdk.x11_get_default_root_xwindow(), owner_events, X.GrabMode.Async, X.GrabMode.Async);
+        if (res != 0)
+            stderr.printf("Grab result: %d\n", res); // We get BadRequest and don't know why
+        grabbed.append(keycode);
+    }
+
+    /// Start reading from the device
+    public override void start()
+    {
+        if (started) return;
+
+        //gdk_window_add_filter (NULL, _wxgtk_global_hotkey_callback, this);
+        ((Gdk.Window*)null)->add_filter((Gdk.FilterFunc)on_hotkey);
+
+        grab(160, 0, false);
+
+        base.start();
+    }
+
+    // Stop reading from the device
+    public override void stop()
+    {
+        if (!started) return;
+
+        //gdk_window_remove_filter(NULL, _wxgtk_global_hotkey_callback, this); 
+        ((Gdk.Window*)null)->remove_filter((Gdk.FilterFunc)on_hotkey);
+
+        base.stop();
+    }
+}
+
+public class PowerButton : zavai.Service
+{
+    protected DevInput devinput;
+
+    public signal void power_button(Posix.timeval* time, bool pressed);
+
+    public PowerButton()
+    {
+        // FIXME: change to event0 for the power button
+        // FIXME: change to event4 for the aux button and headset button
+        string inputdev = "/dev/input/event0";
+        if (Posix.access(inputdev, Posix.R_OK) == 0)
+        {
+            zavai.log.info("Handle power button via " + inputdev);
+            // Listen via input device
+            devinput = new DevInput("input.power_button", "/dev/input/event0");
+            devinput.event += on_event;
+            devinput.request("powerbutton");
+        } else {
+            zavai.log.info("Handle power button via XGrabKey on keycode " + zavai.config.power_button_keycode.to_string());
+            // Listen via X
+            hotkeys.hotkey += on_hotkey;
+            hotkeys.grab(zavai.config.power_button_keycode, 0, false);
+            hotkeys.request("powerbutton");
+        }
+    }
+
+    protected bool on_event(LinuxInput.Event* ev)
+    {
+        if (ev->type == LinuxInput.Type.KEY && 
+            ev->code == LinuxInput.Key.POWER)
+        {
+            power_button(&(ev->time), ev->val == 0 ? false : true);
+        }
+        return true;
+    }
+
+    protected bool on_hotkey(uint keycode, ulong time, bool pressed)
+    {
+        if (keycode == zavai.config.power_button_keycode)
+        {
+            // Convert X time to a fake timeval
+            // TODO: handle wraparound
+            Posix.timeval tv = {
+                (time_t)(time / 1000),
+                (long)((time % 1000) * 1000)
+            };
+            power_button(&tv, pressed);
+            return true;
+        }
+        return false;
+    }
+}
+
+
+/*
+# TODO:
+#  - hook into the headset plugged/unplugged event
+#  - if unplugged, turn on handset microphone
+#  - if plugged, redo headest mixer settings
+class Audio:
+    "Handle mixer settings, audio recording and headset button presses"
+    def __init__(self, button_press_handler = None):
+        self.saved_scenario = os.path.expanduser("~/.audiomap.state")
+
+        # Setup the mixer
+        # Set mixer to record from headset and handle headset button
+        self.save_scenario(self.saved_scenario)
+        self.load_scenario("/usr/share/openmoko/scenarios/voip-handset.state")
+
+        # This is a work-around because I have not found a way to query for the
+        # current headset state, I can only know when it changes. So in my
+        # system I configured oeventsd with a rule to touch this file when the
+        # headset is plugged in, and remove the file when it's plugged out.
+        if os.path.exists("/tmp/has_headset"):
+            self.mixer_for_headset(True)
+        else:
+            self.mixer_for_handset(True)
+
+        #self.mixer_set("DAPM Handset Mic", "mute")
+        #self.mixer_set("DAPM Headset Mic", "unmute")
+        #self.mixer_set("Left Mixer Sidetone Playback Sw", "unmute")
+        #self.mixer_set("ALC Mixer Mic1", "cap")
+        #self.mixer_set("Amp Spk", "mute") # We don't need the phone playing what we say
+
+        # Watch the headset button
+        self.button_press_handler = button_press_handler
+        self.input_fd = open("/dev/input/event4", "rb")
+        self.input_watch = gobject.io_add_watch(self.input_fd.fileno(), gobject.IO_IN, self.on_input_data)
+
+        self.last_button_press = 0
+        self.recorder = None
+        self.basename = None
+
+    def mixer_for_headset(self, force=False):
+        if not force and self.has_headset: return
+        info("Setting mixer for headset")
+        # TODO: find out how to disable the handset microphone: this does not
+        # seem to be sufficient
+        self.mixer_set_many(
+                ("DAPM Handset Mic", "mute"),
+                ("DAPM Headset Mic", "unmute"),
+                ("Left Mixer Sidetone Playback Sw", "unmute"),
+                ("ALC Mixer Mic1", "cap"),
+                ("Amp Spk", "mute") # We don't need the phone playing what we say
+        )
+        self.has_headset = True
+
+    def mixer_for_handset(self, force=False):
+        if not force and not self.has_headset: return
+        info("Setting mixer for handset")
+        self.mixer_set_many(
+                ("DAPM Handset Mic", "unmute"),
+                ("DAPM Headset Mic", "mute"),
+                ("Left Mixer Sidetone Playback Sw", "mute"),
+                ("ALC Mixer Mic1", "cap"),
+                ("Amp Spk", "mute") # We don't need the phone playing what we say
+        )
+        self.has_headset = False
+
+    def set_basename(self, basename):
+        self.basename = basename
+
+    def start_recording(self):
+        if self.basename is None:
+            raise RuntimeError("Recording requested but basename not set")
+        self.recorder = subprocess.Popen(
+            ["arecord", "-D", "hw", "-f", "cd", "-r", "8000", "-t", "wav", self.basename + ".wav"])
+
+    def start_levels(self):
+        self.recorder = subprocess.Popen(
+            ["arecord", "-D", "hw", "-f", "cd", "-r", "8000", "-t", "wav", "-V", "stereo", "/dev/null"])
+
+    def close(self):
+        if self.recorder is not None:
+            os.kill(self.recorder.pid, signal.SIGINT)
+            self.recorder.wait()
+
+        # Restore mixer settings
+        self.load_scenario(self.saved_scenario)
+
+        gobject.source_remove(self.input_watch)
+        self.input_fd.close()
+
+    def on_input_data(self, source, condition):
+        buf = self.input_fd.read(16)
+        ts1, ts2, type, code, value = struct.unpack("LLHHI", buf)
+        #print ts1, ts2, type, code, value
+        if type == 1 and code == 119:
+            if value:
+                #print "BUTTON RELEASE"
+                pass
+            else:
+                if self.last_button_press + 1 < ts1:
+                    self.last_button_press = ts1
+                    if self.button_press_handler is not None:
+                        self.button_press_handler()
+                    #print "BUTTON PRESS"
+        elif type == 5 and code == 2:
+            if value:
+                info("Headset plugged in")
+                self.mixer_for_headset(self)
+            else:
+                info("Headset plugged out")
+                self.mixer_for_handset(self)
+        return True
+
+    def save_scenario(self, name):
+        res = subprocess.call(["alsactl", "store", "-f", name])
+        if res != 0:
+            raise RuntimeError("Saving audio scenario to '%s' failed" % name)
+
+    def load_scenario(self, name):
+        res = subprocess.call(["alsactl", "restore", "-f", name])
+        if res != 0:
+            raise RuntimeError("Loading audio scenario '%s' failed" % name)
+
+    def mixer_set(self, name, *args):
+        args = map(str, args)
+        res = subprocess.call(["amixer", "-q", "set", name] + args)
+        if res != 0:
+            raise RuntimeError("Setting mixer '%s' to %s failed" % (name, " ".join(args)))
+
+    # Will do this when we find out the syntax for giving amixer commands on stdin
+    def mixer_set_many(self, *args):
+        """Perform many mixer set operations via amixer --stdin"""
+        proc = subprocess.Popen(["amixer", "-q", "--stdin"], stdin=subprocess.PIPE)
+        cmd_input = []
+        for k, v in args:
+            cmd_input.append("sset " + repr(k) + " " + repr(v))
+        (out, err) = proc.communicate(input="\n".join(cmd_input))
+        res = proc.wait()
+        if res != 0:
+            raise RuntimeError("Setting mixer failed")
+*/
+
+
+public HotKeys hotkeys = null;
+public PowerButton power_button = null;
+
+public void init()
+{
+    hotkeys = new HotKeys();
+    power_button = new PowerButton();
+}
+
+}
+}
diff --git a/src/libgps.vapi b/src/libgps.vapi
new file mode 100644 (file)
index 0000000..da29fcd
--- /dev/null
@@ -0,0 +1,238 @@
+[CCode (lower_case_cprefix="", cprefix="", cheader_filename="gps.h")]
+namespace libgps
+{
+    public const int MAXCHANNELS;
+
+    [SimpleType]
+    [IntegerType (rank = 9)]
+    public struct mask_t {}
+
+    [CCode (cname = "struct gps_fix_t")]
+    public struct fix_t
+    {
+        double time;   /* Time of update, seconds since Unix epoch */
+        int    mode;   /* Mode of fix */
+        double ept;            /* Expected time uncertainty */
+        double latitude;       /* Latitude in degrees (valid if mode >= 2) */
+        double epy;    /* Latitude position uncertainty, meters */
+        double longitude;      /* Longitude in degrees (valid if mode >= 2) */
+        double epx;    /* Longitude position uncertainty, meters */
+        double altitude;       /* Altitude in meters (valid if mode == 3) */
+        double epv;    /* Vertical position uncertainty, meters */
+        double track;  /* Course made good (relative to true north) */
+        double epd;            /* Track uncertainty, degrees */
+        double speed;  /* Speed over ground, meters/sec */
+        double eps;            /* Speed uncertainty, meters/sec */
+        double climb;   /* Vertical speed, meters/sec */
+        double epc;            /* Vertical speed uncertainty */
+    }
+    public const int MODE_NOT_SEEN; /* mode update not seen yet */
+    public const int MODE_NO_FIX;   /* none */
+    public const int MODE_2D;       /* good for latitude/longitude */
+    public const int MODE_3D;       /* good for altitude/climb too */
+
+    [CCode (cname = "struct dop_t")]
+    public struct dop_t
+    {
+        /* Dilution of precision factors */
+        double xdop;
+        double ydop;
+        double pdop;
+        double hdop;
+        double vdop;
+        double tdop;
+        double gdop;
+    }
+
+    [CCode (cname = "struct gps_data_t", destroy_function = "")]
+    public struct data_t
+    {
+        mask_t set;
+        double online;
+        int gps_fd;
+        fix_t fix;
+        double separation;
+        int status;
+        int satellites_used;        /* Number of satellites used in solution */
+        int[] used;      /* PRNs of satellites used in solution */
+        dop_t dop;
+        /* redundant with the estimate elements in the fix structure */
+        double epe;  /* spherical position error, 95% confidence (meters)  */
+
+        /* satellite status -- valid when satellites_visible > 0 */
+        double skyview_time;        /* skyview timestamp */
+        int satellites_visible;     /* # of satellites in view */
+        int[] PRN;       /* PRNs of satellite */
+        int[] elevation; /* elevation of satellite */
+        int[] azimuth;   /* azimuth */
+        double[] ss;     /* signal-to-noise ratio (dB) */
+
+        //struct devconfig_t dev;     /* device that shipped last update */
+
+        //struct policy_t policy;     /* our listening policy */
+
+        //char tag[MAXTAGLEN+1];      /* tag of last sentence processed */
+    }
+    public const int ONLINE_SET;
+    public const int TIME_SET;
+    public const int TIMERR_SET;
+    public const int LATLON_SET;
+    public const int ALTITUDE_SET;
+    public const int SPEED_SET;
+    public const int TRACK_SET;
+    public const int CLIMB_SET;
+    public const int STATUS_SET;
+    public const int MODE_SET;
+    public const int DOP_SET;
+    public const int VERSION_SET; /* only used in client library */
+    public const int HERR_SET;
+    public const int VERR_SET;
+    public const int PERR_SET;
+    public const int POLICY_SET; /* only used in client library */
+    public const int ERR_SET;
+    public const int SATELLITE_SET;
+    public const int RAW_SET;
+    public const int USED_SET;
+    public const int SPEEDERR_SET;
+    public const int TRACKERR_SET;
+    public const int CLIMBERR_SET;
+    public const int DEVICE_SET;
+    public const int DEVICELIST_SET;
+    public const int DEVICEID_SET;
+    public const int ERROR_SET;
+    public const int RTCM2_SET;
+    public const int RTCM3_SET;
+    public const int AIS_SET;
+    public const int PACKET_SET;
+    public const int CLEAR_SET; /* sentence starts a reporting cycle */
+    public const int REPORT_SET; /* sentence ends a reporting cycle */
+    public const int DATA_SET;
+
+    public const int STATUS_NO_FIX;   /* no */
+    public const int STATUS_FIX;      /* yes, without DGPS */
+    public const int STATUS_DGPS_FIX; /* yes, with DGPS */
+
+    [CCode (cname = "gps_open_r")]
+    public int open_r(string server, string port, ref data_t gpsdata);
+
+    [CCode (cname = "gps_close")]
+    public int close(ref data_t gpsdata);
+
+    [CCode (cname = "gps_errstr")]
+    public weak string errstr(int err);
+
+    [CCode (cname = "gps_poll")]
+    public int poll(ref data_t gpsdata);
+
+    [CCode (cname = "gps_waiting")]
+    public bool waiting(ref data_t gpsdata);
+
+    [CCode (cname = "gps_send")]
+    public int send(ref data_t gpsdata, string fmt, ...);
+
+    [CCode (cname = "gps_stream")]
+    public int stream(ref data_t gpsdata, uint flags, void* data);
+
+    /* mode flags for gps_stream() */
+    public int WATCH_DISABLE;  /* disable watching */
+    public int WATCH_ENABLE;   /* enable streaming */
+    public int WATCH_JSON;     /* enable JSON output */
+    public int WATCH_NMEA;     /* enable output in NMEA */
+    public int WATCH_RARE;     /* enable output of packets in hex */
+    public int WATCH_RAW;      /* enable output of raw packets */
+    public int WATCH_SCALED;   /* scale output to floats, when applicable */ 
+    public int WATCH_NEWSTYLE; /* force JSON streaming */
+    public int WATCH_OLDSTYLE; /* force old-style streaming */
+    public int WATCH_DEVICE;   /* watch specific device */
+    public int POLL_NONBLOCK;  /* set non-blocking poll */
+
+    /*
+       [CCode (cname = "struct input_event")]
+       public struct Event
+       {
+               public Posix.timeval time;
+               public uint16 type;
+               public uint16 code;
+               [CCode (cname="value")]
+               public int32 val;
+       }
+
+       [CCode (cprefix="KEY_")]
+       public enum Key
+       {
+               POWER
+       }
+
+       [CCode (cprefix="EV_")]
+       public enum Type
+       {
+               SYN,
+               KEY,
+               REL,
+               ABS,
+               MSC,
+               SW,
+               LED,
+               SND,
+               REP,
+               FF,
+               PWR,
+               FF_STATUS
+       }
+}
+[CCode (cprefix="", cheader_filename="omhacks/all.h")]
+namespace Omhacks
+{
+    [CCode (cname = "struct om_led", cheader_filename = "omhacks/led.h", destroy_function = "")]
+    public struct Led
+    {
+        public char name[255];
+        public string dir;
+        public int dir_len;
+        public int brightness;
+        public char trigger[255];
+        public int delay_on;
+        public int delay_off;
+
+        [CCode (cname = "om_led_init")]
+        public int init(string name);
+        [CCode (cname = "om_led_get")]
+        public int get();
+        [CCode (cname = "om_led_set")]
+        public int set();
+    }
+
+    namespace Screen
+    {
+        namespace Brightness
+        {
+            [CCode (cname = "om_screen_brightness_get")]
+            public int get();
+            [CCode (cname = "om_screen_brightness_get_max")]
+            public int get_max();
+            [CCode (cname = "om_screen_brightness_set")]
+            public int set(int val);
+        }
+    }
+
+    namespace UEvent
+    {
+        [CCode (cname = "struct om_uevent", cheader_filename = "omhacks/uevent.h", destroy_function = "")]
+        public struct Event
+        {
+            public string buffer;
+            size_t buflen;
+            weak string action;
+            weak string devpath;
+            weak string[] envp;
+        }
+
+        [CCode (cname = "om_uevent_open")]
+        public int open();
+        [CCode (cname = "om_uevent_read")]
+        public int read(int sock, ref Event ou);
+        [CCode (cname = "om_uevent_parse")]
+        public int parse(ref Event ou);
+    }
+    */
+}
diff --git a/src/libomhacks.vapi b/src/libomhacks.vapi
new file mode 100644 (file)
index 0000000..83434f3
--- /dev/null
@@ -0,0 +1,55 @@
+[CCode (cprefix="", cheader_filename="omhacks/all.h")]
+namespace Omhacks
+{
+    [CCode (cname = "struct om_led", cheader_filename = "omhacks/led.h", destroy_function = "")]
+    public struct Led
+    {
+        public char name[255];
+        public string dir;
+        public int dir_len;
+        public int brightness;
+        public char trigger[255];
+        public int delay_on;
+        public int delay_off;
+
+        [CCode (cname = "om_led_init")]
+        public int init(string name);
+        [CCode (cname = "om_led_get")]
+        public int get();
+        [CCode (cname = "om_led_set")]
+        public int set();
+    }
+
+    namespace Screen
+    {
+        namespace Brightness
+        {
+            [CCode (cname = "om_screen_brightness_get")]
+            public int get();
+            [CCode (cname = "om_screen_brightness_get_max")]
+            public int get_max();
+            [CCode (cname = "om_screen_brightness_set")]
+            public int set(int val);
+        }
+    }
+
+    namespace UEvent
+    {
+        [CCode (cname = "struct om_uevent", cheader_filename = "omhacks/uevent.h", destroy_function = "")]
+        public struct Event
+        {
+            public string buffer;
+            size_t buflen;
+            weak string action;
+            weak string devpath;
+            weak string[] envp;
+        }
+
+        [CCode (cname = "om_uevent_open")]
+        public int open();
+        [CCode (cname = "om_uevent_read")]
+        public int read(int sock, ref Event ou);
+        [CCode (cname = "om_uevent_parse")]
+        public int parse(ref Event ou);
+    }
+}
diff --git a/src/linux-input.vapi b/src/linux-input.vapi
new file mode 100644 (file)
index 0000000..211eab5
--- /dev/null
@@ -0,0 +1,42 @@
+[CCode (lower_case_cprefix="", cprefix="", cheader_filename="linux/input.h")]
+namespace LinuxInput
+{
+       [CCode (cname = "struct input_event")]
+       public struct Event
+       {
+               public Posix.timeval time;
+               public uint16 type;
+               public uint16 code;
+               [CCode (cname="value")]
+               public int32 val;
+       }
+
+       [CCode (cprefix="KEY_")]
+       public enum Key
+       {
+               POWER
+       }
+
+       [CCode (cprefix="EV_")]
+       public enum Type
+       {
+               SYN,
+               KEY,
+               REL,
+               ABS,
+               MSC,
+               SW,
+               LED,
+               SND,
+               REP,
+               FF,
+               PWR,
+               FF_STATUS
+       }
+
+    [CCode (cprefix="EVIO")]
+    public enum Evio
+    {
+        CGRAB
+    }
+}
diff --git a/src/log.vala b/src/log.vala
new file mode 100644 (file)
index 0000000..cd89471
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * log - logging functions
+ *
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace log {
+
+public class Waypoint : Object
+{
+    public time_t ts;
+    public double lat;
+    public double lon;
+
+    public Waypoint()
+    {
+        if (gps.gps.fix_status() != libgps.STATUS_NO_FIX)
+        {
+            lat = gps.gps.info().fix.latitude;
+            lon = gps.gps.info().fix.longitude;
+            ts = (time_t)gps.gps.info().fix.time;
+        } else {
+            // Use 1000 as missing values
+            lat = 1000;
+            lon = 1000;
+            ts = time_t();
+        }
+    }
+
+    public void writeInside(FileStream outfd)
+    {
+        var t = Time.gm(ts);
+        outfd.printf("   <time>%s</time>\n", t.format("%Y-%m-%dT%H:%M:%S%z"));
+    }
+}
+
+
+public class LogEntry : Waypoint
+{
+    public string msg;
+
+    public LogEntry()
+    {
+        base();
+    }
+
+    public void write(FileStream outfd)
+    {
+        outfd.printf("   <wpt lat=\"%f\" lon=\"%f\">\n", lat, lon);
+        writeInside(outfd);
+        outfd.printf("   <name>%s</name>\n", Markup.escape_text(msg));
+        outfd.puts("   </wpt>\n");
+    }
+}
+
+public class TrackEntry : Waypoint
+{
+    public TrackEntry()
+    {
+        base();
+    }
+
+    public void write(FileStream outfd)
+    {
+        outfd.printf("   <trkpt lat=\"%f\" lon=\"%f\">\n", lat, lon);
+        writeInside(outfd);
+        outfd.puts("   </trkpt>\n");
+    }
+}
+
+
+public class Log : Object
+{
+    public string tag;
+    public string title;
+    public bool acked;
+    public List<LogEntry> entries;
+    public List<TrackEntry> track;
+
+    public Log(string tag, string title, bool acked=false)
+    {
+        this.tag = tag;
+        this.title = title;
+        this.acked = acked;
+        entries = null;
+        track = null;
+    }
+
+    public void add(string msg)
+    {
+        var entry = new LogEntry();
+        entry.msg = msg;
+        entries.append(entry);
+    }
+
+    public void add_trackpoint()
+    {
+        track.append(new TrackEntry());
+    }
+
+    public void save()
+    {
+        if (entries == null) return;
+
+        // Directory where we save the log
+        string dir;
+        if (acked)
+            dir = config.homedir + "/archive";
+        else
+            dir = config.homedir + "/log";
+        DirUtils.create(dir, 0777);
+
+        // First try with a plain name
+        var t = Time.local(entries.data.ts);
+        string basename = dir + "/" + t.format("%Y%m%d-%H%M%S") + "-" + tag;
+
+        string pathname = basename + ".gpx";
+
+        // Find a pathname that does not exist already
+        for (int i = 1; FileUtils.test(pathname, FileTest.EXISTS); ++i)
+            pathname = "%s-%d.gpx".printf(basename, i);
+
+        // Write out
+        var outfd = FileStream.open(pathname, "w");
+        if (outfd == null)
+        {
+            zavai.log.error("opening " + pathname + ": " + strerror(errno));
+            return;
+        }
+
+        write(outfd);
+        outfd.flush();
+    }
+
+    public void dump()
+    {
+        write(stderr);
+    }
+
+    protected void writeTrack(FileStream outfd)
+    {
+        outfd.puts("   <trk>\n");
+        outfd.puts("     <trkseg>\n");
+        for (weak List<TrackEntry> i = track; i != null; i = i.next)
+            i.data.write(outfd);
+        outfd.puts("     </trkseg>\n");
+        outfd.puts("   </trk>\n");
+    }
+
+    protected void writeEntries(FileStream outfd)
+    {
+        for (weak List<LogEntry> i = entries; i != null; i = i.next)
+            i.data.write(outfd);
+    }
+
+    protected void write(FileStream outfd)
+    {
+        outfd.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+        outfd.puts("<gpx version=\"1.0\"\n");
+        outfd.printf("     creator=\"zavai %s\"\n", zavai.config.version);
+        outfd.puts("     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+        outfd.puts("     xmlns=\"http://www.topografix.com/GPX/1/0\"\n");
+        outfd.puts("     xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n");
+        outfd.puts("  <metadata>\n");
+        outfd.printf("    <name>%s</name>\n", Markup.escape_text(title));
+        outfd.printf("    <keywords>%s</keywords>\n", Markup.escape_text(tag));
+        outfd.puts("  </metadata>\n");
+        if (track != null) writeTrack(outfd);
+        if (entries != null) writeEntries(outfd);
+        outfd.puts(" </gpx>\n");
+    }
+}
+
+enum LogParserState {
+    NONE,
+    METADATA,
+    TRACK,
+    WPT,
+}
+
+class LogParser: Object
+{
+    const MarkupParser parser = { // It's a structure, not an object
+        start,// when an element opens
+        end,  // when an element closes
+        text, // when text is found
+        null, // when comments are found
+        null  // when errors occur
+    };
+
+    MarkupParseContext context = null;
+    public Log result = null;
+    LogParserState state = LogParserState.NONE;
+    string cur_text = "";
+    LogEntry cur_logentry = null;
+    TrackEntry cur_trackentry = null;
+
+    construct
+    {
+        context = new MarkupParseContext(
+            parser, // the structure with the callbacks
+            0,      // MarkupParseFlags
+            this,   // extra argument for the callbacks, methods in this case
+            destroy // when the parsing ends
+        );
+    }
+
+    void destroy()
+    {
+        cur_text = "";
+        cur_logentry = null;
+        cur_trackentry = null;
+    }
+
+    public bool parse(string content, ssize_t len = -1) throws MarkupError
+    {
+        string oldtz = Environment.get_variable("TZ");
+        Environment.set_variable("TZ", "UTC", true);
+        bool res = context.parse(content, len);
+        if (oldtz == null)
+            Environment.unset_variable("TZ");
+        else
+            Environment.set_variable("TZ", oldtz, true);
+        return res;
+    }
+
+    void parse_attrs(Waypoint w, string[] attr_names, string[] attr_values)
+    {
+        w.lat = 1000;
+        w.lon = 1000;
+        for (int i = 0; attr_names[i] != null; ++i)
+        {
+            if (attr_names[i] == "lat")
+                w.lat = attr_values[i].to_double();
+            else if (attr_names[i] == "lon")
+                w.lon = attr_values[i].to_double();
+        }
+    }
+
+    void start (MarkupParseContext context, string name,
+                string[] attr_names, string[] attr_values) throws MarkupError
+    {
+        if (name == "gpx")
+        {
+            state = LogParserState.NONE;
+            result = new Log("TODO:TAG", "TODO:TITLE");
+        } else if (name == "metadata") {
+            state = LogParserState.METADATA;
+        } else if (name == "wpt") {
+            cur_logentry = new LogEntry();
+            parse_attrs(cur_logentry, attr_names, attr_values);
+            result.entries.append(cur_logentry);
+            state = LogParserState.WPT;
+        } else if (name == "trkpt") {
+            cur_trackentry = new TrackEntry();
+            parse_attrs(cur_trackentry, attr_names, attr_values);
+            result.track.append(cur_trackentry);
+            state = LogParserState.TRACK;
+        }
+        cur_text = "";
+    }
+
+    void end (MarkupParseContext context, string name) throws MarkupError
+    {
+        if (name == "name")
+        {
+            switch (state)
+            {
+                case LogParserState.METADATA:
+                    result.title = cur_text;
+                    break;
+                case LogParserState.WPT:
+                    cur_logentry.msg = cur_text;
+                    break;
+            }
+        }
+        else if (name == "keywords")
+        {
+            result.tag = cur_text;
+        }
+        else if (name == "time")
+        {
+            Time t = Time();
+            t.strptime(cur_text, "%Y-%m-%dT%H:%M:%S%z");
+            if (state == LogParserState.WPT)
+                cur_logentry.ts = t.mktime();
+            else if (state == LogParserState.TRACK)
+                cur_trackentry.ts = t.mktime();
+        }
+    }
+
+    void text (MarkupParseContext context,
+               string text, size_t text_len) throws MarkupError
+    {
+        cur_text += text;
+    }
+}
+
+public class Logger : Resource, Object
+{
+    protected List<Log> logs;
+
+    public signal void entries_changed();
+
+    public Logger()
+    {
+        logs = null;
+        zavai.registry.register(this);
+    }
+
+    protected void start_trace()
+    {
+        gps.gps.pos_changed += on_pos_changed;
+    }
+
+    protected void end_trace()
+    {
+        gps.gps.pos_changed -= on_pos_changed;
+    }
+
+    protected void on_pos_changed()
+    {
+        for (weak List<Log> i = logs; i != null; i = i.next)
+            i.data.add_trackpoint();
+    }
+
+    protected void pop(Log log)
+    {
+        for (weak List<Log> i = logs; i != null; i = i.next)
+            if (i.data == log)
+                logs.delete_link(i);
+    }
+
+    public Log start(string tag, string title)
+    {
+        bool was_empty = (logs == null);
+        Log res = new Log(tag, title);
+        logs.append(res);
+        if (was_empty) start_trace();
+        return res;
+    }
+
+    public void end(Log log)
+    {
+        pop(log);
+        log.save();
+        if (logs == null) end_trace();
+        entries_changed();
+    }
+
+    public Log load(string fname)
+    {
+        string contents;
+        size_t length;
+        FileUtils.get_contents(fname, out contents, out length);
+        LogParser parser = new LogParser();
+        parser.parse(contents, (ssize_t)length);
+        return parser.result;
+    }
+
+    public void set_acknowledged(string name, bool acked)
+    {
+        string from, to;
+        if (acked)
+        {
+            from = config.homedir + "/log/" + name;
+            to = config.homedir + "/archive/" + name;
+            DirUtils.create(config.homedir + "/archive", 0777);
+        } else {
+            from = config.homedir + "/archive/" + name;
+            to = config.homedir + "/log/" + name;
+            DirUtils.create(config.homedir + "/log", 0777);
+        }
+        if (FileUtils.test(from, FileTest.EXISTS))
+        {
+            FileUtils.rename(from, to);
+            entries_changed();
+        }
+    }
+
+    public delegate bool EntriesVisitor(string dir, string name);
+
+    protected void list_dir(string dir, EntriesVisitor visitor)
+    {
+        var d = File.new_for_path(dir);
+        var enumerator = d.enumerate_children(FILE_ATTRIBUTE_STANDARD_NAME, 0, null);
+        FileInfo file_info;
+        while ((file_info = enumerator.next_file(null)) != null)
+        {
+            if (!file_info.get_name().has_suffix(".gpx")) continue;
+            if (!visitor(dir, file_info.get_name()))
+                break;
+        }
+    }
+
+    public void list_entries(EntriesVisitor visitor, bool only_unacked=true)
+    {
+        if (!only_unacked)
+            list_dir(config.homedir + "/archive", visitor);
+        list_dir(config.homedir + "/log", visitor);
+    }
+
+    public void instant(string tag, string msg)
+    {
+        var log = new Log(tag, msg);
+        log.add(msg);
+        log.save();
+    }
+
+    public void shutdown()
+    {
+        bool had_logs = (logs != null);
+        while (logs != null)
+        {
+            logs.data.save();
+            logs.delete_link(logs);
+        }
+        if (had_logs) end_trace();
+    }
+}
+
+public void error(string s)
+{
+       stderr.printf("%s\n", s);
+}
+public void warning(string s)
+{
+       stderr.printf("%s\n", s);
+}
+public void info(string s)
+{
+       stderr.printf("%s\n", s);
+}
+public void debug(string s)
+{
+       stderr.printf("%s\n", s);
+}
+
+Logger log = null;
+
+public void init()
+{
+    log = new Logger();
+}
+
+}
+}
diff --git a/src/lua5.1.vapi b/src/lua5.1.vapi
new file mode 120000 (symlink)
index 0000000..e730dfc
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/vala/vapi/lua.vapi
\ No newline at end of file
diff --git a/src/power.vala b/src/power.vala
new file mode 100644 (file)
index 0000000..5571117
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * power - zavai power event handling
+ *
+ * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace power {
+
+public class Power : Service
+{
+    public enum State
+    {
+        UNKNOWN,
+        CHARGING,
+        DISCHARGING,
+        FULLY_CHARGED,
+    }
+
+    protected string battery_device;
+    protected uint timeout;
+    public signal void changed();
+    public State state;
+    public int percentage;
+
+    public Power()
+    {
+        battery_device = "/sys/class/power_supply/battery/";
+        if (Posix.access(battery_device, Posix.R_OK) != 0)
+            battery_device = null;
+        timeout = 0;
+        state = State.UNKNOWN;
+        percentage = 0;
+    }
+
+    /// Activate the service
+    protected override void start()
+    {
+        if (started) return;
+
+        uint poll_time;
+        if (uevent.uevent != null)
+        {
+            zavai.log.info("We have uevent: poll rarely");
+            uevent.uevent.event += on_uevent;
+            uevent.uevent.request("zavai.power");
+            // If we can get plug/unplug notifications, it's ok to just poll
+            // every 5 minutes
+            poll_time = 300 * 1000;
+        } else {
+            if (battery_device == null)
+            {
+                zavai.log.warning("No battery device found that I know how to read: try building with devkit-power");
+                poll_time = 0;
+            } else {
+                zavai.log.info("Polling battery device only");
+                // Else poll every 30 seconds to be somehow reactive to plug/unplug
+                // events
+                poll_time = 30 * 1000;
+            }
+        }
+
+        poll();
+
+        // Poll battery every minute
+        if (poll_time != 0)
+            timeout = Timeout.add(poll_time, on_timeout);
+
+        base.start();
+    }
+
+    /// Deactivate the service
+    protected override void stop()
+    {
+        if (!started) return;
+
+        // Stop polling
+        if (timeout != 0)
+            Source.remove(timeout);
+
+        if (uevent.uevent != null)
+        {
+            uevent.uevent.release("zavai.power");
+            uevent.uevent.event -= on_uevent;
+        }
+
+        base.stop();
+    }
+
+    protected void poll()
+    {
+        if (battery_device == null)
+            return;
+
+        char buf[200];
+        State new_state = State.UNKNOWN;
+        int new_percentage = 0;
+
+        FileStream state_fd = FileStream.open(battery_device + "/status", "r");
+        string val = state_fd.gets(buf);
+        if (val == "Charging")
+            new_state = State.CHARGING;
+        else if (val == "Discharging")
+            new_state = State.DISCHARGING;
+        else if (val == "Not charging")
+            new_state = State.FULLY_CHARGED;
+
+        FileStream cap_fd = FileStream.open(battery_device + "/capacity", "r");
+        val = cap_fd.gets(buf);
+        new_percentage = val.to_int();
+
+        if (new_state != state || new_percentage != percentage)
+        {
+            state = new_state;
+            percentage = new_percentage;
+            changed();
+        }
+    }
+
+    protected bool on_timeout()
+    {
+        poll();
+        return true;
+    }
+
+    protected void on_uevent()
+    {
+        /* if (uevent.uevent.event_data.buffer.has_prefix("change@/class/power_supply/ac"))
+        {
+            changed();
+        }
+        else */
+        if (uevent.uevent.event_data.buffer.has_prefix("change@/class/power_supply/battery"))
+        {
+            State new_state = State.UNKNOWN;
+            int new_percentage = 0;
+
+            Omhacks.UEvent.parse(ref uevent.uevent.event_data);
+            for (int i = 0; uevent.uevent.event_data.envp[i] != null; ++i)
+            {
+                if (uevent.uevent.event_data.envp[i].has_prefix("POWER_SUPPLY_STATUS="))
+                {
+                    var val = uevent.uevent.event_data.envp[i].offset(20);
+                    if (val == "Charging")
+                        new_state = State.CHARGING;
+                    else if (val == "Discharging")
+                        new_state = State.DISCHARGING;
+                    else if (val == "Not charging")
+                        new_state = State.FULLY_CHARGED;
+                    else
+                        zavai.log.warning("Unknown state: " + uevent.uevent.event_data.envp[i]);
+                }
+                else if (uevent.uevent.event_data.envp[i].has_prefix("POWER_SUPPLY_CAPACITY="))
+                {
+                    new_percentage = uevent.uevent.event_data.envp[i].offset(22).to_int();
+                }
+            }
+            if (new_state != state || new_percentage != percentage)
+            {
+                state = new_state;
+                percentage = new_percentage;
+                changed();
+            }
+        }
+    }
+}
+
+public Power power;
+
+public void init()
+{
+    power = new Power();
+}
+
+}
+}
diff --git a/src/registry.vala b/src/registry.vala
new file mode 100644 (file)
index 0000000..3d549da
--- /dev/null
@@ -0,0 +1,83 @@
+/* 
+ * registry - zavai resource registry
+ *
+ * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+
+public class Registry : Object, Resource
+{
+    List<Resource> resources;
+    public DBus.Connection sbus;
+    public string bus_name;
+
+    public Registry()
+    {
+        resources = new List<Resource>();
+        try {
+            sbus = DBus.Bus.get(DBus.BusType.SYSTEM);
+        } catch (DBus.Error e) {
+            stderr.printf("Cannot access system DBus bus: %s\n", e.message);
+            sbus = null;
+        }
+
+        bus_name = DBus.bus_get_unique_name(sbus.get_connection());
+        zavai.log.info("My bus name: " + bus_name);
+
+        dynamic DBus.Object tmp_dbus = sbus.get_object(
+            "org.freedesktop.DBus",
+            "/org/freedesktop/DBus",
+            "org.freedesktop.DBus");
+        bus_name = "org.enricozini.zavai";
+        uint res = tmp_dbus.RequestName(bus_name, (uint)DBus.NameFlag.DO_NOT_QUEUE);
+        switch (res)
+        {
+            case DBus.RequestNameReply.PRIMARY_OWNER:
+                zavai.log.info("Registered to dbus as " + bus_name);
+                break;
+            case DBus.RequestNameReply.IN_QUEUE:
+                zavai.log.info("In queue, but I asked not to");
+                break;
+            case DBus.RequestNameReply.EXISTS:
+                zavai.log.info(bus_name + " already exists");
+                break;
+            case DBus.RequestNameReply.ALREADY_OWNER:
+                zavai.log.info("I already own the name " + bus_name + " but I do not remember asking for it");
+                break;
+        }
+    }
+
+    public void shutdown()
+    {
+        // Shutdown in reverse registration order
+        for (weak List<Resource> i = resources; i != null; i = i.next)
+            i.data.shutdown();
+    }
+
+    public void register(Resource obj)
+    {
+        resources.prepend(obj);
+    }
+}
+
+public zavai.Registry registry;
+
+}
+
diff --git a/src/uevent.vala b/src/uevent.vala
new file mode 100644 (file)
index 0000000..b9475ae
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * uevent - zavai uevent handling
+ *
+ * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace uevent {
+
+class UEvent : Service
+{
+    protected IOChannel sock;
+    protected uint sock_watch = 0;
+    public Omhacks.UEvent.Event event_data;
+    public signal void event();
+
+    public UEvent()
+    {
+        event_data = Omhacks.UEvent.Event();
+    }
+
+    protected bool on_input_data(IOChannel source, IOCondition condition)
+    {
+        if (condition != IOCondition.IN) return true;
+
+        Omhacks.UEvent.read(sock.unix_get_fd(), ref event_data);
+        event();
+
+        return true;
+    }
+
+    /// Activate the service
+    protected override void start()
+    {
+        if (started) return;
+
+        int sock_fd = Omhacks.UEvent.open();
+        if (sock_fd < 0)
+        {
+            zavai.log.error("UEvent: error getting socket");
+            return;
+        }
+
+        sock = new IOChannel.unix_new(sock_fd);
+        sock_watch = sock.add_watch(IOCondition.IN, on_input_data);
+
+        base.start();
+    }
+
+    /// Deactivate the service
+    protected override void stop()
+    {
+        if (!started) return;
+        Source.remove(sock_watch);
+        try {
+            sock.shutdown(false);
+        } catch (IOChannelError e) {
+            zavai.log.error("When closing UEvent socket: " + e.message);
+        }
+        sock = null;
+        base.stop();
+    }
+}
+
+UEvent uevent;
+
+public void init()
+{
+    if (Posix.getuid() == 0)
+        uevent = new UEvent();
+    else
+        uevent = null;
+}
+
+}
+}
diff --git a/src/wifi.vala b/src/wifi.vala
new file mode 100644 (file)
index 0000000..55cf1cc
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * wifi - wifi resource for zavai
+ *
+ * Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace wifi {
+
+public class Wifi: zavai.ScriptService
+{
+    public Wifi()
+    {
+        Object(name: "wifi");
+        started = script_status();
+    }
+
+    /// Start wifi
+    public override void start()
+    {
+        if (started) return;
+        if (!script_start()) return;
+        zavai.log.info("wifi turned on");
+        base.start();
+    }
+
+    // Release usage of wifi
+    public override void stop()
+    {
+        if (!started) return;
+        script_stop();
+        base.stop();
+    }
+}
+
+public Wifi wifi = null;
+
+public void init()
+{
+    wifi = new Wifi();
+
+}
+
+}
+}
diff --git a/src/x11.vapi b/src/x11.vapi
new file mode 100644 (file)
index 0000000..ec8b074
--- /dev/null
@@ -0,0 +1,883 @@
+/* x11.vapi
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/Xlib.h,X11/Xatom.h,X11/Xutil.h")]
+namespace X {
+       // Note: must be called before opening a display or calling any other Xlib function,
+       // see http://tronche.com/gui/x/xlib/display/XInitThreads.html
+       [CCode (cname = "XInitThreads")]
+       public Status init_threads ();
+
+       [Compact]
+       [CCode (cname = "Display", ref_function = "", unref_function = "")]
+       public class Display {
+               [CCode (cname = "XOpenDisplay")]
+               public Display (string? name = null);
+
+               [CCode (cname = "XGetAtomName")]
+               public string get_atom_name(Atom a);
+
+               [CCode (cname = "XAllPlanes")]
+               public static ulong get_all_planes ();
+
+               [CCode (cname = "XAddToSaveSet")]
+               public int add_to_save_set (Window w);
+
+               [CCode (cname = "XAllowEvents")]
+               public int allow_events (int event_mode, int time);
+
+               [CCode (cname = "XBitmapBitOrder")]
+               public int bitmap_bit_order ();
+
+               [CCode (cname = "XBitmapUnit")]
+               public int bitmap_scanline_unit ();
+
+               [CCode (cname = "XBitmapPad")]
+               public int bitmap_scanline_padding ();
+
+               [CCode (cname = "XChangeProperty")]
+               public int change_property (Window w, Atom property, Atom type, int format, int mode, [CCode (array_length = false)] uchar[] data, int nelements);
+
+               [CCode (cname = "XChangeWindowAttributes")]
+               public int change_window_attributes (Window w, ulong valuemask, SetWindowAttributes attributes);
+
+               [CCode (cname = "XConfigureWindow")]
+               public int configure_window (Window w, uint value_mask, WindowChanges values);
+
+               [CCode (cname = "ConnectionNumber")]
+               public int connection_number ();
+
+               [CCode (cname = "DefaultRootWindow")]
+               public Window default_root_window ();
+
+               [CCode (cname = "XDefaultScreenOfDisplay")]
+               public unowned Screen default_screen ();
+
+               [CCode (cname = "XScreenOfDisplay")]
+               public unowned Screen screen_by_id (int screen_number);
+
+               [CCode (cname = "DisplayString")]
+               public string display_string ();
+
+               [CCode (cname = "XQLength")]
+               public int event_queue_length ();
+
+               [CCode (cname = "XFlush")]
+               public int flush ();
+
+               [CCode (cname = "XGetKeyboardMapping", array_length = false)]
+               public weak uint[] get_keyboard_mapping (uint first_keycode, int keycode_count, ref int keysyms_per_keycode_return);
+
+               [CCode (cname = "XGetModifierMapping")]
+               public ModifierKeymap get_modifier_mapping ();
+
+               [CCode (cname = "XGetSelectionOwner")]
+               public Window get_selection_owner (Atom selection);
+
+               [CCode (cname = "XGetWindowAttributes")]
+               public void get_window_attributes (Window w, out WindowAttributes window_attributes_return);
+
+               [CCode (cname = "XGetWindowProperty")]
+               public int get_window_property (Window w, Atom property, long long_offset, long long_length, bool delete, Atom req_type, out Atom actual_type_return, out int actual_format_return, out ulong nitems_return, out ulong bytes_after_return, out void* prop_return);
+
+               [CCode (cname = "XGrabButton")]
+               public int grab_button (uint button, uint modifiers, Window grab_window, bool owner_events, uint event_mask, int pointer_mode, int keyboard_mode, Window confine_to, uint cursor);
+
+               [CCode (cname = "XGrabKey")]
+               public int grab_key (int keycode, uint modifiers, Window grab_window, bool owner_events, int pointer_mode, int keyboard_mode);
+
+               [CCode (cname = "XGrabPointer")]
+               public int grab_pointer (Window grab_window, bool owner_events, uint event_mask, int pointer_mode, int keyboard_mode, Window confine_to, uint cursor, int time);
+
+               [CCode (cname = "XGrabServer")]
+               public int grab_server ();
+
+               [CCode (cname = "XImageByteOrder")]
+               public int image_byte_order ();
+
+               [CCode (cname = "XInternAtom")]
+               public Atom intern_atom (string atom_name, bool only_if_exists);
+
+               [CCode (cname = "XInternAtoms")]
+               public void intern_atoms (string[] names, bool only_if_exists, [CCode (array_length = false)] Atom[] atoms_return);
+
+               [CCode (cname = "XInternalConnectionNumbers")]
+               public Status internal_connection_numbers (ref int[] fd_return);
+
+               [CCode (cname = "XDisplayKeycodes")]
+               public int keycodes (ref int min_keycodes_return, ref int max_keycodes_return);
+
+               [CCode (cname = "XKeysymToKeycode")]
+               public int keysym_to_keycode (uint keysym);
+
+               [CCode (cname = "XLastKnownRequestProcessed")]
+               public ulong last_known_request_processed ();
+
+               [CCode (cname = "XLockDisplay")]
+               public void lock_display ();
+
+               [CCode (cname = "XMapWindow")]
+               public int map_window (Window w);
+
+               [CCode (cname = "XMaxRequestSize")]
+               public long max_request_size ();
+
+               [CCode (cname = "XExtendedMaxRequestSize")]
+               public long max_extended_request_size ();
+
+               [CCode (cname = "XNextEvent")]
+               public int next_event (ref Event event_return);
+
+               [CCode (cname = "XNextRequest")]
+               public ulong next_request ();
+
+               [CCode (cname = "XNoOp")]
+               public void no_operation ();
+
+               [CCode (cname = "XScreenCount")]
+               public int number_of_screens ();
+
+               [CCode (cname = "XPending")]
+               public int pending ();
+
+               [CCode (cname = "XProcessInternalConnection")]
+               public void process_internal_connection (int fd);
+
+               [CCode (cname = "XProtocolVersion")]
+               public int protocol_version ();
+
+               [CCode (cname = "XProtocolRevision")]
+               public int protocol_revision ();
+
+               [CCode (cname = "XRaiseWindow")]
+               public int raise_window (Window w);
+
+               [CCode (cname = "XReparentWindow")]
+               public int reparent_window (Window w, Window parent, int x, int y);
+
+               [CCode (cname = "XResizeWindow")]
+               public int resize_window (Window w, uint width, uint height);
+
+               [CCode (cname = "XRootWindow")]
+               public Window root_window (int screen_number);
+
+               [CCode (cname = "ScreenCount")]
+               public int screen_count ();
+
+               [CCode (cname = "XScreenOfDisplay")]
+               public weak Screen screen_of_display (int screen_number);
+
+               [CCode (cname = "XSelectInput")]
+               public int select_input (Window w, long event_mask);
+
+               [CCode (cname = "XSendEvent")]
+               public void send_event (Window w, bool prpagate, long event_mask, ref Event event_send);
+
+               [CCode (cname = "XSetCloseDownMode")]
+               public void set_close_down_mode (int close_mode);
+
+               [CCode (cname = "XSetSelectionOwner")]
+               public Window set_selection_owner (Atom selection, Window owner, int time);
+
+               [CCode (cname = "XSetInputFocus")]
+               public int set_input_focus (Window focus, int revert_to, int time);
+
+               [CCode (cname = "XUngrabButton")]
+               public int ungrab_button (uint button, uint modifiers, Window grab_window);
+
+               [CCode (cname = "XUngrabPointer")]
+               public int ungrab_pointer (int time);
+
+               [CCode (cname = "XUngrabServer")]
+               public int ungrab_server ();
+
+               [CCode (cname = "XUnlockDisplay")]
+               public void unlock_display ();
+
+               [CCode (cname = "XUnmapWindow")]
+               public int unmap_window (Window w);
+
+               [CCode (cname = "XQueryTree")]
+               public void query_tree (Window w, out Window root_return, out Window parent_return, out Window[] children_return);
+
+               [CCode (cname = "XWindowEvent")]
+               public int window_event (Window w, EventMask event_mask, out Event event_return);
+
+               [CCode (cname = "XServerVendor")]
+               public string xserver_vendor_name ();
+
+               [CCode (cname = "XVendorRelease")]
+               public string xserver_vendor_release ();
+
+               [CCode (cname = "XMoveWindow")]
+               public void move_window (Window window, int x, int y);
+       }
+
+       [Compact]
+       [CCode (cname = "XModifierKeymap", free_function = "XFreeModifiermap")]
+       public class ModifierKeymap {
+               // The server's max # of keys per modifier
+               public int max_keypermod;
+               // An 8 by max_keypermod array of modifiers
+               public uchar[] modifiermap;
+       }
+
+       [SimpleType]
+       [IntegerType (rank = 9)]
+       [CCode (cname = "Atom")]
+       public struct Atom {
+       }
+
+       [SimpleType]
+       [IntegerType (rank = 9)]
+       [CCode (cname = "Colormap")]
+       public struct Colormap {
+       }
+
+       [SimpleType]
+       [CCode (cname = "GC")]
+       public struct GC {
+       }
+
+       [SimpleType]
+       [IntegerType (rank = 9)]
+       [CCode (cname = "Status")]
+       public struct Status {
+       }
+
+       [SimpleType]
+       [IntegerType (rank = 9)]
+       [CCode (cname = "Window", type_id = "G_TYPE_INT",
+               marshaller_type_name = "INT",
+               get_value_function = "g_value_get_int",
+               set_value_function = "g_value_set_int", default_value = "0",
+               type_signature = "i")]
+       public struct Window {
+       }
+
+       public struct Visual {
+       }
+
+       public struct WindowChanges {
+               public int x;
+               public int y;
+               public int width;
+               public int height;
+               public int border_width;
+               public Window sibling;
+               public int stack_mode;
+       }
+       public struct SizeHints {
+               public long @flags;
+               public int x;
+               public int y;
+               public int width;
+               public int height;
+       }
+
+       [CCode (cname = "XCreateWindow")]
+       public Window create_window (Display display, Window parent, int x, int y, uint width, uint height, uint border_width, int depth, uint @class, Visual? visual, X.CW valuemask, ref SetWindowAttributes attributes);
+
+       [CCode (cname = "XSetWindowAttributes")]
+       public struct SetWindowAttributes {
+               // public Pixmap background_pixmap;     /* background or None or ParentRelative */
+               public ulong background_pixel;  /* background pixel */
+               // public Pixmap border_pixmap; /* border of the window */
+               public ulong border_pixel;      /* border pixel value */
+               public int bit_gravity;         /* one of bit gravity values */
+               public int win_gravity;         /* one of the window gravity values */
+               public int backing_store;               /* NotUseful, WhenMapped, Always */
+               public ulong backing_planes;/* planes to be preseved if possible */
+               public ulong backing_pixel;/* value to use in restoring planes */
+               public bool save_under;         /* should bits under be saved? (popups) */
+               public long event_mask;         /* set of events that should be saved */
+               public long do_not_propagate_mask;      /* set of events that should not propagate */
+               public bool override_redirect;  /* boolean value for override-redirect */
+               // public Colormap colormap;            /* color map to be associated with window */
+               // public Cursor cursor;                /* cursor to be displayed (or None) */
+       }
+
+       [CCode(cname = "XWindowAttributes",
+              cheader_filename = "X11/Xlib.h,X11/Xatom.h,X11/Xutil.h")]
+       public struct WindowAttributes {
+               public int x;
+               public int y;                   /* location of window */
+               public int width;
+               public int height;              /* width and height of window */
+               public int border_width;                /* border width of window */
+               public int depth;               /* depth of window */
+               public Visual visual;           /* the associated visual structure */
+               public Window root;             /* root of screen containing window */
+               public int @class;                      /* InputOutput, InputOnly*/
+               public int bit_gravity;         /* one of bit gravity values */
+               public int win_gravity;         /* one of the window gravity values */
+               public int backing_store;               /* NotUseful, WhenMapped, Always */
+               public ulong backing_planes;/* planes to be preserved if possible */
+               public ulong backing_pixel;/* value to be used when restoring planes */
+               public bool save_under;         /* boolean, should bits under be saved? */
+               // public Colormap colormap;            /* color map to be associated with window */
+               public bool map_installed;              /* boolean, is color map currently installed*/
+               public int map_state;           /* IsUnmapped, IsUnviewable, IsViewable */
+               public long all_event_masks;    /* set of events all people have interest in*/
+               public long your_event_mask;    /* my event mask */
+               public long do_not_propagate_mask; /* set of events that should not propagate */
+               public bool override_redirect;  /* boolean value for override-redirect */
+               // public Screen screen;                /* back pointer to correct screen */
+       }
+
+       [CCode (cname = "CopyFromParent")]
+       public const int COPY_FROM_PARENT;
+
+       [CCode (cname = "CurrentTime")]
+       public const ulong CURRENT_TIME;
+
+       [CCode (cname = "Success")]
+       public int Success;
+
+       [CCode (cname = "XFree")]
+       public int free (void* data);
+
+       [CCode (cprefix = "CW", cname = "int")]
+       public enum CW {
+               BackPixmap,
+               BackPixel,
+               BackingStore,
+               BackingPlanes,
+               BackingPixel,
+               BitGravity,
+               BorderPixmap,
+               BorderPixel,
+               BorderWidth,
+               Colormap,
+               Cursor,
+               DontPropagate,
+               EventMask,
+               Height,
+               OverrideRedirect,
+               SaveUnder,
+               Sibling,
+               StackMode,
+               X,
+               Y,
+               Width,
+               WinGravity
+       }
+
+       [CCode (cprefix = "GrabMode")]
+       public enum GrabMode {
+               Sync,
+               Async
+       }
+
+       [CCode (cprefix = "")]
+       public enum EventMask {
+               NoEventMask,
+               KeyPressMask,
+               KeyReleaseMask,
+               ButtonPressMask,
+               ButtonReleaseMask,
+               EnterWindowMask,
+               LeaveWindowMask,
+               PointerMotionMask,
+               PointerMotionHintMask,
+               Button1MotionMask,
+               Button2MotionMask,
+               Button3MotionMask,
+               Button4MotionMask,
+               Button5MotionMask,
+               ButtonMotionMask,
+               KeymapStateMask,
+               ExposureMask,
+               VisibilityChangeMask,
+               StructureNotifyMask,
+               ResizeRedirectMask,
+               SubstructureNotifyMask,
+               SubstructureRedirectMask,
+               FocusChangeMask,
+               PropertyChangeMask,
+               ColormapChangeMask,
+               OwnerGrabButtonMask
+       }
+
+       [CCode (cprefix = "")]
+       public enum KeyMask {
+               ShiftMask,
+               LockMask,
+               ControlMask,
+               Mod1Mask,
+               Mod2Mask,
+               Mod3Mask,
+               Mod4Mask,
+               Mod5Mask
+       }
+
+       [CCode (cprefix = "")]
+       public enum EventType {
+               KeyPress,
+               KeyRelease,
+               ButtonPress,
+               ButtonRelease,
+               MotionNotify,
+               EnterNotify,
+               LeaveNotify,
+               FocusIn,
+               FocusOut,
+               KeymapNotify,
+               Expose,
+               GraphicsExpose,
+               NoExpose,
+               VisibilityNotify,
+               CreateNotify,
+               DestroyNotify,
+               UnmapNotify,
+               MapNotify,
+               MapRequest,
+               ReparentNotify,
+               ConfigureNotify,
+               ConfigureRequest,
+               GravityNotify,
+               ResizeRequest,
+               CirculateNotify,
+               CirculateRequest,
+               PropertyNotify,
+               SelectionClear,
+               SelectionRequest,
+               SelectionNotify,
+               ColormapNotify,
+               ClientMessage,
+               MappingNotify
+       }
+
+       // union
+       [CCode (cname = "XEvent")]
+       public struct Event {
+               public int type;
+               public AnyEvent xany;
+               public KeyEvent xkey;
+               public ButtonEvent xbutton;
+               public MotionEvent xmotion;
+               public CrossingEvent xcrossing;
+               public CreateWindowEvent xcreatewindow;
+               public DestroyWindowEvent xdestroywindow;
+               public UnmapEvent xunmap;
+               public MapEvent xmap;
+               public MapRequestEvent xmaprequest;
+               public ReparentEvent xreparent;
+               public ConfigureEvent xconfigure;
+               public GravityEvent xgravity;
+               public ConfigureRequestEvent xconfigurerequest;
+               public CirculateEvent xcirculate;
+               public CirculateRequestEvent xcirculaterequest;
+               public PropertyEvent xproperty;
+               public SelectionEvent xselection;
+               public ClientMessageEvent xclient;
+       }
+
+       [CCode (cname = "XAnyEvent")]
+       public struct AnyEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window window;
+       }
+
+       [CCode (cname = "XKeyEvent")]
+       public struct KeyEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window window;
+               public Window root;
+               public Window subwindow;
+               public ulong time;
+               public int x;
+               public int y;
+               public int x_root;
+               public int y_root;
+               public uint state;
+               public uint keycode;
+               public bool same_screen;
+       }
+
+       [CCode (cname = "XButtonEvent")]
+       public struct ButtonEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window window;
+               public Window subwindow;
+               public ulong time;
+               public int x;
+               public int y;
+               public int x_root;
+               public int y_root;
+               public uint state;
+               public uint button;
+               public bool same_screen;
+       }
+
+       [CCode (cname = "XMotionEvent")]
+       public struct MotionEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window window;
+               public Window subwindow;
+               public ulong time;
+               public int x;
+               public int y;
+               public int x_root;
+               public int y_root;
+               public uint state;
+               public char is_hint;
+               public bool same_screen;
+       }
+
+       [CCode (cname = "XCrossingEvent")]
+       public struct CrossingEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window window;
+               public Window root;
+               public Window subwindow;
+               public ulong time;
+               public int x;
+               public int y;
+               public int x_root;
+               public int y_root;
+               public int mode;
+               public int detail;
+               public bool same_screen;
+               public bool focus;
+               public uint state;
+       }
+
+       [CCode (cname = "XCreateWindowEvent")]
+       public struct CreateWindowEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window parent;
+               public Window window;
+               public int x;
+               public int y;
+               public int width;
+               public int height;
+               public int border_width;
+               public bool override_redirect;
+       }
+
+       [CCode (cname = "XDestroyWindowEvent")]
+       public struct DestroyWindowEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+       }
+
+       [CCode (cname = "XUnmapEvent")]
+       public struct UnmapEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+               public bool from_configure;
+       }
+
+       [CCode (cname = "XMapEvent")]
+       public struct MapEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+               public bool override_redirect;
+       }
+
+       [CCode (cname = "XMapRequestEvent")]
+       public struct MapRequestEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window parent;
+               public Window window;
+       }
+
+       [CCode (cname = "XReparentEvent")]
+       public struct ReparentEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+               public Window parent;
+               public int x;
+               public int y;
+               public bool override_redirect;
+       }
+
+       [CCode (cname = "XConfigureEvent")]
+       public struct ConfigureEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+               public int x;
+               public int y;
+               public int width;
+               public int height;
+               public int border_width;
+               public Window above;
+               public bool override_redirect;
+       }
+
+       [CCode (cname = "XGravityEvent")]
+       public struct GravityEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+               public int x;
+               public int y;
+       }
+
+       [CCode (cname = "XConfigureRequestEvent")]
+       public struct ConfigureRequestEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window parent;
+               public Window window;
+               public int x;
+               public int y;
+               public int width;
+               public int height;
+               public int border_width;
+               public Window above;
+               public int detail;
+               public ulong value_mask;
+       }
+
+       [CCode (cname = "XCirculateEvent")]
+       public struct CirculateEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window event;
+               public Window window;
+               public int place;
+       }
+
+       [CCode (cname = "XCirculateRequestEvent")]
+       public struct CirculateRequestEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window parent;
+               public Window window;
+               public int place;
+       }
+
+       [CCode (cname = "XPropertyEvent")]
+       public struct PropertyEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window window;
+               public Atom atom;
+               public ulong time;
+               public int state;
+       }
+
+       [CCode (cname = "XSelectionEvent")]
+       public struct SelectionEvent {
+               public int type;
+               public ulong serial;
+               public bool send_event;
+               public unowned Display display;
+               public Window requestor;
+               public Atom selection;
+               public Atom target;
+               public Atom property;
+               public ulong time;
+       }
+
+       [CCode (cname = "XClientMessageEvent")]
+       public struct ClientMessageEvent {
+               public int type;
+               public ulong serial;    /* # of last request processed by server */
+               public bool send_event; /* true if this came from a SendEvent request */
+               public unowned Display display; /* Display the event was read from */
+               public Window window;
+               public Atom message_type;
+               public int format;
+               public ClientMessageEventData data;
+       }
+
+       // union
+       public struct ClientMessageEventData {
+               public unowned char[] b;
+               public unowned short[] s;
+               public unowned long[] l;
+       }
+
+       [CCode (cprefix = "PropMode")]
+       public enum PropMode {
+               Replace,
+               Prepend,
+               Append
+       }
+
+       [CCode (cprefix = "")]
+       public enum AllowEventsMode {
+               AsyncPointer,
+               SyncPointer,
+               ReplayPointer,
+               AsyncKeyboard,
+               SyncKeyboard,
+               ReplayKeyboard,
+               AsyncBoth,
+               SyncBoth
+       }
+
+       [CCode (cprefix = "")]
+       public enum MapState {
+               IsUnmapped,
+               IsUnviewable,
+               IsViewable
+       }
+
+       [CCode (cprefix = "RevertTo")]
+       public enum RevertTo {
+               None,
+               PointerRoot,
+               Parent
+       }
+
+       [Compact]
+       [CCode (cname = "Screen")]
+       public class Screen {
+               public Display display;
+               public Window root;
+               public int width;
+               public int height;
+
+               [CCode (cname = "XScreenOfDisplay")]
+               public static unowned Screen get_screen (Display disp, int screen_number);
+
+               [CCode (cname = "XBlackPixelOfScreen")]
+               public ulong black_pixel_of_screen ();
+
+               [CCode (cname = "XCellsOfScreen")]
+               public int cells_of_screen ();
+
+               [CCode (cname = "XDefaultColormapOfScreen")]
+               public Colormap default_colormap_of_screen ();
+
+               [CCode (cname = "XDefaultDepthOfScreen")]
+               public int default_depth_of_screen ();
+
+               [CCode (cname = "XDefaultGCOfScreen")]
+               public GC default_gc_of_screen ();
+
+               [CCode (cname = "XDefaultVisualOfScreen")]
+               public Visual default_visual_of_screen ();
+
+               [CCode (cname = "XDisplayOfScreen")]
+               public unowned Display display_of_screen ();
+
+               [CCode (cname = "XDoesBackingStore")]
+               public int does_backing_store ();
+
+               [CCode (cname = "XDoesSaveUnders")]
+               public bool does_save_unders ();
+
+               [CCode (cname = "XEventMaskOfScreen")]
+               public long event_mask_of_Screen ();
+
+               [CCode (cname = "XHeightMMOfScreen")]
+               public int height_in_mm_of_screen ();
+
+               [CCode (cname = "XHeightOfScreen")]
+               public int height_of_screen ();
+
+               [CCode (cname = "XMaxCmapsOfScreen")]
+               public int max_colormaps_of_screen ();
+
+               [CCode (cname = "XMinCmapsOfScreen")]
+               public int min_colormaps_of_screen ();
+
+               [CCode (cname = "XPlanesOfScreen")]
+               public int planes_of_screen ();
+
+               [CCode (cname = "XRootWindowOfScreen")]
+               public Window root_window_of_screen ();
+
+               [CCode (cname = "XScreenNumberOfScreen")]
+               public int screen_number_of_screen ();
+
+               [CCode (cname = "XWhitePixelOfScreen")]
+               public ulong white_pixel_of_screen ();
+
+               [CCode (cname = "XWidthMMOfScreen")]
+               public int width_in_mm_of_screen ();
+
+               [CCode (cname = "XWidthOfScreen")]
+               public int width_of_screen ();
+       }
+
+       public const X.Atom XA_ATOM;
+       public const X.Atom XA_CARDINAL;
+       public const X.Atom XA_WINDOW;
+       public const X.Atom XA_WM_CLASS;
+       public const X.Atom XA_WM_HINTS;
+       public const X.Atom XA_WM_ICON_NAME;
+       public const X.Atom XA_WM_NAME;
+       public const X.Atom XA_WM_NORMAL_HINTS;
+       public const X.Atom XA_WM_TRANSIENT_FOR;
+
+       public const uint XK_Num_Lock;
+       public const uint XK_Scroll_Lock;
+}
+
diff --git a/src/zavai-calendar.vala b/src/zavai-calendar.vala
deleted file mode 100644 (file)
index 5d34139..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * zavai-calendar - simple calendar tool
- *
- * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-//string VERSION = "0.1";
-
-static Posix.pid_t is_running()
-{
-       string pidfile = zavai.config.homedir + "/calendar.pid";
-       string contents;
-       try {
-               if (!FileUtils.get_contents(pidfile, out contents))
-                       return 0;
-       } catch (FileError e) {
-               return 0;
-       }
-       int val = contents.to_int();
-       string procdir = "/proc/%d".printf(val);
-       if (FileUtils.test(procdir, FileTest.IS_DIR))
-               return (Posix.pid_t)val;
-       else
-               return 0;
-}
-
-static void make_pidfile()
-{
-       string pidfile = zavai.config.homedir + "/calendar.pid";
-       FileUtils.set_contents(pidfile, "%d".printf(Posix.getpid()));
-}
-
-static void on_kill(int sig)
-{
-       Gtk.main_quit();
-}
-
-static int main (string[] args) {
-       bool opt_popup = false;
-       GLib.OptionEntry[] entries = new GLib.OptionEntry[] {
-               OptionEntry() {
-                       long_name = "popup",
-                       short_name = 'p',
-                       flags = 0,
-                       arg = OptionArg.NONE,
-                       arg_data = &opt_popup,
-                       description = "run as a popup at the specified location on screen",
-                       arg_description = null },
-               OptionEntry()
-       };
-        Gtk.init_with_args(ref args, "", entries, null);
-
-       // parser = Parser(usage="usage: %prog [options]",
-       //                 version="%prog "+ VERSION,
-       //                 description="Simple interactive interface for the OpenMoko")
-       // parser.add_option("-v", "--verbose", action="store_true", help="verbose mode")
-       // 
-       // (opts, args) = parser.parse_args()
-       // 
-       // if not opts.verbose:
-       //     zavai.set_quiet()
-       // 
-       // # Read configuration
-       // zavai.info("Loading configuration")
-       // conf = zavai.Config()
-
-       // Set up zavai
-
-       // Core infrastructure
-       zavai.config = new zavai.Config();
-
-       // User interface
-       var calendar = new zavai.widgets.Calendar();
-
-       Gtk.Window win = new Gtk.Window(Gtk.WindowType.TOPLEVEL);
-       if (opt_popup)
-       {
-               Posix.pid_t pid = is_running();
-               if (pid != 0)
-               {
-                       // Kill a running calendar
-                       Posix.kill(pid, Posix.SIGINT);
-                       FileUtils.unlink(zavai.config.homedir + "/calendar.pid");
-                       return 0;
-               }
-
-               make_pidfile();
-
-               win.set_decorated(false);
-               //win.set_resizable(false);
-               win.set_border_width(5);
-               win.set_skip_taskbar_hint(true);
-               win.set_skip_pager_hint(true);
-               //    gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
-               win.set_position(Gtk.WindowPosition.MOUSE);
-               win.stick();
-       }
-
-       win.title = "Zavai calendar";
-       win.destroy += Gtk.main_quit;
-       win.add(calendar);
-       win.set_size_request(300, 500);
-       win.show_all();
-       win.show();
-
-       // Shutdown the main loop on SIGINT
-       Posix.signal(Posix.SIGINT, on_kill);
-       Posix.signal(Posix.SIGTERM, on_kill);
-
-       Gtk.main();
-
-       calendar.flush();
-
-       return 0;
-}
index d1dede55f8208a3884af2d800873aa3f899bb98e..f9838c5af31a51de2aa3ef3b077bdb5753715889 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * zavai - simple interface to the OpenMoko (or to the FSO stack)
  *
- * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+ * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 using GLib;
 
 //string VERSION = "0.1";
+static string pidfilename;
+
+static Posix.pid_t is_running()
+{
+       string pidfile = zavai.config.homedir + "/" + pidfilename + ".pid";
+       string contents;
+       try {
+               if (!FileUtils.get_contents(pidfile, out contents))
+                       return 0;
+       } catch (FileError e) {
+               return 0;
+       }
+       int val = contents.to_int();
+       string procdir = "/proc/%d".printf(val);
+       if (FileUtils.test(procdir, FileTest.IS_DIR))
+               return (Posix.pid_t)val;
+       else
+               return 0;
+}
+
+static void make_pidfile()
+{
+       string pidfile = zavai.config.homedir + "/" + pidfilename + ".pid";
+    try {
+        FileUtils.set_contents(pidfile, "%d".printf(Posix.getpid()));
+    } catch (FileError e) {
+        zavai.log.error("Cannot create pidfile " + pidfile + ": " + e.message);
+    }
+}
+
+static void on_kill(int sig)
+{
+       Gtk.main_quit();
+}
+
 
 static int main (string[] args) {
-       Gtk.init (ref args);
+       bool opt_popup = false;
+       bool opt_calendar = false;
+       GLib.OptionEntry[] entries = new GLib.OptionEntry[] {
+               OptionEntry() {
+                       long_name = "popup",
+                       short_name = 'p',
+                       flags = 0,
+                       arg = OptionArg.NONE,
+                       arg_data = &opt_popup,
+                       description = "run as a popup at the specified location on screen",
+                       arg_description = null },
+               OptionEntry() {
+                       long_name = "calendar",
+                       short_name = 0,
+                       flags = 0,
+                       arg = OptionArg.NONE,
+                       arg_data = &opt_calendar,
+                       description = "run as calendar only",
+                       arg_description = null },
+               OptionEntry()
+       };
+    try {
+        Gtk.init_with_args(ref args, "", entries, null);
+    } catch (Error e) {
+        zavai.log.error("Cannot init gtk: " + e.message);
+        return 1;
+    }
     Gst.init (ref args);
 
-       // parser = Parser(usage="usage: %prog [options]",
-       //                 version="%prog "+ VERSION,
-       //                 description="Simple interactive interface for the OpenMoko")
-       // parser.add_option("-v", "--verbose", action="store_true", help="verbose mode")
-       // 
-       // (opts, args) = parser.parse_args()
-       // 
+    pidfilename = "zavai";
+
        // if not opts.verbose:
        //     zavai.set_quiet()
-       // 
-       // # Read configuration
-       // zavai.info("Loading configuration")
-       // conf = zavai.Config()
 
        // Set up zavai
 
@@ -89,6 +141,57 @@ static int main (string[] args) {
     // Core infrastructure
        zavai.config = new zavai.Config();
        zavai.config.argv0 = args[0];
+
+    if (opt_calendar)
+    {
+        pidfilename = "calendar";
+
+        // User interface
+        var calendar = new zavai.widgets.Calendar();
+
+        Gtk.Window win = new Gtk.Window(Gtk.WindowType.TOPLEVEL);
+        if (opt_popup)
+        {
+            Posix.pid_t pid = is_running();
+            if (pid != 0)
+            {
+                // Kill a running calendar
+                Posix.kill(pid, Posix.SIGINT);
+                FileUtils.unlink(zavai.config.homedir + "/" + pidfilename + ".pid");
+                return 0;
+            }
+
+            make_pidfile();
+
+            win.set_decorated(false);
+            //win.set_resizable(false);
+            win.set_border_width(5);
+            win.set_skip_taskbar_hint(true);
+            win.set_skip_pager_hint(true);
+            //    gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
+            win.set_position(Gtk.WindowPosition.MOUSE);
+            win.stick();
+        }
+
+        win.title = "Zavai calendar";
+        win.destroy += Gtk.main_quit;
+        win.add(calendar);
+        win.set_size_request(300, 500);
+        win.show_all();
+        win.show();
+
+        // Shutdown the main loop on SIGINT
+        Posix.signal(Posix.SIGINT, on_kill);
+        Posix.signal(Posix.SIGTERM, on_kill);
+
+        Gtk.main();
+
+        calendar.flush();
+
+        return 0;
+    }
+
+
        zavai.registry = new zavai.Registry();
 
     zavai.main.init();
@@ -117,7 +220,7 @@ static int main (string[] args) {
        zavai.ui.main.init();
        zavai.ui.gps.init();
        zavai.ui.gsm.init();
-       zavai.config.run_script(zavai.config.homedir + "/display init");
+       zavai.config.find_and_run_script("display", "init");
        zavai.ui.power.init();
        zavai.ui.aux.init();
        zavai.ui.kbd.init();
@@ -126,6 +229,7 @@ static int main (string[] args) {
        zavai.ui.alarm.init();
        zavai.ui.wifi.init();
        zavai.ui.bluetooth.init();
+       zavai.ui.logview.init();
        zavai.ui.debug.init();
 
        //zavai.app.show_applet("menu.main");
@@ -174,6 +278,21 @@ static int main (string[] args) {
         zavai.clock.alarm_trigger_queue.enqueue_trigger(alarm);
     }
 
+    if (args.length > 2 && args[1] == "showlog")
+    {
+        zavai.log.log.list_entries((d, f) => {
+            stderr.printf("FALSE %s %s\n", d, f);
+            return true;
+        }, false);
+        zavai.log.log.list_entries((d, f) => {
+            stderr.printf("TRUE %s %s\n", d, f);
+            return true;
+        }, true);
+        zavai.log.Log l = zavai.log.log.load(args[2]);
+        l.dump();
+        return 0;
+    }
+
        if (args.length > 2 && args[1] == "play")
     {
         zavai.audio.musicplayer.play("file://" + args[2]);
index d27624c4dff684301a36a2240bc8d462bf389560..64e95e89c66f91ae7140631a8977adfd80ee9641 100644 (file)
@@ -4,8 +4,8 @@ include(../vala.cmake)
 set(packages gtk+-2.0 dbus-glib-1>=0.80 libwnck-1.0>=2.26.0 lua5.1 libomhacks x11 gdk-x11-2.0 libgps gstreamer-0.10)
 add_packages(ZAVAI ${packages})
 
-set(VALA_PACKAGES ${packages} posix linux-input dbus-extra gtkfisheyelist libzavai)
-set(VFLAGS --vapidir=${gtkfisheyelist_BINARY_DIR} --vapidir=${libzavai_SOURCE_DIR} --vapidir=${libzavai_BINARY_DIR})
+set(VALA_PACKAGES ${packages} posix linux-input dbus-extra gtkfisheyelist)
+set(VFLAGS --vapidir=${gtkfisheyelist_BINARY_DIR} --vapidir=${zavai_SOURCE_DIR} --vapidir=${zavai_BINARY_DIR})
 add_definitions(-Wall)
 # -Werror 
 
@@ -20,11 +20,7 @@ else()
   message("-- Not using devkit-power-gobject")
 endif ()
 
-set(VFLAGS ${VFLAGS} --vapidir=${zavai_BINARY_DIR})
-
-add_definitions(-DWNCK_I_KNOW_THIS_IS_UNSTABLE -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE -I${gtkfisheyelist_BINARY_DIR} -I${zavai_BINARY_DIR} -I${libzavai_BINARY_DIR})
-set(VALA_PACKAGES ${VALA_PACKAGES} libzavai)
-link_libraries(libzavai)
+add_definitions(-DWNCK_I_KNOW_THIS_IS_UNSTABLE -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE -I${gtkfisheyelist_BINARY_DIR} -I${zavai_BINARY_DIR})
 
 file(GLOB gsm-receive test-gsm-receive.vala)
 add_vala_program(test-gsm-receive ${gsm-receive})
index 7ad3542d3c20c3e9dec439c2247f4b6df6ffbabc..79539627662e906a00d162c704a2e03a47920657 100644 (file)
 
 using GLib;
 
+public DBus.Connection sbus;
+
 //string VERSION = "0.1";
 
+public class GSMReceive: Object //, zavai.Resource
+{
+    public dynamic DBus.Object device;
+    public dynamic DBus.Object network;
+    public dynamic DBus.Object call;
+
+    public GSMReceive()
+    {
+        //zavai.gsm.gsm.request("GSMReceive");
+
+        device = sbus.get_object(
+                   "org.freesmartphone.ogsmd",
+                   "/org/freesmartphone/GSM/Device",
+                   "org.freesmartphone.GSM.Device");
+
+        network = sbus.get_object(
+            "org.freesmartphone.ogsmd", 
+            "/org/freesmartphone/GSM/Device",
+            "org.freesmartphone.GSM.Network");
+
+        call = sbus.get_object(
+                "org.freesmartphone.ogsmd",
+                "/org/freesmartphone/GSM/Device",
+                "org.freesmartphone.GSM.Call");
+
+       stderr.printf("Antenna is %s\n", device.GetAntennaPower() ? "on" : "off");
+       stderr.printf("Signal strength: %d\n", network.GetSignalStrength());
+       stderr.printf("Calling identification: %s\n", network.GetCallingIdentification());
+       GLib.HashTable<string, GLib.Value?> status = network.GetStatus();
+       stderr.printf("Network status:\n");
+       dump_table(status);
+
+        network.Status += on_network_Status;
+        network.SignalStrength += on_network_SignalStrength;
+        call.CallStatus += on_call_Status;
+    }
+
+    public void shutdown()
+    {
+        //zavai.gsm.gsm.release("GSMReceive");
+    }
+
+    protected void dump_table(HashTable<string, Value?> vals)
+    {
+       vals.for_each((pk, pv) => {
+               string k = (string)pk;
+               Value? v = (Value?)pv;
+               stderr.printf("K: %s V: %s\n", k, v == null ? "(null)" : v.strdup_contents());
+       });
+    }
+
+    public void on_network_SignalStrength(DBus.Object sender, int strength)
+    {
+        stderr.printf("SIGNAL STRENGTH %d\n", strength);
+    }
+
+    public void on_network_Status(DBus.Object sender, HashTable<string, Value?> status)
+    {
+        stderr.printf("NETWORK STATUS\n");
+       dump_table(status);
+
+        // dbg("cbNetworkStatus %s" % formatDict(status))
+    }
+
+    public void on_call_Status(DBus.Object sender, int index, string status, HashTable<string, Value?> properties)
+    {
+        stderr.printf("CALL STATUS %d %s\n", index, status);
+       dump_table(properties);
+        /*
+        dbg("cbCallStatus %d, %s, %s" % (id, status, formatDict(properties)))
+        self.status = status
+        if status == "incoming":
+            if "peer" in properties and properties["peer"] == "+358942832031":
+                self.gsm_call_iface.ReleaseAll()
+                os.system("kapula-debug-call-handler &")
+            else:
+                os.system("alsactl restore -f /etc/alsa-scenarios/stereoout-maxvolume.state")
+                os.system("vibrator-start")
+                os.system("ringtone-start")
+                os.system("ledctrl --on-time 400 --off-time 200 gta02-aux:red");
+        if status == "release":
+            os.system("ringtone-stop")
+            os.system("vibrator-stop")
+            os.system("ledctrl --off gta02-aux:red");
+        */
+    }
+
+
+/*
+        def onIncomingUssd( self, mode, message ):
+                logger.info( "USSD Message: %s" % message )
+                        self.main.groups["alert"].activate( "<title>Operator Message</title>%s" % message, [("OK")] )
+    def onCallStatus( self, id, status, properties ):
+        self.call = id
+        self.update_status(status)
+        if not status in ["release"]:
+            if "peer" in properties:
+                self.part_text_set( "label", self.main.groups["contacts"].tryNumberToName( properties[ "peer" ] ) )
+                self.part_text_set( "sublabel", properties[ "peer" ] )
+            else:
+                self.part_text_set( "label", _("unknown number") )
+                self.part_text_set( "sublabel", "" )
+
+    @edje.decorators.signal_callback( "mouse,clicked,1", "button_*" )
+    def on_edje_signal_dialer_button_pressed(self, emission, source):
+        key = source.split("_", 1)[1]
+        if key in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
+            dbus_object.gsm_call_iface.SendDtmf( key )
+            self.text.append(key)
+        elif key in "star":
+            dbus_object.gsm_call_iface.SendDtmf( "*" )
+            self.text.append("*")
+        elif key in "hash":
+            dbus_object.gsm_call_iface.SendDtmf( "#" )
+            self.text += "#"
+        # The trailing whitespace is a workaround for the one char invisible
+        # bug due to some problems with scaling of text parts.
+        self.part_text_set("label", "".join(self.text)+" ")
+
+    @edje.decorators.signal_callback("call_button_pressed", "button_right")
+    def on_edje_signal_call_button_right_pressed(self, emission, source):
+        self.main.transition_to("call")
+
+    def sendMessage( self, index ):
+        logger.info( "trying to send message w/ index %d..." % index )
+        dbus_object.gsm_sim_iface.SendStoredMessage( index, reply_handler=self.cbSendReply, error_handler=self.cbSendError )
+
+    def cbSendReply( self, reference, timestamp ):
+        logger.info( "sent message successfully w/ reference number %d (timestamp: %s)" % ( reference, timestamp ) )
+
+    def cbSendError( self, e ):
+        logger.error( "could not send message. leaving in outgoing. error was: %s" % e )
+
+    def cbStoreReply( self, result ):
+        logger.info( "stored message lives at SIM position %d" % result )
+        self.sendMessage( result )
+        if not self.busy:
+            dbus_object.gsm_sim_iface.RetrieveMessagebook(
+                "all",
+                reply_handler=self.cbMessagebookReply,
+                error_handler=self.cbMessagebookError
+            )
+            self.busy = True
+
+    def cbStoreError( self, e ):
+        logger.warning( "error while storing message - %s" % e.get_dbus_name() )
+        if e.get_dbus_name() == "org.freesmartphone.GSM.SIM.MemoryFull":
+            self.main.groups["alert"].activate( "<title>Failed to send message</title>SIM Memory Full", [("OK")] )
+
+    def cbSend1( self, selected, cb_data ):
+        self.main.groups["text_edit"].setup(
+            "sms",
+            "", # text
+            selected[0], # title
+            selected[1], # reference
+            self.cbSend2
+        )
+
+    def cbSend2( self, text, number ):
+        if dbus_object.gsm_device_obj:
+            dbus_object.gsm_sim_iface.StoreMessage(
+                number, text, {},
+                reply_handler=self.cbStoreReply,
+                error_handler=self.cbStoreError
+            )
+
+    def cbDelete( self, result, reference ):
+        if result == "abort":
+            return
+        if dbus_object.gsm_device_obj:
+            dbus_object.gsm_sim_iface.DeleteMessage(
+                reference
+            )
+        for i in range( len( self.messagebook ) ):
+            if self.messagebook[i][0] == reference:
+                del self.messagebook[i]
+                break
+        self.updateList()
+
+    def cbForward( self, selected, text ):
+        if dbus_object.gsm_device_obj:
+            dbus_object.gsm_sim_iface.StoreMessage(
+                selected[1], text, {},
+                reply_handler=self.cbStoreReply,
+                error_handler=self.cbStoreError
+            )
+
+    def cbReply( self, text, number):
+        if dbus_object.gsm_device_obj:
+            dbus_object.gsm_sim_iface.StoreMessage(
+                number, text, {},
+                reply_handler=self.cbStoreReply,
+                error_handler=self.cbStoreError
+            )
+
+    def cbMenu( self, result ):
+        if result == _("send"):
+            self.main.groups["contacts"].prepare()
+            if self.main.groups["contacts"].ready:
+                self.main.groups["list_choose"].setup(
+                    "sms",
+                    [ (x[1], x[2]) for x in  self.main.groups["contacts"].phonebook],
+                    None,
+                    self.cbSend1
+                )
+        elif result == _("delete"):
+            self.main.groups["alert"].activate(
+                _("delete?"),
+                (_("abort"), _("delete")),
+                self.current[self.selected][0], # reference
+                self.cbDelete
+            )
+        elif result == _("forward"):
+            self.main.groups["contacts"].prepare()
+            if self.main.groups["contacts"].ready:
+                self.main.groups["list_choose"].setup(
+                    "sms",
+                    [ (x[1], x[2] ) for x in  self.main.groups["contacts"].phonebook],
+                    self.current[self.selected][3],
+                    self.cbForward
+                )
+        elif result == _("reply"):
+            self.main.groups["text_edit"].setup(
+                "sms",
+                "", # text
+                self.current[self.selected][2], # title = number
+                self.current[self.selected][2], # reference = number
+                self.cbReply
+            )
+
+    def cbMessagebookReply( self, result ):
+        logger.info( "retrieved messagebook: %s" % result )
+        self.busy = False
+        self.messagebook = result
+        self.ready = True
+        self.updateList()
+        self.main.groups["main"].targets["sms"] = True
+        self.main.groups["main"].update()
+        if not self.newindex is None:
+            message = [x for x in self.messagebook if x[0] == self.newindex]
+            self.newindex = None
+            if message and self.main.current_group == self.main.groups["main"]:
+                message = message[0]
+                if "read" in message[1]:
+                    from_to = _("From")
+                    timestamp = message[4]["timestamp"]
+                else:
+                    from_to = _("To")
+                    timestamp = _("Unknown")
+                from_text = self.main.groups["contacts"].tryNumberToName( message[2] )
+                self.main.groups["text_show"].setup(
+                    "sms",
+                    _("%s: %s<br>Date: %s<p>%s") % (
+                        from_to,
+                        from_text,
+                        timestamp,
+                        textblock_escape( message[3] ).replace( '\n', '<br>' )
+                    )
+                )
+            if dbus_object.gsm_device_obj:
+                messagebookInfo = dbus_object.gsm_sim_iface.GetMessagebookInfo()
+                if messagebookInfo["used"] == messagebookInfo["last"]:
+                    self.main.groups["alert"].activate( "<title>Warning</title>SIM Memory Full", [("OK")] )
+
+    def cbMessagebookError( self, e ):
+        logger.warning( "error while retrieving messagebook" )
+        self.busy = False
+
+    def onIncomingMessage( self, index ):
+        logger.info( "new message! Retrieving messagebook..." )
+        self.newindex = index
+        if not self.busy:
+            dbus_object.gsm_sim_iface.RetrieveMessagebook(
+                "all",
+                reply_handler=self.cbMessagebookReply,
+                error_handler=self.cbMessagebookError
+            )
+            self.busy = True
+
+    def prepare( self ):
+        if not self.ready and not self.busy:
+            if dbus_object.gsm_device_obj:
+                logger.info( "retrieving messagebook..." )
+                dbus_object.gsm_sim_iface.RetrieveMessagebook(
+                    "all",
+                    reply_handler=self.cbMessagebookReply,
+                    error_handler=self.cbMessagebookError
+                )
+                self.busy = True
+            else:
+                # Fake messagebook...
+                self.cbMessagebookReply( [
+                    (0, "read", "+4544555", "Hello World!"),
+                    (1, "read", "+456663443", "Zhone!"),
+                    (2, "read", "+456663443", "Hi Guy\nGuess what, I now "+
+                        "know to write multi-line SMSs.\nIsn't that "+
+                        "nice?\n\nSome Buddy"),
+                    (3, "read", "Flash SMS", "An SMS without digits. Strange, isn't it?"),
+                ] )
+
+    def onReadyStatus( self, status ):
+        logger.debug( "SIM is ready: %s" % status )
+        if status:
+            # Force update
+            self.ready = False
+            self.prepare()
+
+    def onShow( self ):
+        self.prepare()
+        self.updateList()
+
+    def updateList( self):
+        self.main.groups["contacts"].prepare()
+        self.pages = max( ( len( self.messagebook ) - 1 ) / 6 + 1, 1 )
+        if self.page >= self.pages:
+            self.page = self.pages - 1
+        if self.page < 0:
+            self.page = 0
+        self.current = self.messagebook[self.page*6:(self.page+1)*6]
+        text = u"".join( [u"□"]*self.page+[u"▣"]+[u"□"]*(self.pages-self.page-1) )
+        self.part_text_set( "pager", text )
+        for i in range( 0, len( self.current ) ):
+            main_text = self.main.groups["contacts"].tryNumberToName( self.current[i][2] )
+            self.part_text_set( "label_main_list_%i" % i, main_text )
+            sub_text = " ".join(self.current[i][3].splitlines())
+            self.part_text_set( "label_sub_list_%i" % i, u"(%s) %s" % ( self.current[i][1], sub_text ) )
+        for i in range( len( self.current ), 6):
+            self.part_text_set( "label_main_list_%i" % i, u"" )
+            self.part_text_set( "label_sub_list_%i" % i, u"" )
+        self.selected = None
+        for i in range( 6 ):
+            self.signal_emit( "deactivate_target_list_%i" % i, "" )
+
+
+    @edje.decorators.signal_callback( "mouse,clicked,1", "target_list_*" )
+    def on_edje_signal_button_list_pressed( self, emission, source ):
+        id = int( source.split( "_" )[-1] )
+        if self.selected == id:
+            return
+        if self.selected is not None:
+            self.signal_emit( "deactivate_target_list_%i" % self.selected, "" )
+        self.signal_emit( "activate_target_list_%i" % id, "" )
+        self.selected = id
+
+    @edje.decorators.signal_callback( "mouse,clicked,1", "button_action_left" )
+    def on_edje_signal_button_action_left_pressed( self, emission, source ):
+        self.page -= 1
+        self.updateList()
+
+    @edje.decorators.signal_callback( "mouse,clicked,1", "button_action_right" )
+    def on_edje_signal_button_action_right_pressed( self, emission, source ):
+        self.page += 1
+        self.updateList()
+
+    @edje.decorators.signal_callback( "mouse,clicked,1", "button_action_open" )
+    def on_edje_signal_button_action_open_pressed( self, emission, source ):
+        if self.selected is not None:
+            if "read" in self.current[self.selected][1]:
+                from_to = _("From")
+                timestamp = self.current[self.selected][4]["timestamp"]
+            else:
+                from_to = _("To")
+                timestamp = _("Unknown")
+            from_text = self.main.groups["contacts"].tryNumberToName( self.current[self.selected][2] )
+            self.main.groups["text_show"].setup(
+                "sms",
+                _("%s: %s<br>Date: %s<p>%s") % (
+                    from_to,
+                    from_text,
+                    timestamp,
+                    textblock_escape( self.current[self.selected][3] ).replace( '\n', '<br>' )
+                )
+            )
+
+    @edje.decorators.signal_callback( "mouse,clicked,1", "button_bottom_middle" )
+    def on_edje_signal_button_bottom_middle_pressed( self, emission, source ):
+        self.main.groups["menu"].activate( ( _("send"), _("delete"), _("forward"), _("reply") ), self.cbMenu )
+        self.main.groups["menu"].part_text_set( "target_label_cancel", _("cancel") )
+*/
+}
+
 static int main (string[] args) {
        Gtk.init (ref args);
-    Gst.init (ref args);
+    // Gst.init (ref args);
 
        // Set up zavai
+       sbus = DBus.Bus.get(DBus.BusType.SYSTEM);
 
     // Core infrastructure
-       zavai.config = new zavai.Config();
-       zavai.config.argv0 = args[0];
-       zavai.registry = new zavai.Registry();
+//     zavai.config = new zavai.Config();
+//     zavai.config.argv0 = args[0];
+//     zavai.registry = new zavai.Registry();
 
     // Additional infrastructure
-       zavai.gsm.init();
-       zavai.log.init();
+       //zavai.gsm.init();
+       //zavai.log.init();
 
     // PLAY here
+    var gr = new GSMReceive();
 
        Gtk.main();
 
        // zavai.info("Shutting down")
-       zavai.registry.shutdown();
+       // zavai.registry.shutdown();
 
        return 0;
 }
diff --git a/zavai/CMakeLists.txt b/zavai/CMakeLists.txt
deleted file mode 100644 (file)
index 76f8252..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-project(libzavai)
-include(../vala.cmake)
-
-set(zavai_version 0.1)
-
-set(packages dbus-glib-1>=0.80 lua5.1 libomhacks x11 gdk-x11-2.0 libgps gstreamer-0.10)
-add_packages(LIBZAVAI ${packages})
-
-set(VALA_PACKAGES ${packages} posix linux-input dbus-extra)
-set(VFLAGS --vapidir=${libzavai_SOURCE_DIR})
-add_definitions(-Wall)
-# -Werror 
-
-pkg_check_modules(DKP devkit-power-gobject>=010)
-if (DKP_VERSION)
-  message("-- Using devkit-power-gobject version ${DKP_VERSION}")
-  set(VFLAGS ${VFLAGS} --define=USE_DKP)
-  set(VALA_PACKAGES ${VALA_PACKAGES} devkit-power-gobject)
-  add_definitions(-DUSE_DKP ${DKP_CFLAGS})
-  link_libraries(${DKP_LDFLAGS})
-else()
-  message("-- Not using devkit-power-gobject")
-endif ()
-
-file(GLOB libvala [a-y]*.vala)
-add_vala_library(libzavai ${libvala})
-add_library(libzavai STATIC ${libzavai_CSOURCES})
-
-set_target_properties(libzavai PROPERTIES VERSION ${zavai_version} SOVERSION 0 OUTPUT_NAME "zavai" CLEAN_DIRECT_OUTPUT 1)
-
-add_definitions(-I${zavai_BINARY_DIR})
-set(VFLAGS ${VFLAGS} --vapidir=${zavai_BINARY_DIR})
diff --git a/zavai/at.vala b/zavai/at.vala
deleted file mode 100644 (file)
index 33cdf27..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * at - at interface
- *
- * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace at {
-
-public struct Event
-{
-       int id;
-       time_t deadline;
-}
-
-// Return the earliest ID in the queue, or -1 if none are found
-// Queue is null for all queues, otherwise a queue name
-public static Event earliestID(string? queue = null)
-{
-       Event res = { -1, 0 };
-
-       string argv[4];
-       argv[0] = "/usr/bin/atq";
-       if (queue == null)
-               argv[1] = null;
-       else
-       {
-               argv[1] = "-q";
-               argv[2] = queue;
-               argv[3] = null;
-       }
-
-       Pid pid;
-       int stdout;
-
-       try
-       {
-               if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdout, null))
-                       return res;
-       } catch (SpawnError e) {
-               stderr.printf("Cannot run 'at -q': %s\n", e.message);
-               return res;
-       }
-
-       FileStream fs = FileStream.fdopen(stdout, "r");
-       if (fs == null)
-               return res;
-
-       char buf[200];
-       string? line;
-       while ((line = fs.gets(buf)) != null)
-       {
-               if (!line[0].isdigit()) continue;
-               weak string rest;
-               ulong id = line.to_ulong(out rest, 10);
-               Time t = Time();
-               rest = t.strptime(rest.offset(1), "%a %b %d %H:%M:%S %Y");
-               if (rest == null) continue;
-               if (rest.size() < 2) continue;
-               //stderr.printf("PARSE QUEUE rest %s\n", rest);
-               // Skip the queue of tasks currently being executed
-               //if (rest[1] == '=') continue;
-               // Skip entries not in the wanted queue
-               if (queue != null && rest[1] != queue[0]) continue;
-               time_t tt = t.mktime();
-               if (res.deadline == 0 || tt < res.deadline) {
-                       res.id = (int)id;
-                       res.deadline = tt;
-               }
-       }
-       Process.close_pid(pid);
-       return res;
-}
-
-public delegate bool jobParser(int fd);
-
-// Get the contents of a job given its id
-public static bool jobContents(int id, jobParser parser)
-{
-       string argv[4];
-       argv[0] = "/usr/bin/at";
-       argv[1] = "-c";
-       argv[2] = id.to_string();
-       argv[3] = null;
-
-       Pid pid;
-       int stdoutfd;
-
-       try
-       {
-               if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdoutfd, null))
-                       return false;
-       } catch (SpawnError e) {
-               stderr.printf("Cannot run 'at -c': %s\n", e.message);
-               return false;
-       }
-
-       bool res = parser(stdoutfd);
-
-       Process.close_pid(pid);
-
-       return res;
-}
-
-/*
-TODO: schedule alarms via at
-
-Uses the 'z' queue.
-
-atq -q z  can be used to list the jobs (for example, at startup, or after a job has run)
-at -c id  can be used to query a job, parsing its contents (which can have
-          comments or variables being set)
-zavai --notify ...  can be used to notify the job (and start zavai if it's not running)
-
-Alarm needs to be able to serialize itself to an at invocation and to
-deserialize itself from the output of at -c
-
-Alarm needs to deserialize also a job with no special markers whatsoever: a
-generic at job.
-*/
-
-
-/*
-public class Alarm : Object
-{
-       // TODO: make a factory method to construct from an "at -c" output
-
-       // TODO: make a method that provides an at invocation
-
-       public signal void trigger(Alarm a);
-
-       public time_t deadline;
-       public string label;
-
-       public Alarm(time_t deadline, string label)
-       {
-               this.deadline = deadline;
-               this.label = label;
-       }
-}
-*/
-
-       // Schedule a task that notifies a string
-       // TODO public void schedule_label(const Alarm a);
-
-       // Return the next item in the queue due to be run
-       // TODO public Alarm? next_scheduled();
-
-}
diff --git a/zavai/audio.vala b/zavai/audio.vala
deleted file mode 100644 (file)
index 1c39420..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * audio - audio resource for zavai
- *
- * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace zavai {
-namespace audio {
-
-public class Audio: zavai.Service
-{
-    protected Omhacks.Led vibrator;
-    protected bool has_vibrator;
-
-    /*
-       protected dynamic DBus.Object audiodev;
-       protected dynamic DBus.Object vibdev;
-   */
-
-    public Audio()
-    {
-        Object(name: "audio");
-
-        has_vibrator = (vibrator.init("neo1973:vibrator") == 0);
-
-/*
-        audiodev = zavai.registry.sbus.get_object(
-                "org.freesmartphone.odeviced",
-                "/org/freesmartphone/Device/Audio",
-                "org.freesmartphone.Device.Audio");
-        vibdev = zavai.registry.sbus.get_object(
-                "org.freesmartphone.odeviced",
-                "/org/freesmartphone/Device/LED/neo1973_vibrator",
-                "org.freesmartphone.Device.LED");
-*/
-        clock.alarm_trigger_queue.triggered += on_alarm_trigger;
-        clock.alarm_trigger_queue.acked += on_alarm_done;
-        clock.alarm_trigger_queue.canceled += on_alarm_done;
-    }
-
-    public void on_alarm_trigger(clock.AlarmTriggerInfo info)
-    {
-        zavai.log.debug("Make noise for alarm");
-        if (has_vibrator)
-        {
-            vibrator.brightness = 256;
-            // FIXME: is there a better way? I hope there is a better way. Please
-            // tell me there is a better way.
-            var trig = "timer";
-            for (int i = 0; ; ++i)
-            {
-                vibrator.trigger[i] = (char)trig[i];
-                if (trig[i] == 0) break;
-            }
-            vibrator.delay_on = 200;
-            vibrator.delay_off = 300;
-            vibrator.set();
-        }
-        soundplayer.play(config.ringtone_alarm, true);
-    }
-
-    public void on_alarm_done(clock.AlarmTriggerInfo info)
-    {
-        zavai.log.debug("Stop noise for alarm");
-        if (has_vibrator)
-        {
-            var trig = "none";
-            for (int i = 0; ; ++i)
-            {
-                vibrator.trigger[i] = (char)trig[i];
-                if (trig[i] == 0) break;
-            }
-            vibrator.brightness = 0;
-            vibrator.set();
-        }
-        soundplayer.stop();
-    }
-
-/*
-    public void notify_alarm(zavai.clock.Alarm a)
-    {
-        // Wiggle screen to turn on backlight
-        zavai.ui.power.backlight.wiggle();
-        try {
-            // Method does not exist in this frameworkd
-            vibdev.BlinkSeconds(5, 500, 200);
-        } catch (Error e) {
-            zavai.log.error("Cannot blink vibrator: " + e.message);
-        }
-        // TODO: play music?
-    }
-*/
-}
-
-public class Player: zavai.Resource, Object
-{
-    protected Gst.Element player;
-    protected bool playing;
-    protected Player slave;
-    protected Player master;
-    protected bool loop;
-    protected string uri;
-    public signal void state_changed(Gst.State new_state);
-
-    public Player()
-    {
-        slave = null;
-        master = null;
-        player = Gst.ElementFactory.make("playbin", null);
-        playing = false;
-        loop = false;
-        var bus = player.get_bus();
-        bus.add_signal_watch();
-        bus.message += on_message;
-    }
-
-    public void set_slave(Player player)
-    {
-        slave = player;
-        slave.master = this;
-    }
-
-    public void play(string uri, bool loop = false)
-    {
-stderr.printf("Playing %s\n", uri);
-        this.uri = uri;
-
-        if (slave != null && slave.playing)
-            slave.pause();
-
-        player.set_property("uri", uri);
-        player.set_state(master != null && master.playing ? Gst.State.PAUSED : Gst.State.PLAYING);
-        playing = true;
-        this.loop = loop;
-    }
-
-    public Gst.State get_state()
-    {
-        Gst.State state;
-        Gst.State pending;
-
-        player.get_state(out state, out pending, (Gst.ClockType)Gst.CLOCK_TIME_NONE);
-
-        return state;
-    }
-
-    public void pause()
-    {
-        player.set_state(Gst.State.PAUSED);
-        state_changed(Gst.State.PAUSED);
-    }
-
-    public void resume()
-    {
-        player.set_state(Gst.State.PLAYING);
-        state_changed(Gst.State.PLAYING);
-    }
-
-    public void restart()
-    {
-        player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
-        player.set_state(Gst.State.PLAYING);
-        state_changed(Gst.State.PLAYING);
-    }
-
-    public void stop()
-    {
-        playing = false;
-        player.set_state(Gst.State.NULL);
-        state_changed(Gst.State.NULL);
-
-        // Resume slave after we are done
-        if (slave != null && slave.playing)
-            slave.resume();
-    }
-
-    protected void on_message(Gst.Message message)
-    {
-        if (message.type == Gst.MessageType.EOS)
-        {
-            if (loop)
-                restart();
-            else
-                stop();
-        }
-    }
-
-    public void shutdown()
-    {
-        stop();
-    }
-}
-
-public Audio audio = null;
-public Player musicplayer = null;
-public Player soundplayer = null;
-
-public void init()
-{
-    audio = new Audio();
-    musicplayer = new Player();
-    soundplayer = new Player();
-    soundplayer.set_slave(musicplayer);
-    zavai.registry.register(musicplayer);
-    zavai.registry.register(soundplayer);
-}
-
-}
-}
diff --git a/zavai/bluetooth.vala b/zavai/bluetooth.vala
deleted file mode 100644 (file)
index 0103d0f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * bluetooth - bluetooth resource for zavai
- *
- * Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace zavai {
-namespace bluetooth {
-
-public class Bluetooth: zavai.ScriptService
-{
-    public Bluetooth()
-    {
-        Object(name: "bluetooth");
-        started = script_status();
-    }
-
-    /// Start Bluetooth
-    public override void start()
-    {
-        if (started) return;
-        if (!script_start()) return;
-        zavai.log.info("bluetooth turned on");
-        base.start();
-    }
-
-    // Release usage of GPS
-    public override void stop()
-    {
-        if (!started) return;
-        script_stop();
-        base.stop();
-    }
-}
-
-public Bluetooth bluetooth = null;
-
-public void init()
-{
-    bluetooth = new Bluetooth();
-
-}
-
-}
-}
diff --git a/zavai/clock.vala b/zavai/clock.vala
deleted file mode 100644 (file)
index d08717b..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * clock - clock resource for zavai
- *
- * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace zavai {
-namespace clock {
-
-public enum SourceType
-{
-    SYSTEM,
-    GPS
-}
-
-/*
-TODO: schedule alarms via at
-
-Uses the 'z' queue.
-
-atq -q z  can be used to list the jobs (for example, at startup, or after a job has run)
-at -c id  can be used to query a job, parsing its contents (which can have
-          comments or variables being set)
-zavai --notify ...  can be used to notify the job (and start zavai if it's not running)
-
-Alarm needs to be able to serialize itself to an at invocation and to
-deserialize itself from the output of at -c
-
-Alarm needs to deserialize also a job with no special markers whatsoever: a
-generic at job.
-
-
-
-refresh_alarms()
-{
-    oldtime = next_alarm ? next_alarm.time : 0
-    next_alarm = the first alarm from atq
-    if (oldtime != next_alarm.time)
-    {
-        remove existing triggers
-          (triggers can be skipped if we don't need to support non-zavai alarms)
-        schedule a trigger calling refresh_alarms() at next_alarm.time + 30 seconds
-          (triggers can be skipped if we don't need to support non-zavai alarms)
-    }
-}
-
-at clock constructor: refresh_alarms()
-inotifywait -e close /usr/bin/at -> refresh_alarms()  (shows when someone has just used at)
-  (can be skipped if we don't need to support non-zavai alarms)
-at alarm triggered through zavai: refresh_alarms()
-
-
-*/
-
-
-public class Alarm : Object
-{
-    public at.Event ev;
-    public string label;
-
-    // Schedule with at
-    public static void schedule(string timespec, string label) throws Error
-    {
-        string argv[5];
-        argv[0] = "/usr/bin/at";
-        argv[1] = "-q";
-        argv[2] = "z";
-        argv[3] = timespec;
-        argv[4] = null;
-
-        Pid pid;
-        int stdinfd;
-
-        if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, out stdinfd, null, null))
-            return;
-
-        {
-            FileStream fs = FileStream.fdopen(stdinfd, "w");
-            string display = GLib.Environment.get_variable("DISPLAY");
-            if (display != null)
-                fs.printf("DISPLAY=\"%s\"; export DISPLAY\n", display);
-            fs.printf("# Zavai variables start here\n");
-            fs.printf("ZAVAI_LABEL=\"%s\"\n", label.escape(""));
-            fs.printf("# Zavai commands starts here\n");
-            fs.printf("%s notify \"$ZAVAI_LABEL\"", zavai.config.argv0);
-        }
-        
-        Process.close_pid(pid);
-    }
-
-    // Get the label of the job with the given at ID
-    public static string? getLabel(int atID)
-    {
-        string label = null;
-        at.jobContents(atID, fd => {
-            FileStream fs = FileStream.fdopen(fd, "r");
-            while (true)
-            {
-                string? line = fs.read_line();
-                if (line == null) break;
-                if (line.has_prefix("ZAVAI_LABEL=\""))
-                {
-                    size_t size = line.size();
-                    if (size < 15) continue;
-                    label = line.substring(13, (long)(size - 14));
-                    label = label.compress();
-                    break;
-                }
-            }
-            return true;
-        });
-        return label;
-    }
-}
-
-[DBus (name = "org.enricozini.zavai.Alarm")]
-public class ZavaiClock : Object {
-    public void Notify (string label) {
-        clock.notify_alarm(label);
-    }
-}
-
-public class AlarmTriggerInfo
-{
-    public uint id;
-    public string label;
-    public bool acked;
-    public bool canceled;
-
-    public AlarmTriggerInfo(string label)
-    {
-        id = 0;
-        this.label = label;
-        acked = false;
-        canceled = false;
-    }
-}
-
-public class AlarmTriggerQueue : zavai.Service
-{
-    protected List<AlarmTriggerInfo> queue;
-
-    public signal void triggered(AlarmTriggerInfo info);
-    public signal void acked(AlarmTriggerInfo info);
-    public signal void canceled(AlarmTriggerInfo info);
-
-    public AlarmTriggerQueue()
-    {
-        queue = new List<AlarmTriggerInfo>();
-    }
-
-    public uint enqueue_trigger(AlarmTriggerInfo info)
-    {
-        // Reuse IDs from the associated logger object
-        info.id = zavai.log.log.start("alarm", "Alarm " + info.label);
-        queue.append(info);
-        if (queue.data.id == info.id)
-            triggered(queue.data);
-        return info.id;
-    }
-
-    protected void done_with_first()
-    {
-        var first = queue.data;
-        queue.remove_link(queue);
-        if (queue != null)
-            triggered(queue.data);
-    }
-
-    public void ack(AlarmTriggerInfo info)
-    {
-        if (queue == null || info.id != queue.data.id) return;
-        if (!info.acked && !info.canceled)
-        {
-            info.acked = true;
-            acked(info);
-            zavai.log.log.add(info.id, "alarm acknowledged");
-            zavai.log.log.end(info.id);
-        }
-        done_with_first();
-    }
-
-    public void cancel(AlarmTriggerInfo info)
-    {
-        if (queue == null || info.id != queue.data.id) return;
-        if (!info.acked && !info.canceled)
-        {
-            info.canceled = true;
-            canceled(info);
-            zavai.log.log.add(info.id, "alarm canceled");
-            zavai.log.log.end(info.id);
-        }
-        done_with_first();
-    }
-}
-
-public class Clock: zavai.Service
-{
-    protected time_t last_gps_time;
-    protected time_t last_gps_time_system_time;
-    protected time_t last_system_time;
-    protected uint system_time_timeout;
-    protected time_t last_minute;
-    protected time_t chosen_time;
-    protected SourceType chosen_type;
-    protected ZavaiClock dbusClock;
-
-    protected dynamic DBus.Object otimed_alarm;
-    protected dynamic DBus.Object rtc;
-    protected SList<Alarm> alarms;
-
-    // Ticks once a minute
-    public signal void minute_changed(long time, SourceType source);
-    public signal void schedule_changed(Alarm? next);
-
-    public Clock()
-    {
-        Object(name: "clock");
-        alarms = null;
-        dbusClock = new ZavaiClock();
-        last_minute = 0;
-        last_gps_time = 0;
-        last_gps_time_system_time = 0;
-        last_system_time = time_t();
-        chosen_time = last_system_time;
-
-        // FSO alarm system
-        otimed_alarm = zavai.registry.sbus.get_object(
-                "org.freesmartphone.otimed",
-                "/org/freesmartphone/Time/Alarm",
-                "org.freesmartphone.Time.Alarm");
-
-        rtc = zavai.registry.sbus.get_object(
-                "org.freesmartphone.odeviced",
-                "/org/freesmartphone/Device/RTC/0",
-                "org.freesmartphone.Device.RealtimeClock");
-
-        zavai.registry.sbus.register_object("/org/enricozini/Zavai/Clock", dbusClock);
-    }
-
-    public void notify_alarm(string label)
-    {
-        stderr.printf("Notifying %s\n", label);
-        AlarmTriggerInfo info = new AlarmTriggerInfo(label);
-        alarm_trigger_queue.enqueue_trigger(info);
-        schedule_changed(next_alarm());
-    }
-
-    public Alarm? next_alarm()
-    {
-        at.Event ev;
-        ev = at.earliestID("z");
-        if (ev.deadline == 0)
-            return null;
-        string label = Alarm.getLabel(ev.id);
-        Alarm res = new Alarm();
-        res.ev = ev;
-        res.label = label;
-        return res;
-    }
-
-    public void schedule(string timespec, string label) throws Error
-    {
-        Alarm.schedule(timespec, label);
-        schedule_changed(next_alarm());
-    }
-
-    private void on_gps_time(uint t)
-    {
-        if (t == 0)
-        {
-            last_gps_time_system_time = 0;
-            update_time();
-        } else {
-            last_gps_time = (time_t)t;
-            last_gps_time_system_time = time_t();
-            update_time();
-        }
-    }
-
-    private bool on_system_time()
-    {
-        last_system_time = time_t();
-        update_time();
-        return true;
-    }
-
-    private void update_time()
-    {
-        if (last_gps_time_system_time + 10 > last_system_time)
-        {
-            chosen_time = last_gps_time;
-            chosen_type = SourceType.GPS;
-        }
-        else
-        {
-            chosen_time = last_system_time;
-            chosen_type = SourceType.SYSTEM;
-        }
-        if (chosen_time / 60 != last_minute)
-        {
-            last_minute = chosen_time / 60;
-            minute_changed(chosen_time, chosen_type);
-        }
-    }
-
-    /// Request GPS resource
-    public override void start()
-    {
-        if (started) return;
-
-        system_time_timeout = Timeout.add(5000, on_system_time);
-        zavai.gps.gps.time_changed += on_gps_time;
-        last_system_time = time_t();
-        update_time();
-
-        base.start();
-    }
-
-    public override void stop()
-    {
-        if (!started) return;
-
-        Source.remove(system_time_timeout);
-        zavai.gps.gps.time_changed -= on_gps_time;
-
-        base.stop();
-    }
-}
-
-public Clock clock = null;
-public AlarmTriggerQueue alarm_trigger_queue = null;
-
-public void init()
-{
-    clock = new Clock();
-    alarm_trigger_queue = new AlarmTriggerQueue();
-}
-
-}
-}
diff --git a/zavai/config.vala b/zavai/config.vala
deleted file mode 100644 (file)
index 444bbc2..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * config - zavai configuration
- *
- * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-namespace zavai {
-
-public class Config
-{
-    protected Lua.LuaVM lua;
-    protected weak string get_string(string name)
-    {
-        lua.get_global(name);
-        weak string res = lua.to_string(-1);
-        lua.pop(1);
-        return res;
-    }
-    protected string set_string(string name, string? val)
-    {
-        if (val == null)
-            lua.push_nil();
-        else
-            lua.push_string(val);
-        lua.set_global(name);
-        return val;
-    }
-    protected weak int get_int(string name)
-    {
-        lua.get_global(name);
-        int res = lua.to_integer(-1);
-        lua.pop(1);
-        return res;
-    }
-    protected int set_int(string name, int val)
-    {
-        lua.push_integer(val);
-        lua.set_global(name);
-        return val;
-    }
-
-    private string _version;
-    public string version
-    {
-        get { return _version; }
-        set { _version = set_string("version", value); }
-    }
-
-    // "phone" or "laptop"
-    private string _profile;
-    public string profile
-    {
-        get { return _profile; }
-        set { _profile = set_string("profile", value); }
-    }
-
-    private string _homedir;
-    public string homedir
-    {
-        get { return _homedir; }
-        set { _homedir = set_string("homedir", value); }
-    }
-
-    private string _icondir;
-    public string icondir
-    {
-        get { return _icondir; }
-        set { _icondir = set_string("icondir", value); }
-    }
-
-    private int _min_button_height;
-    public int min_button_height
-    {
-        get { return _min_button_height; }
-        set { _min_button_height = set_int("min_button_height", value); }
-    }
-
-    private string _gpsd_host;
-    public string gpsd_host
-    {
-        get { return _gpsd_host; }
-        set { _gpsd_host = set_string("gpsd_host", value); }
-    }
-
-    private string _gpsd_port;
-    public string gpsd_port
-    {
-        get { return _gpsd_port; }
-        set { _gpsd_port = set_string("gpsd_port", value); }
-    }
-
-    private string _gprs_apn;
-    public string gprs_apn
-    {
-        get { return _gprs_apn; }
-        set { _gprs_apn = set_string("gprs_apn", value); }
-    }
-
-    private string _gprs_user;
-    public string gprs_user
-    {
-        get { return _gprs_user; }
-        set { _gprs_user = set_string("gprs_user", value); }
-    }
-
-    private string _gprs_pass;
-    public string gprs_pass
-    {
-        get { return _gprs_pass; }
-        set { _gprs_pass = set_string("gprs_pass", value); }
-    }
-
-    private string _sim_pin;
-    public string sim_pin
-    {
-        get { return _sim_pin; }
-        set { _sim_pin = set_string("sim_pin", value); }
-    }
-
-    private int _power_button_keycode;
-    public int power_button_keycode
-    {
-        get { return _power_button_keycode; }
-        set { _power_button_keycode = set_int("power_button_keycode", value); }
-    }
-
-    private int _aux_button_keycode;
-    public int aux_button_keycode
-    {
-        get { return _aux_button_keycode; }
-        set { _aux_button_keycode = set_int("aux_button_keycode", value); }
-    }
-
-    private string _ringtone_alarm;
-    public string ringtone_alarm
-    {
-        get { return _ringtone_alarm; }
-        set { _ringtone_alarm = set_string("ringtone_alarm", value); }
-    }
-
-    public int backlight_max
-    {
-        get;
-        set;
-    }
-
-    private string _argv0;
-    public string argv0 {
-        get { return _argv0; }
-        set {
-            if (value.chr(-1, '/') != null)
-            {
-                if (Path.is_absolute(value))
-                {
-                    _argv0 = value;
-                } else {
-                    _argv0 = Path.build_filename(Environment.get_current_dir(), value, null);
-                }
-            } else {
-                _argv0 = Environment.find_program_in_path(value);
-            }
-            zavai.log.debug("ARGV0: " + _argv0);
-        }
-    }
-
-    /// Reread config values from the Lua VM, to be run after running Lua code
-    protected void refresh_from_lua()
-    {
-        _version = get_string("version");
-        _profile = get_string("profile");
-        _homedir = get_string("homedir");
-        _icondir = get_string("icondir");
-        _min_button_height = get_int("min_button_height");
-        _gpsd_host = get_string("gpsd_host");
-        _gpsd_port = get_string("gpsd_port");
-        _gprs_apn = get_string("gprs_apn");
-        _gprs_user = get_string("gprs_user");
-        _gprs_pass = get_string("gprs_pass");
-        _sim_pin = get_string("sim_pin");
-        _power_button_keycode = get_int("power_button_keycode");
-        _aux_button_keycode = get_int("aux_button_keycode");
-        _ringtone_alarm = get_string("ringtone_alarm");
-    }
-
-    public Config()
-    {
-        lua = new Lua.LuaVM();
-        lua.open_libs();
-
-        // Set defaults
-        version = "0.1";
-        profile = "phone";
-        homedir = GLib.Environment.get_home_dir() + "/.zavai";
-        icondir = GLib.Environment.get_variable("ZAVAI_ICONDIR");
-        if (icondir == null)
-                icondir = "/usr/share/zavai/icons";
-        min_button_height = 80;
-        gpsd_host = "localhost";
-        gpsd_port = "gpsd";
-        gprs_apn = "general.t-mobile.uk";
-        gprs_user = "x";
-        gprs_pass = "x";
-        sim_pin = "1234";
-        backlight_max = 15;
-        power_button_keycode = 124;
-        aux_button_keycode = 177;
-        ringtone_alarm = "file:///usr/share/sounds/yue-fso/lec1.ogg";
-
-        // Read config
-        if (lua.do_file(homedir + "/config"))
-        {
-            zavai.log.error("Failed to parse " + homedir + "/config: " + lua.to_string(-1));
-        }
-        refresh_from_lua();
-    }
-
-    public void run_script(string command)
-    {
-        zavai.log.info("Run program: " + command);
-        string[] args = command.split(" ");
-        Pid pid;
-        try {
-            Process.spawn_async(
-                Environment.get_home_dir(),
-                args,
-                null,
-                SpawnFlags.SEARCH_PATH,
-                null,
-                out pid);
-        } catch (SpawnError e) {
-            zavai.log.error("Running " + command + ": " + e.message);
-        }
-    }
-
-    public int run_script_sync(string command, out string std_out, out string std_err)
-    {
-        int status = -1;
-        zavai.log.info("Run program: " + command);
-        string[] args = command.split(" ");
-        try {
-            bool res = Process.spawn_sync(Environment.get_home_dir(), args, null, SpawnFlags.SEARCH_PATH, null, out std_out, out std_err, out status);
-        } catch (SpawnError e) {
-            zavai.log.error("Running " + command + ": " + e.message);
-        }
-        return status;
-    }
-}
-
-public Config config = null;
-
-}
diff --git a/zavai/core.vala b/zavai/core.vala
deleted file mode 100644 (file)
index 3c31ccd..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * app - zavai main window
- *
- * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace zavai {
-
-public interface Resource : Object {
-    /**
-     * Shut down this resource.
-     *
-     * Normally one does nothing here, but it is important to give resources a
-     * chance to do cleanup when the program quits.
-     * 
-     * This can be used for tasks like closing the tags on a GPX track,
-     * releasing a FSO resource, restoring mixer settings and so on.
-     */
-    public abstract void shutdown();
-}
-
-public abstract class Service : Object, Resource {
-    public string name { get; construct; }
-
-    bool _started;
-    public bool started {
-        get { return _started; }
-        set { _started = value; }
-    }
-
-    public signal void toggled(bool new_state);
-
-    protected class Request
-    {
-        public string requestor;
-        public int count;
-        public Request(string requestor)
-        {
-            this.requestor = requestor;
-            count = 1;
-        }
-    }
-
-    protected List<Request> requests;
-
-    construct
-    {
-        started = false;
-        requests = null;
-        zavai.registry.register(this);
-    }
-
-    public void shutdown()
-    {
-        stop();
-    }
-
-    /// Activate the service
-    protected virtual void start()
-    {
-        if (!started)
-        {
-            zavai.log.info("Service " + name + " started\n");
-            started = true;
-            toggled(started);
-        }
-    }
-
-    /// Deactivate the service
-    protected virtual void stop()
-    {
-        if (started)
-        {
-            zavai.log.info("Service " + name + " stopped\n");
-            started = false;
-            toggled(started);
-        }
-    }
-
-    /**
-      Request a resource using the given ID.
-     *
-     * If it is the first time the resource is requested, start it and
-     * return true. Else, take note of the request and return false.
-     *
-     * If a resource is requested multiple times with the same ID, it will
-     * need to be released multiple times with that ID.
-     */
-    public bool request(string id)
-    {
-        bool res = (requests == null);
-        bool got = false;
-        for (weak List<Request> i = requests; i != null; i = i.next)
-            if (i.data.requestor == id)
-            {
-                ++i.data.count;
-                got = true;
-                break;
-            }
-        if (!got)
-            requests.prepend(new Request(id));
-        if (res) start();
-        return res;
-    }
-
-    /**
-     * Release a resource using the given ID.
-     *
-     * If after the call nothing is requesting the resource, stop it and
-     * return true. Else, take note of the release and return false.
-     *
-     * If a resource is requested multiple times with the same ID, it will
-     * need to be released multiple times with that ID.
-     */
-    public bool release(string id)
-    {
-        weak List<Request> el = null;
-        for (weak List<Request> i = requests; i != null; i = i.next)
-            if (i.data.requestor == id)
-            {
-                el = i;
-                break;
-            }
-
-        if (el == null)
-            return false;
-
-        requests.delete_link(el);
-
-        if (requests != null)
-            return false;
-
-        stop();
-        return true;
-    }
-}
-
-public abstract class ScriptService : Service
-{
-    protected bool script_start()
-    {
-        try {
-            // Then run our own script
-            zavai.config.run_script(zavai.config.homedir + "/" + name + " start");
-            return true;
-        } catch (Error e) {
-            zavai.log.error("Running " + zavai.config.homedir + "/" + name + " start: " + e.message);
-            return false;
-        }
-    }
-
-    protected bool script_stop()
-    {
-        try {
-            // Then run our own script
-            zavai.config.run_script(zavai.config.homedir + "/" + name + " stop");
-            return true;
-        } catch (Error e) {
-            zavai.log.error("Running " + zavai.config.homedir + "/" + name + " stop: " + e.message);
-            return false;
-        }
-    }
-
-    protected bool script_status()
-    {
-        string std_out;
-        string std_err;
-        string command = zavai.config.homedir + "/" + name + " status";
-        int res = zavai.config.run_script_sync(command, out std_out, out std_err);
-        if (res != 0)
-        {
-            zavai.log.error("Running " + command + ": " + std_err);
-            return false;
-        }
-
-        std_out._strip();
-
-        return (std_out == "on");
-    }
-}
-
-public abstract class ScriptMonitorService : Service
-{
-    protected Pid child_pid;
-    protected int child_watch_id;
-
-    ScriptMonitorService()
-    {
-        child_pid = 0;
-        child_watch_id = 0;
-    }
-
-    protected bool script_start()
-    {
-        string command = zavai.config.homedir + "/" + name + " pre";
-        try {
-            // Then run our own script
-            zavai.config.run_script(command);
-        } catch (Error e) {
-            zavai.log.error("Running " + command + ": " + e.message);
-            return false;
-        }
-
-        command = zavai.config.homedir + "/" + name + " run";
-        zavai.log.info("Run program: " + command);
-        string[] args = command.split(" ");
-        try {
-            Process.spawn_async(
-                Environment.get_home_dir(),
-                args,
-                null,
-                SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
-                null,
-                out child_pid);
-        } catch (SpawnError e) {
-            zavai.log.error("Running " + command + ": " + e.message);
-            return false;
-        }
-
-        // Add a child watch source to know when it ends
-        ChildWatch.add(child_pid, on_child);
-
-        return true;
-    }
-
-    protected bool script_stop()
-    {
-        Posix.kill((Posix.pid_t)child_pid, Posix.SIGTERM);
-        return true;
-    }
-
-    protected void on_child(Pid pid, int status)
-    {
-        zavai.log.info("Exited");
-stderr.printf("STATUS %d\n", status);
-        Process.close_pid(pid);
-
-        string command = zavai.config.homedir + "/" + name + " post";
-        try {
-            // Then run our own script
-            zavai.config.run_script(command);
-        } catch (Error e) {
-            zavai.log.error("Running " + command + ": " + e.message);
-            return;
-        }
-
-        cleanup_after_script_stop();
-
-        base.stop();
-    }
-
-    protected virtual void cleanup_after_script_stop()
-    {
-    }
-
-    /*
-    protected bool script_status()
-    {
-    }
-    */
-}
-
-}
diff --git a/zavai/dbus-extra.vapi b/zavai/dbus-extra.vapi
deleted file mode 100644 (file)
index 5213899..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace DBus {
-       [CCode (cname = "dbus_bus_get_unique_name")]
-       public unowned string bus_get_unique_name (DBus.RawConnection conn);
-}
-
diff --git a/zavai/devkit-power-gobject.vapi b/zavai/devkit-power-gobject.vapi
deleted file mode 100644 (file)
index 139abc2..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/* devkit-power-gobject.vapi generated by vapigen, do not modify. */
-
-[CCode (cprefix = "Dkp", lower_case_cprefix = "dkp_")]
-namespace Dkp {
-       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class Client : GLib.Object {
-               [CCode (has_construct_function = false)]
-               public Client ();
-               public unowned GLib.PtrArray enumerate_devices () throws GLib.Error;
-               [CCode (cname = "dkp_client_can_hibernate")]
-               public bool get_can_hibernate ();
-               [CCode (cname = "dkp_client_can_suspend")]
-               public bool get_can_suspend ();
-               public unowned string get_daemon_version ();
-               [CCode (cname = "dkp_client_lid_is_closed")]
-               public bool get_lid_is_closed ();
-               [CCode (cname = "dkp_client_on_battery")]
-               public bool get_on_battery ();
-               [CCode (cname = "dkp_client_on_low_battery")]
-               public bool get_on_low_battery ();
-               public bool hibernate () throws GLib.Error;
-               public bool suspend () throws GLib.Error;
-               [NoAccessorMethod]
-               public bool can_hibernate { get; }
-               [NoAccessorMethod]
-               public bool can_suspend { get; }
-               public string daemon_version { get; }
-               [NoAccessorMethod]
-               public bool lid_is_closed { get; }
-               [NoAccessorMethod]
-               public bool lid_is_present { get; }
-               [NoAccessorMethod]
-               public bool on_battery { get; }
-               [NoAccessorMethod]
-               public bool on_low_battery { get; }
-               public virtual signal void changed ();
-               public virtual signal void device_added (void* device);
-               public virtual signal void device_changed (void* device);
-               public virtual signal void device_removed (void* device);
-       }
-       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class Device : GLib.Object {
-               [CCode (has_construct_function = false)]
-               public Device ();
-               public unowned GLib.PtrArray get_history (string type, uint timespec, uint resolution) throws GLib.Error;
-               public unowned string get_object_path ();
-               public unowned GLib.PtrArray get_statistics (string type) throws GLib.Error;
-               public bool print ();
-               public bool refresh () throws GLib.Error;
-               public bool set_object_path (string object_path) throws GLib.Error;
-               public static Dkp.DeviceState state_from_text (string state);
-               public static unowned string state_to_text (Dkp.DeviceState state_enum);
-               public static Dkp.DeviceTechnology technology_from_text (string technology);
-               public static unowned string technology_to_text (Dkp.DeviceTechnology technology_enum);
-               public static Dkp.DeviceType type_from_text (string type);
-               public static unowned string type_to_text (Dkp.DeviceType type_enum);
-               [NoAccessorMethod]
-               public double capacity { get; set; }
-               [NoAccessorMethod]
-               public double energy { get; set; }
-               [NoAccessorMethod]
-               public double energy_empty { get; set; }
-               [NoAccessorMethod]
-               public double energy_full { get; set; }
-               [NoAccessorMethod]
-               public double energy_full_design { get; set; }
-               [NoAccessorMethod]
-               public double energy_rate { get; set; }
-               [NoAccessorMethod]
-               public bool has_history { get; set; }
-               [NoAccessorMethod]
-               public bool has_statistics { get; set; }
-               [NoAccessorMethod]
-               public bool is_present { get; set; }
-               [NoAccessorMethod]
-               public bool is_rechargeable { get; set; }
-               [NoAccessorMethod]
-               public string model { owned get; set; }
-               [NoAccessorMethod]
-               public string native_path { owned get; set; }
-               [NoAccessorMethod]
-               public bool online { get; set; }
-               [NoAccessorMethod]
-               public double percentage { get; set; }
-               [NoAccessorMethod]
-               public bool power_supply { get; set; }
-               [NoAccessorMethod]
-               public bool recall_notice { get; set; }
-               [NoAccessorMethod]
-               public string recall_url { owned get; set; }
-               [NoAccessorMethod]
-               public string recall_vendor { owned get; set; }
-               [NoAccessorMethod]
-               public string serial { owned get; set; }
-               [NoAccessorMethod]
-               public uint state { get; set; }
-               [NoAccessorMethod]
-               public uint technology { get; set; }
-               [NoAccessorMethod]
-               public int64 time_to_empty { get; set; }
-               [NoAccessorMethod]
-               public int64 time_to_full { get; set; }
-               [NoAccessorMethod]
-               public uint type { get; set; }
-               [NoAccessorMethod]
-               public uint64 update_time { get; set; }
-               [NoAccessorMethod]
-               public string vendor { owned get; set; }
-               [NoAccessorMethod]
-               public double voltage { get; set; }
-               public virtual signal void changed (void* obj);
-       }
-       [Compact]
-       [CCode (copy_function = "dkp_history_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class HistoryObj {
-               public Dkp.DeviceState state;
-               public uint time;
-               public double value;
-               [CCode (has_construct_function = false)]
-               public HistoryObj ();
-               public bool clear ();
-               public unowned Dkp.HistoryObj copy ();
-               public static unowned Dkp.HistoryObj create (double value, Dkp.DeviceState state);
-               public bool equal (Dkp.HistoryObj obj2);
-               public static unowned Dkp.HistoryObj from_string (string text);
-               public bool print ();
-               public unowned string to_string ();
-       }
-       [Compact]
-       [CCode (copy_function = "dkp_qos_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class QosObj {
-               public weak string cmdline;
-               public uint cookie;
-               public bool persistent;
-               public uint pid;
-               public weak string sender;
-               public uint64 timespec;
-               public Dkp.QosType type;
-               public uint uid;
-               public int value;
-               [CCode (has_construct_function = false)]
-               public QosObj ();
-               public unowned Dkp.QosObj copy ();
-               public bool equal (Dkp.QosObj obj2);
-               public bool print ();
-       }
-       [Compact]
-       [CCode (copy_function = "dkp_stats_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class StatsObj {
-               public double accuracy;
-               public double value;
-               [CCode (has_construct_function = false)]
-               public StatsObj ();
-               public unowned Dkp.StatsObj copy ();
-               public static unowned Dkp.StatsObj create (double value, double accuracy);
-               public static unowned Dkp.StatsObj from_string (string text);
-               public unowned string to_string ();
-       }
-       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class Wakeups : GLib.Object {
-               [CCode (has_construct_function = false)]
-               public Wakeups ();
-               public unowned GLib.PtrArray get_data () throws GLib.Error;
-               public uint get_total () throws GLib.Error;
-               public bool has_capability ();
-               public virtual signal void data_changed ();
-               public virtual signal void total_changed (uint value);
-       }
-       [Compact]
-       [CCode (copy_function = "dkp_wakeups_obj_copy", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public class WakeupsObj {
-               public weak string cmdline;
-               public weak string details;
-               public uint id;
-               public bool is_userspace;
-               public uint old;
-               public float value;
-               [CCode (has_construct_function = false)]
-               public WakeupsObj ();
-               public unowned Dkp.WakeupsObj copy ();
-               public bool equal (Dkp.WakeupsObj obj2);
-               public bool print ();
-       }
-       [CCode (cprefix = "DKP_DEVICE_STATE_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public enum DeviceState {
-               UNKNOWN,
-               CHARGING,
-               DISCHARGING,
-               EMPTY,
-               FULLY_CHARGED,
-               PENDING_CHARGE,
-               PENDING_DISCHARGE,
-               LAST
-       }
-       [CCode (cprefix = "DKP_DEVICE_TECHNOLOGY_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public enum DeviceTechnology {
-               UNKNOWN,
-               LITHIUM_ION,
-               LITHIUM_POLYMER,
-               LITHIUM_IRON_PHOSPHATE,
-               LEAD_ACID,
-               NICKEL_CADMIUM,
-               NICKEL_METAL_HYDRIDE,
-               LAST
-       }
-       [CCode (cprefix = "DKP_DEVICE_TYPE_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public enum DeviceType {
-               UNKNOWN,
-               LINE_POWER,
-               BATTERY,
-               UPS,
-               MONITOR,
-               MOUSE,
-               KEYBOARD,
-               PDA,
-               PHONE,
-               LAST
-       }
-       [CCode (cprefix = "DKP_QOS_TYPE_", has_type_id = "0", cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public enum QosType {
-               UNKNOWN,
-               NETWORK,
-               CPU_DMA,
-               LAST
-       }
-       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public const int COMPILE_VERSION;
-       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public static Dkp.QosType qos_type_from_text (string type);
-       [CCode (cheader_filename = "devkit-power-gobject/devicekit-power.h")]
-       public static unowned string qos_type_to_text (Dkp.QosType type);
-}
diff --git a/zavai/gps.vala b/zavai/gps.vala
deleted file mode 100644 (file)
index 950d76b..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * gps - gps resource for zavai
- *
- * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace zavai {
-namespace gps {
-
-// For a list of dbus services, look in /etc/dbus-1/system.d/
-public class GPS: zavai.ScriptService
-{
-    protected libgps.data_t data;
-    protected IOChannel gpsfd = null;
-    protected uint gpsfd_watch = 0;
-
-    protected int old_fix_status = libgps.STATUS_NO_FIX;
-    protected uint old_time = 0;
-    protected double old_lat = 1000;
-    protected double old_lon = 1000;
-
-    public signal void fix_status_changed(int status);
-    public signal void time_changed(uint time);
-    public signal void pos_changed();
-
-    public GPS()
-    {
-        Object(name: "gps");
-        data = libgps.data_t();
-        started = script_status();
-    }
-
-    public int fix_status() { return old_fix_status; }
-    public double time() { return old_time; }
-    public weak libgps.data_t info() { return data; }
-
-    protected bool on_input_data(IOChannel source, IOCondition condition)
-    {
-        while (libgps.waiting(ref data))
-        {
-            int res = libgps.poll(ref data);
-            if (res != 0)
-                zavai.log.error(libgps.errstr(res));
-
-            if (data.status != old_fix_status)
-            {
-                fix_status_changed(data.status);
-                old_fix_status = data.status;
-            }
-
-            uint cur_time = (uint)data.fix.time;
-            if (data.status != libgps.STATUS_NO_FIX && old_time != cur_time)
-            {
-                time_changed(cur_time);
-                old_time = cur_time;
-            }
-
-            double lat = (data.status == libgps.STATUS_NO_FIX ? 1000 : data.fix.latitude);
-            double lon = (data.status == libgps.STATUS_NO_FIX ? 1000 : data.fix.longitude);
-            if (lat != old_lat || lon != old_lon)
-                pos_changed();
-
-            /*
-            stderr.printf("GPSMSG %d %d\n", (int)data.set, data.status);
-            stderr.printf("SATUSED %d\n", data.satellites_used);
-            stderr.printf("SWT %f\n", data.skyview_time);
-            stderr.printf("SATVIS %d\n", data.satellites_visible);
-            for (int i = 0; i < data.satellites_visible; ++i)
-            {
-                stderr.printf("PRN %d ELE %d AZI %d SS %f\n",
-                    data.PRN[i], data.elevation[i], data.azimuth[i], data.ss[i]);
-            }
-            */
-        }
-        return true;
-    }
-
-    /// Request GPS resource
-    public override void start()
-    {
-        if (started) return;
-
-        if (!script_start()) return;
-
-        zavai.log.info("Connecting to gpsd at " + config.gpsd_host + ":" + config.gpsd_port);
-        int res = libgps.open_r(config.gpsd_host, config.gpsd_port, ref data);
-        if (res != 0)
-        {
-            zavai.log.error(libgps.errstr(res));
-            return;
-        }
-
-        res = libgps.stream(ref data, libgps.WATCH_ENABLE, null);
-        if (res != 0)
-        {
-            zavai.log.error(libgps.errstr(res));
-            return;
-        }
-
-        //res = libgps.send(ref data, "?SKY;");
-        //res = libgps.send(ref data, "?WATCH;");
-        //if (res != 0) zavai.log.error(libgps.errstr(res));
-
-        gpsfd = new IOChannel.unix_new(data.gps_fd);
-        try {
-            gpsfd.set_encoding(null);
-        } catch (Error e) {
-            zavai.log.error("Setting encoding to null on gpsd io channel: " + e.message);
-        }
-        //gpsfd.set_buffered(false);
-        gpsfd_watch = gpsfd.add_watch(IOCondition.IN, on_input_data);
-
-        zavai.log.info("GPS turned on");
-        base.start();
-    }
-
-    // Release usage of GPS
-    public override void stop()
-    {
-        if (!started) return;
-
-        Source.remove(gpsfd_watch);
-
-        int res = libgps.close(ref data);
-        if (res != 0)
-            zavai.log.error(libgps.errstr(res));
-
-        script_stop();
-
-        if (old_fix_status != libgps.STATUS_NO_FIX)
-        {
-            old_fix_status = libgps.STATUS_NO_FIX;
-            fix_status_changed(old_fix_status);
-        }
-
-        if (old_time != 0)
-        {
-            old_time = 0;
-            time_changed(old_time);
-        }
-
-        base.stop();
-    }
-}
-
-// #    def start_recording(self):
-// #        if self.gps_monitor:
-// #            self.gps_monitor.stop()
-// #            self.gps_monitor = None
-// #
-// #        if not self.audio:
-// #            return
-// #
-// #        # Sync system time
-// #        gpstime = self.gps.gps_time.GetTime()
-// #        subprocess.call(["date", "-s", "@%d" % gpstime])
-// #        subprocess.call(["hwclock", "--systohc"])
-// #
-// #        # Compute basename for output files
-// #        self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
-// #        self.basename = os.path.join(AUDIODIR, self.basename)
-// #
-// #        # Start recording the GPX track
-// #        self.gpx = GPX(self.basename)
-// #        self.gps.track_position(self.on_position_changed)
-// #
-// #        # Start recording in background forking arecord
-// #        self.audio.set_basename(self.basename)
-// #        self.audio.start_recording()
-// #
-
-// Write GPX track and waypoint files
-public class GPX : Service
-{
-    protected uint wpt_seq = 0;
-    protected uint log_id = 0;
-
-    public GPX()
-    {
-        Object(name: "gps.gpx");
-    }
-
-    public override void start()
-    {
-        if (!started)
-        {
-            log_id = log.log.start("track", "GPS track");
-            base.start();
-        }
-    }
-
-    public override void stop()
-    {
-        if (started)
-        {
-            log.log.end(log_id);
-            log_id = 0;
-            base.stop();
-        }
-    }
-
-    // Mark a waypoint
-    public void waypoint(string? name = null)
-    {
-        if (log_id == 0) return;
-
-        string wptname;
-        if (name == null)
-        {
-            wptname = "wpt_%u".printf(wpt_seq);
-            wpt_seq += 1;
-        } else {
-            wptname = name;
-        }
-
-        log.log.add(log_id, wptname);
-    }
-}
-
-public zavai.gps.GPS gps = null;
-public zavai.gps.GPX gpx = null;
-
-public void init()
-{
-    gps = new GPS();
-    gpx = new GPX();
-
-}
-
-}
-}
diff --git a/zavai/gsm.vala b/zavai/gsm.vala
deleted file mode 100644 (file)
index 3a7ac23..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * gsm - gsm resource for zavai
- *
- * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-using GLib;
-
-namespace zavai {
-namespace gsm {
-
-// Isolate here the insane loops we need to go through to turn on the bloody
-// gsm
-protected class GSMActivator : Object
-{
-    public dynamic DBus.Object device;
-    public dynamic DBus.Object network;
-    public dynamic DBus.Object sim;
-
-    public signal void status_changed(string message);
-
-    public GSMActivator()
-    {
-        device = null;
-        network = null;
-        sim = null;
-    }
-
-    public void begin()
-    {
-        if (device == null)
-        {
-            device = zavai.registry.sbus.get_object(
-                    "org.freesmartphone.ogsmd", 
-                    "/org/freesmartphone/GSM/Device",
-                    "org.freesmartphone.GSM.Device");
-            network = zavai.registry.sbus.get_object(
-                "org.freesmartphone.ogsmd", 
-                "/org/freesmartphone/GSM/Device",
-                "org.freesmartphone.GSM.Network");
-            sim = zavai.registry.sbus.get_object(
-                    "org.freesmartphone.ogsmd", 
-                    "/org/freesmartphone/GSM/Device",
-                    "org.freesmartphone.GSM.SIM");
-        }
-
-        status_changed("Turning on antenna");
-        device.SetAntennaPower(true, on_antenna_power);
-    }
-
-    protected void on_antenna_power(Error e)
-    {
-        if (e != null)
-        {
-            zavai.log.warning("on_antenna_power: " + e.message);
-            if (e.message.str("current status is 'enabling'") != null
-                || e.message.str("current status is 'unknown'") != null)
-            {
-                status_changed("Waiting for ogsmd to settle");
-                zavai.log.info("trying again after 2 seconds");
-                Timeout.add(2 * 1000, () => {
-                    device.SetAntennaPower(true, on_antenna_power);
-                    return false;
-                });
-            } else {
-                status_changed("Checking if PIN is required");
-                sim.GetAuthStatus(on_auth_status);
-            }
-            return;
-        }
-        zavai.log.warning("on_antenna_power ok");
-        status_changed("Registering with network");
-        network.Register(on_network_register);
-    }
-
-    protected void on_network_register(Error e)
-    {
-        if (e != null)
-        {
-            zavai.log.warning("on_network_register: " + e.message);
-            return;
-        }
-        status_changed("Registered with network");
-    }
-
-    protected void on_auth_status(string status, Error e)
-    {
-        if (e != null)
-        {
-            zavai.log.warning("on_auth_status: " + e.message);
-            return;
-        }
-        zavai.log.info("on_auth_status: " + status);
-        if (status == "READY")
-        {
-            status_changed("PIN ok");
-            device.SetAntennaPower(true, on_antenna_power);
-        }
-        else if (status == "SIM PIN")
-        {
-            status_changed("Sending PIN");
-            sim.SendAuthCode(zavai.config.sim_pin, on_auth_code);
-        }
-        else
-            zavai.log.debug("Unknown status: " + status);
-    }
-
-    protected void on_auth_code(Error e)
-    {
-        if (e != null)
-        {
-            zavai.log.warning("on_auth_code: " + e.message);
-            return;
-        }
-        status_changed("PIN OK");
-    }
-}
-
-public class GSM: zavai.ScriptMonitorService
-{
-    protected dynamic DBus.Object dbus;
-    public dynamic DBus.Object call;
-    protected GSMActivator activator;
-
-    public signal void status_changed(string message);
-
-    public GSM()
-    {
-        Object(name: "gsm");
-
-        activator = new GSMActivator();
-        activator.status_changed += (msg) => { status_changed(msg); };
-
-        call = null;
-
-        dbus = zavai.registry.sbus.get_object(
-                "org.freedesktop.DBus",
-                "/org/freedesktop/DBus",
-                "org.freedesktop.DBus");
-        dbus.NameOwnerChanged += on_name_owner_changed;
-    }
-
-    /// Request GPS resource
-    public override void start()
-    {
-        if (started) return;
-
-        status_changed("Starting");
-
-        script_start();
-
-        call = zavai.registry.sbus.get_object(
-            "org.freesmartphone.ogsmd", 
-            "/org/freesmartphone/GSM/Device",
-            "org.freesmartphone.GSM.Call");
-
-        base.start();
-    }
-
-    protected void on_name_owner_changed(DBus.Object sender, string name, string oldOwner, string newOwner)
-    {
-        zavai.log.debug("NOC " + name + " from " + oldOwner + " to " + newOwner);
-        if (name == "org.freesmartphone.ogsmd" && newOwner != "")
-        {
-            status_changed("ogpsd came online");
-            activator.begin();
-        }
-    }
-
-    // Release usage of GPS
-    public override void stop()
-    {
-        if (!started) return;
-
-        script_stop();
-    }
-
-    protected override void cleanup_after_script_stop()
-    {
-        call = null;
-    }
-}
-
-public class GPRS: zavai.Service
-{
-    public dynamic DBus.Object device;
-
-    public GPRS()
-    {
-        Object(name: "gsm.gprs");
-
-        device = zavai.registry.sbus.get_object(
-            "org.freesmartphone.ogsmd", 
-            "/org/freesmartphone/GSM/Device",
-            "org.freesmartphone.GSM.PDP");
-    }
-
-    /// Request GPS resource
-    public override void start()
-    {
-        if (started) return;
-        try {
-            //gsm.request(name);
-            device.ActivateContext(
-                zavai.config.gprs_apn,
-                zavai.config.gprs_user,
-                zavai.config.gprs_pass);
-            zavai.log.info("Started GPRS");
-            base.start();
-        } catch (GLib.Error e) {
-            zavai.log.error(e.message);
-        }
-        base.start();
-    }
-
-    // Release usage of GPS
-    public override void stop()
-    {
-        if (!started) return;
-        try {
-            //gsm.release(name);
-            device.DeactivateContext();
-            zavai.log.info("Stopped GPRS");
-            base.stop();
-        } catch (GLib.Error e) {
-            zavai.log.error(e.message);
-        }
-        base.stop();
-    }
-}
-
-public zavai.gsm.GSM gsm = null;
-public zavai.gsm.GPRS gprs = null;
-
-public void init()
-{
-    gsm = new GSM();
-    gprs = new GPRS();
-}
-
-}
-}
diff --git a/zavai/input.vala b/zavai/input.vala
deleted file mode 100644 (file)
index ffa0add..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * devinput - zavai /dev/input device handling
- *
- * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-namespace zavai {
-namespace input {
-
-public class DevInput : zavai.Service
-{
-    public string device { get; construct; }
-
-    public signal bool event(LinuxInput.Event* ev);
-
-    protected IOChannel fd = null;
-    protected uint fd_watch = 0;
-
-    public DevInput(string name, string device)
-    {
-        Object(name: "input.power_button", device: "/dev/input/event0");
-    }
-
-    protected void close_fd()
-    {
-        if (fd != null)
-        {
-            try {
-                fd.shutdown(false);
-            } catch (IOChannelError e) {
-                zavai.log.error("When closing " + device + ": " + e.message);
-            }
-
-            fd = null;
-        }
-    }
-
-    protected bool on_input_data(IOChannel source, IOCondition condition)
-    {
-        if (condition != IOCondition.IN) return true;
-
-        //stderr.printf("GOT INPUT ON %s %d\n", device, source.unix_get_fd());
-        char[] buf = new char[sizeof(LinuxInput.Event)];
-        size_t count_read;
-        try {
-            source.read_chars(buf, out count_read);
-        } catch (Error e) {
-            zavai.log.error("Reading from " + device + ": " + e.message);
-            return true;
-        }
-        //stderr.printf("READ %zu chars\n", count_read);
-
-        LinuxInput.Event* ie = (LinuxInput.Event*)buf;
-        //stderr.printf("INPUT EVENT time %lu.%lu type %hu code %hu val %d\n", (ulong)ie->time.tv_sec, ie->time.tv_usec, ie->type, ie->code, ie->val);
-
-        /*
-        ts1, ts2, type, code, value = struct.unpack("LLHHI", buf)
-        #print ts1, ts2, type, code, value
-        if type == 1 and code == 119:
-            if value:
-                #print "BUTTON RELEASE"
-                pass
-            else:
-                if self.last_button_press + 1 < ts1:
-                    self.last_button_press = ts1
-                    if self.button_press_handler is not None:
-                        self.button_press_handler()
-                    #print "BUTTON PRESS"
-        elif type == 5 and code == 2:
-            if value:
-                info("Headset plugged in")
-                self.mixer_for_headset(self)
-            else:
-                info("Headset plugged out")
-                self.mixer_for_handset(self)
-        */
-        return event(ie);
-    }
-
-    /// Start reading from the device
-    public override void start()
-    {
-        if (started) return;
-
-        if (fd != null)
-            close_fd();
-
-        // Open the device and listed to it using the GObject main loop
-        zavai.log.info("Opening device " + device);
-        fd = new IOChannel.file(device, "r");
-        try {
-            fd.set_encoding(null);
-        } catch (Error e) {
-            zavai.log.error("Setting encoding to null on " + device + ": " + e.message);
-        }
-        fd.set_buffered(false);
-        fd_watch = fd.add_watch(IOCondition.IN, on_input_data);
-
-        base.start();
-    }
-
-    // Stop reading from the device
-    public override void stop()
-    {
-        if (!started) return;
-
-        if (fd != null)
-        {
-            Source.remove(fd_watch);
-            close_fd();
-        }
-
-        base.stop();
-    }
-}
-
-public class HotKeys : zavai.Service
-{
-    protected List<int> grabbed;
-    public signal bool hotkey(uint keycode, ulong time, bool pressed);
-
-    public HotKeys()
-    {
-        Object(name: "input.hotkeys");
-
-        grabbed = new List<int>();
-    }
-
-    // Hotkey handlink takes inspiration from
-    // http://old.nabble.com/-PATCH--Initial-non-working-implementation-of-wxWindow::%28Un%29RegisterHotKey-on-wxGTK-td14557263.html
-    private static Gdk.FilterReturn on_hotkey(Gdk.XEvent* xevent, Gdk.Event? event, void* data)
-    {
-        // Global events don't get their data translated to gdk, as there is no
-        // GdkWindow to work with, therefore we need to use the xevent, because
-        // GdkEvent* is always GDK_NOTHING
-        X.Event* xev = (X.Event*)xevent;
-
-        switch (xev->type)
-        {
-            case X.EventType.KeyPress:
-                return zavai.input.hotkeys.my_on_hotkey(xev, true);
-            case X.EventType.KeyRelease:
-                return zavai.input.hotkeys.my_on_hotkey(xev, false);
-            default:
-                return Gdk.FilterReturn.CONTINUE;
-        }
-    }
-
-    //public Gdk.FilterReturn on_hotkey(Gdk.XEvent xevent, Gdk.Event? event)
-    private Gdk.FilterReturn my_on_hotkey(X.Event* xev, bool pressed)
-    {
-        // From http://tronche.com/gui/x/xlib/input/pointer-grabbing.html:
-        //
-        // A timestamp is a time value, expressed in milliseconds. It typically is the
-        // time since the last server reset. Timestamp values wrap around (after about
-        // 49.7 days). The server, given its current time is represented by timestamp
-        // T, always interprets timestamps from clients by treating half of the
-        // timestamp space as being later in time than T. One timestamp value, named
-        // CurrentTime, is never generated by the server. This value is reserved for
-        // use in requests to represent the current server time. 
-
-        if (grabbed.index((int)xev->xkey.keycode) == -1)
-            return Gdk.FilterReturn.CONTINUE;
-
-        if (hotkey(xev->xkey.keycode, xev->xkey.time, pressed))
-            return Gdk.FilterReturn.REMOVE;
-        return Gdk.FilterReturn.CONTINUE;
-    }
-
-    public void grab(int keycode, int modifiers, bool owner_events)
-    {
-        // We need to grab the keys we want to listen to
-        int res = Gdk.x11_get_default_xdisplay().grab_key(keycode, modifiers, Gdk.x11_get_default_root_xwindow(), owner_events, X.GrabMode.Async, X.GrabMode.Async);
-        if (res != 0)
-            stderr.printf("Grab result: %d\n", res); // We get BadRequest and don't know why
-        grabbed.append(keycode);
-    }
-
-    /// Start reading from the device
-    public override void start()
-    {
-        if (started) return;
-
-        //gdk_window_add_filter (NULL, _wxgtk_global_hotkey_callback, this);
-        ((Gdk.Window*)null)->add_filter((Gdk.FilterFunc)on_hotkey);
-
-        grab(160, 0, false);
-
-        base.start();
-    }
-
-    // Stop reading from the device
-    public override void stop()
-    {
-        if (!started) return;
-
-        //gdk_window_remove_filter(NULL, _wxgtk_global_hotkey_callback, this); 
-        ((Gdk.Window*)null)->remove_filter((Gdk.FilterFunc)on_hotkey);
-
-        base.stop();
-    }
-}
-
-public class PowerButton : zavai.Service
-{
-    protected DevInput devinput;
-
-    public signal void power_button(Posix.timeval* time, bool pressed);
-
-    public PowerButton()
-    {
-        // FIXME: change to event0 for the power button
-        // FIXME: change to event4 for the aux button and headset button
-        string inputdev = "/dev/input/event0";
-        if (Posix.access(inputdev, Posix.R_OK) == 0)
-        {
-            zavai.log.info("Handle power button via " + inputdev);
-            // Listen via input device
-            devinput = new DevInput("input.power_button", "/dev/input/event0");
-            devinput.event += on_event;
-            devinput.request("powerbutton");
-        } else {
-            zavai.log.info("Handle power button via XGrabKey on keycode " + zavai.config.power_button_keycode.to_string());
-            // Listen via X
-            hotkeys.hotkey += on_hotkey;
-            hotkeys.grab(zavai.config.power_button_keycode, 0, false);
-            hotkeys.request("powerbutton");
-        }
-    }
-
-    protected bool on_event(LinuxInput.Event* ev)
-    {
-        if (ev->type == LinuxInput.Type.KEY && 
-            ev->code == LinuxInput.Key.POWER)
-        {
-            power_button(&(ev->time), ev->val == 0 ? false : true);
-        }
-        return true;
-    }
-
-    protected bool on_hotkey(uint keycode, ulong time, bool pressed)
-    {
-        if (keycode == zavai.config.power_button_keycode)
-        {
-            // Convert X time to a fake timeval
-            // TODO: handle wraparound
-            Posix.timeval tv = {
-                (time_t)(time / 1000),
-                (long)((time % 1000) * 1000)
-            };
-            power_button(&tv, pressed);
-            return true;
-        }
-        return false;
-    }
-}
-
-
-/*
-# TODO:
-#  - hook into the headset plugged/unplugged event
-#  - if unplugged, turn on handset microphone
-#  - if plugged, redo headest mixer settings
-class Audio:
-    "Handle mixer settings, audio recording and headset button presses"
-    def __init__(self, button_press_handler = None):
-        self.saved_scenario = os.path.expanduser("~/.audiomap.state")
-
-        # Setup the mixer
-        # Set mixer to record from headset and handle headset button
-        self.save_scenario(self.saved_scenario)
-        self.load_scenario("/usr/share/openmoko/scenarios/voip-handset.state")
-
-        # This is a work-around because I have not found a way to query for the
-        # current headset state, I can only know when it changes. So in my
-        # system I configured oeventsd with a rule to touch this file when the
-        # headset is plugged in, and remove the file when it's plugged out.
-        if os.path.exists("/tmp/has_headset"):
-            self.mixer_for_headset(True)
-        else:
-            self.mixer_for_handset(True)
-
-        #self.mixer_set("DAPM Handset Mic", "mute")
-        #self.mixer_set("DAPM Headset Mic", "unmute")
-        #self.mixer_set("Left Mixer Sidetone Playback Sw", "unmute")
-        #self.mixer_set("ALC Mixer Mic1", "cap")
-        #self.mixer_set("Amp Spk", "mute") # We don't need the phone playing what we say
-
-        # Watch the headset button
-        self.button_press_handler = button_press_handler
-        self.input_fd = open("/dev/input/event4", "rb")
-        self.input_watch = gobject.io_add_watch(self.input_fd.fileno(), gobject.IO_IN, self.on_input_data)
-
-        self.last_button_press = 0
-        self.recorder = None
-        self.basename = None
-
-    def mixer_for_headset(self, force=False):
-        if not force and self.has_headset: return
-        info("Setting mixer for headset")
-        # TODO: find out how to disable the handset microphone: this does not
-        # seem to be sufficient
-        self.mixer_set_many(
-                ("DAPM Handset Mic", "mute"),
-                ("DAPM Headset Mic", "unmute"),
-                ("Left Mixer Sidetone Playback Sw", "unmute"),
-                ("ALC Mixer Mic1", "cap"),
-                ("Amp Spk", "mute") # We don't need the phone playing what we say
-        )
-        self.has_headset = True
-
-    def mixer_for_handset(self, force=False):
-        if not force and not self.has_headset: return
-        info("Setting mixer for handset")
-        self.mixer_set_many(
-                ("DAPM Handset Mic", "unmute"),
-                ("DAPM Headset Mic", "mute"),
-                ("Left Mixer Sidetone Playback Sw", "mute"),
-                ("ALC Mixer Mic1", "cap"),
-                ("Amp Spk", "mute") # We don't need the phone playing what we say
-        )
-        self.has_headset = False
-
-    def set_basename(self, basename):
-        self.basename = basename
-
-    def start_recording(self):
-        if self.basename is None:
-            raise RuntimeError("Recording requested but basename not set")
-        self.recorder = subprocess.Popen(
-            ["arecord", "-D", "hw", "-f", "cd", "-r", "8000", "-t", "wav", self.basename + ".wav"])
-
-    def start_levels(self):
-        self.recorder = subprocess.Popen(
-            ["arecord", "-D", "hw", "-f", "cd", "-r", "8000", "-t", "wav", "-V", "stereo", "/dev/null"])
-
-    def close(self):
-        if self.recorder is not None:
-            os.kill(self.recorder.pid, signal.SIGINT)
-            self.recorder.wait()
-
-        # Restore mixer settings
-        self.load_scenario(self.saved_scenario)
-
-        gobject.source_remove(self.input_watch)
-        self.input_fd.close()
-
-    def on_input_data(self, source, condition):
-        buf = self.input_fd.read(16)
-        ts1, ts2, type, code, value = struct.unpack("LLHHI", buf)
-        #print ts1, ts2, type, code, value
-        if type == 1 and code == 119:
-            if value:
-                #print "BUTTON RELEASE"
-                pass
-            else:
-                if self.last_button_press + 1 < ts1:
-                    self.last_button_press = ts1
-                    if self.button_press_handler is not None:
-                        self.button_press_handler()
-                    #print "BUTTON PRESS"
-        elif type == 5 and code == 2:
-            if value:
-                info("Headset plugged in")
-                self.mixer_for_headset(self)
-            else:
-                info("Headset plugged out")
-                self.mixer_for_handset(self)
-        return True
-
-    def save_scenario(self, name):
-        res = subprocess.call(["alsactl", "store", "-f", name])
-        if res != 0:
-            raise RuntimeError("Saving audio scenario to '%s' failed" % name)
-
-    def load_scenario(self, name):
-        res = subprocess.call(["alsactl", "restore", "-f", name])
-        if res != 0:
-            raise RuntimeError("Loading audio scenario '%s' failed" % name)
-
-    def mixer_set(self, name, *args):
-        args = map(str, args)
-        res = subprocess.call(["amixer", "-q", "set", name] + args)
-        if res != 0:
-            raise RuntimeError("Setting mixer '%s' to %s failed" % (name, " ".join(args)))
-
-    # Will do this when we find out the syntax for giving amixer commands on stdin
-    def mixer_set_many(self, *args):
-        """Perform m