Merge lp:~david4dev/slingshot/fix-804518 into lp:~elementary-pantheon/slingshot/slingshot

Proposed by David Green
Status: Merged
Merged at revision: 128
Proposed branch: lp:~david4dev/slingshot/fix-804518
Merge into: lp:~elementary-pantheon/slingshot/slingshot
Diff against target: 777 lines (+260/-154)
6 files modified
backend/AppMonitor.vala (+37/-0)
build (+3/-0)
build_run (+3/-5)
frontend/widgets/AppItem.vala (+37/-37)
install (+5/-0)
slingshot.vala (+175/-112)
To merge this branch: bzr merge lp:~david4dev/slingshot/fix-804518
Reviewer Review Type Date Requested Status
Danielle Foré Approve
Review via email: mp+68154@code.launchpad.net

Description of the change

Fixes bug 804518:
  - Slingshot now launches in the background. This makes it suitable for auto starting.
  - If the slingshot executable is run and an instance of slingshot is already running, the slingshot window will be activated. This shows the launcher without much delay.
  - Slingshot now monitors /usr/share/applications and ~/.local/share/applications so that it updates whenever launchers are added/removed (normally when installing/uninstalling apps).
  - Slingshot no longer shows/unshows the desktop. This is because I couldn't work out how to this with the new functionality. IMO this is actually better because you can still look at the windows you have open. This may be useful, for example, if one of them is a guide telling you which application to run.
  - Removed gradient to improve readability when running slingshot over windows (or light coloured wallpapers).

To post a comment you must log in.
lp:~david4dev/slingshot/fix-804518 updated
60. By David Green

If slinshot is already running, it now shows the existing instance if it is hidden and hides the existing instance if it is showing.

61. By David Green

fixed issue with slingshot showing behind windows

62. By David Green

Now shows/hides the desktop again

Revision history for this message
xapantu (xapantu) wrote :

Apparently, this branch has been merged separately (i.e. the branch hasn't been merged directly but parts were taken) so we have these features in the trunk now.
Thanks for your work :)

