diff options
| author | Neil Jagdish Patel <neil.patel@canonical.com> | 2010-08-24 13:02:16 +0100 |
|---|---|---|
| committer | Neil Jagdish Patel <neil.patel@canonical.com> | 2010-08-24 13:02:16 +0100 |
| commit | de1d46e08a477e69108fb6aaa5142d66da004278 (patch) | |
| tree | 7e8144ef13214e50ae5f6fd4ff5aca4ff72d78e4 | |
| parent | 6ece6e81bad2d838899dc040631eafb512341ad1 (diff) | |
| parent | 0bb8516abcda57f320160c87432867de30a7332a (diff) | |
[merge] trunk
(bzr r424.1.28)
45 files changed, 2217 insertions, 409 deletions
diff --git a/.bzrignore b/.bzrignore index 7034e2473..8f8851524 100644 --- a/.bzrignore +++ b/.bzrignore @@ -341,6 +341,8 @@ unity-private/places/places-folder-browser-renderer.c unity/unity-place-activation.c unity-private/places/places-place-search-navigation.c unity-private/panel/panel-window-buttons.c +unity-private/places/places-volume-controller.c +unity-private/places/places-volume-child-controller.c tests/unit/test-place-browser.c unity-private/gesture/gesture-dispatcher-xcb-glu.c unity-private/gesture/gesture-dispatcher-xcb.c @@ -348,3 +350,6 @@ unity-private/gesture/gesture-dispatcher.c unity-private/gesture/gesture-event.c unity-private/gesture/gesture-dispatcher-geis-glu.c unity-private/gesture/gesture-dispatcher-geis.c +unity-private/places/places-place-home-renderer.c +unity/unity-stripe-texture.c + diff --git a/configure.ac b/configure.ac index 10b3d1885..538569273 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ m4_define([unity_major], [0]) m4_define([unity_minor], [2]) -m4_define([unity_micro], [25]) +m4_define([unity_micro], [28]) m4_define([unity_api], [unity_major.unity_minor]) @@ -116,6 +116,7 @@ PKG_CHECK_MODULES(BASE, indicator libbamf >= 0.2 libgnomeui-2.0 + pango >= 1.6.0 unique-1.0 unity-misc x11) diff --git a/targets/mutter/Makefile.am b/targets/mutter/Makefile.am index bbb6d5b80..1e34e1d33 100644 --- a/targets/mutter/Makefile.am +++ b/targets/mutter/Makefile.am @@ -22,6 +22,7 @@ libunity_mutter_la_CPPFLAGS = \ -I$(top_srcdir)/unity \ -I$(top_srcdir)/unity-private \ -I$(top_srcdir)/src \ + -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ $(BASE_CFLAGS) \ $(MUTTER_CFLAGS) \ $(MAINTAINER_CFLAGS) diff --git a/targets/mutter/expose-manager.vala b/targets/mutter/expose-manager.vala index 33a490f8a..22f513d44 100644 --- a/targets/mutter/expose-manager.vala +++ b/targets/mutter/expose-manager.vala @@ -24,11 +24,22 @@ namespace Unity { private Clutter.Clone clone; private Clutter.Actor darken_box; + private Clutter.Actor original_parent; private bool hovered; + private bool dragging; + private float drag_start_x; + private float drag_start_y; + private bool drag_moved; + + public Clutter.Actor pre_drag_parent { get { return original_parent; } } + public float pre_drag_scale_x { get; private set; } + public float pre_drag_scale_y { get; private set; } public bool fade_on_close { get; set; } public unowned Clutter.Actor source { get; private set; } + + public signal void drag_dropped (Clutter.Actor onto); public uint8 hovered_opacity { get; set; } public uint8 unhovered_opacity { get; set; } @@ -42,12 +53,15 @@ namespace Unity darken_box.opacity = darken; } } + + public bool enable_dnd { get; set; } public ExposeClone (Clutter.Actor source) { darken = 0; hovered_opacity = 255; unhovered_opacity = 255; + enable_dnd = false; this.source = source; @@ -56,6 +70,8 @@ namespace Unity else clone = new Clutter.Clone (source); + source.destroy.connect (on_source_destroyed); + add_actor (clone); clone.show (); clone.reactive = true; @@ -75,6 +91,102 @@ namespace Unity { this.enter_event.connect (this.on_mouse_enter); this.leave_event.connect (this.on_mouse_leave); + this.button_press_event.connect (this.on_button_press); + } + + private void on_source_destroyed () + { + destroy (); + } + + private bool on_button_press (Clutter.Event evnt) + { + if (!enable_dnd) + return false; + + start_drag (evnt); + return true; + } + + private void start_drag (Clutter.Event evnt) + { + dragging = true; + this.get_stage ().captured_event.connect (on_stage_captured_event); + original_parent = get_parent (); + + float x, y; + double scale_x, scale_y; + evnt.get_coords (out x, out y); + get_scale (out scale_x, out scale_y); + + drag_start_x = x; + drag_start_y = y; + + pre_drag_scale_x = (float) scale_x; + pre_drag_scale_y = (float) scale_y; + + drag_moved = false; + } + + private void end_drag (int x, int y) + { + dragging = false; + clone.reactive = true; + reactive = true; + this.get_stage ().captured_event.disconnect (on_stage_captured_event); + + if (!drag_moved) + return; + + hide (); + Clutter.Actor target = (get_stage () as Clutter.Stage).get_actor_at_pos (Clutter.PickMode.REACTIVE, x, y); + show (); + + drag_dropped (target); + + on_mouse_leave (null); + } + + private bool on_stage_captured_event (Clutter.Event event) + { + float x, y; + event.get_coords (out x, out y); + + if (!dragging) + { + end_drag ((int) x, (int) y); + return false; + } + + if (event.type == Clutter.EventType.MOTION) + { + if (Math.fabs (event.motion.x - drag_start_x) > 30 || Math.fabs (event.motion.y - drag_start_y) > 30 || drag_moved) + { + if (!drag_moved) + { + float width, height; + + get_transformed_size (out width, out height); + + reparent (get_stage ()); + + this.set_scale (width / this.width, height / this.height); + + raise_top (); + drag_moved = true; + reactive = false; + clone.reactive = false; + } + set_position (event.motion.x - width / 2, event.motion.y - height / 2); + } + } + else if (event.type == Clutter.EventType.BUTTON_RELEASE) + { + end_drag ((int) x, (int) y); + return drag_moved; + } + + return false; } private bool on_mouse_enter (Clutter.Event evnt) @@ -85,7 +197,7 @@ namespace Unity return false; } - private bool on_mouse_leave (Clutter.Event evnt) + private bool on_mouse_leave (Clutter.Event? evnt) { hovered = false; opacity = unhovered_opacity; @@ -172,7 +284,7 @@ namespace Unity expose_group.destroy (); expose_group = new Clutter.Group (); - Clutter.Actor window_group = owner.plugin.get_normal_window_group (); + Clutter.Actor window_group = owner.plugin.get_window_group (); (window_group as Clutter.Container).add_actor (expose_group); expose_group.raise_top (); @@ -195,6 +307,8 @@ namespace Unity expose_group.add_actor (clone); + clone.destroy.connect (on_clone_destroyed); + clone.hovered_opacity = hovered_opacity; clone.unhovered_opacity = unhovered_opacity; clone.opacity = unhovered_opacity; @@ -223,6 +337,12 @@ namespace Unity stage.captured_event.connect (on_stage_captured_event); } + private void on_clone_destroyed () + { + if (expose_group.get_children ().length () <= 1) + end_expose (); + } + public void end_expose () { if (!expose_showing) diff --git a/targets/mutter/plugin.vala b/targets/mutter/plugin.vala index 646867611..ddaae16a0 100644 --- a/targets/mutter/plugin.vala +++ b/targets/mutter/plugin.vala @@ -110,6 +110,12 @@ namespace Unity public bool menus_swallow_events { get { return false; } } + private bool _super_key_active = false; + public bool super_key_active { + get { return _super_key_active; } + set { _super_key_active = value; } + } + public bool expose_showing { get { return expose_manager.expose_showing; } } private static const int PANEL_HEIGHT = 24; @@ -161,6 +167,7 @@ namespace Unity construct { + fullscreen_requests = new Gee.ArrayList<Object> (); Unity.global_shell = this; Unity.TimelineLogger.get_default(); // just inits the timer for logging // attempt to get a boot logging filename @@ -208,8 +215,8 @@ namespace Unity private bool real_construct () { START_FUNCTION (); - - fullscreen_requests = new Gee.ArrayList<Object> (); + + Clutter.set_gl_picking_enabled (false); this.stage = (Clutter.Stage)this.plugin.get_stage (); this.stage.actor_added.connect ((a) => { ensure_input_region (); }); @@ -237,6 +244,26 @@ namespace Unity Clutter.Group window_group = (Clutter.Group) this.plugin.get_window_group (); + /* we need to hook into the super key bound by mutter for g-shell. + don't ask me why mutter binds things for g-shell explictly... + */ + Mutter.MetaDisplay display = Mutter.MetaScreen.get_display (plugin.get_screen ()); + display.overlay_key_down.connect (() => { + super_key_active = true; + }); + + display.overlay_key.connect (() => { + super_key_active = false; + }); + + display.overlay_key_with_modifier.connect ((keysym) => { + super_key_modifier_release (keysym); + }); + + display.overlay_key_with_modifier_down.connect ((keysym) => { + super_key_modifier_press (keysym); + }); + this.background = new Background (); this.stage.add_actor (background); this.background.lower_bottom (); @@ -1118,13 +1145,10 @@ namespace Unity int width, int height) { - /*FIXME: This doesn't work in Mutter if (window.get_data<string> (UNDECORATED_HINT) == null) { - uint32 xid = (uint32)window.get_x_window (); - Utils.window_set_decorations (xid, 0); + Utils.window_set_decorations (Mutter.MetaWindow.get_xwindow (window.get_meta_window ()), 0); } - */ this.window_maximized (this, window, x, y, width, height); @@ -1137,13 +1161,10 @@ namespace Unity int width, int height) { - /* FIXME: This doesn't work in Mutter if (window.get_data<string> (UNDECORATED_HINT) == null) { - uint32 xid = (uint32)window.get_x_window (); - Utils.window_set_decorations (xid, 1); + Utils.window_set_decorations (Mutter.MetaWindow.get_xwindow (window.get_meta_window ()), 1); } - */ this.window_unmaximized (this, window, x, y, width, height); @@ -1152,11 +1173,30 @@ namespace Unity public void map (Mutter.Window window) { - /* FIXME: This doesn't work in Mutter - uint32 xid = (uint32)window.get_x_window (); - if (Utils.window_is_decorated (xid) == false) - window.set_data (UNDECORATED_HINT, "%s".printf ("true")); - */ + unowned Mutter.MetaWindow win = window.get_meta_window (); + + if (window.get_window_type () == Mutter.MetaCompWindowType.NORMAL) + { + Idle.add (() => { + if (win is Object) + { + if (Utils.window_is_decorated (Mutter.MetaWindow.get_xwindow (win)) == false && Mutter.MetaWindow.is_maximized (win) == false) + { + window.set_data (UNDECORATED_HINT, "%s".printf ("true")); + } + else + { + if (Mutter.MetaWindow.is_maximized (win)) + { + Utils.window_set_decorations (Mutter.MetaWindow.get_xwindow (win), 0); + } + } + } + + return false; + }); + } + this.maximus.process_window (window); this.window_mapped (this, window); diff --git a/targets/mutter/spaces-manager.vala b/targets/mutter/spaces-manager.vala index fff8b005b..e72874a4d 100644 --- a/targets/mutter/spaces-manager.vala +++ b/targets/mutter/spaces-manager.vala @@ -31,7 +31,7 @@ namespace Unity { this.parent = _parent; parent.notify["showing"].connect (on_notify_showing); - name = "Workspace Overview"; + name = _("Workspaces"); load_icon_from_icon_name ("workspace-switcher"); } @@ -52,10 +52,80 @@ namespace Unity { else parent.show_spaces_picker (); } + public override QuicklistController? get_menu_controller () + { + return new ApplicationQuicklistController (this); + } + + public override void get_menu_actions (ScrollerChildController.menu_cb callback) + { + callback (null); + } + + public override void get_menu_navigation (ScrollerChildController.menu_cb callback) + { + callback (null); + } + + public override bool can_drag () + { + return true; + } + + } + + public class WorkspaceClone : Clutter.Group + { + bool gridded; + Unity.Plugin plugin; + public unowned Mutter.MetaWorkspace workspace { get; private set; } + + public WorkspaceClone (Mutter.MetaWorkspace wsp, Unity.Plugin plugin) + { + workspace = wsp; + this.plugin = plugin; + + actor_added.connect (() => { + if (gridded) + grid (); + }); + + actor_removed.connect (() => { + if (gridded) + grid (); + }); + } + + private List<Clutter.Actor> toplevel_windows () + { + List<Clutter.Actor> windows = new List<Clutter.Actor> (); + + foreach (Clutter.Actor actor in get_children ()) + if (actor is ExposeClone && (actor as ExposeClone).source is Mutter.Window) + windows.prepend (actor); + + return windows; + } + + public void grid () + { + gridded = true; + plugin.expose_manager.position_windows_on_grid (toplevel_windows (), 50, 50, 50, 50); + } + + public void ungrid () + { + gridded = false; + int active_workspace = Mutter.MetaScreen.get_active_workspace_index (plugin.plugin.get_screen ()); + foreach (Clutter.Actor actor in toplevel_windows ()) + if (actor is ExposeClone) + (actor as ExposeClone).restore_window_position (active_workspace); + } } public class SpacesManager : GLib.Object { + Clutter.Group selector_group; Clutter.Actor background; List<Clutter.Actor> clones; Plugin plugin; @@ -118,10 +188,17 @@ namespace Unity { showing = true; plugin.add_fullscreen_request (this); + global_shell.get_stage ().captured_event.connect (on_stage_capture_event); + if (background is Clutter.Actor) background.destroy (); + + if (selector_group is Clutter.Actor) + selector_group.destroy (); background = new Clutter.Rectangle.with_color ({0, 0, 0, 255}); + selector_group = new Clutter.Group (); + unowned Mutter.MetaScreen screen = plugin.plugin.get_screen (); unowned GLib.List<Mutter.MetaWorkspace> workspaces = Mutter.MetaScreen.get_workspaces (screen); unowned Clutter.Container window_group = plugin.plugin.get_normal_window_group() as Clutter.Container; @@ -130,23 +207,42 @@ namespace Unity { Mutter.MetaScreen.get_monitor_geometry (screen, 0, rect); background.set_size (rect.width, rect.height); - window_group.add_actor (background); + selector_group.add_actor (background); background.raise_top (); + background.reactive = true; foreach (unowned Mutter.MetaWorkspace workspace in workspaces) { Clutter.Actor clone = workspace_clone (workspace); clones.append (clone); - window_group.add_actor (clone); + selector_group.add_actor (clone); clone.reactive = true; clone.raise_top (); clone.show (); - + clone.opacity = 200; + unowned Mutter.MetaWorkspace cpy = workspace; - clone.button_release_event.connect (() => { select_workspace (cpy); return true; }); + clone.button_release_event.connect (() => { + select_workspace (cpy); + return true; + }); + + clone.enter_event.connect (() => { + clone.opacity = 255; + clone.raise_top (); + return true; + }); + + clone.leave_event.connect (() => { + clone.opacity = 200; + return true; + }); } + window_group.add_actor (selector_group); + selector_group.raise_top (); + layout_workspaces (clones, screen); unowned GLib.List<Mutter.Window> windows = plugin.plugin.get_windows (); @@ -156,6 +252,20 @@ namespace Unity { } } + private bool on_stage_capture_event (Clutter.Event event) + { + if (event.type == Clutter.EventType.BUTTON_PRESS) + { + if (event.button.y <= global_shell.get_panel_height_foobar () || + event.button.x <= global_shell.get_launcher_width_foobar ()) + { + select_workspace (null); + } + } + + return false; + } + private void select_workspace (Mutter.MetaWorkspace? workspace) { if (workspace == null) { @@ -169,16 +279,17 @@ namespace Unity { Mutter.MetaWorkspace.activate (workspace, time_); plugin.remove_fullscreen_request (this); showing = false; - } + global_shell.get_stage ().captured_event.disconnect (on_stage_capture_event); + } + private Clutter.Actor workspace_clone (Mutter.MetaWorkspace workspace) { - Clutter.Group wsp; + WorkspaceClone wsp; unowned GLib.List<Mutter.Window> windows; windows = plugin.plugin.get_windows (); - wsp = new Clutter.Group (); - List<Clutter.Actor> toplevel_windows = new List<Clutter.Actor> (); + wsp = new WorkspaceClone (workspace, plugin); foreach (Mutter.Window window in windows) { @@ -194,12 +305,58 @@ namespace Unity { ExposeClone clone = new ExposeClone (window); clone.fade_on_close = false; + clone.reactive = true; + clone.darken = 25; + clone.enable_dnd = true; + + clone.drag_dropped.connect ((t) => { + WorkspaceClone new_parent = clone.pre_drag_parent as WorkspaceClone; + + while (!(t is Clutter.Stage)) + { + if (t is WorkspaceClone) + { + new_parent = t as WorkspaceClone; + break; + } + t = t.get_parent (); + } + + float x, y; + + clone.move_anchor_point_from_gravity (Clutter.Gravity.CENTER); + new_parent.transform_stage_point (clone.x, clone.y, out x, out y); + + clone.set_scale (clone.pre_drag_scale_x, clone.pre_drag_scale_y); + clone.set_position (x, y); + + clone.move_anchor_point_from_gravity (Clutter.Gravity.NORTH_WEST); + + clone.reparent (new_parent); + + Mutter.MetaWindow.change_workspace_by_index ((clone.source as Mutter.Window).get_meta_window (), + Mutter.MetaWorkspace.index (new_parent.workspace), + true, + plugin.get_current_time ()); + }); wsp.add_actor (clone); - toplevel_windows.prepend (clone); clone.set_size (window.width, window.height); clone.set_position (window.x, window.y); + + clone.button_release_event.connect (() => { + uint32 time_; + + clone.raise_top (); + unowned Mutter.MetaWindow meta = (clone.source as Mutter.Window).get_meta_window (); + + time_ = Mutter.MetaDisplay.get_current_time (Mutter.MetaWindow.get_display (meta)); + Mutter.MetaWorkspace.activate (Mutter.MetaWindow.get_workspace (meta), time_); + Mutter.MetaWindow.activate (meta, time_); + + return false; + }); clone.show (); } @@ -211,8 +368,10 @@ namespace Unity { wsp.add_actor (background_clone); background_clone.lower_bottom (); background_clone.show (); - - plugin.expose_manager.position_windows_on_grid (toplevel_windows, 50, 50, 50, 50); + + wsp.grid (); + + wsp.set_size (background_clone.width, background_clone.height); return wsp; } @@ -242,11 +401,8 @@ namespace Unity { "y", (float) yoffset, "scale-x", 1.0f, "scale-y", 1.0f); - - int active_workspace = Mutter.MetaScreen.get_active_workspace_index (plugin.plugin.get_screen ()); - foreach (Clutter.Actor actor in (clone as Clutter.Group).get_children ()) - if (actor is ExposeClone) - (actor as ExposeClone).restore_window_position (active_workspace); + + (clone as WorkspaceClone).ungrid (); anim.completed.connect (() => { clone.destroy (); diff --git a/tests/ui/test-home-button.vala b/tests/ui/test-home-button.vala index e957b13b0..95692883b 100644 --- a/tests/ui/test-home-button.vala +++ b/tests/ui/test-home-button.vala @@ -34,6 +34,7 @@ namespace Unity.Tests.UI Clutter.Stage? stage; Unity.Testing.Director director; Unity.Panel.HomeButton home_button; + public bool super_key_active {get; set;} public HomeButtonSuite () { diff --git a/tests/unit/test-appinfo-manager.vala b/tests/unit/test-appinfo-manager.vala index 28c4572bd..f008d054c 100644 --- a/tests/unit/test-appinfo-manager.vala +++ b/tests/unit/test-appinfo-manager.vala @@ -91,12 +91,20 @@ namespace Unity.Tests.Unit string old_datadir = Environment.get_user_data_dir (); var manager = AppInfoManager.get_instance(); - Environment.set_variable ("XDG_DATA_HOME", Config.TESTUNITDIR, true); + Environment.set_variable ("XDG_DATA_HOME", Config.TESTUNITDIR+"/data", true); + debug ("XDG %s", Config.TESTUNITDIR+"/data"); var info = manager.lookup ("ubuntu-about.desktop"); + assert (info != null); assert (info is AppInfo); assert ("About Ubuntu" == info.get_name ()); + Gee.List<string> categories = manager.get_categories ("ubuntu-about.desktop"); + assert (categories != null); + assert (categories[0] == "GNOME"); + assert (categories[1] == "Application"); + assert (categories[2] == "Core"); + /* Reset the environment like a good citizen */ Environment.set_variable ("XDG_DATA_HOME", old_datadir, true); } @@ -113,7 +121,7 @@ namespace Unity.Tests.Unit string old_datadir = Environment.get_user_data_dir (); var manager = AppInfoManager.get_instance(); - Environment.set_variable ("XDG_DATA_HOME", Config.TESTUNITDIR, true); + Environment.set_variable ("XDG_DATA_HOME", Config.TESTUNITDIR+"/data", true); try{ var info = yield manager.lookup_async ("ubuntu-about.desktop"); @@ -123,6 +131,12 @@ namespace Unity.Tests.Unit error ("Error reading desktop file: %s", e.message); } + Gee.List<string> categories = manager.get_categories ("ubuntu-about.desktop"); + assert (categories != null); + assert (categories[0] == "GNOME"); + assert (categories[1] == "Application"); + assert (categories[2] == "Core"); + /* Reset the environment like a good citizen */ Environment.set_variable ("XDG_DATA_HOME", old_datadir, true); diff --git a/unity-private/Makefile.am b/unity-private/Makefile.am index 38b98be75..0637e5eb0 100644 --- a/unity-private/Makefile.am +++ b/unity-private/Makefile.am @@ -38,6 +38,7 @@ libunity_private_la_VALAFLAGS = \ --library unity-private \ --vapidir=$(top_srcdir)/vapi/ \ --vapidir=$(top_srcdir)/unity/ \ + --pkg Bamf-0.2 \ --pkg clutk-0.3 \ --pkg clutter-1.0 \ --pkg clutter-gtk-0.10 \ @@ -54,8 +55,8 @@ libunity_private_la_VALAFLAGS = \ --pkg gtk+-2.0 \ --pkg gnome-bg-2.0 \ --pkg indicator \ - --pkg Bamf-0.2 \ --pkg libwnck-1.0 \ + --pkg pango \ --pkg unity \ --pkg unity-const \ --pkg unity-misc \ @@ -97,6 +98,7 @@ places_sources = \ places/places-place-entry-view.vala \ places/places-place-entry.vala \ places/places-place-home.vala \ + places/places-place-home-renderer.vala \ places/places-place-model.vala \ places/places-place-view.vala \ places/places-place.vala \ @@ -105,7 +107,9 @@ places_sources = \ places/places-place-search-navigation.vala \ places/places-place-search-sections-bar.vala \ places/places-trash-controller.vala \ - places/places-view.vala + places/places-view.vala \ + places/places-volume-controller.vala \ + places/places-volume-child-controller.vala launcher_sources = \ launcher/application-controller.vala \ diff --git a/unity-private/launcher/quicklist-check-menu-item.vala b/unity-private/launcher/quicklist-check-menu-item.vala index 804958e9e..e503cad05 100644 --- a/unity-private/launcher/quicklist-check-menu-item.vala +++ b/unity-private/launcher/quicklist-check-menu-item.vala @@ -55,7 +55,9 @@ namespace Unity.Launcher this.label, out width, out height); - min_width_p = (float) width + (float) Ctk.em_to_pixel (2 * MARGIN) + 30.0f; + min_width_p = (float) width + + (float) Ctk.em_to_pixel (2 * MARGIN) + + ITEM_INDENT_ABS; natural_width_p = min_width_p; } diff --git a/unity-private/launcher/quicklist-image-menu-item.vala b/unity-private/launcher/quicklist-image-menu-item.vala index feb71f975..806f071b0 100644 --- a/unity-private/launcher/quicklist-image-menu-item.vala +++ b/unity-private/launcher/quicklist-image-menu-item.vala @@ -56,7 +56,9 @@ namespace Unity.Launcher this.label, out width, out height); - min_width_p = (float) width + (float) Ctk.em_to_pixel (2 * MARGIN); + min_width_p = (float) width + + (float) Ctk.em_to_pixel (2 * MARGIN) + + ITEM_INDENT_ABS; natural_width_p = min_width_p; } diff --git a/unity-private/launcher/quicklist-menu-item.vala b/unity-private/launcher/quicklist-menu-item.vala index 1c3b61ebf..0a6b62ee6 100644 --- a/unity-private/launcher/quicklist-menu-item.vala +++ b/unity-private/launcher/quicklist-menu-item.vala @@ -57,7 +57,9 @@ namespace Unity.Launcher this.label, out width, out height); - min_width_p = (float) width + (float) Ctk.em_to_pixel (2 * MARGIN); + min_width_p = (float) width + + (float) Ctk.em_to_pixel (2 * MARGIN) + + 2 * ITEM_INDENT_ABS; natural_width_p = min_width_p; } diff --git a/unity-private/launcher/quicklist-radio-menu-item.vala b/unity-private/launcher/quicklist-radio-menu-item.vala index 5a49319ba..e9b826c31 100644 --- a/unity-private/launcher/quicklist-radio-menu-item.vala +++ b/unity-private/launcher/quicklist-radio-menu-item.vala @@ -55,7 +55,9 @@ namespace Unity.Launcher this.label, out width, out height); - min_width_p = (float) width + (float) Ctk.em_to_pixel (2 * MARGIN) + 30.0f; + min_width_p = (float) width + + (float) Ctk.em_to_pixel (2 * MARGIN) + + ITEM_INDENT_ABS; natural_width_p = min_width_p; } diff --git a/unity-private/launcher/quicklist-view.vala b/unity-private/launcher/quicklist-view.vala index c2fa933a2..ce0675cfc 100644 --- a/unity-private/launcher/quicklist-view.vala +++ b/unity-private/launcher/quicklist-view.vala @@ -34,6 +34,7 @@ namespace Unity.Launcher const float ITEM_HEIGHT = 2.0f; const float ITEM_CORNER_RADIUS = 0.3f; const float ITEM_CORNER_RADIUS_ABS = 4.0f; + const float ITEM_INDENT_ABS = 20.0f; const float ANCHOR_HEIGHT = 1.5f; const float ANCHOR_HEIGHT_ABS = 18.0f; const float ANCHOR_WIDTH = 0.75f; @@ -71,7 +72,7 @@ namespace Unity.Launcher new_width = (int) (box.x2 - box.x1); new_height = (int) (box.y2 - box.y1); - + // exit early if the allocation-width/height didn't change, this is needed // because clutter triggers calling allocate even if nothing changed if ((this.last_width == new_width) && (this.last_height == new_height)) @@ -81,23 +82,23 @@ namespace Unity.Launcher this.last_width = new_width; this.last_height = new_height; - debug ("Num Items in Menu %d \n", get_num_items ()); - + //debug ("Num Items in Menu %d \n", get_num_items ()); + base.allocate (box, flags); - + // float x; // float y; // this.get_position(out x, out y); // this.compute_style_textures (); // this.set_expansion_size_factor (0.0f); // this.set_anchor_position ((int)60 + 60, (int)100+48, 25); -// +// // if(get_num_items () > 1) // this.animate (Clutter.AnimationMode.LINEAR, // 100, // "expansion-size-factor", 1.0f); - - + + } construct diff --git a/unity-private/launcher/scroller-controller.vala b/unity-private/launcher/scroller-controller.vala index 02fa113b0..cdd3e2ccc 100644 --- a/unity-private/launcher/scroller-controller.vala +++ b/unity-private/launcher/scroller-controller.vala @@ -66,6 +66,41 @@ namespace Unity.Launcher // hook up to the drag controller var drag_controller = Drag.Controller.get_default (); drag_controller.drag_start.connect (on_unity_drag_start); + + Unity.global_shell.notify["super-key-active"].connect (on_super_key_active); + Unity.global_shell.super_key_modifier_release.connect (on_super_key_modifier_release); + } + + private void on_super_key_modifier_release (uint keycode) + { + if (!Unity.global_shell.super_key_active) return; + int index = (int)keycode - 10; + index = int.min (index, model.size - 1); + if (index < 0 || index > 9) return; + + Unity.global_shell.super_key_active = false; + + var childcontroller = get_controller_for_view (model[index]); + childcontroller.activate (); + } + + uint super_key_source = 0; + private void on_super_key_active () + { + if (Unity.global_shell.super_key_active && super_key_source == 0) + super_key_source = Timeout.add (300, () => { + view.enable_keyboard_selection_mode (Unity.global_shell.super_key_active); + return false; + }); + else + { + if (super_key_source != 0) + { + Source.remove (super_key_source); + super_key_source = 0; + } + view.enable_keyboard_selection_mode (false); + } } private void handle_bamf_view_opened (Object object) @@ -317,7 +352,7 @@ namespace Unity.Launcher } ScrollerChildController model_controller = drag_controller.get_drag_model () as ScrollerChildController; ScrollerChild retcont = model_controller.child; - + if (retcont.group_type == ScrollerChild.GroupType.PLACE || retcont.group_type == ScrollerChild.GroupType.SYSTEM) { @@ -331,9 +366,12 @@ namespace Unity.Launcher (retcont.controller as ApplicationController).set_sticky (false); (retcont.controller as ApplicationController).close_windows (); } - if (retcont in model) - model.remove (retcont); - + if (retcont in model || + retcont.group_type == ScrollerChild.GroupType.DEVICE) + { + retcont.drag_removed (); + model.remove (retcont); + } if (model_controller is ApplicationController) { (model_controller as ApplicationController).set_sticky (false); diff --git a/unity-private/launcher/scroller-view.vala b/unity-private/launcher/scroller-view.vala index a13bd7db3..c2a144887 100644 --- a/unity-private/launcher/scroller-view.vala +++ b/unity-private/launcher/scroller-view.vala @@ -73,6 +73,8 @@ namespace Unity.Launcher private ScrollerPhase current_phase = ScrollerPhase.SETTLING; private uint last_motion_event_time = 0; private ScrollerViewType view_type = ScrollerViewType.CONTRACTED; + private float last_known_pointer_x = 0.0f; + /* * scrolling variables */ @@ -91,13 +93,17 @@ namespace Unity.Launcher private uint stored_delta = 0; private float scroll_speed = 0.0f; // the current speed (pixels/per second) that we are scrolling - private float contract_icon_degrees = 30.0f; + private float contract_icon_degrees = 70.0f; + private float contract_icon_partial_degrees = 30.0f; private int focused_launcher = 0; /* helps out with draw order */ private Gee.ArrayList<ScrollerChild> draw_ftb; private Gee.ArrayList<ScrollerChild> draw_btf; + /* Key binding indicators */ + private Gee.ArrayList<Clutter.CairoTexture> keyboard_indicators; + /* * Refrence holders */ @@ -124,6 +130,7 @@ namespace Unity.Launcher this.padding = mypadding; + keyboard_indicators = new Gee.ArrayList <Clutter.CairoTexture> (); load_textures (); model.child_added.connect (model_child_added); model.child_removed.connect (model_child_removed); @@ -141,9 +148,11 @@ namespace Unity.Launcher button_release_event.connect (on_button_release_event); motion_event.connect (on_motion_event); enter_event.connect (on_enter_event); + leave_event.connect (on_leave_event); notify["is-autoscrolling"].connect (on_auto_scrolling_state_change); Unity.Drag.Controller.get_default ().drag_motion.connect (on_drag_motion_event); + // set a timeline for our fling animation fling_timeline = new Clutter.Timeline (1000); fling_timeline.loop = true; @@ -258,6 +267,7 @@ namespace Unity.Launcher { var drag_controller = Drag.Controller.get_default (); if (drag_controller.is_dragging) return false; + if (is_scrolling) return false; enter_event.disconnect (on_enter_event); leave_event.disconnect (on_leave_event); motion_event.disconnect (on_motion_event); @@ -278,6 +288,7 @@ namespace Unity.Launcher { var drag_controller = Drag.Controller.get_default (); if (drag_controller.is_dragging) return false; + if (is_scrolling) return false; enter_event.disconnect (on_enter_event); leave_event.disconnect (on_leave_event); @@ -296,6 +307,8 @@ namespace Unity.Launcher { var drag_controller = Drag.Controller.get_default (); if (drag_controller.is_dragging) return false; + if (is_scrolling) return false; + enter_event.disconnect (on_enter_event); leave_event.disconnect (on_leave_event); button_release_event.disconnect (passthrough_button_release_event); @@ -309,6 +322,52 @@ namespace Unity.Launcher return false; } + private float last_scroll_position = 0.0f; + public void enable_keyboard_selection_mode (bool choice) + { + if (choice) + last_scroll_position = scroll_position; + + uint8 new_opacity = (choice) ? 0xff : 0x00; + + int index = 1; + foreach (Clutter.CairoTexture kb_ind in keyboard_indicators) + { + kb_ind.animate (Clutter.AnimationMode.EASE_OUT_SINE, 150, + "opacity", new_opacity); + if (model.size <= index) new_opacity = 0x00; + index++; + } + + + if (!choice) + { + if (view_type != ScrollerViewType.CONTRACTED && + last_known_pointer_x >= get_width ()) + { + foreach (ScrollerChild child in model) + { + if (child.active) + { + focused_launcher = model.index_of (child); + break; + } + } + contract_launcher (); + } + else if (last_known_pointer_x < get_width ()) + { + move_scroll_position (last_scroll_position - scroll_position); + } + } + else + { + expand_launcher (0); + } + + + } + public int get_model_index_at_y_pos_no_anim (float y, bool return_minus_if_fail=false) { SList<float?> positions = new SList<float?> (); @@ -387,6 +446,57 @@ namespace Unity.Launcher return ret_val; } + private void draw_keyboard_indicator_cairo (Cairo.Context cr, string text) + { + double x = 0; + double y = 0; + double w = 10; + double h = 10; + double r = Ctk.em_to_pixel (1); + + Gtk.Settings settings = Gtk.Settings.get_default (); + Pango.FontDescription desc = Pango.FontDescription.from_string (settings.gtk_font_name); + + cr.select_font_face (desc.get_family (), + Cairo.FontSlant.NORMAL, + Cairo.FontWeight.NORMAL); + double size; + size = Ctk.em_to_pixel (1) * 0.9; + cr.set_font_size (size); + + + Cairo.TextExtents extents = Cairo.TextExtents (); + cr.text_extents ("2", out extents); + + Cairo.TextExtents real_extents = Cairo.TextExtents (); + cr.text_extents (text, out extents); + + double w_diff = extents.width - real_extents.width; + double h_diff = extents.height - real_extents.height; + + w += extents.width; + h += extents.height; + cr.set_source_rgba (0.07, 0.07, 0.07, 0.8); + + cr.move_to(x+r,y); // Move to A + cr.line_to(x+w-r,y); // Straight line to B + cr.curve_to(x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q + cr.line_to(x+w,y+h-r); // Move to D + cr.curve_to(x+w,y+h,x+w,y+h,x+w-r,y+h); // Curve to E + cr.line_to(x+r,y+h); // Line to F + cr.curve_to(x,y+h,x,y+h,x,y+h-r); // Curve to G + cr.line_to(x,y+r); // Line to H + cr.curve_to(x,y,x,y,x+r,y); // Curve to + + cr.fill (); + + //x = (extents.width - real_extents.width) / 2.0; + y = 0;//(extents.height - real_extents.height) / 2.0; + cr.set_source_rgba (1, 1, 1, 1); + cr.move_to (x + 5 - (real_extents.width * 0.5), y+5+extents.height); + cr.show_text (text); + } + /* * private methods */ @@ -399,6 +509,47 @@ namespace Unity.Launcher top_shadow = new ThemeImage ("overflow_top"); top_shadow.set_repeat (true, false); top_shadow.set_parent (this); + + var color = Clutter.Color () { + red = 0xff, + green = 0xff, + blue = 0xff, + alpha = 0xff + }; + + //!!FIXME!! these are positioned wrong, needs to know the absolute + // size of the resulting cario surface before creating it =\ + int index = 1; + // indicator size find out activate! + int key_indicator_w, key_indicator_h; + Gtk.Settings settings = Gtk.Settings.get_default (); + + Unity.QuicklistRendering.get_text_extents (settings.gtk_font_name, "2", + out key_indicator_w, out key_indicator_h); + + key_indicator_w += 10; + key_indicator_h += 10; + + for (; index <= 10; index++) + { + var keyboard_indicator = new Clutter.CairoTexture (key_indicator_w, key_indicator_h); + keyboard_indicator.set_parent (this); + keyboard_indicator.opacity = 0x00; + + keyboard_indicator.set_surface_size (key_indicator_w, key_indicator_h); + keyboard_indicator.set_size (key_indicator_w, key_indicator_h); + keyboard_indicator.clear (); + { + Cairo.Context cr = keyboard_indicator.create (); + + string ind_str = index.to_string (); + if (index == 10) + ind_str = "0"; + + draw_keyboard_indicator_cairo (cr, ind_str); + } + keyboard_indicators.add (keyboard_indicator); + } } // will move the scroller by the given pixels @@ -441,6 +592,58 @@ namespace Unity.Launcher } + private void expand_launcher (float absolute_y) + { + if (view_type == ScrollerViewType.EXPANDED) return; + view_type = ScrollerViewType.EXPANDED; + + // we need to set a new scroll position + // get the index of the icon we are hovering over + if (get_total_children_height () > get_available_height ()) + { + int index = get_model_index_at_y_pos (absolute_y); + + // set our state to what we will end up being so we can find the correct + //place to be. + float contracted_position = model[index].position; + var old_scroll_position = scroll_position; + scroll_position = 0; + order_children (true); + + float new_scroll_position = -(model[index].position - contracted_position); + + //reset our view so that we animate cleanly to the new view + view_type = ScrollerViewType.CONTRACTED; + scroll_position = old_scroll_position; + order_children (true); + + // and finally animate to the new view + view_type = ScrollerViewType.EXPANDED; + + scroll_position = new_scroll_position; + order_children (false); // have to order twice, boo + + queue_relayout (); + } + } + + + private void contract_launcher () + { + if (view_type == ScrollerViewType.CONTRACTED) return; + + foreach (ScrollerChild child in model) + { + if (child.active) + focused_launcher = model.index_of (child); + } + + view_type = ScrollerViewType.CONTRACTED; + order_children (false); + queue_relayout (); + is_autoscrolling = false; + } + /* * model signal connections */ @@ -556,60 +759,46 @@ namespace Unity.Launcher return false; } + + uint queue_contract_launcher = 0; private bool on_enter_event (Clutter.Event event) { - if (view_type == ScrollerViewType.EXPANDED) return false; - view_type = ScrollerViewType.EXPANDED; - - // we need to set a new scroll position - // get the index of the icon we are hovering over - if (get_total_children_height () > get_available_height ()) + if (queue_contract_launcher != 0) { - int index = get_model_index_at_y_pos (event.crossing.y); - - // set our state to what we will end up being so we can find the correct - //place to be. - float contracted_position = model[index].position; - var old_scroll_position = scroll_position; - scroll_position = 0; - order_children (true); - - float new_scroll_position = -(model[index].position - contracted_position); - - //reset our view so that we animate cleanly to the new view - view_type = ScrollerViewType.CONTRACTED; - scroll_position = old_scroll_position; - order_children (true); - - // and finally animate to the new view - view_type = ScrollerViewType.EXPANDED; + Source.remove (queue_contract_launcher); + queue_contract_launcher = 0; + } - scroll_position = new_scroll_position; - order_children (false); // have to order twice, boo + expand_launcher (event.crossing.y); + return false; + } - queue_relayout (); - } + private bool on_queue_contract_launcher () + { + if (queue_contract_launcher != 0) + contract_launcher (); + queue_contract_launcher = 0; + return false; + } + private bool do_queue_contract_launcher () + { + queue_contract_launcher = Timeout.add (250, on_queue_contract_launcher); return false; } private bool on_leave_event (Clutter.Event event) { - if (view_type == ScrollerViewType.CONTRACTED) return false; + last_known_pointer_x = 200; + if (is_scrolling) return false; + do_queue_contract_launcher (); - foreach (ScrollerChild child in model) + if (last_picked_actor is Clutter.Actor && + last_picked_actor != this) { - if (child.active) - focused_launcher = model.index_of (child); + last_picked_actor.do_event (event, false); + last_picked_actor = null; } - - view_type = ScrollerViewType.CONTRACTED; - order_children (false); - queue_relayout (); - is_autoscrolling = false; - - if (last_picked_actor is Clutter.Actor) - last_picked_actor.do_event (event, false); return false; } @@ -948,7 +1137,7 @@ namespace Unity.Launcher child.rotation = transitions[index].rotation; if (do_new_position) - child.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, + child.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300, "position", transitions[index].position ); @@ -964,6 +1153,8 @@ namespace Unity.Launcher float min_height, nat_height; if (!(draw_ftb is Gee.ArrayList)) draw_ftb = new Gee.ArrayList<ScrollerChild> (); + + if (!(draw_ftb is Gee.ArrayList)) draw_btf = new Gee.ArrayList<ScrollerChild> (); foreach (ScrollerChild child in model) @@ -973,8 +1164,8 @@ namespace Unity.Launcher transition.position = h + scroll_position; transition.rotation = 0.0f; ret_transitions.add (transition); - if (!(child in draw_ftb || child in draw_ftb)) - draw_ftb.add (child); + //if (!(child in draw_ftb || child in draw_ftb)) + //draw_ftb.add (child); h += nat_height + spacing; } return ret_transitions; @@ -1037,10 +1228,9 @@ namespace Unity.Launcher { ScrollerChild child = model[index]; var transition = new ChildTransition (); + child.get_preferred_height (get_width (), out min_height, out nat_height); if (index >= index_start_flat && index < index_end_flat) { - - child.get_preferred_height (get_width (), out min_height, out nat_height); transition.position = h; h += nat_height + spacing; num_children_handled++; @@ -1054,20 +1244,38 @@ namespace Unity.Launcher else { // contracted launcher - if (index == index_end_flat) h -= spacing * 2; + if (index == index_end_flat) h -= nat_height * 0.3333f - spacing;//spacing * 2; - transition.position = h; - h += 8 + spacing; if (num_children_handled < index_start_flat) { - transition.rotation = -contract_icon_degrees; + if (num_children_handled == index_start_flat - 1) + { + transition.rotation = -contract_icon_partial_degrees; + h += spacing; + } + else + { + transition.rotation = -contract_icon_degrees; + } + transition.position = h; draw_ftb.add (child); } else { - transition.rotation = contract_icon_degrees; + transition.position = h; + if (index == index_end_flat) + { + transition.rotation = contract_icon_partial_degrees; + h += spacing; + } + else + { + transition.rotation = contract_icon_degrees; + } draw_btf.add (child); } + + h += 8 + spacing; num_children_handled++; if (index +1 == index_start_flat) h += 30; @@ -1108,6 +1316,7 @@ namespace Unity.Launcher float available_width = box.get_width () - padding.right; total_child_height = 0.0f; + uint index = 0; foreach (ScrollerChild child in model) { @@ -1133,7 +1342,26 @@ namespace Unity.Launcher total_child_height += child_height + spacing; + + if (index >= 0 && index <= 9) + { + Clutter.CairoTexture? keyboard_indicator = null; + keyboard_indicator = keyboard_indicators[(int)index]; + + if (keyboard_indicator is Clutter.Actor) + { + uint surface_width, surface_height; + keyboard_indicator.get_surface_size (out surface_width, out surface_height); + child_box.x1 = box.get_width () - padding.right - surface_width - 6; + child_box.x2 = child_box.x1 + keyboard_indicator.get_width (); + child_box.y1 = child.position + padding.top + ((child_box.get_height ()*0.5f) - (surface_height*0.5f)); + child_box.y2 = child_box.y1 + keyboard_indicator.get_height (); + keyboard_indicator.allocate (child_box, flags); + } + + index += 1; } + } child_box.x1 = 0; child_box.x2 = box.get_width (); @@ -1202,11 +1430,28 @@ namespace Unity.Launcher } } + foreach (ScrollerChild child in model) + { + if ((child in draw_ftb) || (child in draw_btf)) + continue; + + if (child is ScrollerChild && child.opacity > 0) + { + (child as ScrollerChild).paint (); + } + } + + foreach (ScrollerChild child in child_refs) { child.paint (); } + foreach (Clutter.CairoTexture kb_ind in keyboard_indicators) + { + kb_ind.paint (); + } + top_shadow.paint (); } @@ -1215,10 +1460,16 @@ namespace Unity.Launcher base.map (); bgtex.map (); top_shadow.map (); + foreach (Clutter.CairoTexture kb_ind in keyboard_indicators) + { + kb_ind.map (); + } + foreach (ScrollerChild child in model) { child.map (); } + } public override void unmap () @@ -1226,6 +1477,11 @@ namespace Unity.Launcher base.unmap (); bgtex.map (); top_shadow.map (); + foreach (Clutter.CairoTexture kb_ind in keyboard_indicators) + { + kb_ind.paint (); + } + foreach (ScrollerChild child in model) { child.unmap (); diff --git a/unity-private/launcher/scrollerchild.vala b/unity-private/launcher/scrollerchild.vala index cc4995cca..62a6288f7 100644 --- a/unity-private/launcher/scrollerchild.vala +++ b/unity-private/launcher/scrollerchild.vala @@ -92,13 +92,13 @@ namespace Unity.Launcher private Clutter.Animation running_indicator_anim; private Clutter.Timeline wiggle_timeline; private Clutter.Timeline glow_timeline; - private Clutter.Timeline rotate_timeline; private AnimState glow_state; private AnimState wiggle_state; - private AnimState rotate_state; private float old_rotate_value = 0.0f; + public signal void drag_removed (); + public ScrollerChild () { Object (group_type:GroupType.APPLICATION); @@ -112,11 +112,9 @@ namespace Unity.Launcher //icon glow glow_timeline = new Clutter.Timeline (1); wiggle_timeline = new Clutter.Timeline (1); - rotate_timeline = new Clutter.Timeline (1); glow_timeline.new_frame.connect (on_glow_timeline_new_frame); wiggle_timeline.new_frame.connect (on_wiggle_timeline_new_frame); - rotate_timeline.new_frame.connect (on_rotate_timeline_new_frame); notify["rotation"].connect (on_rotation_changed); } @@ -184,42 +182,13 @@ namespace Unity.Launcher } /* animation callbacks */ - private void on_rotate_timeline_new_frame () - { - float progress = (float)rotate_timeline.get_progress (); - switch (rotate_state) - { - case AnimState.RISING: - rotate_anim_rising (progress); - break; - - case AnimState.STOPPED: - rotate_timeline.stop (); - break; - } - processed_icon.do_queue_redraw (); - } - - private void rotate_anim_rising (float progress) - { - progress = get_ease_out_sine (progress); - var diff = rotation - old_rotate_value; - float rotate_val = old_rotate_value + (progress * diff); - - processed_icon.rotation = rotate_val; - if (progress >= 1.0) - { - rotate_state = AnimState.STOPPED; - rotate_timeline.stop (); - } - } - public void force_rotation_jump (float degrees) { + if (processed_icon.get_animation () is Clutter.Animation) + processed_icon.get_animation ().completed (); + processed_icon.rotation = degrees; rotation = degrees; - rotate_state = AnimState.STOPPED; - rotate_timeline.stop (); do_queue_redraw (); } @@ -455,18 +424,12 @@ namespace Unity.Launcher { old_rotate_value = processed_icon.rotation; - if (rotate_timeline is Clutter.Timeline == false) - return; - - if (rotate_timeline.is_playing ()) - { - rotate_timeline.stop (); - processed_icon.rotation = old_rotate_value; - } + if (processed_icon.get_animation () is Clutter.Animation) + processed_icon.get_animation ().completed (); - rotate_timeline.set_duration (300); - rotate_state = AnimState.RISING; - rotate_timeline.start (); + processed_icon.rotation = old_rotate_value; + processed_icon.animate (Clutter.AnimationMode.EASE_OUT_QUINT, 300, + "rotation", rotation); } private void on_activating_changed () @@ -487,7 +450,6 @@ namespace Unity.Launcher blue = 255, alpha = 255 }; - effect_icon_glow.set_background_texture (honeycomb_mask); effect_icon_glow.set_color (c); effect_icon_glow.set_opacity (1.0f); processed_icon.add_effect (effect_icon_glow); diff --git a/unity-private/panel/panel-home-button.vala b/unity-private/panel/panel-home-button.vala index 3bb08298b..d36abb29d 100644 --- a/unity-private/panel/panel-home-button.vala +++ b/unity-private/panel/panel-home-button.vala @@ -95,8 +95,8 @@ namespace Unity.Panel warning ("Could not load active-state bg-texture: %s", e.message); } - //set_background_for_state (Ctk.ActorState.STATE_NORMAL, bfb_bg_normal); - //set_background_for_state (Ctk.ActorState.STATE_PRELIGHT, bfb_bg_prelight); + set_background_for_state (Ctk.ActorState.STATE_NORMAL, bfb_bg_normal); + set_background_for_state (Ctk.ActorState.STATE_PRELIGHT, bfb_bg_prelight); set_background_for_state (Ctk.ActorState.STATE_ACTIVE, bfb_bg_active); search_shown = false; @@ -186,8 +186,8 @@ namespace Unity.Panel { if (mode == ShellMode.MINIMIZED) { - //set_background_for_state (Ctk.ActorState.STATE_NORMAL, bfb_bg_normal); - //set_background_for_state (Ctk.ActorState.STATE_PRELIGHT, bfb_bg_prelight); + set_background_for_state (Ctk.ActorState.STATE_NORMAL, bfb_bg_normal); + set_background_for_state (Ctk.ActorState.STATE_PRELIGHT, bfb_bg_prelight); set_background_for_state (Ctk.ActorState.STATE_ACTIVE, bfb_bg_active); search_shown = false; } diff --git a/unity-private/panel/panel-indicator-object-entry-view.vala b/unity-private/panel/panel-indicator-object-entry-view.vala index 35d2f9fc3..f24ce0a3b 100644 --- a/unity-private/panel/panel-indicator-object-entry-view.vala +++ b/unity-private/panel/panel-indicator-object-entry-view.vala @@ -82,6 +82,12 @@ namespace Unity.Panel.Indicators image.size = entry.image.pixbuf.width; } + if (entry.image.gicon is GLib.Icon) + { + image.gicon = entry.image.gicon; + image.size = 22; + } + if ((entry.image.get_flags () & Gtk.WidgetFlags.VISIBLE) != 0) { image.show (); @@ -125,6 +131,15 @@ namespace Unity.Panel.Indicators } }); + entry.image.notify["gicon"].connect (() => + { + if (image.gicon is GLib.Icon) + { + image.gicon = entry.image.gicon; + image.size = 22; + } + }); + unowned Gtk.IconTheme theme = Gtk.IconTheme.get_default (); theme.changed.connect (() => { @@ -138,11 +153,12 @@ namespace Unity.Panel.Indicators text.color = { 233, 216, 200, 255 }; add_actor (text); - text.text = entry.label.label; + /* FIXME: What about the __ case? Well, should that me in a menu? */ + text.text = entry.label.label.replace ("_", ""); entry.label.notify["label"].connect (() => { - text.text = entry.label.label; + text.text = entry.label.label.replace ("_", ""); }); if ((entry.label.get_flags () & Gtk.WidgetFlags.VISIBLE) != 0) diff --git a/unity-private/panel/panel-tray.vala b/unity-private/panel/panel-tray.vala index 41a727fd8..c3a6a9ae0 100644 --- a/unity-private/panel/panel-tray.vala +++ b/unity-private/panel/panel-tray.vala @@ -57,7 +57,19 @@ namespace Unity.Panel string? disable_tray = Environment.get_variable ("UNITY_DISABLE_TRAY"); if (disable_tray == null) - this.manager.manage_stage (this.stage); + { + Gdk.error_trap_push (); + + this.manager.manage_stage (this.stage); + Gdk.flush (); + + int err = 0; + if ((err = Gdk.error_trap_pop ()) != 0) + { + warning ("Unable to connect to the system tray: Error code: %d", + err); + } + } return false; } diff --git a/unity-private/panel/panel-window-buttons.vala b/unity-private/panel/panel-window-buttons.vala index 053bd941f..0f399409d 100644 --- a/unity-private/panel/panel-window-buttons.vala +++ b/unity-private/panel/panel-window-buttons.vala @@ -25,7 +25,6 @@ namespace Unity.Panel private Ctk.Text appname; private WindowButton close; private WindowButton minimize; - private WindowButton maximize; private WindowButton unmaximize; private unowned Bamf.Matcher matcher; @@ -47,28 +46,21 @@ namespace Unity.Panel appname.max_length = 9; pack (appname, true, true); - close = new WindowButton ("close.png"); + close = new WindowButton ("close"); pack (close, false, false); close.clicked.connect (() => { if (last_xid > 0) global_shell.do_window_action (last_xid, WindowAction.CLOSE); }); - minimize = new WindowButton ("minimize.png"); + minimize = new WindowButton ("minimize"); pack (minimize, false, false); minimize.clicked.connect (() => { if (last_xid > 0) global_shell.do_window_action (last_xid, WindowAction.MINIMIZE); }); - maximize = new WindowButton ("maximize.png"); - pack (maximize, false, false); - maximize.clicked.connect (() => { - if (last_xid > 0) - global_shell.do_window_action (last_xid, WindowAction.MAXIMIZE); - }); - - unmaximize = new WindowButton ("unmaximize.png"); + unmaximize = new WindowButton ("unmaximize"); pack (unmaximize, false, false); unmaximize.clicked.connect (() => { if (last_xid > 0) @@ -91,6 +83,13 @@ namespace Unity.Panel return false; }); }); + + Idle.add (() => { + unowned Bamf.Window? win = matcher.get_active_window (); + on_active_window_changed (null, win as GLib.Object); + + return false; + }); } private void on_active_window_changed (GLib.Object? object, @@ -98,6 +97,13 @@ namespace Unity.Panel { unowned Bamf.View? new_view = object1 as Bamf.View; + appname.set_markup (""); + appname.hide (); + close.hide (); + minimize.hide (); + unmaximize.hide (); + last_xid = 0; + if (new_view is Bamf.Window) { unowned Bamf.Window win = new_view as Bamf.Window; @@ -113,7 +119,6 @@ namespace Unity.Panel appname.hide (); close.show (); minimize.show (); - maximize.hide (); unmaximize.show (); } else @@ -121,7 +126,6 @@ namespace Unity.Panel appname.show (); close.hide (); minimize.hide (); - maximize.hide (); unmaximize.hide (); } @@ -136,7 +140,11 @@ namespace Unity.Panel AppInfo? info = appinfo.lookup (app.get_desktop_file ()); if (info != null) - appname.set_markup (FORMAT.printf (info.get_display_name ())); + { + string display_name = info.get_display_name (); + display_name = display_name.split (" ")[0]; + appname.set_markup (FORMAT.printf (display_name)); + } else appname.set_markup (FORMAT.printf (win.get_name ())); } @@ -145,15 +153,6 @@ namespace Unity.Panel appname.set_markup (FORMAT.printf (win.get_name ())); } } - else - { - appname.hide (); - close.hide (); - minimize.hide (); - maximize.hide (); - unmaximize.hide (); - last_xid = 0; - } } private override void get_preferred_width (float for_height, @@ -168,10 +167,15 @@ namespace Unity.Panel public class WindowButton : Ctk.Button { public static const string AMBIANCE = "/usr/share/themes/Ambiance/metacity-1"; + public static const string AMBIANCE_BETA = "/usr/share/themes/Ambiance-maverick-beta/metacity-1"; public string filename { get; construct; } public Clutter.Actor bg; + private bool using_beta = false; + private int icon_size = 18; + private string directory = AMBIANCE; + public WindowButton (string filename) { Object (filename:filename); @@ -179,40 +183,46 @@ namespace Unity.Panel construct { + if (using_beta = FileUtils.test (AMBIANCE_BETA, FileTest.EXISTS)) + { + icon_size = 19; + directory = AMBIANCE_BETA; + } try { + bg = new Ctk.Image.from_filename (icon_size, + directory + + "/" + + filename + + ".png"); + set_background_for_state (Ctk.ActorState.STATE_NORMAL, bg); + bg.show (); - bg = new Ctk.Image.from_filename (20, AMBIANCE + "/" + filename); - add_actor (bg); + bg = new Ctk.Image.from_filename (icon_size, + directory + + "/" + + filename + + "_focused_prelight.png"); + set_background_for_state (Ctk.ActorState.STATE_PRELIGHT, bg); + bg.show (); + + bg = new Ctk.Image.from_filename (icon_size, + directory + + "/" + + filename + + "_focused_pressed.png"); + set_background_for_state (Ctk.ActorState.STATE_ACTIVE, bg); bg.show (); } catch (Error e) { warning (@"Unable to load window button theme: You need Ambiance installed: $(e.message)"); } - - notify["state"].connect (() => { - switch (state) - { - case Ctk.ActorState.STATE_NORMAL: - bg.opacity = 255; - break; - - case Ctk.ActorState.STATE_PRELIGHT: - bg.opacity = 120; - break; - - case Ctk.ActorState.STATE_ACTIVE: - default: - bg.opacity = 50; - break; - } - }); } private override void get_preferred_width (float for_height, out float min_width, out float nat_width) { - min_width = 20.0f; + min_width = icon_size; nat_width = min_width; } @@ -220,7 +230,7 @@ namespace Unity.Panel out float min_height, out float nat_height) { - min_height = 18.0f; + min_height = icon_size; nat_height = min_height; } } diff --git a/unity-private/places/places-controller.vala b/unity-private/places/places-controller.vala index 650c3f29f..415fb90b9 100644 --- a/unity-private/places/places-controller.vala +++ b/unity-private/places/places-controller.vala @@ -29,8 +29,9 @@ namespace Unity.Places * This class takes care of reading in the places, creating the view and * keeping it up-to-date **/ - public Shell shell { get; construct; } - public PlaceModel model { get; set; } + public Shell shell { get; construct; } + public PlaceModel model { get; set; } + public VolumeController volumes { get; set; } private View view; @@ -49,6 +50,8 @@ namespace Unity.Places on_entry_added (e); }); + volumes = new VolumeController (); + ScrollerModel s = ObjectRegistry.get_default ().lookup ("UnityScrollerModel")[0] as ScrollerModel; /* Add the Trash launcher icon */ @@ -63,7 +66,7 @@ namespace Unity.Places return view; } - public void activate_entry (string entry_name) + public void activate_entry (string entry_name, int section_id = 0) { foreach (Place place in model) { @@ -71,13 +74,33 @@ namespace Unity.Places { if (entry.name == entry_name) { - view.on_entry_view_activated (entry, 0); + view.on_entry_view_activated (entry, section_id); break; } } } } + public void activate_entry_by_dbus_path (string entry_path, + int section_id = 0) + { + foreach (Place place in model) + { + foreach (PlaceEntry ent in place.get_entries ()) + { + if (ent is PlaceEntryDbus) + { + unowned PlaceEntryDbus entry = ent as PlaceEntryDbus; + if (entry.dbus_path == entry_path) + { + view.on_entry_view_activated (entry, section_id); + break; + } + } + } + } + } + private void on_entry_added (PlaceEntry entry) { ScrollerModel s = ObjectRegistry.get_default ().lookup ("UnityScrollerModel")[0] as ScrollerModel; diff --git a/unity-private/places/places-default-renderer-group.vala b/unity-private/places/places-default-renderer-group.vala index 3ad8ce78d..f757a82ba 100644 --- a/unity-private/places/places-default-renderer-group.vala +++ b/unity-private/places/places-default-renderer-group.vala @@ -32,11 +32,12 @@ namespace Unity.Places public Dee.Model results { get; construct; } private Ctk.VBox vbox; + private Ctk.Button title_button; private Ctk.HBox title_box; private Ctk.Image icon; private Ctk.Text text; - private Ctk.Image expander; - private Clutter.Actor sep; + private Expander expander; + private Ctk.Button sep; private Ctk.IconView renderer; private MoreResultsButton? more_results_button; @@ -77,11 +78,32 @@ namespace Unity.Places vbox.homogeneous = false; add_actor (vbox); vbox.show (); + + title_button = new Ctk.Button (Ctk.Orientation.HORIZONTAL); + title_button.padding = { 4.0f, 6.0f, 4.0f, 6.0f }; + vbox.pack (title_button, false, false); + title_button.show (); + var title_bg = new StripeTexture (null); + title_button.set_background_for_state (Ctk.ActorState.STATE_PRELIGHT, + title_bg); + title_button.notify["state"].connect (() => { + if (title_button.state == Ctk.ActorState.STATE_PRELIGHT) + sep.opacity = 0; + else + sep.opacity = 255; + unowned GLib.SList<unowned Ctk.Effect> effects = title_button.get_effects (); + foreach (unowned Ctk.Effect effect in effects) + effect.set_invalidate_effect_cache (true); + }); + var glow = new Ctk.EffectGlow (); + glow.set_factor (1.0f); + glow.set_margin (3); + //title_button.add_effect (glow); + title_box = new Ctk.HBox (5); - vbox.pack (title_box, false, false); + title_button.add_actor (title_box); title_box.show (); - title_box.reactive = true; icon = new Ctk.Image (22); icon.set_from_filename (Config.PKGDATADIR + "/favourites.png"); @@ -89,37 +111,42 @@ namespace Unity.Places icon.show (); text = new Ctk.Text (display_name); - title_box.pack (text, true, true); + text.set_markup ("<big>" + display_name + "</big>"); + title_box.pack (text, false, false); text.show (); - expander = new Ctk.Image (22); - expander.set_from_filename (Config.PKGDATADIR + "/maximize_up.png"); + expander = new Expander (); expander.opacity = 0; title_box.pack (expander, false, true); expander.show (); - sep = new Clutter.Rectangle.with_color ({ 255, 255, 255, 255 }); - sep.height = 1; + sep = new Ctk.Button (Ctk.Orientation.HORIZONTAL); + var rect = new Clutter.Rectangle.with_color ({ 255, 255, 255, 100 }); + sep.add_actor (rect); + rect.height = 1.0f; vbox.pack (sep, false, false); sep.show (); + glow = new Ctk.EffectGlow (); + glow.set_factor (1.0f); + glow.set_margin (5); + //sep.add_effect (glow); - title_box.button_release_event.connect (() => { + title_button.clicked.connect (() => { if (n_results <= renderer.get_n_cols () || allow_expand == false) - return true; + return; if (bin_state == ExpandingBinState.UNEXPANDED) { bin_state = ExpandingBinState.EXPANDED; - expander.set_from_filename (Config.PKGDATADIR + "/minimize_up.png"); + expander.expanding_state = Expander.State.EXPANDED; } else { bin_state = ExpandingBinState.UNEXPANDED; - expander.set_from_filename (Config.PKGDATADIR + "/maximize_up.png"); + expander.expanding_state = Expander.State.UNEXPANDED; } - return true; }); - title_box.motion_event.connect (() => { + title_button.motion_event.connect (() => { if (dirty && allow_expand) { var children = renderer.get_children (); @@ -130,6 +157,8 @@ namespace Unity.Places } dirty = false; } + + return false; }); renderer = new Ctk.IconView (); @@ -172,7 +201,7 @@ namespace Unity.Places } else if (group_renderer == "UnityFolderGroupRenderer") { - title_box.hide (); + title_button.hide (); sep.hide (); bin_state = ExpandingBinState.EXPANDED; } @@ -207,7 +236,7 @@ namespace Unity.Places child.height != unexpanded_height) { var h = more_results_button != null ? more_results_button.height : 0; - unexpanded_height = title_box.height + 1.0f + child.height + h; + unexpanded_height = title_button.height + 1.0f + child.height + h; } } @@ -344,6 +373,104 @@ namespace Unity.Places } } + public class Expander : Ctk.Bin + { + public enum State + { + EXPANDED, + UNEXPANDED + } + + private float arrow_size = 12.0f; + private float arrow_quart = 3.0f; + + private CairoCanvas arrow; + + public State expanding_state { + get { return _state; } + set { + if (_state != value) + { + _state = value; + arrow.update (); + } + } + } + + private State _state = State.UNEXPANDED; + + public Expander () + { + Object (); + } + + construct + { + arrow = new CairoCanvas (paint_arrow); + add_actor (arrow); + arrow.show (); + } + + private override void allocate (Clutter.ActorBox box, + Clutter.AllocationFlags flags) + { + Clutter.ActorBox child_box = Clutter.ActorBox (); + + base.allocate (box, flags); + + child_box.x1 = ((box.x2 - box.x1)/2.0f) - arrow_quart *2; + child_box.x2 = child_box.x1 + arrow_size; + child_box.y1 = ((box.y2 - box.y1)/2.0f) - arrow_quart *2; + child_box.y2 = child_box.y1 + arrow_size; + + arrow.allocate (child_box, flags); + } + + private override void get_preferred_height (float for_width, + out float mheight, + out float nheight) + { + mheight = arrow_size; + nheight = arrow_size; + } + + private override void get_preferred_width (float for_height, + out float mwidth, + out float nwidth) + { + mwidth = arrow_size; + nwidth = arrow_size; + } + + private void paint_arrow (Cairo.Context cr, int width, int height) + { + cr.set_operator (Cairo.Operator.CLEAR); + cr.paint (); + + cr.set_operator (Cairo.Operator.OVER); + cr.set_line_width (1.0f); + cr.translate (-0.5, -0.5); + cr.set_source_rgba (1.0f, 1.0f, 1.0f, 1.0f); + + if (_state == State.UNEXPANDED) + { + cr.move_to (arrow_quart, arrow_quart); + cr.line_to (arrow_size - arrow_quart, arrow_size/2.0f); + cr.line_to (arrow_quart, arrow_size - arrow_quart); + cr.close_path (); + } + else + { + cr.move_to (arrow_quart, arrow_quart); + cr.line_to (arrow_size - arrow_quart, arrow_quart); + cr.line_to (arrow_size /2.0f, arrow_size - arrow_quart); + cr.close_path (); + } + + cr.fill (); + } + } + public class MoreResultsButton : Ctk.Button { public uint count { @@ -367,7 +494,7 @@ namespace Unity.Places construct { - var bg = new CairoCanvas (paint_bg); + var bg = new StripeTexture (paint_bg); set_background (bg); text = new Ctk.Text (""); @@ -398,17 +525,10 @@ namespace Unity.Places float nwidth; text.get_preferred_width (height, null, out nwidth); - cr.translate (0.5, 0.5); cr.rectangle (0.0, vpad, hpad + nwidth + hpad, height - vpad - vpad); - cr.set_source_rgba (1.0, 1.0, 1.0, 0.2); - cr.fill_preserve (); - - cr.set_line_width (1.5); - cr.set_source_rgba (1.0, 1.0, 1.0, 0.5); - cr.stroke (); } } diff --git a/unity-private/places/places-default-renderer.vala b/unity-private/places/places-default-renderer.vala index ecbd9fb25..77fa0bdea 100644 --- a/unity-private/places/places-default-renderer.vala +++ b/unity-private/places/places-default-renderer.vala @@ -67,14 +67,33 @@ namespace Unity.Places private void on_group_added (Dee.Model model, Dee.ModelIter iter) { - var group = new DefaultRendererGroup (model.get_position (iter), - model.get_string (iter, 0), - model.get_string (iter, 1), - model.get_string (iter, 2), + string renderer = model.get_string (iter, 0); + + if (renderer == "UnityEmptySearchRenderer") + { + var group = new EmptySearchGroup (model.get_position (iter), results_model); - group.activated.connect ((u, m) => { activated (u, m); } ); - group.set_data<unowned Dee.ModelIter> ("model-iter", iter); - box.pack (group, false, true); + box.pack (group, false, true); + group.activated.connect ((u, m) => { activated (u, m); } ); + + } + else if (renderer == "UnityEmptySectionRenderer") + { + var group = new EmptrySectionGroup (model.get_position (iter), + results_model); + box.pack (group, false, true); + } + else + { + var group = new DefaultRendererGroup (model.get_position (iter), + model.get_string (iter, 0), + model.get_string (iter, 1), + model.get_string (iter, 2), + results_model); + group.activated.connect ((u, m) => { activated (u, m); } ); + group.set_data<unowned Dee.ModelIter> ("model-iter", iter); + box.pack (group, false, true); + } } private void on_group_removed (Dee.Model model, Dee.ModelIter iter) @@ -91,5 +110,147 @@ namespace Unity.Places } } } + + public class EmptySearchGroup : ExpandingBin + { + public uint group_id { get; construct set; } + + public Dee.Model results { get; construct set; } + + public signal void activated (string uri, string mimetype); + + private Ctk.VBox box; + + public EmptySearchGroup (uint group_id, Dee.Model results) + { + Object (group_id:group_id, results:results); + } + + construct + { + bin_state = ExpandingBinState.CLOSED; + unexpanded_height = 0.0f; + + var hbox = new Ctk.HBox (0); + add_actor (hbox); + hbox.show (); + + box = new Ctk.VBox (12); + hbox.pack (box, false, false); + box.show (); + + results.row_added.connect (on_result_added); + results.row_removed.connect (on_result_removed); + + opacity = 0; + } + + private void on_result_added (Dee.ModelIter iter) + { + if (!interesting (iter)) + return; + + bin_state = ExpandingBinState.EXPANDED; + + string mes = results.get_string (iter, 4); + + var button = new Ctk.Button (Ctk.Orientation.HORIZONTAL); + button.padding = { 12.0f, 12.0f, 12.0f, 12.0f }; + var text = new Ctk.Text (""); + text.set_markup ("<big>" + mes + "</big>"); + button.add_actor (text); + + box.pack (button, false, false); + + if (box.get_children ().length () >= 2) + { + var bg = new StripeTexture (null); + button.set_background (bg); + + string uri = results.get_string (iter, 0); + string mimetype = results.get_string (iter, 3); + + button.clicked.connect (() => { activated (uri, mimetype); }); + } + } + + private void on_result_removed (Dee.ModelIter iter) + { + if (!interesting (iter)) + return; + + var children = box.get_children (); + foreach (Clutter.Actor child in children) + { + box.remove_actor (child); + } + + bin_state = ExpandingBinState.CLOSED; + } + + private bool interesting (Dee.ModelIter iter) + { + return (results.get_uint (iter, 2) == group_id); + } + } + + + public class EmptrySectionGroup : ExpandingBin + { + public uint group_id { get; construct set; } + + private Ctk.Text text; + public Dee.Model results { get; construct set; } + + public signal void activated (string uri, string mimetype); + + public EmptrySectionGroup (uint group_id, Dee.Model results) + { + Object (group_id:group_id, results:results); + } + + construct + { + bin_state = ExpandingBinState.CLOSED; + unexpanded_height = 0.0f; + + padding = { 100.0f, 0.0f, 0.0f, 0.0f }; + + text = new Ctk.Text (""); + text.set_alignment (Pango.Alignment.CENTER); + + add_actor (text); + text.show (); + + results.row_added.connect (on_result_added); + results.row_removed.connect (on_result_removed); + + opacity = 0; + } + + private void on_result_added (Dee.ModelIter iter) + { + if (!interesting (iter)) + return; + + bin_state = ExpandingBinState.EXPANDED; + + string mes = results.get_string (iter, 4); + text.set_markup ("<big>" + mes + "</big>"); + } + + private void on_result_removed (Dee.ModelIter iter) + { + if (!interesting (iter)) + return; + + bin_state = ExpandingBinState.CLOSED; + } + + private bool interesting (Dee.ModelIter iter) + { + return (results.get_uint (iter, 2) == group_id); + } + } } diff --git a/unity-private/places/places-place-home-renderer.vala b/unity-private/places/places-place-home-renderer.vala new file mode 100644 index 000000000..360a5e269 --- /dev/null +++ b/unity-private/places/places-place-home-renderer.vala @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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/>. + * + * Authored by Neil Jagdish Patel <neil.patel@canonical.com> + * + */ + +namespace Unity.Places +{ + public class HomeRenderer : Ctk.Bin, Unity.Place.Renderer + { + static const int SPACING = 60; + static const string FILES_PLACE = "/com/canonical/unity/filesplace/files"; + static const string APPS_PLACE = "/com/canonical/unity/applicationsplace/applications"; + + private Gtk.IconTheme? theme = null; + private Ctk.IconView icon_view; + + public HomeRenderer () + { + Object (); + } + + construct + { + padding = { 0.0f, 0.0f, 0.0f, 0.0f }; + icon_view = new Ctk.IconView (); + icon_view.spacing = SPACING; + add_actor (icon_view); + icon_view.show (); + + /* Load up the world */ + var icon = new HomeButton (_("Web"), filename_for_icon ("web"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + var client = GConf.Client.get_default (); + try { + var exec = client.get_string ("/desktop/gnome/applications/browser/exec"); + if (exec != null) + Process.spawn_command_line_async (exec); + } catch (Error e) { + warning (@"Unable to start web browser: $(e.message)"); + } + + global_shell.hide_unity (); + + }); + + icon = new HomeButton (_("Music"), filename_for_icon ("music"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + activate_place (APPS_PLACE, 4); + }); + + icon = new HomeButton (_("Photos & Videos"), filename_for_icon ("photos"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + activate_place (APPS_PLACE, 4); + }); + + icon = new HomeButton (_("Games"), filename_for_icon ("games"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + activate_place (APPS_PLACE, 2); + }); + + icon = new HomeButton (_("Email & Chat"), filename_for_icon ("email_and_chat"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + activate_place (APPS_PLACE, 3); + }); + + icon = new HomeButton (_("Office"), filename_for_icon ("work"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + activate_place (APPS_PLACE, 5); + }); + + icon = new HomeButton (_("Files & Folders"), filename_for_icon ("work"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + activate_place (FILES_PLACE, 0); + }); + + icon = new HomeButton (_("Get New Apps"), filename_for_icon ("softwarecentre"), ""); + icon_view.add_actor (icon); + icon.show (); + icon.clicked.connect (() => { + try { + Process.spawn_command_line_async ("software-center"); + } catch (Error e) { + warning (@"Unable to start software centre: $(e.message)"); + } + global_shell.hide_unity (); + + }); + + } + + public void set_models (Dee.Model groups, + Dee.Model results, + Gee.HashMap<string, string> hints) + { + + } + + /* + * Private Methods + */ + private void activate_place (string place_path, int section_id) + { + /* FIXME:!!! + * This is not the way we'll end up doing this. This is a stop-gap + * until we have better support for signalling things through + * a place + */ + Controller cont = Testing.ObjectRegistry.get_default ().lookup ("UnityPlacesController")[0] as Controller; + + if (cont is Controller) + { + cont.activate_entry_by_dbus_path (place_path, section_id); + } + } + + private override void allocate (Clutter.ActorBox box, + Clutter.AllocationFlags flags) + { + base.allocate (box, flags); + float icon_width; + float icon_height; + + var children = icon_view.get_children (); + var child = children.nth_data (0) as Clutter.Actor; + child.get_preferred_size (out icon_width, null, + out icon_height, null); + + float left = (box.x2 - box.x1 - (3 * SPACING) - (4 * icon_width))/2.0f; + float top = (box.y2 - box.y1 - (1 * SPACING) - (2 * icon_height))/2.0f; + top -= SPACING /2.0f; + + Clutter.ActorBox child_box = Clutter.ActorBox (); + child_box.x1 = left; + child_box.x2 = box.x2 - box.x1; + child_box.y1 = top; + child_box.y2 = box.y2 - box.y1; + + icon_view.allocate (child_box, flags); + } + + private string filename_for_icon (string icon) + { + if (theme == null) + { + theme = new Gtk.IconTheme (); + theme.set_custom_theme ("unity-icon-theme"); + } + + string icon_file = ""; + if (theme.has_icon (icon)) + { + var info = theme.lookup_icon (icon, 128, 0); + if (info != null) + { + var filename = info.get_filename (); + if (FileUtils.test(filename, FileTest.IS_REGULAR)) + { + icon_file = filename; + } + } + + } + + return icon_file; + } + } + + public class HomeButton : Ctk.Button + { + static const int ICON_SIZE = 128; + + public new string name { get; construct; } + public string icon { get; construct; } + public string exec { get; construct; } + + public HomeButton (string name, string icon, string exec) + { + Object (name:name, + icon:icon, + exec:exec, + orientation:Ctk.Orientation.VERTICAL); + } + + construct + { + get_image ().size = 128; + get_image ().filename = icon; + get_text ().text = name; + } + + + private override void get_preferred_width (float for_height, + out float mwidth, + out float nwidth) + { + mwidth = ICON_SIZE; + nwidth = ICON_SIZE; + } +/* + private override void get_preferred_width (float for_width, + out float mheight, + out float nheight) + { + + }*/ + } +} diff --git a/unity-private/places/places-place-home.vala b/unity-private/places/places-place-home.vala index b29f13a6e..a73c49049 100644 --- a/unity-private/places/places-place-home.vala +++ b/unity-private/places/places-place-home.vala @@ -153,14 +153,30 @@ namespace Unity.Places public void set_search (string search, HashTable<string, string> hints) { - debug ("Global search %s", search); + var old_renderer = entry_renderer_name; - foreach (Gee.Map.Entry<PlaceEntry, uint> e in entry_group_map.entries) + if (search == "" || search == null) { - PlaceEntry? entry = e.key; + entry_renderer_name = "UnityHomeScreen"; + } + else + { + entry_renderer_name = "UnityDefaultRenderer"; + + foreach (Gee.Map.Entry<PlaceEntry, uint> e in entry_group_map.entries) + { + PlaceEntry? entry = e.key; - if (entry != null) - entry.set_global_search (search, hints); + if (entry != null) + entry.set_global_search (search, hints); + } + } + + debug (@"$entry_renderer_name, $search"); + if (old_renderer != entry_renderer_name) + { + updated (); + renderer_info_changed (); } } diff --git a/unity-private/places/places-place-model.vala b/unity-private/places/places-place-model.vala index 9e4c47dc0..250dde3df 100644 --- a/unity-private/places/places-place-model.vala +++ b/unity-private/places/places-place-model.vala @@ -25,7 +25,7 @@ namespace Unity.Places * Contains the loaded Place objects. Abstract class so views can be * tested with fake model **/ - public abstract class PlaceModel : Gee.ArrayList<Place> + public abstract class PlaceModel : Gee.ArrayList<unowned Place> { public signal void place_added (Place place); } diff --git a/unity-private/places/places-place-search-bar.vala b/unity-private/places/places-place-search-bar.vala index 1d127cf19..3addbf12b 100644 --- a/unity-private/places/places-place-search-bar.vala +++ b/unity-private/places/places-place-search-bar.vala @@ -21,7 +21,7 @@ namespace Unity.Places { public class PlaceSearchBar : Ctk.Box { - static const int SPACING = 10; + static const int SPACING = 12; static const int RANDOM_TEXT_WIDTH = 400; /* Properties */ @@ -136,7 +136,12 @@ namespace Unity.Places bg.entry_position = x; sections.set_active_entry (entry); if (section != 0) - sections.set_active_section (section); + { + Idle.add (() => { + sections.set_active_section (section); + return false; + }); + } navigation.set_active_entry (entry); this.entry.text.grab_key_focus (); diff --git a/unity-private/places/places-place-search-sections-bar.vala b/unity-private/places/places-place-search-sections-bar.vala index fa0f0e694..a7f4b6f69 100644 --- a/unity-private/places/places-place-search-sections-bar.vala +++ b/unity-private/places/places-place-search-sections-bar.vala @@ -235,6 +235,7 @@ namespace Unity.Places var pos = active_section.model.get_position (active_section.iter); active_entry.set_active_section (pos); + bg.update (); } private bool on_section_clicked (Clutter.Actor actor, Clutter.Event e) @@ -254,9 +255,6 @@ namespace Unity.Places private void paint_bg (Cairo.Context cr, int width, int height) { - if (_style != SectionStyle.BREADCRUMB) - return; - cr.set_operator (Cairo.Operator.CLEAR); cr.paint (); @@ -269,45 +267,85 @@ namespace Unity.Places width -= 1; height -= 1; var radius = 5; - - cr.line_to (x, y + radius); - cr.curve_to (x, y, - x, y, - x + radius, y); - cr.line_to (width - radius, y); - cr.curve_to (width, y, - width, y, - width, y + radius); - cr.line_to (width, height - radius); - cr.curve_to (width, height, - width, height, - width - radius, height); - cr.line_to (x + radius, height); - cr.curve_to (x, height, - x, height, - x, height - radius); - cr.close_path (); - - cr.set_source_rgba (1.0, 1.0, 1.0, 0.5); - cr.fill_preserve (); - cr.stroke (); - - var chevron = 5; var point = x; - var children = get_children (); - foreach (Clutter.Actor child in children) + + if (_style != SectionStyle.BREADCRUMB) { - point += (int)(child.width) + SPACING/2; + var children = get_children (); + unowned Section? last_sec = null; + + point -= SPACING/2; + + foreach (Clutter.Actor child in children) + { + unowned Section sec = child as Section; + + if (point < width - SPACING + && (last_sec == null || last_sec.active == false) + && sec.active != true) + { + cr.rectangle (point, y, 0.5, height); + var pat = new Cairo.Pattern.linear (x, y, x, y + height); + pat.add_color_stop_rgba (0.0, 0.0, 0.0, 0.0, 0.0); + pat.add_color_stop_rgba (0.5, 0.0, 0.0, 0.0, 0.5); + pat.add_color_stop_rgba (1.0, 0.0, 0.0, 0.0, 0.0); + cr.set_source (pat); + cr.fill (); + + cr.rectangle (point+1, y, 0.5, height); + pat = new Cairo.Pattern.linear (x, y, x, y + height); + pat.add_color_stop_rgba (0.0, 1.0, 1.0, 1.0, 0.0); + pat.add_color_stop_rgba (0.5, 1.0, 1.0, 1.0, 0.5); + pat.add_color_stop_rgba (1.0, 1.0, 1.0, 1.0, 0.0); + cr.set_source (pat); + cr.fill (); + } + + point += (int)(child.width) + SPACING; + last_sec = sec; + } + } + else + { + cr.line_to (x, y + radius); + cr.curve_to (x, y, + x, y, + x + radius, y); + cr.line_to (width - radius, y); + cr.curve_to (width, y, + width, y, + width, y + radius); + cr.line_to (width, height - radius); + cr.curve_to (width, height, + width, height, + width - radius, height); + cr.line_to (x + radius, height); + cr.curve_to (x, height, + x, height, + x, height - radius); + cr.close_path (); - if (point < width - chevron - SPACING) + cr.set_source_rgba (1.0, 1.0, 1.0, 0.5); + cr.fill_preserve (); + cr.stroke (); + + var chevron = 5; + var children = get_children (); + point = x; + foreach (Clutter.Actor child in children) { - cr.move_to (point - chevron, y); - cr.line_to (point + chevron, y + height/2); - cr.line_to (point - chevron, y + height); - cr.set_source_rgba (1.0, 1.0, 1.0, 0.8); - cr.stroke (); + point += (int)(child.width) + SPACING/2; + + if (point < width - chevron - SPACING) + { + cr.move_to (point - chevron, y); + cr.line_to (point + chevron, y + height/2); + cr.line_to (point - chevron, y + height); + cr.set_source_rgba (1.0, 1.0, 1.0, 1.0); + cr.stroke (); + } + point += SPACING/2; } - point += SPACING/2; } } } @@ -345,7 +383,7 @@ namespace Unity.Places if (_active) { - color = { 152, 74, 131, 255 }; + color = { 50, 50, 50, 255 }; mode = Clutter.AnimationMode.EASE_IN_QUAD; opacity = 255; } @@ -406,21 +444,6 @@ namespace Unity.Places public void start_destroy () { (get_parent () as Clutter.Container).remove_actor (this); - /* - if (_destroy_factor != 1.0f) - return; - - var anim = animate (Clutter.AnimationMode.EASE_OUT_QUAD, 2000, - "destroy_factor", 0.0f); - - anim.completed.connect ((a) => { - var obj = a.get_object () as Clutter.Actor; - - (obj.get_parent () as Clutter.Container).remove_actor (obj); - }); - - debug ("started_animation"); - */ } private override void get_preferred_width (float for_height, diff --git a/unity-private/places/places-view.vala b/unity-private/places/places-view.vala index 8e91bc4de..38fc1bd9b 100644 --- a/unity-private/places/places-view.vala +++ b/unity-private/places/places-view.vala @@ -106,8 +106,7 @@ namespace Unity.Places update_views (entry, section_id); - if (active_entry != home_entry) - entry.renderer_info_changed.connect (on_entry_renderer_info_changed); + entry.renderer_info_changed.connect (on_entry_renderer_info_changed); } private void update_views (PlaceEntry entry, uint section_id=0) @@ -154,6 +153,8 @@ namespace Unity.Places if (browser_path != null) return new FolderBrowserRenderer (); + else if (entry.entry_renderer_name == "UnityHomeScreen") + return new HomeRenderer (); else return new DefaultRenderer (); } diff --git a/unity-private/places/places-volume-child-controller.vala b/unity-private/places/places-volume-child-controller.vala new file mode 100644 index 000000000..81ef7e6fa --- /dev/null +++ b/unity-private/places/places-volume-child-controller.vala @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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/>. + * + * Authored by Neil Jagdish Patel <neil.patel@canonical.com> + * + */ + +using Unity.Launcher; +using Unity.Testing; + +namespace Unity.Places +{ + public class VolumeChildController : ScrollerChildController + { + public static const string ICON = "/usr/share/unity/trash.png"; + + public Volume volume { get; construct; } + + public VolumeChildController (Volume volume) + { + Object (child:new ScrollerChild (), + volume:volume); + } + + construct + { + name = volume.get_name (); + + var icon = volume.get_icon (); + var icon_name = ""; + if (icon is ThemedIcon) + { + icon_name = (icon as ThemedIcon).get_names ()[0]; + } + else if (icon is FileIcon) + { + icon_name = (icon as FileIcon).get_file ().get_path (); + } + else + { + icon_name = ICON; + } + load_icon_from_icon_name (icon_name); + + debug ("ICON NAME: %s", icon_name); + + child.group_type = ScrollerChild.GroupType.DEVICE; + child.drag_removed.connect (eject_volume); + + volume.removed.connect (on_volume_removed); + } + + private void on_volume_removed () + { + ScrollerModel s; + + s = ObjectRegistry.get_default ().lookup ("UnityScrollerModel")[0] as ScrollerModel; + s.remove (this.child); + + this.unref (); + } + + private void open_volume () + { + Mount? mount = volume.get_mount (); + string error_msg = @"Cannot open volume '$(volume.get_name ())': "; + + if (mount is Mount) + { + var loc = mount.get_root (); + try { + AppInfo.launch_default_for_uri (loc.get_uri (), null); + } catch (Error err) { + warning (error_msg + err.message); + } + } + else + { + if (volume.can_mount () == false) + { + warning (error_msg + "Cannot be mounted"); + return; + } + try { + volume.mount.begin (0, null, null); + + mount = volume.get_mount (); + if (mount is Mount) + AppInfo.launch_default_for_uri (mount.get_root ().get_uri (), null); + else + warning (error_msg + "Unable to mount"); + + } catch (Error e) { + warning (error_msg + e.message); + } + + } + } + + private void eject_volume () + { + /* + * Because there are bugs in making this work through the vala 0.9.5 and + * I don't have time to debug them. + */ + Utils.volume_eject (volume); + } + + /* Overides */ + public override void activate () + { + open_volume (); + } + + public override QuicklistController? get_menu_controller () + { + return new ApplicationQuicklistController (this); + } + + public override void get_menu_actions (ScrollerChildController.menu_cb callback) + { + Dbusmenu.Menuitem root = new Dbusmenu.Menuitem (); + root.set_root (true); + + Dbusmenu.Menuitem item; + + item = new Dbusmenu.Menuitem (); + item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Open")); + item.property_set_bool (Dbusmenu.MENUITEM_PROP_ENABLED, true); + item.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, true); + item.item_activated.connect (open_volume); + root.child_append (item); + + callback (root); + } + + public override void get_menu_navigation (ScrollerChildController.menu_cb callback) + { + Dbusmenu.Menuitem root = new Dbusmenu.Menuitem (); + root.set_root (true); + + if (volume.get_mount () != null) + { + Dbusmenu.Menuitem item; + + item = new Dbusmenu.Menuitem (); + item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Eject")); + item.property_set_bool (Dbusmenu.MENUITEM_PROP_ENABLED, true); + item.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, true); + root.child_append (item); + item.item_activated.connect (eject_volume); + } + + callback (root); + } + + public override bool can_drag () + { + return true; + } + } +} diff --git a/unity-private/places/places-volume-controller.vala b/unity-private/places/places-volume-controller.vala new file mode 100644 index 000000000..79ec94615 --- /dev/null +++ b/unity-private/places/places-volume-controller.vala @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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/>. + * + * Authored by Neil Jagdish Patel <neil.patel@canonical.com> + * + */ + +using Unity.Launcher; +using Unity.Testing; + +namespace Unity.Places +{ + public class VolumeController : Object + { + private VolumeMonitor monitor; + + public VolumeController () + { + Object (); + } + + construct + { + monitor = VolumeMonitor.get (); + monitor.volume_added.connect (on_volume_added); + + var volumes = monitor.get_volumes (); + foreach (Volume volume in volumes) + { + on_volume_added_real (volume); + + /* Because get_volumes () returns a list of ref'd volumes */ + volume.unref (); + } + } + + private bool on_volume_added_real (Volume volume) + { + if (volume.can_eject ()) + { + debug ("VOLUME_ADDED: %s", volume.get_name ()); + + var child = new VolumeChildController (volume); + + ScrollerModel s; + + s = ObjectRegistry.get_default ().lookup ("UnityScrollerModel")[0] as ScrollerModel; + s.add (child.child); + + return true; + } + else + return false; + } + + private void on_volume_added (Volume volume) + { + on_volume_added_real (volume); + } + } +} diff --git a/unity-private/testing/test-window.vala b/unity-private/testing/test-window.vala index 3d3319579..cb76fbd5f 100644 --- a/unity-private/testing/test-window.vala +++ b/unity-private/testing/test-window.vala @@ -26,6 +26,7 @@ namespace Unity.Testing public class Window : Gtk.Window, Shell { public bool menus_swallow_events { get { return true; } } + public bool super_key_active {get; set;} public bool is_popup { get; construct; } public int popup_width { get; construct; } public int popup_height { get; construct; } diff --git a/unity-private/unity-utils.c b/unity-private/unity-utils.c index cc9d1c808..2d5d2e758 100644 --- a/unity-private/unity-utils.c +++ b/unity-private/unity-utils.c @@ -55,7 +55,7 @@ typedef struct { #define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS" gboolean -utils_window_is_decorated (guint32 xid) +utils_window_is_decorated (Window xid) { GdkDisplay *display = gdk_display_get_default(); Atom hints_atom = None; @@ -76,20 +76,23 @@ utils_window_is_decorated (guint32 xid) False, AnyPropertyType, &type, &format, &nitems, &bytes_after, &data); - if (type == None || !data) return TRUE; + if (type == None || !data) + { + return TRUE; + } hints = (MotifWmHints *)data; retval = hints->decorations; - + if (data) XFree (data); - return retval; + return retval == 1; } static void -gdk_window_set_mwm_hints (guint32 xid, +gdk_window_set_mwm_hints (Window xid, MotifWmHints *new_hints) { GdkDisplay *display = gdk_display_get_default(); @@ -103,7 +106,7 @@ gdk_window_set_mwm_hints (guint32 xid, g_return_if_fail (GDK_IS_DISPLAY (display)); - g_debug ("gdk_window_set_mwm_hints: %lld %d\n", xid, new_hints->decorations); + g_debug ("gdk_window_set_mwm_hints: %lu %lu\n", xid, new_hints->decorations); hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS); @@ -148,7 +151,7 @@ gdk_window_set_mwm_hints (guint32 xid, } void -utils_window_set_decorations (guint32 xid, +utils_window_set_decorations (Window xid, GdkWMDecoration decorations) { MotifWmHints *hints; @@ -420,3 +423,20 @@ indicator_object_entry_free (IndicatorObjectEntry *entry) entry = NULL; } + + +static void +on_volume_ejected (GVolume *volume, + GAsyncResult *res) +{ + g_volume_eject_with_operation_finish (volume, res, NULL); +} + +void +utils_volume_eject (GVolume *volume) +{ + g_return_if_fail (G_IS_VOLUME (volume)); + + g_volume_eject_with_operation (volume, 0, NULL, NULL, + (GAsyncReadyCallback)on_volume_ejected, NULL); +} diff --git a/unity-private/utils.vala b/unity-private/utils.vala index 07af3d253..01ac63fde 100644 --- a/unity-private/utils.vala +++ b/unity-private/utils.vala @@ -117,8 +117,11 @@ namespace Utils string img2_path); [CCode (lower_case_prefix = "utils_")] - public extern bool window_is_decorated (uint32 xid); + public extern bool window_is_decorated (X.Window window); [CCode (lower_case_prefix = "utils_")] - public extern void window_set_decorations (uint32 xid, uint decorations); + public extern void window_set_decorations (X.Window window, uint decorations); + + [CCode (lower_case_prefix = "utils_")] + public extern void volume_eject (GLib.Volume volume); } diff --git a/unity/Makefile.am b/unity/Makefile.am index 6a6032753..a8afcf088 100644 --- a/unity/Makefile.am +++ b/unity/Makefile.am @@ -79,6 +79,7 @@ libunity_la_VALASOURCES = \ unity-place-activation.vala \ unity-place-browser.vala \ unity-place-renderer.vala \ + unity-stripe-texture.vala \ webapp-fetcher.vala diff --git a/unity/icon-postprocessor.vala b/unity/icon-postprocessor.vala index 1833b0274..2d211c1c5 100644 --- a/unity/icon-postprocessor.vala +++ b/unity/icon-postprocessor.vala @@ -296,8 +296,9 @@ namespace Unity private Cogl.Material icon_material; private Cogl.Material bgcol_material; - public float rotation = 0.0f; - + public float rotation {get; set;} + public float stored_height = 0; + public float stored_ymod = 0; public UnityIcon (Clutter.Texture? icon, Clutter.Texture? bg_tex) { @@ -347,6 +348,8 @@ namespace Unity tex = (Cogl.Texture)(unity_icon_fg_layer.get_cogl_texture ()); mat.set_layer (0, tex); fg_mat = mat; + notify["rotation"].connect (() => { queue_relayout (); }); + stored_height = 48; } public override void get_preferred_width (float for_height, @@ -376,8 +379,8 @@ namespace Unity { set_effects_painting (true); var mat = new Cogl.Material (); - mat.set_color4ub (color.red, color.green, color.blue, color.alpha); - Cogl.rectangle (0, 0, 48, 48); + //mat.set_color4ub (color.red, color.green, color.blue, color.alpha); + //Cogl.rectangle (0, stored_ymod, 1, 1);//stored_height); base.pick (color); set_effects_painting (false); } @@ -399,23 +402,25 @@ namespace Unity Cogl.Matrix modelview = Cogl.Matrix.identity (); //model view matrix Cogl.Matrix projection = Cogl.Matrix.identity (); // projection matrix - projection.perspective (60.0f, 1.0f, 0.1f, 100.0f); - modelview.translate (0.0f, 0.0f, -44.0f - Math.fabsf (self.rotation / 360.0f) * 100); + projection.perspective (45.0f, 1.0f, 0.1f, 100.0f); + modelview.translate (0.0f, 0.0f, -59.5f - Math.fabsf (self.rotation / 360.0f) * 100); modelview.rotate (self.rotation, 1.0f, 0.0f, 0.0f); Cogl.Matrix viewmatrix = Cogl.Matrix.multiply (projection, modelview); + float base_z = -((Math.fabsf (self.rotation) / 90.0f) * 15.0f); + p1_x = -25.0f; p1_y = -25.0f; p2_x = 25.0f; p2_y = -25.0f; p3_x = 25.0f; p3_y = 25.0f; p4_x = -25.0f; p4_y = 25.0f; - z = 0.0f; + z = base_z; w = 1.0f; - viewmatrix.transform_point (out p1_x, out p1_y, out z, out w); p1_x /= w; p1_y /= w; z = 0.0f; w = 1.0f; - viewmatrix.transform_point (out p2_x, out p2_y, out z, out w); p2_x /= w; p2_y /= w; z = 0.0f; w = 1.0f; - viewmatrix.transform_point (out p3_x, out p3_y, out z, out w); p3_x /= w; p3_y /= w; z = 0.0f; w = 1.0f; - viewmatrix.transform_point (out p4_x, out p4_y, out z, out w); p4_x /= w; p4_y /= w; z = 0.0f; w = 1.0f; + viewmatrix.transform_point (out p1_x, out p1_y, out z, out w); p1_x /= w; p1_y /= w; z = base_z; w = 1.0f; + viewmatrix.transform_point (out p2_x, out p2_y, out z, out w); p2_x /= w; p2_y /= w; z = base_z; w = 1.0f; + viewmatrix.transform_point (out p3_x, out p3_y, out z, out w); p3_x /= w; p3_y /= w; z = base_z; w = 1.0f; + viewmatrix.transform_point (out p4_x, out p4_y, out z, out w); p4_x /= w; p4_y /= w; z = base_z; w = 1.0f; //transform into screen co-ordinates @@ -431,16 +436,25 @@ namespace Unity p4_x = (50 * (p4_x + 1) / 2); p4_y = 48 + (50 * (p4_y - 1) / 2); - if (Math.fabsf (self.rotation) <= 3.0) + if (Math.fabsf (self.rotation) <= 1.0) { // floor all the values. we don't floor when its rotated because then // we lose subpixel accuracy and things look like a 1991 video game - p1_x = Math.floorf (p1_x); p1_y = Math.floorf (p1_y); - p2_x = Math.floorf (p2_x); p2_y = Math.floorf (p2_y); + p1_x = Math.ceilf (p1_x); p1_y = Math.ceilf (p1_y); + p2_x = Math.floorf (p2_x); p2_y = Math.ceilf (p2_y); p3_x = Math.floorf (p3_x); p3_y = Math.floorf (p3_y); - p4_x = Math.floorf (p4_x); p4_y = Math.floorf (p4_y); + p4_x = Math.ceilf (p4_x); p4_y = Math.floorf (p4_y); } + self.stored_height = p3_y - p1_y; + self.stored_ymod = (50 - self.stored_height) / 2.0f; +/* + p1_y += self.stored_ymod; + p2_y += self.stored_ymod; + p3_y += self.stored_ymod; + p4_y += self.stored_ymod; +*/ + Cogl.TextureVertex[4] points = { Cogl.TextureVertex () { x = p1_x, @@ -528,13 +542,13 @@ namespace Unity p2_x = 25.0f; p2_y = -25.0f; p3_x = 25.0f; p3_y = 25.0f; p4_x = -25.0f; p4_y = 25.0f; - z = 0.0f; + z = base_z; w = 1.0f; - viewmatrix.transform_point (out p1_x, out p1_y, out z, out w); p1_x /= w; p1_y /= w; z = 0.0f; w = 1.0f; - viewmatrix.transform_point (out p2_x, out p2_y, out z, out w); p2_x /= w; p2_y /= w; z = 0.0f; w = 1.0f; - viewmatrix.transform_point (out p3_x, out p3_y, out z, out w); p3_x /= w; p3_y /= w; z = 0.0f; w = 1.0f; - viewmatrix.transform_point (out p4_x, out p4_y, out z, out w); p4_x /= w; p4_y /= w; z = 0.0f; w = 1.0f; + viewmatrix.transform_point (out p1_x, out p1_y, out z, out w); p1_x /= w; p1_y /= w; z = base_z; w = 1.0f; + viewmatrix.transform_point (out p2_x, out p2_y, out z, out w); p2_x /= w; p2_y /= w; z = base_z; w = 1.0f; + viewmatrix.transform_point (out p3_x, out p3_y, out z, out w); p3_x /= w; p3_y /= w; z = base_z; w = 1.0f; + viewmatrix.transform_point (out p4_x, out p4_y, out z, out w); p4_x /= w; p4_y /= w; z = base_z; w = 1.0f; //transform into screen co-ordinates p1_x = xpad + (base_width * (p1_x + 1) / 2); @@ -549,16 +563,23 @@ namespace Unity p4_x = xpad + (base_width * (p4_x + 1) / 2); p4_y = (48 - ypad) + (base_height * (p4_y - 1) / 2); - if (Math.fabsf (self.rotation) <= 3.0) + if (Math.fabsf (self.rotation) <= 1.0) { // floor all the values. we don't floor when its rotated because then // we lose subpixel accuracy and things look like a 1991 video game - p1_x = Math.floorf (p1_x); p1_y = Math.floorf (p1_y); - p2_x = Math.floorf (p2_x); p2_y = Math.floorf (p2_y); + p1_x = Math.ceilf (p1_x); p1_y = Math.ceilf (p1_y); + p2_x = Math.floorf (p2_x); p2_y = Math.ceilf (p2_y); p3_x = Math.floorf (p3_x); p3_y = Math.floorf (p3_y); - p4_x = Math.floorf (p4_x); p4_y = Math.floorf (p4_y); + p4_x = Math.ceilf (p4_x); p4_y = Math.floorf (p4_y); } +/* + p1_y += self.stored_ymod; + p2_y += self.stored_ymod; + p3_y += self.stored_ymod; + p4_y += self.stored_ymod; +*/ + Cogl.TextureVertex[4] icon_points = { Cogl.TextureVertex () { x = p1_x, diff --git a/unity/quicklist-rendering.vala b/unity/quicklist-rendering.vala index 22df34cb6..652282200 100644 --- a/unity/quicklist-rendering.vala +++ b/unity/quicklist-rendering.vala @@ -35,6 +35,7 @@ namespace Unity.QuicklistRendering const float ITEM_HEIGHT = 2.0f; const float ITEM_CORNER_RADIUS = 0.3f; const float ITEM_CORNER_RADIUS_ABS = 4.0f; + const float ITEM_INDENT_ABS = 20.0f; const float ANCHOR_HEIGHT = 1.5f; const float ANCHOR_HEIGHT_ABS = 18.0f; const float ANCHOR_WIDTH = 0.75f; @@ -202,17 +203,8 @@ namespace Unity.QuicklistRendering // draw checkmark cr.save (); - cr.translate (_align ((30.0f - 16.0f) / 2.0f), - _align (((double) h - 16.0f) / 2.0f)); - cr.set_source_rgba (1.0f, 1.0f, 1.0f, 0.65f); - _round_rect (cr, - 1.0f, // aspect - 0.0f, // top-left corner - 0.0f, // top-left corner - 3.0f, // "size" of the corners - 16.0f, // width of the rectangle - 16.0f); // height of the rectangle - cr.stroke (); + cr.translate (_align ((ITEM_INDENT_ABS - 16.0f) / 2.0f), + _align (((double) h - 16.0f)/ 2.0f)); cr.set_source_rgba (1.0f, 1.0f, 1.0f, 1.0f); @@ -255,7 +247,7 @@ namespace Unity.QuicklistRendering int text_width; int text_height; get_text_extents (font, text, out text_width, out text_height); - cr.move_to (30.0f + Ctk.em_to_pixel (MARGIN), + cr.move_to (ITEM_INDENT_ABS + Ctk.em_to_pixel (MARGIN), (float) (h - text_height) / 2.0f); Pango.cairo_show_layout (cr, layout); @@ -293,18 +285,9 @@ namespace Unity.QuicklistRendering // draw checkmark cr.save (); - cr.translate (_align ((30.0f - 16.0f) / 2.0f), + cr.translate (_align ((ITEM_INDENT_ABS - 16.0f) / 2.0f), _align (((double) h - 16.0f) / 2.0f)); - _round_rect (cr, - 1.0f, // aspect - 0.0f, // top-left corner - 0.0f, // top-left corner - 3.0f, // "size" of the corners - 16.0f, // width of the rectangle - 16.0f); // height of the rectangle - cr.stroke (); - if (enabled) { cr.translate (3.0f, 1.0f); @@ -344,7 +327,7 @@ namespace Unity.QuicklistRendering int text_width; int text_height; get_text_extents (font, text, out text_width, out text_height); - cr.move_to (30.0f + Ctk.em_to_pixel (MARGIN), + cr.move_to (ITEM_INDENT_ABS + Ctk.em_to_pixel (MARGIN), (float) (h - text_height) / 2.0f); Pango.cairo_show_layout (cr, layout); @@ -371,7 +354,7 @@ namespace Unity.QuicklistRendering cr.scale (1.0f, 1.0f); cr.set_line_width (1.0f); - double x = _align (15.0f); + double x = _align (ITEM_INDENT_ABS / 2.0f); double y = _align ((double) h / 2.0f); double r1 = 3.5f; double r2 = 8.5f; @@ -383,17 +366,6 @@ namespace Unity.QuicklistRendering cr.arc (x, y, r1, 0.0f * (GLib.Math.PI / 180.0f), 360.0f * (GLib.Math.PI / 180.0f)); cr.fill (); - cr.set_source_rgba (1.0f, 1.0f, 1.0f, 0.65f); - cr.arc (x, y, r2, 0.0f * (GLib.Math.PI / 180.0f), - 360.0f * (GLib.Math.PI / 180.0f)); - cr.stroke (); - } - else - { - cr.set_source_rgba (1.0f, 1.0f, 1.0f, 0.65f); - cr.arc (x, y, r2, 0.0f * (GLib.Math.PI / 180.0f), - 360.0f * (GLib.Math.PI / 180.0f)); - cr.stroke (); } cr.set_source_rgba (1.0f, 1.0f, 1.0f, 1.0f); @@ -419,7 +391,7 @@ namespace Unity.QuicklistRendering int text_width; int text_height; get_text_extents (font, text, out text_width, out text_height); - cr.move_to (30.0f + Ctk.em_to_pixel (MARGIN), + cr.move_to (ITEM_INDENT_ABS + Ctk.em_to_pixel (MARGIN), (float) (h - text_height) / 2.0f); Pango.cairo_show_layout (cr, layout); @@ -452,7 +424,7 @@ namespace Unity.QuicklistRendering h - 1.0f); cr.fill (); - double x = _align (15.0f); + double x = _align (ITEM_INDENT_ABS / 2.0f); double y = _align ((double) h / 2.0f); double r1 = 3.5f; double r2 = 8.5f; @@ -465,16 +437,7 @@ namespace Unity.QuicklistRendering cr.arc (x, y, r1, 0.0f * (GLib.Math.PI / 180.0f), 360.0f * (GLib.Math.PI / 180.0f)); cr.fill (); - cr.arc (x, y, r2, 0.0f * (GLib.Math.PI / 180.0f), - 360.0f * (GLib.Math.PI / 180.0f)); - cr.stroke (); } - else - { - cr.arc (x, y, r2, 0.0f * (GLib.Math.PI / 180.0f), - 360.0f * (GLib.Math.PI / 180.0f)); - cr.stroke (); - } // draw text Pango.Layout layout = Pango.cairo_create_layout (cr); @@ -498,7 +461,7 @@ namespace Unity.QuicklistRendering int text_width; int text_height; get_text_extents (font, text, out text_width, out text_height); - cr.move_to (30.0f + Ctk.em_to_pixel (MARGIN), + cr.move_to (ITEM_INDENT_ABS + Ctk.em_to_pixel (MARGIN), (float) (h - text_height) / 2.0f); Pango.cairo_show_layout (cr, layout); @@ -543,7 +506,7 @@ namespace Unity.QuicklistRendering int text_width; int text_height; get_text_extents (font, text, out text_width, out text_height); - cr.move_to (Ctk.em_to_pixel (MARGIN), + cr.move_to (ITEM_INDENT_ABS + Ctk.em_to_pixel (MARGIN), (float) (h - text_height) / 2.0f); Pango.cairo_show_layout (cr, layout); @@ -597,7 +560,7 @@ namespace Unity.QuicklistRendering int text_width; int text_height; get_text_extents (font, text, out text_width, out text_height); - cr.move_to (Ctk.em_to_pixel (MARGIN), + cr.move_to (ITEM_INDENT_ABS + Ctk.em_to_pixel (MARGIN), (float) (h - text_height) / 2.0f); cr.set_source_rgba (0.0f, 0.0f, 0.0f, 0.0f); diff --git a/unity/shell.vala b/unity/shell.vala index c0f4224a0..7a7239795 100644 --- a/unity/shell.vala +++ b/unity/shell.vala @@ -63,6 +63,7 @@ namespace Unity public abstract void expose_xids (Array<uint32> xids); public abstract void stop_expose (); + public abstract bool super_key_active {get; set;} public abstract void get_window_details (uint32 xid, out bool allows_resize, out bool is_maximised); @@ -73,6 +74,9 @@ namespace Unity public signal void indicators_changed (int width); public signal void mode_changed (ShellMode mode); public signal void active_window_state_changed (); + public signal void super_key_modifier_release (uint keysym); + public signal void super_key_modifier_press (uint keysym); + } public Shell? global_shell; // our global shell diff --git a/unity/unity-appinfo-manager.vala b/unity/unity-appinfo-manager.vala index 75eab0df6..24d82f04b 100644 --- a/unity/unity-appinfo-manager.vala +++ b/unity/unity-appinfo-manager.vala @@ -33,21 +33,42 @@ namespace Unity { /** * A singleton class that caches GLib.AppInfo objects. * Singletons are evil, yes, but this on slightly less - * so because the exposed API is immutable + * so because the exposed API is immutable. + * + * To detect when any of the managed AppInfo objects changes, appears, + * or goes away listen for the 'changed' signal. */ public class AppInfoManager : Object { private static AppInfoManager singleton = null; - private Map<string,AppInfo> appinfo_by_id; + private Map<string,AppInfo?> appinfo_by_id; /* id or path -> AppInfo */ + private Map<string,FileMonitor> monitors; /* parent uri -> monitor */ + private Map<string, Gee.List<string>> categories_by_id; /* desktop id or path -> xdg cats */ private uchar[] buffer; private size_t buffer_size; private AppInfoManager () { - appinfo_by_id = new HashMap<string,AppInfo> (GLib.str_hash, GLib.str_equal); + appinfo_by_id = new HashMap<string,AppInfo?> (GLib.str_hash, GLib.str_equal); + categories_by_id = new HashMap<string,Gee.List<string>> (GLib.str_hash, GLib.str_equal); buffer_size = 1024; buffer = new uchar[buffer_size]; + + monitors = new HashMap<string,AppInfo?> (GLib.str_hash, GLib.str_equal); + foreach (string path in IO.get_system_data_dirs()) + { + var dir = File.new_for_path ( + Path.build_filename (path, "applications")); + try { + var monitor = dir.monitor_directory (FileMonitorFlags.NONE); + monitor.changed.connect (on_dir_changed); + monitors.set (dir.get_uri(), monitor); + } catch (IOError e) { + warning ("Error setting up directory monitor on '%s': %s", + dir.get_uri (), e.message); + } + } } /** @@ -56,12 +77,41 @@ namespace Unity { public static AppInfoManager get_instance () { if (AppInfoManager.singleton == null) - AppInfoManager.singleton = new AppInfoManager(); + AppInfoManager.singleton = new AppInfoManager(); return AppInfoManager.singleton; } /** + * Emitted whenever an AppInfo in any of the monitored paths change. + * Note that @new_appinfo may be null in case it has been removed. + */ + public signal void changed (string id, AppInfo? new_appinfo); + + /* Whenever something happens to a monitored file, + * we remove it from the cache */ + private void on_dir_changed (FileMonitor mon, File file, File? other_file, FileMonitorEvent e) + { + var desktop_id = file.get_basename (); + var path = file.get_path (); + AppInfo? appinfo; + + if (appinfo_by_id.has_key(desktop_id)) + { + appinfo_by_id.unset(desktop_id); + appinfo = lookup (desktop_id); + changed (desktop_id, appinfo); + } + + if (appinfo_by_id.has_key(path)) + { + appinfo_by_id.unset(path); + appinfo = lookup (path); + changed (path, appinfo); + } + } + + /** * Look up an AppInfo given its desktop id or absolute path. The desktop id * is the base filename of the .desktop file for the application including * the .desktop extension. @@ -71,26 +121,97 @@ namespace Unity { */ public AppInfo? lookup (string id) { - /* Try the cache */ - var appinfo = appinfo_by_id.get (id); - if (appinfo != null) - return appinfo; + /* Check the cache. Note that null is a legal value since it means that + * the files doesn't exist */ + if (appinfo_by_id.has_key (id)) + return appinfo_by_id.get (id); /* Look up by path or by desktop id */ + AppInfo? appinfo; + KeyFile? keyfile = new KeyFile (); if (id.has_prefix("/")) - appinfo = new DesktopAppInfo.from_filename (id); + { + try { + keyfile.load_from_file (id, KeyFileFlags.NONE); + } catch (Error e) { + keyfile = null; + if (!(e is IOError.NOT_FOUND || e is KeyFileError.NOT_FOUND)) + warning ("Error loading '%s': %s", id, e.message); + } + var dir = File.new_for_path (id).get_parent (); + var dir_uri = dir.get_uri (); + if (!monitors.has_key (dir_uri)) + { + try { + var monitor = dir.monitor_directory (FileMonitorFlags.NONE); + monitor.changed.connect (on_dir_changed); + monitors.set (dir_uri, monitor); + debug ("Monitoring extra app directory: %s", dir_uri); + } catch (IOError ioe) { + warning ("Error setting up extra app directory monitor on '%s': %s", + dir_uri, ioe.message); + } + } + } else - appinfo = new DesktopAppInfo (id); - - if (appinfo != null) { - appinfo_by_id.set (id, appinfo); - // FIXME install monitor + string path = Path.build_filename ("applications", id, null); + string full_path; + try { + keyfile.load_from_data_dirs (path, out full_path, KeyFileFlags.NONE); + } catch (Error e) { + keyfile = null; + if (!(e is IOError.NOT_FOUND || e is KeyFileError.NOT_FOUND)) + warning ("Error loading '%s': %s", id, e.message); + } + } + + /* If keyfile is null we had an error loading it */ + if (keyfile != null) + { + appinfo = new DesktopAppInfo.from_keyfile (keyfile); + try { + string[] categories = keyfile.get_string_list ("Desktop Entry", + "Categories"); + var cats = new Gee.ArrayList<string>(); + foreach (var cat in categories) + cats.add (cat); + + categories_by_id.set (id, cats); + } catch (KeyFileError e) { + /* Unknown key or group. This app has no XDG Catories */ + } } + else + appinfo = null; + + /* If we don't find the file, we also cache that fact since we'll store + * a null AppInfo in that case */ + appinfo_by_id.set (id, appinfo); + return appinfo; } /** + * Look up XDG categories for for desktop id or file path @id. + * Returns null if id is not found. + * This method will do sync IO if the desktop file for @id is not + * already cached. So if you are living in an async world you must first + * do an async call to lookup_async(id) before calling this method, in which + * case no sync io will be done. + */ + public Gee.List<string>? get_categories (string id) + { + /* Make sure we have loaded the relevant .desktop file: */ + AppInfo? appinfo = lookup (id); + + if (appinfo == null) + return null; + + return categories_by_id.get (id); + } + + /** * Look up an AppInfo given its desktop id or absolute path. * The desktop id is the base filename of the .desktop file for the * application including the .desktop extension. @@ -100,10 +221,10 @@ namespace Unity { */ public async AppInfo? lookup_async (string id) throws Error { - /* Check the cache */ - var appinfo = appinfo_by_id.get (id); - if (appinfo != null) - return appinfo; + /* Check the cache. Note that null is a legal value since it means that + * the files doesn't exist */ + if (appinfo_by_id.has_key (id)) + return appinfo_by_id.get (id); /* Load it async */ size_t data_size; @@ -115,6 +236,20 @@ namespace Unity { { var f = File.new_for_path (id); input = yield f.read_async (Priority.DEFAULT, null); + var dir = f.get_parent (); + var dir_uri = dir.get_uri (); + if (!monitors.has_key (dir_uri)) + { + try { + var monitor = dir.monitor_directory (FileMonitorFlags.NONE); + monitor.changed.connect (on_dir_changed); + monitors.set (dir_uri, monitor); + debug ("Monitoring extra app directory: %s", dir_uri); + } catch (IOError ioe) { + warning ("Error setting up extra app directory monitor on '%s': %s", + dir_uri, ioe.message); + } + } } else { @@ -122,8 +257,13 @@ namespace Unity { input = yield IO.open_from_data_dirs (path); } + /* If we don't find the file, we also cache that fact by caching a + * null value for that id */ if (input == null) - return null; + { + appinfo_by_id.set (id, null); + return null; + } try { @@ -150,7 +290,7 @@ namespace Unity { } /* Create the appinfo and cache it */ - appinfo = new DesktopAppInfo.from_keyfile (keyfile); + var appinfo = new DesktopAppInfo.from_keyfile (keyfile); appinfo_by_id.set (id, appinfo); /* Manually free the raw file data */ diff --git a/unity/unity-cairo-canvas.vala b/unity/unity-cairo-canvas.vala index 91aee9a2f..8b1738fef 100644 --- a/unity/unity-cairo-canvas.vala +++ b/unity/unity-cairo-canvas.vala @@ -38,7 +38,7 @@ namespace Unity private int last_width = 0; private int last_height = 0; - private CairoCanvasPaint paint_func; + public CairoCanvasPaint paint_func; public CairoCanvas (CairoCanvasPaint _func) { diff --git a/unity/unity-place.vala b/unity/unity-place.vala index 8fd5c1730..cf17eaee8 100644 --- a/unity/unity-place.vala +++ b/unity/unity-place.vala @@ -172,6 +172,11 @@ namespace Unity.Place { return search; } + public List<unowned string> get_hints () + { + return hints.get_keys (); + } + public void set_hint (string hint, string val) { hints.insert (hint, val); @@ -196,6 +201,27 @@ namespace Unity.Place { { return hints.size (); } + + /* Returns true if search strings and all hints match */ + public bool equals (Search? other) + { + if (other == null) + return false; + + if (get_search_string() != other.get_search_string ()) + return false; + + if (num_hints () != other.num_hints()) + return false; + + foreach (var hint in get_hints ()) + { + if (other.get_hint (hint) != get_hint (hint)) + return false; + } + + return true; + } } /** @@ -695,13 +721,19 @@ namespace Unity.Place { public void set_global_search (string search, HashTable<string,string> hints) { - this._entry_info.active_global_search = new Search (search, hints); + var s = new Search (search, hints); + + if (!s.equals (this._entry_info.active_global_search)) + this._entry_info.active_global_search = s; } public void set_search (string search, HashTable<string,string> hints) { - this._entry_info.active_search = new Search (search, hints); + var s = new Search (search, hints); + + if (!s.equals (this._entry_info.active_search)) + this._entry_info.active_search = s; } public void set_active (bool is_active) @@ -842,6 +874,7 @@ namespace Unity.Place { private string _dbus_path; private bool _exported = false; private HashTable<string, _EntrySignals?> entry_signals; + private Gee.Set<string> ignore_remote_notify_props; /* * Properties @@ -873,6 +906,12 @@ namespace Unity.Place { construct { service = new ServiceImpl (_dbus_path); entry_signals = new HashTable<string, _EntrySignals?>(str_hash, str_equal); + + ignore_remote_notify_props = new Gee.HashSet<string> (); + ignore_remote_notify_props.add ("active-search"); + ignore_remote_notify_props.add ("active-global-search"); + ignore_remote_notify_props.add ("active"); + ignore_remote_notify_props.add ("active-section"); } public Controller (string dbus_path) @@ -1015,6 +1054,11 @@ namespace Unity.Place { entry.dbus_path); return; } + + /* Don't emit signals on the bus that are strictly local metadata */ + if (pspec.get_name () in ignore_remote_notify_props) + return; + entry_service.queue_place_entry_info_changed_signal (); } diff --git a/unity/unity-stripe-texture.vala b/unity/unity-stripe-texture.vala new file mode 100644 index 000000000..df6ed1c95 --- /dev/null +++ b/unity/unity-stripe-texture.vala @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2010 Canonical, Ltd. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * version 3.0 as published by the Free Software Foundation. + * + * 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 version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authored by Neil Jagdish Patel <neil.patel@canonical.com> + * + */ + +namespace Unity +{ + /* + * UnityStripeTexture will paint itself in the stripe-style that's used + * in many places in Unity. This is best-used as a background for CtkActor. + * However there are some options to make the painting of more complex + * objects easier + */ + public class StripeTexture : CairoCanvas + { + /* Set the outline_paint_func if you want to draw your own outline for + * the stripe to paint in + */ + public delegate void StripeTextureOutlineFunc (Cairo.Context cr, + int width, + int height); + + public float radius { get; construct set; } + + public StripeTextureOutlineFunc outline_paint_func; + + private Cairo.Surface? pattern; + + public StripeTexture (StripeTextureOutlineFunc? func) + { + Object (radius:10.0f); + + outline_paint_func = rounded_outline; + if (func != null) + outline_paint_func = func; + } + + construct + { + paint_func = paint_bg; + } + + public void rounded_outline (Cairo.Context cr, int width, int height) + { + var x = 0; + var y = 0; + width -= 1; + height -= 1; + + cr.line_to (x, y + radius); + cr.curve_to (x, y, + x, y, + x + radius, y); + cr.line_to (width - radius, y); + cr.curve_to (width, y, + width, y, + width, y + radius); + cr.line_to (width, height - radius); + cr.curve_to (width, height, + width, height, + width - radius, height); + cr.line_to (x + radius, height); + cr.curve_to (x, height, + x, height, + x, height - radius); + cr.close_path (); + } + + private void paint_bg (Cairo.Context cr, int width, int height) + { + cr.set_operator (Cairo.Operator.CLEAR); + cr.paint (); + + cr.set_operator (Cairo.Operator.OVER); + cr.set_line_width (1.0); + + cr.translate (0.5, 0.5); + + outline_paint_func (cr, width, height); + + if (pattern == null) + { + pattern = new Cairo.Surface.similar (cr.get_target (), + Cairo.Content.COLOR_ALPHA, + 4, 4); + var context = new Cairo.Context (pattern); + + context.set_operator (Cairo.Operator.CLEAR); + context.paint (); + + context.set_line_width (0.3); + context.set_operator (Cairo.Operator.OVER); + context.set_source_rgba (1.0, 1.0, 1.0, 0.65); + + context.move_to (0, 0); + context.line_to (4, 4); + + context.stroke (); + } + + var pat = new Cairo.Pattern.for_surface (pattern); + pat.set_extend (Cairo.Extend.REPEAT); + cr.set_source (pat); + cr.fill_preserve (); + + cr.set_line_width (1.75); + cr.set_source_rgba (1.0, 1.0, 1.0, 0.5); + cr.stroke (); + } + } +} diff --git a/vapi/clutter-1.0.vapi b/vapi/clutter-1.0.vapi index bac197fd5..6c3a49fd8 100644 --- a/vapi/clutter-1.0.vapi +++ b/vapi/clutter-1.0.vapi @@ -5654,6 +5654,8 @@ namespace Clutter { [CCode (cheader_filename = "clutter/clutter.h")] public static bool get_motion_events_enabled (); [CCode (cheader_filename = "clutter/clutter.h")] + public static bool get_gl_picking_enabled (); + [CCode (cheader_filename = "clutter/clutter.h")] public static GLib.OptionGroup get_option_group (); [CCode (cheader_filename = "clutter/clutter.h")] public static GLib.OptionGroup get_option_group_without_init (); @@ -5698,6 +5700,8 @@ namespace Clutter { [CCode (cheader_filename = "clutter/clutter.h")] public static void set_motion_events_enabled (bool enable); [CCode (cheader_filename = "clutter/clutter.h")] + public static void set_gl_picking_enabled (bool enable); + [CCode (cheader_filename = "clutter/clutter.h")] public static uint threads_add_frame_source (uint fps, GLib.SourceFunc func, void* data); [CCode (cheader_filename = "clutter/clutter.h")] public static uint threads_add_frame_source_full (int priority, uint fps, GLib.SourceFunc func, void* data, GLib.DestroyNotify notify); diff --git a/vapi/mutter-2.28.vapi b/vapi/mutter-2.28.vapi index f5f8cbab6..a6a2ed1ea 100644 --- a/vapi/mutter-2.28.vapi +++ b/vapi/mutter-2.28.vapi @@ -130,6 +130,11 @@ namespace Mutter { public static void set_input_focus_window (Mutter.MetaDisplay display, Mutter.MetaWindow window, bool focus_frame, uint32 timestamp); [CCode (cname = "meta_display_xwindow_is_a_no_focus_window")] public static bool xwindow_is_a_no_focus_window (Mutter.MetaDisplay display, X.Window xwindow); + + public signal void overlay_key (); + public signal void overlay_key_down (); + public signal void overlay_key_with_modifier (uint keysym); + public signal void overlay_key_with_modifier_down (uint keysym); } [Compact] [CCode (cheader_filename = "mutter-plugins.h")] |
