diff options
Diffstat (limited to 'src/renderers/pieWindow.vala')
-rw-r--r-- | src/renderers/pieWindow.vala | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/renderers/pieWindow.vala b/src/renderers/pieWindow.vala new file mode 100644 index 0000000..c4ac2ec --- /dev/null +++ b/src/renderers/pieWindow.vala @@ -0,0 +1,263 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +using GLib.Math; + +namespace GnomePie { + +// An invisible window. Used to draw Pies onto. + +public class PieWindow : Gtk.Window { + + public signal void on_closing(); + + private PieRenderer renderer; + private bool closing = false; + private GLib.Timer timer; + + private bool has_compositing = false; + + private Image background = null; + + public PieWindow() { + this.renderer = new PieRenderer(); + + this.set_title("Gnome-Pie"); + this.set_skip_taskbar_hint(true); + this.set_skip_pager_hint(true); + this.set_keep_above(true); + this.set_type_hint(Gdk.WindowTypeHint.SPLASHSCREEN); + this.set_decorated(false); + this.set_resizable(false); + this.icon_name = "gnome-pie"; + this.set_accept_focus(false); + + if (this.screen.is_composited()) { + this.set_colormap(this.screen.get_rgba_colormap()); + this.has_compositing = true; + } + + this.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.KEY_RELEASE_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.POINTER_MOTION_MASK); + + this.button_release_event.connect ((e) => { + if (e.button == 1) this.activate_slice(); + else this.cancel(); + return true; + }); + + // remember last pressed key in order to disable key repeat + uint last_key = 0; + this.key_press_event.connect((e) => { + if (e.keyval != last_key) { + last_key = e.keyval; + this.handle_key_press(e.keyval); + } + return true; + }); + + this.key_release_event.connect((e) => { + last_key = 0; + if (Config.global.turbo_mode) + this.activate_slice(); + else + this.handle_key_release(e.keyval); + return true; + }); + + this.motion_notify_event.connect((e) => { + this.renderer.on_mouse_move(); + return true; + }); + + this.expose_event.connect(this.draw); + } + + public void load_pie(Pie pie) { + this.renderer.load_pie(pie); + this.set_window_position(); + this.set_size_request(renderer.get_size(), renderer.get_size()); + } + + public void open() { + this.realize(); + + if (!this.has_compositing) { + int x, y, width, height; + this.get_position(out x, out y); + this.get_size(out width, out height); + this.background = new Image.capture_screen(x, y, width+1, height+1); + } + + this.show(); + this.fix_focus(); + + this.timer = new GLib.Timer(); + this.timer.start(); + this.queue_draw(); + + Timeout.add((uint)(1000.0/Config.global.refresh_rate), () => { + this.queue_draw(); + return this.visible; + }); + } + + private bool draw(Gtk.Widget da, Gdk.EventExpose event) { + // clear the window + var ctx = Gdk.cairo_create(this.window); + + if (this.has_compositing) { + ctx.set_operator (Cairo.Operator.CLEAR); + ctx.paint(); + ctx.set_operator (Cairo.Operator.OVER); + } else { + ctx.set_operator (Cairo.Operator.OVER); + ctx.set_source_surface(background.surface, -1, -1); + ctx.paint(); + } + + ctx.translate(this.width_request*0.5, this.height_request*0.5); + + double mouse_x = 0.0, mouse_y = 0.0; + this.get_pointer(out mouse_x, out mouse_y); + + double frame_time = this.timer.elapsed(); + this.timer.reset(); + + this.renderer.draw(frame_time, ctx, (int)(mouse_x - this.width_request*0.5), + (int)(mouse_y - this.height_request*0.5)); + + return true; + } + + private void activate_slice() { + if (!this.closing) { + this.closing = true; + this.on_closing(); + this.unfix_focus(); + this.renderer.activate(); + + Timeout.add((uint)(Config.global.theme.fade_out_time*1000), () => { + this.destroy(); + //ThemedIcon.clear_cache(); + return false; + }); + } + } + + private void cancel() { + if (!this.closing) { + this.closing = true; + this.on_closing(); + this.unfix_focus(); + this.renderer.cancel(); + + Timeout.add((uint)(Config.global.theme.fade_out_time*1000), () => { + this.destroy(); + //ThemedIcon.clear_cache(); + return false; + }); + } + } + + private void set_window_position() { + if(Config.global.open_at_mouse) this.set_position(Gtk.WindowPosition.MOUSE); + else this.set_position(Gtk.WindowPosition.CENTER); + } + + private void handle_key_press(uint key) { + if (Gdk.keyval_name(key) == "Escape") this.cancel(); + else if (Gdk.keyval_name(key) == "Return") this.activate_slice(); + else if (!Config.global.turbo_mode) { + if (Gdk.keyval_name(key) == "Up") this.renderer.select_up(); + else if (Gdk.keyval_name(key) == "Down") this.renderer.select_down(); + else if (Gdk.keyval_name(key) == "Left") this.renderer.select_left(); + else if (Gdk.keyval_name(key) == "Right") this.renderer.select_right(); + else if (Gdk.keyval_name(key) == "Alt_L") this.renderer.show_hotkeys = true; + else { + int index = -1; + + if (key >= 48 && key <= 57) index = (int)key - 48; + else if (key >= 97 && key <= 122) index = (int)key - 87; + else if (key >= 65 && key <= 90) index = (int)key - 55; + + if (index >= 0 && index < this.renderer.slice_count()) { + this.renderer.set_highlighted_slice(index); + + if (this.renderer.active_slice == index) { + GLib.Timeout.add((uint)(Config.global.theme.transition_time*1000.0), ()=> { + this.activate_slice(); + return false; + }); + } + + } + } + } + } + + private void handle_key_release(uint key) { + if (!Config.global.turbo_mode) { + if (Gdk.keyval_name(key) == "Alt_L") this.renderer.show_hotkeys = false; + } + } + + // utilities for grabbing focus + // Code from Gnome-Do/Synapse + private void fix_focus() { + uint32 timestamp = Gtk.get_current_event_time(); + this.present_with_time(timestamp); + this.get_window().raise(); + this.get_window().focus(timestamp); + + int i = 0; + Timeout.add(100, () => { + if (++i >= 100) return false; + return !try_grab_window(); + }); + } + + // Code from Gnome-Do/Synapse + private void unfix_focus() { + uint32 time = Gtk.get_current_event_time(); + Gdk.pointer_ungrab(time); + Gdk.keyboard_ungrab(time); + Gtk.grab_remove(this); + } + + // Code from Gnome-Do/Synapse + private bool try_grab_window() { + uint time = Gtk.get_current_event_time(); + if (Gdk.pointer_grab(this.get_window(), true, Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK, + null, null, time) == Gdk.GrabStatus.SUCCESS) { + + if (Gdk.keyboard_grab(this.get_window(), true, time) == Gdk.GrabStatus.SUCCESS) { + Gtk.grab_add(this); + return true; + } else { + Gdk.pointer_ungrab(time); + return false; + } + } + return false; + } +} + +} |