Debugging
[gregoa/zavai.git] / src / app_power.vala
1 /*
2  * app_power - zavai power handling
3  *
4  * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace zavai {
24 namespace ui {
25 namespace power {
26
27 // Compute a-b in microseconds
28 static long timediff(Posix.timeval* a, Posix.timeval* b)
29 {
30         return (a->tv_sec - b->tv_sec) * 1000000 + (a->tv_usec - b->tv_usec);
31 }
32
33 public class Power : zavai.Resource, Object
34 {
35         public dynamic DBus.Object usage;
36         public bool screen_locked;
37         private int screen_lock_fd;
38         // Timestamp of the past power button pressed even (0 if the button has
39         // been released)
40         private Posix.timeval last_down;
41
42         private bool hide_after_closing_power_menu;
43
44         public signal void screen_lock_changed(bool state);
45
46         public Power()
47         {
48                 screen_locked = false;
49                 screen_lock_fd = -1;
50                 hide_after_closing_power_menu = false;
51                 last_down.tv_sec = 0;
52                 last_down.tv_usec = 0;
53
54                 usage = zavai.registry.sbus.get_object(
55                         "org.freesmartphone.ousaged",
56                         "/org/freesmartphone/Usage",
57                         "org.freesmartphone.Usage");
58
59                 zavai.input.power_button.power_button += on_power_button;
60                 zavai.input.power_button.request("zavai.ui.powerbutton.power");
61         }
62
63         public void shutdown()
64         {
65                 zavai.input.power_button.release("zavai.ui.powerbutton.power");
66         }
67
68         public void do_suspend() { usage.Suspend(); }
69         public void do_shutdown() { usage.Shutdown(); }
70         public void do_reboot() { usage.Reboot(); }
71
72         public void set_screen_lock(bool locked)
73         {
74                 if (locked && screen_locked)
75                         return;
76                 if (!locked && !screen_locked)
77                         return;
78
79                 if (locked)
80                 {
81                         screen_lock_fd = Posix.open("/dev/input/event1", Posix.O_RDWR | Posix.O_NONBLOCK);
82                         if (screen_lock_fd < 0)
83                         {
84                                 zavai.log.error("Cannot open /dev/input/event1");
85                                 return;
86                         }
87
88                         int EVIOCGRAB = 0x40044590;
89                         if (Posix.ioctl(screen_lock_fd, EVIOCGRAB, locked ? 1 : 0) != 0)
90                         {
91                                 zavai.log.error("Cannot EVIOCGRAB /dev/input/event1");
92                                 Posix.close(screen_lock_fd);
93                                 return;
94                         }
95                 } else {
96                         Posix.close(screen_lock_fd);
97                 }
98                 screen_locked = locked;
99                 if (!locked)
100                         backlight.wiggle();
101
102                 screen_lock_changed(locked);
103         }
104
105         private void on_power_button(Posix.timeval* t, bool pressed)
106         {
107                 bool short_press = false;
108                 bool long_press = false;
109
110 stderr.printf("EVENT %d\n", (int)pressed);
111
112                 if (pressed)
113                 {
114                         if (last_down.tv_sec == 0)
115                         {
116 stderr.printf("  FIRST PRESSED\n");
117                                 last_down = *t;
118                         }
119                         else
120                         {
121                                 long diff = timediff(t, &last_down);
122 stderr.printf("  PRESSED FOR %ld\n", diff);
123                                 long_press = diff >= 1500000;
124                         }
125                 } else {
126                         long diff = timediff(t, &last_down);
127 stderr.printf("  RELEASED AFTER %ld\n", diff);
128                         if (diff >= 1500000)
129                                 long_press = true;
130                         else
131                                 short_press = true;
132
133                         last_down.tv_sec = 0;
134                         last_down.tv_usec = 0;
135                 }
136
137 stderr.printf("  LP %d SP %d\n", (int)long_press, (int)short_press);
138
139                 if (short_press) {
140                         if (screen_locked)
141                                 // Short press: turn on backlight for a bit
142                                 backlight.wiggle();
143                         else
144                                 // Short press: toggle power menu
145                                 power_menu.toggle();
146                 } else if (long_press) {
147                         if (screen_locked)
148                                 // Long press: unlock
149                                 set_screen_lock(false);
150                         else
151                                 // Long press: lock screen
152                                 set_screen_lock(true);
153                 }
154         }
155 }
156
157 public class BatteryIcon : Gtk.StatusIcon
158 {
159         public dynamic DBus.Object battery;
160         protected string last_status;
161         protected int last_capacity;
162
163         public BatteryIcon()
164         {
165                 battery = zavai.registry.sbus.get_object(
166                         "org.freesmartphone.odeviced",
167                         "/org/freesmartphone/Device/PowerSupply/battery",
168                         "org.freesmartphone.Device.PowerSupply");
169
170                 // activate += on_activate;
171
172                 battery.PowerStatus += on_power_status;
173                 battery.Capacity += on_capacity;
174
175                 last_status = battery.GetPowerStatus();
176                 last_capacity = battery.GetCapacity();
177                 
178                 update_icon();
179         }
180
181         private void on_power_status(dynamic DBus.Object bat, string status)
182         {
183                 zavai.log.info("New battery status: " + status);
184                 last_status = status;
185                 update_icon();
186         }
187
188         private void on_capacity(dynamic DBus.Object bat, int val)
189         {
190 stderr.printf("NEW CAPACITY: %d\n", val);
191                 last_capacity = val;
192                 update_icon();
193         }
194
195         /*
196         private void on_activate()
197         {
198         }
199         */
200
201         protected void update_icon()
202         {
203                 string name = zavai.config.icondir + "/battery/";
204
205                 if (last_status == "charging")
206                         name += "%02d0_charging_500.png".printf(last_capacity/10);
207                 else
208                         name += "%02d0.png".printf(last_capacity/10);
209
210 stderr.printf("Loading icon from %s\n", name);
211
212                 set_from_file(name);
213         }
214 }
215
216 public class ScreenLockButton : Gtk.Button
217 {
218         public ScreenLockButton()
219         {
220                 label = "Lock screen";
221                 clicked += on_clicked;
222                 set_size_request(0, zavai.config.min_button_height);
223         }
224
225         public void on_clicked()
226         {
227                 zavai.log.info("Locking screen");
228                 power.set_screen_lock(true);
229                 power_menu.hide();
230         }
231 }
232
233 public class SuspendButton : Gtk.Button
234 {
235         public SuspendButton()
236         {
237                 label = "Suspend";
238                 clicked += on_clicked;
239                 set_size_request(0, zavai.config.min_button_height);
240         }
241
242         public void on_clicked()
243         {
244                 zavai.log.info("Suspending the phone via FSO");
245                 power.do_suspend();
246                 power_menu.hide();
247         }
248 }
249
250 public class ShutdownButton : Gtk.Button
251 {
252         public ShutdownButton()
253         {
254                 label = "Shut down";
255                 clicked += on_clicked;
256                 set_size_request(0, zavai.config.min_button_height);
257         }
258
259         public void on_clicked()
260         {
261                 zavai.log.info("Shutting down the phone via FSO");
262                 power.do_shutdown();
263                 power_menu.hide();
264         }
265 }
266
267 public class RebootButton : Gtk.Button
268 {
269         public RebootButton()
270         {
271                 label = "Reboot";
272                 clicked += on_clicked;
273                 set_size_request(0, zavai.config.min_button_height);
274         }
275
276         public void on_clicked()
277         {
278                 zavai.log.info("Rebooting the phone via FSO");
279                 power.do_reboot();
280                 power_menu.hide();
281         }
282 }
283
284 // For a list of dbus services, look in /etc/dbus-1/system.d/
285 public class Backlight: zavai.Service
286 {
287         public dynamic DBus.Object usage;
288
289         public Backlight()
290         {
291                 name = "backlight";
292
293                 usage = zavai.registry.sbus.get_object(
294                         "org.freesmartphone.ousaged",
295                         "/org/freesmartphone/Usage",
296                         "org.freesmartphone.Usage");
297         }
298
299         // Turn the backlight and then let it fade off
300         public void wiggle()
301         {
302                 // There must be a better method
303                 usage.RequestResource("Display");
304                 usage.ReleaseResource("Display");
305         }
306
307         /// Request GPS resource
308         public override void start()
309         {
310                 if (started) return;
311                 try {
312                         usage.RequestResource("Display");
313                         zavai.log.info("Acquired display");
314                         base.start();
315                 } catch (GLib.Error e) {
316                         zavai.log.error(e.message);
317                 }
318                 base.start();
319         }
320
321         // Release usage of GPS
322         public override void stop()
323         {
324                 if (!started) return;
325                 try {
326                         usage.ReleaseResource("Display");
327                         zavai.log.info("Released display");
328                         base.stop();
329                 } catch (GLib.Error e) {
330                         zavai.log.error(e.message);
331                 }
332                 base.stop();
333         }
334 }
335
336 public class PowerMenu : zavai.Resource, Gtk.Window
337 {
338         protected Gtk.VBox vbox;
339         protected ScreenLockButton act_screen_lock;
340         protected SuspendButton act_suspend;
341         protected ShutdownButton act_shutdown;
342         protected RebootButton act_reboot;
343         protected ServiceRequestLink act_backlight_on;
344         protected bool shown;
345
346         public PowerMenu()
347         {
348                 type = Gtk.WindowType.TOPLEVEL;
349                 title = "Power Menu";
350                 shown = false;
351                 destroy_with_parent = true;
352                 set_transient_for(zavai.app);
353                 set_modal(true);
354                 set_position(Gtk.WindowPosition.CENTER_ON_PARENT);
355                 set_size_request(300, 500);
356
357                 vbox = new Gtk.VBox(false, 0);
358                 add(vbox);
359
360                 //destroy += Gtk.main_quit;
361                 //set_events(get_events() | Gdk.EventMask.VISIBILITY_NOTIFY_MASK);
362                 //visibility_notify_event += on_visibility;
363                 set_skip_pager_hint(true);
364                 set_skip_taskbar_hint(true);
365                 set_type_hint(Gdk.WindowTypeHint.POPUP_MENU);
366
367                 act_screen_lock = new ScreenLockButton();
368                 vbox.pack_start(act_screen_lock, false, false, 0);
369
370                 act_suspend = new SuspendButton();
371                 vbox.pack_start(act_suspend, false, false, 0);
372
373                 act_shutdown = new ShutdownButton();
374                 vbox.pack_start(act_shutdown, false, false, 0);
375
376                 act_reboot = new RebootButton();
377                 vbox.pack_start(act_reboot, false, false, 0);
378
379                 act_backlight_on = new ServiceRequestLink("backlight", "Keep backlight on", "Let backlight fade");
380                 vbox.pack_start(act_backlight_on, false, false, 0);
381
382                 //vbox.show_all();
383         }
384
385         public void toggle()
386         {
387                 if (!shown)
388                 {
389                         show_all();
390                         show();
391                         visible = true;
392                         present();
393                         shown = true;
394                 } else {
395                         // TODO: do more in case it is visible but has no visibility (is covered by others)
396                         visible = !visible;
397                         if (visible)
398                                 present();
399                 }                               
400         }
401
402         public void hide()
403         {
404                 visible = false;
405         }
406
407         public void shutdown() {}
408 }
409
410 /*
411 public class TogglePowerMenu : Gtk.Button
412 {
413         public TogglePowerMenu()
414         {
415                 label = "Toggle power menu";
416                 clicked += on_clicked;
417                 set_size_request(0, zavai.config.min_button_height);
418         }
419
420         public void on_clicked()
421         {
422                 zavai.log.info("Toggling power menu");
423                 power_menu.toggle();
424         }
425 }
426 */
427
428 Power power;
429 PowerMenu power_menu;
430 BatteryIcon battery_icon;
431 Backlight backlight;
432 //TogglePowerMenu tpm;
433
434 public void init()
435 {
436         power = new Power();
437         backlight = new Backlight();
438         zavai.registry.register_service(backlight);
439
440         battery_icon = new BatteryIcon();
441         battery_icon.set_visible(true);
442
443         power_menu = new PowerMenu();
444         zavai.registry.register_resource("powermenu", power_menu);
445         
446     //zavai.registry.getmenu("menu.main").add_applet("menu.power");
447         //tpm = new TogglePowerMenu();
448     //zavai.registry.getmenu("menu.main").add_widget(tpm);
449
450     /*
451         raise_icon = new RaiseIcon();
452         raise_icon.set_visible(true);
453
454         close_or_back = new CloseOrBack();
455         close_or_back.set_visible(true);
456
457         window_list = new WindowList("Current apps");
458         zavai.registry.register_applet("wm.list", window_list);
459         zavai.registry.getmenu("menu.main").add_applet("wm.list");
460
461         try {
462                 launcher = new Launcher("Run program");
463         } catch (Error e) {
464                 zavai.log.error("Not running launcher: " + e.message);
465                 launcher = null;
466         }
467
468         if (launcher != null)
469         {
470                 zavai.registry.register_applet("wm.launcher", launcher);
471                 zavai.registry.getmenu("menu.main").add_applet("wm.launcher");
472         }
473     */
474 }
475
476 }
477 }
478 }