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