Revision history for this message
Danielle Foré (danrabbit) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'backend/AppMonitor.vala'
--- backend/AppMonitor.vala 1970-01-01 00:00:00 +0000
+++ backend/AppMonitor.vala 2011-08-10 18:49:27 +0000
@@ -0,0 +1,37 @@
1namespace Slingshot.Backend {
2
3 public class AppMonitor : GLib.Object {
4
5 public GLib.File system_applications;
6 public GLib.File user_applications;
7
8 public GLib.FileMonitor system_monitor;
9 public GLib.FileMonitor user_monitor;
10
11 public signal void changed (GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type);
12
13 public void trigger_changed (GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) {
14 this.changed(file, other_file, event_type);
15 }
16
17 construct {
18 this.system_applications = File.new_for_path("/usr/share/applications");
19 this.user_applications = File.new_for_path(GLib.Environment.get_user_data_dir() + "/applications");
20 try {
21 this.system_monitor = this.system_applications.monitor_directory(GLib.FileMonitorFlags.NONE);
22 this.system_monitor.changed.connect(this.trigger_changed);
23 } catch (GLib.Error e) {
24 print("Error: "+e.message+"\n");
25 }
26 try {
27 this.user_monitor = this.user_applications.monitor_directory(GLib.FileMonitorFlags.NONE);
28 this.user_monitor.changed.connect(this.trigger_changed);
29 } catch (GLib.Error e) {
30 print("Error: "+e.message+"\n");
31 }
32 }
33
34 }
35
36
37}
038
=== added file 'build'
--- build 1970-01-01 00:00:00 +0000
+++ build 2011-08-10 18:49:27 +0000
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3valac --pkg gtk+-2.0 --pkg unique-1.0 --pkg gee-1.0 --pkg gio-unix-2.0 --pkg gio-2.0 --pkg libgnome-menu --Xcc='-DGMENU_I_KNOW_THIS_IS_UNSTABLE' --pkg libwnck-1.0 --Xcc='-DWNCK_I_KNOW_THIS_IS_UNSTABLE' slingshot.vala frontend/widgets/*.vala frontend/*.vala backend/*.vala
04
=== modified file 'build_run'
--- build_run 2011-02-12 12:16:02 +0000
+++ build_run 2011-08-10 18:49:27 +0000
@@ -1,7 +1,5 @@
1#!/bin/sh1#!/bin/sh
22
3valac --pkg gtk+-2.0 --pkg unique-1.0 --pkg gee-1.0 --pkg gio-unix-2.0 --pkg libgnome-menu --Xcc='-DGMENU_I_KNOW_THIS_IS_UNSTABLE' --pkg libwnck-1.0 --Xcc='-DWNCK_I_KNOW_THIS_IS_UNSTABLE' slingshot.vala frontend/widgets/*.vala frontend/*.vala backend/*.vala3./build
44
5sudo mv slingshot /usr/bin5killall slingshot ; ./slingshot
6
7slingshot
86
=== modified file 'frontend/widgets/AppItem.vala'
--- frontend/widgets/AppItem.vala 2011-02-12 13:16:08 +0000
+++ frontend/widgets/AppItem.vala 2011-08-10 18:49:27 +0000
@@ -2,13 +2,13 @@
2namespace Slingshot.Frontend {2namespace Slingshot.Frontend {
33
4 public class AppItem : Gtk.EventBox {4 public class AppItem : Gtk.EventBox {
5 5
6 private Gdk.Pixbuf icon;6 private Gdk.Pixbuf icon;
7 private Slingshot.Frontend.Color prominent;7 private Slingshot.Frontend.Color prominent;
8 private string label;8 private string label;
9 private Gtk.VBox wrapper;9 private Gtk.VBox wrapper;
10 private int icon_size;10 private int icon_size;
11 11
12 const int FPS = 24;12 const int FPS = 24;
13 const int DURATION = 200;13 const int DURATION = 200;
14 const int RUN_LENGTH = (int)(DURATION/FPS); // total number of frames14 const int RUN_LENGTH = (int)(DURATION/FPS); // total number of frames
@@ -16,44 +16,44 @@
1616
17 public AppItem (int size) {17 public AppItem (int size) {
18 this.icon_size = size;18 this.icon_size = size;
19 19
20 // EventBox Properties20 // EventBox Properties
21 this.set_visible_window(false);21 this.set_visible_window(false);
22 this.can_focus = true;22 this.can_focus = true;
23 this.set_size_request (icon_size * 2, icon_size + 30); // 30 is the padding between icon and label and label's height23 this.set_size_request (icon_size * 2, icon_size + 30); // 30 is the padding between icon and label and label's height
24 24
25 // VBox properties25 // VBox properties
26 this.wrapper = new Gtk.VBox (false, 0);26 this.wrapper = new Gtk.VBox (false, 0);
27 this.wrapper.expose_event.connect (this.draw_icon);27 this.wrapper.expose_event.connect (this.draw_icon);
28 this.add (this.wrapper);28 this.add (this.wrapper);
29 29
30 30
31 // Focused signals31 // Focused signals
32 this.expose_event.connect (this.draw_background);32 this.expose_event.connect (this.draw_background);
33 this.focus_in_event.connect ( () => { this.focus_in (); return true;} );33 this.focus_in_event.connect ( () => { this.focus_in (); return true;} );
34 this.focus_out_event.connect ( () => { this.focus_out (); return true;} );34 this.focus_out_event.connect ( () => { this.focus_out (); return true;} );
35 35
36 }36 }
37 37
38 public void change_app (Gdk.Pixbuf new_icon, string new_name, string new_tooltip) {38 public void change_app (Gdk.Pixbuf new_icon, string new_name, string new_tooltip) {
39 this.current_frame = 1;39 this.current_frame = 1;
40 40
41 // Icon41 // Icon
42 this.icon = new_icon;42 this.icon = new_icon;
43 this.prominent = Slingshot.Frontend.Utilities.average_color (this.icon);43 this.prominent = Slingshot.Frontend.Utilities.average_color (this.icon);
44 44
45 // Label45 // Label
46 this.label = new_name;46 this.label = new_name;
47 47
48 // Tooltip48 // Tooltip
49 this.set_tooltip_text (new_tooltip);49 this.set_tooltip_text (new_tooltip);
50 50
51 // Redraw51 // Redraw
52 this.wrapper.queue_draw ();52 this.wrapper.queue_draw ();
53 }53 }
54 54
55 public new void focus_in () {55 public new void focus_in () {
56 56
57 GLib.Timeout.add (((int)(1000/this.FPS)), () => {57 GLib.Timeout.add (((int)(1000/this.FPS)), () => {
58 if (this.current_frame >= this.RUN_LENGTH || !this.has_focus) {58 if (this.current_frame >= this.RUN_LENGTH || !this.has_focus) {
59 current_frame = 1;59 current_frame = 1;
@@ -63,11 +63,11 @@
63 this.current_frame++;63 this.current_frame++;
64 return true;64 return true;
65 });65 });
66 66
67 }67 }
68 68
69 public new void focus_out () {69 public new void focus_out () {
70 70
71 GLib.Timeout.add (((int)(1000/this.FPS)), () => {71 GLib.Timeout.add (((int)(1000/this.FPS)), () => {
72 if (this.current_frame >= this.RUN_LENGTH || this.has_focus) {72 if (this.current_frame >= this.RUN_LENGTH || this.has_focus) {
73 current_frame = 1;73 current_frame = 1;
@@ -77,76 +77,76 @@
77 this.current_frame++;77 this.current_frame++;
78 return true;78 return true;
79 });79 });
80 80
81 }81 }
82 82
83 private bool draw_icon (Gtk.Widget widget, Gdk.EventExpose event) {83 private bool draw_icon (Gtk.Widget widget, Gdk.EventExpose event) {
84 Gtk.Allocation size;84 Gtk.Allocation size;
85 widget.get_allocation (out size);85 widget.get_allocation (out size);
86 var context = Gdk.cairo_create (widget.window);86 var context = Gdk.cairo_create (widget.window);
87 87
88 // Draw icon88 // Draw icon
89 Gdk.cairo_set_source_pixbuf (context, this.icon, size.x + ((this.icon.width - size.width) / -2.0), size.y);89 Gdk.cairo_set_source_pixbuf (context, this.icon, size.x + ((this.icon.width - size.width) / -2.0), size.y);
90 context.paint ();90 context.paint ();
91 91
92 // Truncate text92 // Truncate text
93 Cairo.TextExtents extents;93 Cairo.TextExtents extents;
94 context.select_font_face ("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);94 context.select_font_face ("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
95 context.set_font_size (11.5);95 context.set_font_size (11.5);
96 Slingshot.Frontend.Utilities.truncate_text (context, size, 10, this.label, out this.label, out extents); // truncate text96 Slingshot.Frontend.Utilities.truncate_text (context, size, 10, this.label, out this.label, out extents); // truncate text
97 97
98 // Draw text shadow98 // Draw text shadow
99 context.move_to ((size.x + size.width/2 - extents.width/2) + 1, (size.y + size.height - 10) + 1);99 context.move_to ((size.x + size.width/2 - extents.width/2) + 1, (size.y + size.height - 10) + 1);
100 context.set_source_rgba (0.0, 0.0, 0.0, 0.8);100 context.set_source_rgba (0.0, 0.0, 0.0, 0.8);
101 context.show_text (this.label);101 context.show_text (this.label);
102 102
103 // Draw normal text 103 // Draw normal text
104 context.set_source_rgba (1.0, 1.0, 1.0, 1.0); 104 context.set_source_rgba (1.0, 1.0, 1.0, 1.0);
105 context.move_to (size.x + size.width/2 - extents.width/2, size.y + size.height - 10);105 context.move_to (size.x + size.width/2 - extents.width/2, size.y + size.height - 10);
106 context.show_text (this.label);106 context.show_text (this.label);
107 107
108 return false;108 return false;
109 }109 }
110 110
111 private bool draw_background (Gtk.Widget widget, Gdk.EventExpose event) {111 private bool draw_background (Gtk.Widget widget, Gdk.EventExpose event) {
112 Gtk.Allocation size;112 Gtk.Allocation size;
113 widget.get_allocation (out size);113 widget.get_allocation (out size);
114 var context = Gdk.cairo_create (widget.window);114 var context = Gdk.cairo_create (widget.window);
115 115
116 double progress;116 double progress;
117 if (this.current_frame > 1) {117 if (this.current_frame > 1) {
118 progress = (double)this.RUN_LENGTH/(double)this.current_frame;118 progress = (double)this.RUN_LENGTH/(double)this.current_frame;
119 } else {119 } else {
120 progress = 1;120 progress = 1;
121 }121 }
122 122
123 if (this.has_focus) {123 if (this.has_focus) {
124 124
125 var linear_gradient = new Cairo.Pattern.linear (size.x, size.y, size.x, size.y + size.height);125 var linear_gradient = new Cairo.Pattern.linear (size.x, size.y, size.x, size.y + size.height);
126 linear_gradient.add_color_stop_rgba (0.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.0);126 linear_gradient.add_color_stop_rgba (0.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.0);
127 linear_gradient.add_color_stop_rgba (0.5, this.prominent.R, this.prominent.G, this.prominent.B, 0.25/progress);127 linear_gradient.add_color_stop_rgba (0.5, this.prominent.R, this.prominent.G, this.prominent.B, 0.25/progress);
128 linear_gradient.add_color_stop_rgba (1.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.4/progress);128 linear_gradient.add_color_stop_rgba (1.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.4/progress);
129 129
130 context.set_source (linear_gradient);130 context.set_source (linear_gradient);
131 Slingshot.Frontend.Utilities.draw_rounded_rectangle (context, 10, 0.5, size);131 Slingshot.Frontend.Utilities.draw_rounded_rectangle (context, 10, 0.5, size);
132 context.fill ();132 context.fill ();
133 133
134 } else {134 } else {
135 if (this.current_frame > 1) { 135 if (this.current_frame > 1) {
136 var linear_gradient = new Cairo.Pattern.linear (size.x, size.y, size.x, size.y + size.height);136 var linear_gradient = new Cairo.Pattern.linear (size.x, size.y, size.x, size.y + size.height);
137 linear_gradient.add_color_stop_rgba (0.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.0);137 linear_gradient.add_color_stop_rgba (0.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.0);
138 linear_gradient.add_color_stop_rgba (0.5, this.prominent.R, this.prominent.G, this.prominent.B, 0.25 - 0.25/progress);138 linear_gradient.add_color_stop_rgba (0.5, this.prominent.R, this.prominent.G, this.prominent.B, 0.25 - 0.25/progress);
139 linear_gradient.add_color_stop_rgba (1.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.4 - 0.4/progress);139 linear_gradient.add_color_stop_rgba (1.0, this.prominent.R, this.prominent.G, this.prominent.B, 0.4 - 0.4/progress);
140 140
141 context.set_source (linear_gradient);141 context.set_source (linear_gradient);
142 Slingshot.Frontend.Utilities.draw_rounded_rectangle (context, 10, 0.5, size);142 Slingshot.Frontend.Utilities.draw_rounded_rectangle (context, 10, 0.5, size);
143 context.fill ();143 context.fill ();
144 }144 }
145 }145 }
146 146
147 return false;147 return false;
148 }148 }
149 149
150 150
151 }151 }
152}152}
153153
=== added file 'install'
--- install 1970-01-01 00:00:00 +0000
+++ install 2011-08-10 18:49:27 +0000
@@ -0,0 +1,5 @@
1#!/bin/sh
2
3./build
4
5sudo mv slingshot /usr/bin/
06
=== modified file 'slingshot.vala'
--- slingshot.vala 2011-02-19 14:51:06 +0000
+++ slingshot.vala 2011-08-10 18:49:27 +0000
@@ -3,11 +3,11 @@
3 public GLib.List<Slingshot.Frontend.AppItem> children = new GLib.List<Slingshot.Frontend.AppItem> ();3 public GLib.List<Slingshot.Frontend.AppItem> children = new GLib.List<Slingshot.Frontend.AppItem> ();
4 public Slingshot.Frontend.Searchbar searchbar;4 public Slingshot.Frontend.Searchbar searchbar;
5 public Slingshot.Frontend.Grid grid;5 public Slingshot.Frontend.Grid grid;
6 6
7 public Gee.ArrayList<Gee.HashMap<string, string>> apps = new Gee.ArrayList<Gee.HashMap<string, string>> ();7 public Gee.ArrayList<Gee.HashMap<string, string>> apps = new Gee.ArrayList<Gee.HashMap<string, string>> ();
8 public Gee.HashMap<string, Gdk.Pixbuf> icons = new Gee.HashMap<string, Gdk.Pixbuf>();8 public Gee.HashMap<string, Gdk.Pixbuf> icons = new Gee.HashMap<string, Gdk.Pixbuf>();
9 public Gee.ArrayList<Gee.HashMap<string, string>> filtered = new Gee.ArrayList<Gee.HashMap<string, string>> ();9 public Gee.ArrayList<Gee.HashMap<string, string>> filtered = new Gee.ArrayList<Gee.HashMap<string, string>> ();
10 10
11 public Slingshot.Frontend.Indicators pages;11 public Slingshot.Frontend.Indicators pages;
12 public Slingshot.Frontend.Indicators categories;12 public Slingshot.Frontend.Indicators categories;
13 public Gee.ArrayList<GMenu.TreeDirectory> all_categories = Slingshot.Backend.GMenuEntries.get_categories ();13 public Gee.ArrayList<GMenu.TreeDirectory> all_categories = Slingshot.Backend.GMenuEntries.get_categories ();
@@ -15,11 +15,13 @@
15 public int total_pages;15 public int total_pages;
16 public Gtk.HBox top_spacer;16 public Gtk.HBox top_spacer;
1717
18 Slingshot.Backend.AppMonitor monitor;
19 public bool is_showing;
20
18 public SlingshotWindow () {21 public SlingshotWindow () {
19 22
20 // Show desktop23 this.is_showing = false;
21 Wnck.Screen.get_default().toggle_showing_desktop (true);24
22
23 // Window properties25 // Window properties
24 this.title = "Slingshot";26 this.title = "Slingshot";
25 this.skip_pager_hint = true;27 this.skip_pager_hint = true;
@@ -27,13 +29,13 @@
27 this.set_type_hint (Gdk.WindowTypeHint.NORMAL);29 this.set_type_hint (Gdk.WindowTypeHint.NORMAL);
28 this.maximize ();30 this.maximize ();
29 this.stick ();31 this.stick ();
30 this.set_keep_above (true);32 this.set_keep_above(true);
31 33
32 // Set icon size34 // Set icon size
33 Gdk.Rectangle monitor_dimensions;35 Gdk.Rectangle monitor_dimensions;
34 Gdk.Screen screen = Gdk.Screen.get_default();36 Gdk.Screen screen = Gdk.Screen.get_default();
35 screen.get_monitor_geometry(screen.get_primary_monitor(), out monitor_dimensions);37 screen.get_monitor_geometry(screen.get_primary_monitor(), out monitor_dimensions);
36 38
37 double suggested_size = (Math.pow (monitor_dimensions.width * monitor_dimensions.height, ((double) (1.0/3.0))) / 1.6);39 double suggested_size = (Math.pow (monitor_dimensions.width * monitor_dimensions.height, ((double) (1.0/3.0))) / 1.6);
38 if (suggested_size < 27) {40 if (suggested_size < 27) {
39 this.icon_size = 24;41 this.icon_size = 24;
@@ -44,22 +46,22 @@
44 } else if (suggested_size >= 56) {46 } else if (suggested_size >= 56) {
45 this.icon_size = 64;47 this.icon_size = 64;
46 }48 }
47 49
48 // Get all apps50 // Get all apps
49 Slingshot.Backend.GMenuEntries.enumerate_apps (Slingshot.Backend.GMenuEntries.get_all (), this.icons, this.icon_size, out this.apps);51 this.refresh_apps();
50 52
51 // Add container wrapper53 // Add container wrapper
52 var wrapper = new Gtk.EventBox (); // used for the scrolling and button press events54 var wrapper = new Gtk.EventBox (); // used for the scrolling and button press events
53 wrapper.set_visible_window (false);55 wrapper.set_visible_window (false);
54 this.add (wrapper);56 this.add (wrapper);
55 57
56 // Add container58 // Add container
57 var container = new Gtk.VBox (false, 15);59 var container = new Gtk.VBox (false, 15);
58 wrapper.add (container);60 wrapper.add (container);
59 61
60 // Add top bar62 // Add top bar
61 var top = new Gtk.HBox (false, 0);63 var top = new Gtk.HBox (false, 0);
62 64
63 this.categories = new Slingshot.Frontend.Indicators ();65 this.categories = new Slingshot.Frontend.Indicators ();
64 this.categories.child_activated.connect (this.change_category);66 this.categories.child_activated.connect (this.change_category);
65 this.categories.append ("All");67 this.categories.append ("All");
@@ -68,18 +70,18 @@
68 }70 }
69 this.categories.set_active (0);71 this.categories.set_active (0);
70 top.pack_start (this.categories, true, true, 15);72 top.pack_start (this.categories, true, true, 15);
71 73
72 this.top_spacer = new Gtk.HBox (false, 0);74 this.top_spacer = new Gtk.HBox (false, 0);
73 this.top_spacer.realize.connect ( () => { this.top_spacer.visible = false; } );75 this.top_spacer.realize.connect ( () => { this.top_spacer.visible = false; } );
74 this.top_spacer.can_focus = true;76 this.top_spacer.can_focus = true;
75 top.pack_start (this.top_spacer, false, false, 0);77 top.pack_start (this.top_spacer, false, false, 0);
76 78
77 this.searchbar = new Slingshot.Frontend.Searchbar ("Start typing to search...");79 this.searchbar = new Slingshot.Frontend.Searchbar ("Start typing to search...");
78 this.searchbar.changed.connect (this.search);80 this.searchbar.changed.connect (this.search);
79 top.pack_start (this.searchbar, false, true, 15);81 top.pack_start (this.searchbar, false, true, 15);
80 82
81 container.pack_start (top, false, true, 15); 83 container.pack_start (top, false, true, 15);
82 84
83 // Make icon grid and populate85 // Make icon grid and populate
84 if (monitor_dimensions.width > monitor_dimensions.height) { // normal landscape orientation86 if (monitor_dimensions.width > monitor_dimensions.height) { // normal landscape orientation
85 this.grid = new Slingshot.Frontend.Grid (4, 6);87 this.grid = new Slingshot.Frontend.Grid (4, 6);
@@ -87,77 +89,82 @@
87 this.grid = new Slingshot.Frontend.Grid (6, 4);89 this.grid = new Slingshot.Frontend.Grid (6, 4);
88 }90 }
89 container.pack_start (this.grid, true, true, 0);91 container.pack_start (this.grid, true, true, 0);
90 92
91 this.populate_grid ();93 this.populate_grid ();
92 94
93 // Add pages95 // Add pages
94 this.pages = new Slingshot.Frontend.Indicators ();96 this.pages = new Slingshot.Frontend.Indicators ();
95 this.pages.child_activated.connect ( () => { this.update_grid (this.filtered); } );97 this.pages.child_activated.connect ( () => { this.update_grid (this.filtered); } );
96 98
97 var pages_wrapper = new Gtk.HBox (false, 0);99 var pages_wrapper = new Gtk.HBox (false, 0);
98 pages_wrapper.set_size_request (-1, 30); 100 pages_wrapper.set_size_request (-1, 30);
99 container.pack_end (pages_wrapper, false, true, 15);101 container.pack_end (pages_wrapper, false, true, 15);
100 102
101 // Find number of pages and populate103 // Find number of pages and populate
102 this.update_pages (this.apps);104 this.update_pages (this.apps);
103 if (this.total_pages > 1) {105 if (this.total_pages > 1) {
104 pages_wrapper.pack_start (this.pages, true, false, 0);106 pages_wrapper.pack_start (this.pages, true, false, 0);
105 for (int p = 1; p <= this.total_pages; p++) {107 for (int p = 1; p <= this.total_pages; p++) {
106 this.pages.append (p.to_string ());108 this.pages.append (p.to_string ());
107 } 109 }
108 }110 }
109 this.pages.set_active (0);111 this.pages.set_active (0);
110 112
111 // Signals and callbacks113 // Signals and callbacks
112 this.button_release_event.connect ( () => { this.destroy(); return false; });114 this.button_release_event.connect ( () => { this.hide_slingshot(); return false; });
113 this.expose_event.connect (this.draw_background);115 this.expose_event.connect (this.draw_background);
114 this.focus_out_event.connect ( () => { this.destroy(); return true; } ); // close slingshot when the window loses focus116 this.focus_out_event.connect ( () => { this.hide_slingshot(); return true; } ); // close slingshot when the window loses focus
117
118 //set up app monitor
119 //refreshes when apps are added/removed
120 this.monitor = new Slingshot.Backend.AppMonitor();
121 this.monitor.changed.connect(this.refresh_apps);
115 }122 }
116 123
117 private void populate_grid () { 124 private void populate_grid () {
118 125
119 for (int r = 0; r < this.grid.n_rows; r++) {126 for (int r = 0; r < this.grid.n_rows; r++) {
120 127
121 for (int c = 0; c < this.grid.n_columns; c++) {128 for (int c = 0; c < this.grid.n_columns; c++) {
122 129
123 var item = new Slingshot.Frontend.AppItem (this.icon_size);130 var item = new Slingshot.Frontend.AppItem (this.icon_size);
124 this.children.append (item);131 this.children.append (item);
125 132
126 item.button_press_event.connect ( () => { item.grab_focus (); return true; } );133 item.button_press_event.connect ( () => { item.grab_focus (); return true; } );
127 item.enter_notify_event.connect ( () => { item.grab_focus (); return true; } );134 item.enter_notify_event.connect ( () => { item.grab_focus (); return true; } );
128 item.leave_notify_event.connect ( () => { this.top_spacer.grab_focus (); return true; } );135 item.leave_notify_event.connect ( () => { this.top_spacer.grab_focus (); return true; } );
129 item.button_release_event.connect ( () => {136 item.button_release_event.connect ( () => {
130 137
131 try {138 try {
132 new GLib.DesktopAppInfo.from_filename (this.filtered.get((int) (this.children.index(item) + (this.pages.active * this.grid.n_columns * this.grid.n_rows)))["desktop_file"]).launch (null, null);139 new GLib.DesktopAppInfo.from_filename (this.filtered.get((int) (this.children.index(item) + (this.pages.active * this.grid.n_columns * this.grid.n_rows)))["desktop_file"]).launch (null, null);
133 this.destroy();140 this.hide_slingshot();
134 } catch (GLib.Error e) {141 } catch (GLib.Error e) {
135 stdout.printf("Error! Load application: " + e.message);142 stdout.printf("Error! Load application: " + e.message);
136 }143 }
137 144
138 return true;145 return true;
139 146
140 });147 });
141 148
142 this.grid.attach (item, c, c + 1, r, r + 1, Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.EXPAND, 0, 0);149 this.grid.attach (item, c, c + 1, r, r + 1, Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.EXPAND, 0, 0);
143 150
144 } 151 }
145 } 152 }
146 }153 }
147 154
148 private void update_grid (Gee.ArrayList<Gee.HashMap<string, string>> apps) { 155 private void update_grid (Gee.ArrayList<Gee.HashMap<string, string>> apps) {
149 156
150 int item_iter = (int)(this.pages.active * this.grid.n_columns * this.grid.n_rows);157 int item_iter = (int)(this.pages.active * this.grid.n_columns * this.grid.n_rows);
151 for (int r = 0; r < this.grid.n_rows; r++) {158 for (int r = 0; r < this.grid.n_rows; r++) {
152 159
153 for (int c = 0; c < this.grid.n_columns; c++) {160 for (int c = 0; c < this.grid.n_columns; c++) {
154 161
155 int table_pos = c + (r * (int)this.grid.n_columns); // position in table right now162 int table_pos = c + (r * (int)this.grid.n_columns); // position in table right now
156 163
157 var item = this.children.nth_data(table_pos);164 var item = this.children.nth_data(table_pos);
158 if (item_iter < apps.size) {165 if (item_iter < apps.size) {
159 var current_item = apps.get(item_iter);166 var current_item = apps.get(item_iter);
160 167
161 // Update app168 // Update app
162 if (current_item["description"] == null || current_item["description"] == "") {169 if (current_item["description"] == null || current_item["description"] == "") {
163 item.change_app (icons[current_item["command"]], current_item["name"], current_item["name"]);170 item.change_app (icons[current_item["command"]], current_item["name"], current_item["name"]);
@@ -169,36 +176,36 @@
169 } else { // fill with a blank one176 } else { // fill with a blank one
170 item.visible = false;177 item.visible = false;
171 }178 }
172 179
173 item_iter++;180 item_iter++;
174 181
175 }182 }
176 }183 }
177 184
178 // Update number of pages185 // Update number of pages
179 this.update_pages (apps);186 this.update_pages (apps);
180 187
181 // Grab first one's focus188 // Grab first one's focus
182 this.children.nth_data (0).grab_focus ();189 this.children.nth_data (0).grab_focus ();
183 }190 }
184 191
185 private void change_category () {192 private void change_category () {
186 this.filtered.clear ();193 this.filtered.clear ();
187 194
188 if (this.categories.active != 0) {195 if (this.categories.active != 0) {
189 Slingshot.Backend.GMenuEntries.enumerate_apps (Slingshot.Backend.GMenuEntries.get_applications_for_category (this.all_categories.get (this.categories.active - 1)), this.icons, this.icon_size, out this.filtered);196 Slingshot.Backend.GMenuEntries.enumerate_apps (Slingshot.Backend.GMenuEntries.get_applications_for_category (this.all_categories.get (this.categories.active - 1)), this.icons, this.icon_size, out this.filtered);
190 } else {197 } else {
191 this.filtered.add_all (this.apps);198 this.filtered.add_all (this.apps);
192 }199 }
193 200
194 this.pages.set_active (0); // go back to first page in category201 this.pages.set_active (0); // go back to first page in category
195 }202 }
196 203
197 private void update_pages (Gee.ArrayList<Gee.HashMap<string, string>> apps) {204 private void update_pages (Gee.ArrayList<Gee.HashMap<string, string>> apps) {
198 // Find current number of pages and update count205 // Find current number of pages and update count
199 var num_pages = (int) (apps.size / (this.grid.n_columns * this.grid.n_rows));206 var num_pages = (int) (apps.size / (this.grid.n_columns * this.grid.n_rows));
200 (double) apps.size % (double) (this.grid.n_columns * this.grid.n_rows) > 0 ? this.total_pages = num_pages + 1 : this.total_pages = num_pages;207 (double) apps.size % (double) (this.grid.n_columns * this.grid.n_rows) > 0 ? this.total_pages = num_pages + 1 : this.total_pages = num_pages;
201 208
202 // Update pages209 // Update pages
203 if (this.total_pages > 1) {210 if (this.total_pages > 1) {
204 this.pages.visible = true;211 this.pages.visible = true;
@@ -208,41 +215,41 @@
208 } else {215 } else {
209 this.pages.visible = false;216 this.pages.visible = false;
210 }217 }
211 218
212 }219 }
213 220
214 private void search() {221 private void search() {
215 222
216 var current_text = this.searchbar.text.down ();223 var current_text = this.searchbar.text.down ();
217 224
218 this.categories.set_active_no_signal (0); // switch to first page225 this.categories.set_active_no_signal (0); // switch to first page
219 this.filtered.clear ();226 this.filtered.clear ();
220 227
221 foreach (Gee.HashMap<string, string> app in this.apps) {228 foreach (Gee.HashMap<string, string> app in this.apps) {
222 if (current_text in app["name"].down () || current_text in app["description"].down () || current_text in app["command"].down ()) {229 if (current_text in app["name"].down () || current_text in app["description"].down () || current_text in app["command"].down ()) {
223 this.filtered.add (app);230 this.filtered.add (app);
224 }231 }
225 } 232 }
226 233
227 this.pages.set_active (0); 234 this.pages.set_active (0);
228 235
229 this.queue_draw ();236 this.queue_draw ();
230 }237 }
231 238
232 private void page_left() {239 private void page_left() {
233 240
234 if (this.pages.active >= 1) {241 if (this.pages.active >= 1) {
235 this.pages.set_active (this.pages.active - 1);242 this.pages.set_active (this.pages.active - 1);
236 }243 }
237 244
238 }245 }
239 246
240 private void page_right() {247 private void page_right() {
241 248
242 if ((this.pages.active + 1) < this.total_pages) {249 if ((this.pages.active + 1) < this.total_pages) {
243 this.pages.set_active (this.pages.active + 1);250 this.pages.set_active (this.pages.active + 1);
244 }251 }
245 252
246 }253 }
247254
248 private bool draw_background (Gtk.Widget widget, Gdk.EventExpose event) {255 private bool draw_background (Gtk.Widget widget, Gdk.EventExpose event) {
@@ -253,21 +260,19 @@
253 // Semi-dark background260 // Semi-dark background
254 var linear_gradient = new Cairo.Pattern.linear (size.x, size.y, size.x, size.y + size.height);261 var linear_gradient = new Cairo.Pattern.linear (size.x, size.y, size.x, size.y + size.height);
255 linear_gradient.add_color_stop_rgba (0.0, 0.0, 0.0, 0.0, 0.65);262 linear_gradient.add_color_stop_rgba (0.0, 0.0, 0.0, 0.0, 0.65);
256 linear_gradient.add_color_stop_rgba (0.85, 0.0, 0.0, 0.0, 0.65);263
257 linear_gradient.add_color_stop_rgba (0.99, 0.0, 0.0, 0.0, 0.0);
258
259 context.set_source (linear_gradient);264 context.set_source (linear_gradient);
260 context.paint ();265 context.paint ();
261 266
262 return false;267 return false;
263 }268 }
264 269
265 // Keyboard shortcuts270 // Keyboard shortcuts
266 public override bool key_press_event (Gdk.EventKey event) {271 public override bool key_press_event (Gdk.EventKey event) {
267 switch (Gdk.keyval_name (event.keyval)) {272 switch (Gdk.keyval_name (event.keyval)) {
268 273
269 case "Escape":274 case "Escape":
270 this.destroy ();275 this.hide_slingshot ();
271 return true;276 return true;
272 case "ISO_Left_Tab":277 case "ISO_Left_Tab":
273 this.page_left ();278 this.page_left ();
@@ -284,7 +289,10 @@
284 }289 }
285 return true;290 return true;
286 case "BackSpace":291 case "BackSpace":
287 this.searchbar.text = this.searchbar.text.slice (0, (int) this.searchbar.text.length - 1);292 int len = (int) this.searchbar.text.length;
293 if (len > 0) {
294 this.searchbar.text = this.searchbar.text.slice (0,len - 1);
295 }
288 return true;296 return true;
289 case "Left":297 case "Left":
290 var current_item = this.grid.get_children ().index (this.get_focus ());298 var current_item = this.grid.get_children ().index (this.get_focus ());
@@ -292,7 +300,7 @@
292 this.page_left ();300 this.page_left ();
293 return true;301 return true;
294 }302 }
295 303
296 break;304 break;
297 case "Right":305 case "Right":
298 var current_item = this.grid.get_children ().index (this.get_focus ());306 var current_item = this.grid.get_children ().index (this.get_focus ());
@@ -308,16 +316,16 @@
308 this.searchbar.text = this.searchbar.text + event.str;316 this.searchbar.text = this.searchbar.text + event.str;
309 break;317 break;
310 }318 }
311 319
312 base.key_press_event (event);320 base.key_press_event (event);
313 return false;321 return false;
314 322
315 }323 }
316 324
317 // Scrolling left/right for pages325 // Scrolling left/right for pages
318 public override bool scroll_event (Gdk.EventScroll event) {326 public override bool scroll_event (Gdk.EventScroll event) {
319 switch (event.direction.to_string()) {327 switch (event.direction.to_string()) {
320 328
321 case "GDK_SCROLL_UP":329 case "GDK_SCROLL_UP":
322 case "GDK_SCROLL_LEFT":330 case "GDK_SCROLL_LEFT":
323 this.page_left ();331 this.page_left ();
@@ -326,43 +334,98 @@
326 case "GDK_SCROLL_RIGHT":334 case "GDK_SCROLL_RIGHT":
327 this.page_right ();335 this.page_right ();
328 break;336 break;
329 337
330 }338 }
331 339
332 return false;340 return false;
333 }341 }
334 342
343 public void refresh_apps () {
344 print("Refreshing applications list\n");
345 Slingshot.Backend.GMenuEntries.enumerate_apps (Slingshot.Backend.GMenuEntries.get_all (), this.icons, this.icon_size, out this.apps);
346 }
347
348 public void hide_slingshot () {
349 this.iconify();
350 this.categories.set_active (0);
351 this.change_category();
352 this.searchbar.text = "";
353 this.is_showing = false;
354 Wnck.Screen.get_default().toggle_showing_desktop(false);
355 }
356
357 public void show_slingshot () {
358 Wnck.Screen.get_default().toggle_showing_desktop(true);
359 this.deiconify();
360 this.is_showing = true;
361 }
362
363 public void toggle_slingshot () {
364 if (this.is_showing) {
365 print("Hiding slingshot.\n");
366 this.hide_slingshot();
367 } else {
368 print("Showing slingshot.\n");
369 this.show_slingshot();
370 }
371 }
372
335 // Override destroy for fade out and stuff373 // Override destroy for fade out and stuff
336 public new void destroy () {374 public new void destroy () {
337 // Restore windows375 // Restore windows
338 Wnck.Screen.get_default ().toggle_showing_desktop (false);376 //Wnck.Screen.get_default ().toggle_showing_desktop (false);
339 377
340 base.destroy();378 base.destroy();
341 Gtk.main_quit();379 Gtk.main_quit();
342 }380 }
343 381
344}382}
383
384
385public class SlingshotApp : GLib.Object {
386
387 Unique.App app;
388 SlingshotWindow main_win;
389
390 public SlingshotApp (/*string[] args*/) {
391 this.app = new Unique.App("org.elementary.slingshot", null);
392 if (this.app.is_running) {
393 print("Slingshot is already running.\n");
394 Unique.Command command = Unique.Command.ACTIVATE;
395 this.app.send_message (command, new Unique.MessageData());
396 } else {
397 this.app.message_received.connect(this.toggle);
398 this.create(/*args*/);
399 }
400 }
401
402 public Unique.Response toggle (int command, Unique.MessageData message_data, uint time_) {
403 if (command == Unique.Command.ACTIVATE) {
404 print("Toggling slingshot.\n");
405 this.main_win.toggle_slingshot();
406 }
407 return Unique.Response.OK;
408 }
409
410 void create (/*string[] args*/) {
411 //Gtk.init(ref args);
412 print("Starting new slingshot instance.\n");
413 this.main_win = new SlingshotWindow();
414 this.main_win.show_all();
415 this.main_win.iconify();
416 Gtk.main();
417 }
418
419}
420
345421
346int main (string[] args) {422int main (string[] args) {
347423
348 Gtk.init (ref args);424 Gtk.init(ref args); //~
349425
350 Unique.App app = new Unique.App ("org.elementary.slingshot", null);426 new SlingshotApp(/*args*/);
351 427
352 if (app.is_running) { //close if already running
353 Unique.Command command = Unique.Command.NEW;
354 app.send_message (command, new Unique.MessageData());
355 } else {
356
357 var main_win = new SlingshotWindow ();
358 main_win.show_all ();
359
360 app.watch_window (main_win);
361
362 Gtk.main ();
363 }
364
365 return 1;428 return 1;
366 429
367}430}
368431

Subscribers

People subscribed via source and target branches