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