Merge lp:~tintou/slingshot/gtk-popover into lp:~elementary-pantheon/slingshot/trunk

Proposed by Corentin Noël on 2015-01-18
Status: Merged
Approved by: Daniel Fore on 2015-02-01
Approved revision: 505
Merged at revision: 500
Proposed branch: lp:~tintou/slingshot/gtk-popover
Merge into: lp:~elementary-pantheon/slingshot/trunk
Diff against target: 1152 lines (+196/-392)
11 files modified
CMakeLists.txt (+1/-2)
cmake/ValaPrecompile.cmake (+0/-1)
src/Pixels.vala (+2/-2)
src/Slingshot.vala (+1/-2)
src/SlingshotView.vala (+142/-104)
src/Widgets/AppEntry.vala (+22/-28)
src/Widgets/CategoryView.vala (+2/-4)
src/Widgets/Grid.vala (+18/-20)
src/Widgets/PopoverMenu.vala (+0/-188)
src/Widgets/SearchItem.vala (+2/-2)
src/Widgets/SearchView.vala (+6/-39)
To merge this branch: bzr merge lp:~tintou/slingshot/gtk-popover
Reviewer Review Type Date Requested Status
Daniel Fore 2015-01-18 Needs Fixing on 2015-01-18
Review via email: mp+246836@code.launchpad.net

Commit message

Make use of Gtk.Popover instead of Granite.Popover.
Animates the view change from the edges.
Use real size of App Buttons (removed useless and wrong code)

Description of the change

Make use of Gtk.Popover instead of Granite.Popover.
Animates the view change from the edges.
Use real size of App Buttons (removed useless and wrong code)

To post a comment you must log in.
lp:~tintou/slingshot/gtk-popover updated on 2015-01-18
501. By Corentin Noël on 2015-01-18

Fixed RTL animation.

502. By Corentin Noël on 2015-01-18

Use Gtk.STYLE_CLASS_FLAT instead of "app" class.

Daniel Fore (danrabbit) wrote :

This seems to be quite an improvement overall. Gaining regular right click menus and also the cut/copy/paste/etc menu is killer.

I love that the animations go to the edge of the popover. Very sexy!

Something that is annoying is that it seems to animate from the bottom up. I see this as a regression. Ideally it would animate from the origin towards the opposite corner of the display. But at least the current version animates from the center out.

It does seem that this makes Slingshot shorter, which is a bit weird at first, but I think it'll be easy to get used to. I wouldn't really consider this a regression.

When navigating by keyboard, I noticed that moving from the 2nd-to-last to the last page, you can lose the selection if you go from the 2nd (or 3rd) row and there is only 1 row on the last page.

The scrolled window in the search view should have a right margin. Unfortunately because of the rounded corners, it seems to hang off of the bottom right corner of the popover.

There is also a small jump where the popover resizes between grid and search views

lp:~tintou/slingshot/gtk-popover updated on 2015-01-18
503. By Corentin Noël on 2015-01-18

Restore Granite's popover appearing behavior.
Fixed RTL navigation.

Daniel Fore (danrabbit) wrote :

If I open a right click menu and then click outside the popover, it will not be dismissed no matter how many times I click outside the popover

review: Needs Fixing
Cody Garver (codygarver) wrote :

So far I've only found these problems:

* Dan's right click issue mentioned above
* The Popover arrow is closer to the panel than before
* Hovering over icons with cursor gives no highlight
* The top search result is no longer highlighted

lp:~tintou/slingshot/gtk-popover updated on 2015-02-01
504. By Corentin Noël on 2015-02-01

Grab pointer action after showing a menu.

505. By Corentin Noël on 2015-02-01

Fixed alignments with other popovers.

Corentin Noël (tintou) wrote :

I fixed the right click issue and the popover arrow being closer than before.
Hovering is now fixed with new theme revisions.

Daniel Fore (danrabbit) wrote :

I can confirm:
* right click issue is fixed.
* Popover top is aligned with other popover tops
* Hovering over items is indeed a theme problem now

With the search results, focus doesn't seem to want to leave the search box even with pressing arrow keys or tab. Did something change there?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-10-17 01:18:02 +0000
3+++ CMakeLists.txt 2015-02-01 15:13:29 +0000
4@@ -83,7 +83,6 @@
5 src/Widgets/SearchItem.vala
6 src/Widgets/Sidebar.vala
7 src/Widgets/CategoryView.vala
8- src/Widgets/PopoverMenu.vala
9 PACKAGES
10 ${CORE_DEPS}
11 ${UI_DEPS}
12@@ -128,4 +127,4 @@
13 add_schema ("org.pantheon.desktop.slingshot.gschema.xml")
14
15 # Translations
16-add_subdirectory (po)
17\ No newline at end of file
18+add_subdirectory (po)
19
20=== modified file 'cmake/ValaPrecompile.cmake'
21--- cmake/ValaPrecompile.cmake 2014-07-21 11:27:34 +0000
22+++ cmake/ValaPrecompile.cmake 2015-02-01 15:13:29 +0000
23@@ -229,7 +229,6 @@
24 ${vala_pkg_opts}
25 ${ARGS_OPTIONS}
26 "-g"
27- "--save-temps"
28 ${in_files}
29 ${custom_vapi_arguments}
30 COMMAND
31
32=== modified file 'src/Pixels.vala'
33--- src/Pixels.vala 2014-08-14 20:09:55 +0000
34+++ src/Pixels.vala 2015-02-01 15:13:29 +0000
35@@ -1,9 +1,9 @@
36 namespace Slingshot.Pixels {
37
38 const int PADDING = 17;
39- const int ROW_SPACING = 20;
40+ const int ROW_SPACING = 12;
41 const int ITEM_SIZE = 130;
42 const int BOTTOM_SPACE = 180;
43 const int SIDEBAR_GRID_PADDING = 5;
44 const int SIDEBAR_WIDTH = PADDING + ITEM_SIZE - SIDEBAR_GRID_PADDING - 1;
45-}
46\ No newline at end of file
47+}
48
49=== modified file 'src/Slingshot.vala'
50--- src/Slingshot.vala 2014-06-12 09:14:57 +0000
51+++ src/Slingshot.vala 2015-02-01 15:13:29 +0000
52@@ -69,12 +69,11 @@
53 dbus_service = new DBusService (view);
54
55 if (!silent) {
56- //view.move_to_coords (0, 0);
57 view.show_slingshot ();
58 }
59 } else {
60 if (view.visible && !silent)
61- view.hide ();
62+ view.hide ();
63 else
64 view.show_slingshot ();
65 }
66
67=== modified file 'src/SlingshotView.vala'
68--- src/SlingshotView.vala 2014-11-08 10:49:08 +0000
69+++ src/SlingshotView.vala 2015-02-01 15:13:29 +0000
70@@ -24,15 +24,13 @@
71 SEARCH_VIEW
72 }
73
74- public class SlingshotView : Granite.Widgets.PopOver {
75+ public class SlingshotView : Granite.Widgets.CompositedWindow {
76
77 // Widgets
78 public Gtk.SearchEntry search_entry;
79 public Gtk.Stack stack;
80 public Granite.Widgets.ModeButton view_selector;
81 private Gtk.Revealer view_selector_revealer;
82- // Single popover to use for all of app as context menu
83- private Widgets.NofocusPopover context_popover;
84
85 // Views
86 private Widgets.Grid grid_view;
87@@ -44,6 +42,8 @@
88 public Gtk.Stack main_stack;
89 public Gtk.Box content_area;
90 private Gtk.EventBox event_box;
91+ private Gtk.Popover popover;
92+ private Gtk.Grid ref_grid;
93
94 public Backend.AppSystem app_system;
95 private Gee.ArrayList<GMenu.TreeDirectory> categories;
96@@ -75,13 +75,17 @@
97 private int category_column_focus = 0;
98 private int category_row_focus = 0;
99
100+ private int primary_monitor = 0;
101+
102 public SlingshotView () {
103
104 // Window properties
105 this.title = "Slingshot";
106 this.skip_pager_hint = true;
107 this.skip_taskbar_hint = true;
108- set_keep_above (true);
109+ this.set_keep_above (true);
110+ this.set_type_hint (Gdk.WindowTypeHint.MENU);
111+ this.focus_on_map = true;
112
113 // Have the window in the right place
114 read_settings (true);
115@@ -94,12 +98,14 @@
116 categories = app_system.get_categories ();
117 apps = app_system.get_apps ();
118
119- if (Slingshot.settings.screen_resolution != @"$(screen.get_width ())x$(screen.get_height ())")
120+ primary_monitor = screen.get_primary_monitor ();
121+ Gdk.Rectangle geometry;
122+ screen.get_monitor_geometry (primary_monitor, out geometry);
123+ if (Slingshot.settings.screen_resolution != @"$(geometry.width)x$(geometry.height)")
124 setup_size ();
125
126 height_request = calculate_grid_height () + Pixels.BOTTOM_SPACE;
127 setup_ui ();
128- context_popover = new Widgets.NofocusPopover (this, event_box);
129
130 connect_signals ();
131 debug ("Apps loaded");
132@@ -115,16 +121,18 @@
133 }
134
135 private void setup_size () {
136-
137 debug ("In setup_size ()");
138- Slingshot.settings.screen_resolution = @"$(screen.get_width ())x$(screen.get_height ())";
139+ primary_monitor = screen.get_primary_monitor ();
140+ Gdk.Rectangle geometry;
141+ screen.get_monitor_geometry (primary_monitor, out geometry);
142+ Slingshot.settings.screen_resolution = @"$(geometry.width)x$(geometry.height)";
143 default_columns = 5;
144 default_rows = 3;
145- while ((calculate_grid_width () >= 2 * screen.get_width () / 3)) {
146+ while ((calculate_grid_width () >= 2 * geometry.width / 3)) {
147 default_columns--;
148 }
149
150- while ((calculate_grid_height () >= 2 * screen.get_height () / 3)) {
151+ while ((calculate_grid_height () >= 2 * geometry.width / 3)) {
152 default_rows--;
153 }
154
155@@ -142,15 +150,17 @@
156 // Create the base container
157 container = new Gtk.Grid ();
158 container.row_spacing = 12;
159+ container.margin_top = 12;
160
161 // Add top bar
162 top = new Gtk.Grid ();
163 top.orientation = Gtk.Orientation.HORIZONTAL;
164- top.margin_start = 12;
165- top.margin_end = 12;
166+ top.margin_start = 6;
167+ top.margin_end = 6;
168
169 view_selector = new Granite.Widgets.ModeButton ();
170- view_selector.margin_end = 12;
171+ view_selector.margin_end = 6;
172+ view_selector.margin_start = 6;
173 view_selector_revealer = new Gtk.Revealer ();
174 view_selector_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_RIGHT;
175 view_selector_revealer.add (view_selector);
176@@ -171,7 +181,8 @@
177 search_entry = new Gtk.SearchEntry ();
178 search_entry.placeholder_text = _("Search Apps");
179 search_entry.hexpand = true;
180- search_entry.button_press_event.connect ((e) => {return e.button == 3;});
181+ search_entry.margin_start = 6;
182+ search_entry.margin_end = 6;
183
184 if (Slingshot.settings.show_category_filter) {
185 top.add (view_selector_revealer);
186@@ -191,6 +202,7 @@
187
188 // Create the "SEARCH_VIEW"
189 search_view = new Widgets.SearchView (this);
190+ search_view.margin_end = 6;
191 search_view.start_search.connect ((match, target) => {
192 search.begin (search_entry.text, match, target);
193 });
194@@ -203,22 +215,24 @@
195 event_box = new Gtk.EventBox ();
196 event_box.add (container);
197 // Add the container to the dialog's content area
198- content_area = get_content_area () as Gtk.Box;
199- content_area.pack_start (event_box);
200- content_area.set_margin_start (SHADOW_SIZE-1);
201- content_area.set_margin_end (SHADOW_SIZE-1);
202- content_area.set_margin_top (SHADOW_SIZE-1);
203- content_area.set_margin_bottom (SHADOW_SIZE-1);
204+
205+ ref_grid = new Gtk.Grid ();
206+ this.add (ref_grid);
207+
208+ popover = new Gtk.Popover (ref_grid);
209+ popover.add (event_box);
210+ popover.set_position (Gtk.PositionType.TOP);
211+
212+ this.show.connect (() => popover.show ());
213
214 if (Slingshot.settings.use_category)
215 set_modality (Modality.CATEGORY_VIEW);
216 else
217 set_modality (Modality.NORMAL_VIEW);
218 debug ("Ui setup completed");
219-
220 }
221
222- private void grab_device () {
223+ public void grab_device () {
224 var display = Gdk.Display.get_default ();
225 var pointer = display.get_device_manager ().get_client_pointer ();
226 var keyboard = pointer.associated_device;
227@@ -259,6 +273,14 @@
228 return false;
229 }
230
231+ public override void get_preferred_width (out int minimum_width, out int natural_width) {
232+ popover.get_preferred_width (out minimum_width, out natural_width);
233+ }
234+
235+ public override void get_preferred_height (out int minimum_height, out int natural_height) {
236+ popover.get_preferred_height (out minimum_height, out natural_height);
237+ }
238+
239 public override bool map_event (Gdk.EventAny event) {
240 if (visible)
241 grab_device ();
242@@ -286,7 +308,12 @@
243
244 event_box.key_press_event.connect (on_key_press);
245 search_entry.key_press_event.connect (search_entry_key_press);
246-
247+ // Showing a menu reverts the effect of the grab_device function.
248+ search_entry.populate_popup.connect ((menu) => {
249+ menu.hide.connect (() => {
250+ grab_device ();
251+ });
252+ });
253 search_entry.search_changed.connect (() => {
254 if (modality != Modality.SEARCH_VIEW)
255 set_modality (Modality.SEARCH_VIEW);
256@@ -321,15 +348,23 @@
257
258 // position on the right monitor when settings changed
259 screen.size_changed.connect (() => {
260- setup_size ();
261- reposition (false);
262+ Gdk.Rectangle geometry;
263+ screen.get_monitor_geometry (screen.get_primary_monitor (), out geometry);
264+ if (Slingshot.settings.screen_resolution != @"$(geometry.width)x$(geometry.height)") {
265+ setup_size ();
266+ }
267+ reposition ();
268 });
269 screen.monitors_changed.connect (() => {
270- reposition (false);
271+ reposition ();
272 });
273
274 get_style_context ().notify["direction"].connect (() => {
275- reposition (false);
276+ reposition ();
277+ });
278+
279+ popover.hide.connect (() => {
280+ hide ();
281 });
282
283 // check for change in gala settings
284@@ -340,19 +375,6 @@
285 motion_notify_event.connect (hotcorner_trigger);
286 }
287
288- public void show_popover_menu (Gtk.Widget menu, Gtk.Widget relative) {
289- context_popover = new Widgets.NofocusPopover (this, event_box);
290- context_popover.set_relative_to (relative);
291- context_popover.add (menu);
292- context_popover.show_all ();
293-
294- var entry = relative as Widgets.AppEntry;
295- if (entry != null)
296- entry.app_launched.connect (() => {context_popover.hide ();});
297-
298- relative.grab_focus ();
299- }
300-
301 private void gala_settings_changed () {
302 if (Slingshot.settings.gala_settings.hotcorner_topleft == "open-launcher") {
303 can_trigger_hotcorner = true;
304@@ -361,22 +383,20 @@
305 }
306 }
307
308- private void reposition (bool show=true) {
309+ private void reposition () {
310 debug("Repositioning");
311
312- Gdk.Rectangle monitor_dimensions, app_launcher_pos;
313+ Gdk.Rectangle monitor_dimensions;
314 screen.get_monitor_geometry (this.screen.get_primary_monitor(), out monitor_dimensions);
315- app_launcher_pos = Gdk.Rectangle () { x = monitor_dimensions.x,
316- y = monitor_dimensions.y,
317- width = 100,
318- height = 30
319- };
320-
321- if (get_style_context ().direction == Gtk.TextDirection.RTL) {
322- app_launcher_pos.x += monitor_dimensions.width - this.get_window ().get_width ();
323+ if (get_style_context ().direction == Gtk.TextDirection.LTR) {
324+ popover.set_pointing_to ({36, 0, 0, 0});
325+ // Added 36px to y to be aligned with other popovers.
326+ move (monitor_dimensions.x, monitor_dimensions.y + 36);
327+ } else {
328+ popover.set_pointing_to ({ref_grid.get_window ().get_width () - 36, 0, 0, 0});
329+ // Added 36px to y to be aligned with other popovers.
330+ move (monitor_dimensions.x + monitor_dimensions.width - this.get_window ().get_width (), monitor_dimensions.y + 36);
331 }
332-
333- move_to_rect (app_launcher_pos, show);
334 }
335
336 private void change_view_mode (string key) {
337@@ -519,40 +539,27 @@
338 break;
339
340 case "Left":
341- if (modality == Modality.NORMAL_VIEW) {
342- if (event.state == Gdk.ModifierType.SHIFT_MASK) {// Shift + Left
343- grid_view.go_to_previous ();
344- } else {
345- normal_move_focus (-1, 0);
346- }
347- } else if (modality == Modality.CATEGORY_VIEW) {
348- if (event.state == Gdk.ModifierType.SHIFT_MASK) // Shift + Left
349- category_view.app_view.go_to_previous ();
350- else if (!search_entry.has_focus) {//the user has already selected an AppEntry
351- category_move_focus (-1, 0);
352- }
353- } else
354+ if (modality != Modality.NORMAL_VIEW && modality != Modality.CATEGORY_VIEW)
355 return false;
356+
357+ if (get_style_context ().direction == Gtk.TextDirection.LTR) {
358+ move_left (event);
359+ } else {
360+ move_right (event);
361+ }
362+
363 break;
364-
365 case "Right":
366- if (modality == Modality.NORMAL_VIEW) {
367- if (event.state == Gdk.ModifierType.SHIFT_MASK) // Shift + Right
368- grid_view.go_to_next ();
369- else
370- normal_move_focus (+1, 0);
371- } else if (modality == Modality.CATEGORY_VIEW) {
372- if (event.state == Gdk.ModifierType.SHIFT_MASK) // Shift + Right
373- category_view.app_view.go_to_next ();
374- else if (search_entry.has_focus) // there's no AppEntry selected, the user is switching category
375- top_left_focus ();
376- else //the user has already selected an AppEntry
377- category_move_focus (+1, 0);
378+ if (modality != Modality.NORMAL_VIEW && modality != Modality.CATEGORY_VIEW)
379+ return false;
380+
381+ if (get_style_context ().direction == Gtk.TextDirection.LTR) {
382+ move_right (event);
383 } else {
384- return false;
385+ move_left (event);
386 }
387+
388 break;
389-
390 case "Up":
391 if (modality == Modality.NORMAL_VIEW) {
392 normal_move_focus (0, -1);
393@@ -667,7 +674,6 @@
394 }
395
396 public override bool scroll_event (Gdk.EventScroll event) {
397- context_popover.hide ();
398 switch (event.direction.to_string ()) {
399 case "GDK_SCROLL_UP":
400 case "GDK_SCROLL_LEFT":
401@@ -687,15 +693,14 @@
402 }
403
404 return false;
405-
406 }
407
408 public void show_slingshot () {
409- context_popover.hide ();
410 search_entry.text = "";
411
412 reposition ();
413 show_all ();
414+ popover.show_all ();
415 present ();
416
417 set_focus (null);
418@@ -708,6 +713,44 @@
419 stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
420 }
421
422+ /*
423+ * Moves the current view to the left (undependent of the TextDirection).
424+ */
425+ private void move_left (Gdk.EventKey event) {
426+ if (modality == Modality.NORMAL_VIEW) {
427+ if (event.state == Gdk.ModifierType.SHIFT_MASK) {// Shift + Left
428+ grid_view.go_to_previous ();
429+ } else {
430+ normal_move_focus (-1, 0);
431+ }
432+ } else if (modality == Modality.CATEGORY_VIEW) {
433+ if (event.state == Gdk.ModifierType.SHIFT_MASK) // Shift + Left
434+ category_view.app_view.go_to_previous ();
435+ else if (!search_entry.has_focus) {//the user has already selected an AppEntry
436+ category_move_focus (-1, 0);
437+ }
438+ }
439+ }
440+
441+ /*
442+ * Moves the current view to the right (undependent of the TextDirection).
443+ */
444+ private void move_right (Gdk.EventKey event) {
445+ if (modality == Modality.NORMAL_VIEW) {
446+ if (event.state == Gdk.ModifierType.SHIFT_MASK) // Shift + Right
447+ grid_view.go_to_next ();
448+ else
449+ normal_move_focus (+1, 0);
450+ } else if (modality == Modality.CATEGORY_VIEW) {
451+ if (event.state == Gdk.ModifierType.SHIFT_MASK) // Shift + Right
452+ category_view.app_view.go_to_next ();
453+ else if (search_entry.has_focus) // there's no AppEntry selected, the user is switching category
454+ top_left_focus ();
455+ else //the user has already selected an AppEntry
456+ category_move_focus (+1, 0);
457+ }
458+ }
459+
460 private void set_modality (Modality new_modality) {
461 modality = new_modality;
462
463@@ -780,23 +823,18 @@
464 }
465
466 public void populate_grid_view () {
467-
468 grid_view.clear ();
469-
470 foreach (Backend.App app in app_system.get_apps_by_name ()) {
471-
472- var app_entry = new Widgets.AppEntry (app, this);
473+ var app_entry = new Widgets.AppEntry (app);
474 app_entry.app_launched.connect (() => hide ());
475 grid_view.append (app_entry);
476 app_entry.show_all ();
477 }
478
479-
480 stack.set_visible_child_name ("normal");
481 }
482
483 private void read_settings (bool first_start = false, bool check_columns = true, bool check_rows = true) {
484-
485 if (check_columns) {
486 if (Slingshot.settings.columns > 3)
487 default_columns = Slingshot.settings.columns;
488@@ -819,33 +857,35 @@
489 category_view.app_view.resize (default_rows, default_columns);
490 category_view.show_filtered_apps (category_view.category_ids.get (category_view.category_switcher.selected));
491 }
492-
493 }
494
495 private void normal_move_focus (int delta_column, int delta_row) {
496 if (get_focus () as Widgets.AppEntry != null) { // we check if any AppEntry has focus. If it does, we move
497 if (column_focus + delta_column < 0 || row_focus + delta_row < 0)
498 return;
499+
500 var new_focus = grid_view.get_child_at (column_focus + delta_column, row_focus + delta_row); // we check if the new widget exists
501 if (new_focus == null) {
502 if (delta_column <= 0)
503 return;
504 else {
505 new_focus = grid_view.get_child_at (column_focus + delta_column, 0);
506- delta_row = -row_focus; // so it's 0 at the end
507 if (new_focus == null)
508 return;
509+
510+ row_focus = -delta_row; // so it's 0 at the end
511 }
512 }
513+
514 column_focus += delta_column;
515 row_focus += delta_row;
516 if (delta_column > 0 && column_focus % grid_view.get_page_columns () == 0 ) //check if we need to change page
517 grid_view.go_to_next ();
518 else if (delta_column < 0 && (column_focus + 1) % grid_view.get_page_columns () == 0) //check if we need to change page
519 grid_view.go_to_previous ();
520+
521 new_focus.grab_focus ();
522- }
523- else { // we move to the first app in the top left corner of the current page
524+ } else { // we move to the first app in the top left corner of the current page
525 column_focus = (grid_view.get_current_page ()-1) * grid_view.get_page_columns ();
526 if (column_focus >= 0)
527 grid_view.get_child_at (column_focus, 0).grab_focus ();
528@@ -860,36 +900,34 @@
529 category_view.category_switcher.selected--;
530 top_left_focus ();
531 return;
532- }
533- else if (delta_row > 0 && category_view.category_switcher.selected != category_view.category_switcher.cat_size - 1) {
534+ } else if (delta_row > 0 && category_view.category_switcher.selected != category_view.category_switcher.cat_size - 1) {
535 category_view.category_switcher.selected++;
536 top_left_focus ();
537 return;
538- }
539- else if (delta_column > 0 && (category_column_focus + delta_column) % category_view.app_view.get_page_columns () == 0
540+ } else if (delta_column > 0 && (category_column_focus + delta_column) % category_view.app_view.get_page_columns () == 0
541 && category_view.app_view.get_current_page ()+ 1 != category_view.app_view.get_n_pages ()) {
542 category_view.app_view.go_to_next ();
543 top_left_focus ();
544 return;
545- }
546- else if (category_column_focus == 0 && delta_column < 0) {
547+ } else if (category_column_focus == 0 && delta_column < 0) {
548 search_entry.grab_focus ();
549 category_column_focus = 0;
550 category_row_focus = 0;
551 return;
552+ } else {
553+ return;
554 }
555- else
556- return;
557 }
558+
559 category_column_focus += delta_column;
560 category_row_focus += delta_row;
561 if (delta_column > 0 && category_column_focus % category_view.app_view.get_page_columns () == 0 ) { // check if we need to change page
562 category_view.app_view.go_to_next ();
563- }
564- else if (delta_column < 0 && (category_column_focus + 1) % category_view.app_view.get_page_columns () == 0) {
565+ } else if (delta_column < 0 && (category_column_focus + 1) % category_view.app_view.get_page_columns () == 0) {
566 // check if we need to change page
567 category_view.app_view.go_to_previous ();
568 }
569+
570 new_focus.grab_focus ();
571 }
572
573@@ -908,4 +946,4 @@
574 }
575 }
576
577-}
578\ No newline at end of file
579+}
580
581=== modified file 'src/Widgets/AppEntry.vala'
582--- src/Widgets/AppEntry.vala 2014-10-17 04:41:55 +0000
583+++ src/Widgets/AppEntry.vala 2015-02-01 15:13:29 +0000
584@@ -32,10 +32,9 @@
585 private bool dragging = false; //prevent launching
586
587 private Backend.App application;
588- private unowned SlingshotView view;
589+ private Gtk.Menu menu;
590
591- public AppEntry (Backend.App app, SlingshotView view) {
592- this.view = view;
593+ public AppEntry (Backend.App app) {
594 Gtk.TargetEntry dnd = {"text/uri-list", 0, 0};
595 Gtk.drag_source_set (this, Gdk.ModifierType.BUTTON1_MASK, {dnd},
596 Gdk.DragAction.COPY);
597@@ -50,7 +49,7 @@
598 icon_size = Slingshot.settings.icon_size;
599 icon = app.icon;
600
601- get_style_context ().add_class ("app");
602+ get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT);
603
604 app_label = new Gtk.Label (app_name);
605 app_label.halign = Gtk.Align.CENTER;
606@@ -75,11 +74,19 @@
607 add (grid);
608 set_size_request (Pixels.ITEM_SIZE, Pixels.ITEM_SIZE);
609
610+ menu = new Gtk.Menu ();
611+ create_menu ();
612+
613 this.clicked.connect (launch_app);
614+ // Showing a menu reverts the effect of the grab_device function.
615+ menu.hide.connect (() => {
616+ var slingshot_app = (Gtk.Application) GLib.Application.get_default ();
617+ ((SlingshotView)slingshot_app.active_window).grab_device ();
618+ });
619
620- this.button_release_event.connect ((e) => {
621- if (e.button == Gdk.BUTTON_SECONDARY) {
622- show_menu ();
623+ this.button_press_event.connect ((e) => {
624+ if (e.button == Gdk.BUTTON_SECONDARY && menu.get_children ().length () > 0) {
625+ menu.popup (null, null, null, e.button, e.time);
626 return true;
627 }
628 return false;
629@@ -120,7 +127,7 @@
630 app_launched ();
631 }
632
633- private void show_menu () {
634+ private void create_menu () {
635 // Display the apps static quicklist items in a popover menu
636 if (application.actions == null) {
637 try {
638@@ -130,24 +137,13 @@
639 }
640 }
641
642- var menu = new PopoverMenu ();
643 foreach (var action in application.actions) {
644- var values = application.actions_map.get (action).split (";;");
645- Gdk.Pixbuf? icon = null;
646- var flags = Gtk.IconLookupFlags.FORCE_SIZE;
647-
648- try {
649- if (values.length > 1 && values[1] != "" && values[1] != null)
650- icon = Slingshot.icon_theme.load_icon (values[1], 16, flags);
651- } catch (Error e) {
652- error ("Error loading quicklist icon");
653- }
654-
655- var menuitem = new Widgets.PopoverMenuItem (action, icon);
656- menu.add_menu_item (menuitem);
657-
658- menuitem.activated.connect (() => {
659+ var menuitem = new Gtk.MenuItem.with_label (action);
660+ menu.add (menuitem);
661+
662+ menuitem.activate.connect (() => {
663 try {
664+ var values = application.actions_map.get (action).split (";;");
665 AppInfo.create_from_commandline (values[0], null, AppInfoCreateFlags.NONE).launch (null, null);
666 app_launched ();
667 } catch (Error e) {
668@@ -155,9 +151,7 @@
669 }
670 });
671 }
672-
673- if (menu.get_size () > 0)
674- view.show_popover_menu (menu, this);
675+ menu.show_all ();
676 }
677
678-}
679\ No newline at end of file
680+}
681
682=== modified file 'src/Widgets/CategoryView.vala'
683--- src/Widgets/CategoryView.vala 2014-10-27 19:01:28 +0000
684+++ src/Widgets/CategoryView.vala 2015-02-01 15:13:29 +0000
685@@ -43,10 +43,8 @@
686 separator = new Gtk.Separator (Gtk.Orientation.VERTICAL);
687
688 category_switcher = new Sidebar ();
689- category_switcher.can_focus = false;
690
691 app_view = new Widgets.Grid (view.rows, view.columns - 1);
692- app_view.margin_start = Pixels.SIDEBAR_GRID_PADDING;
693
694 container.add (category_switcher);
695 container.add (separator);
696@@ -97,7 +95,7 @@
697 }
698
699 private void add_app (Backend.App app) {
700- var app_entry = new AppEntry (app, view);
701+ var app_entry = new AppEntry (app);
702 app_entry.app_launched.connect (() => view.hide ());
703 app_view.append (app_entry);
704 app_view.show_all ();
705@@ -114,4 +112,4 @@
706
707 }
708
709-}
710\ No newline at end of file
711+}
712
713=== modified file 'src/Widgets/Grid.vala'
714--- src/Widgets/Grid.vala 2014-10-15 21:57:37 +0000
715+++ src/Widgets/Grid.vala 2015-02-01 15:13:29 +0000
716@@ -34,16 +34,17 @@
717
718 private uint current_row = 0;
719 private uint current_col = 0;
720+
721 private Page page;
722
723 public Grid (int rows, int columns) {
724- margin_start = 12;
725- margin_end = 12;
726 page.rows = rows;
727 page.columns = columns;
728 page.number = 1;
729 var main_grid = new Gtk.Grid ();
730 main_grid.orientation = Gtk.Orientation.VERTICAL;
731+ main_grid.row_spacing = 6;
732+ main_grid.margin_bottom = 12;
733 stack = new Gtk.Stack ();
734 stack.expand = true;
735 stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
736@@ -61,13 +62,15 @@
737 create_new_grid ();
738 go_to_number (1);
739 }
740-
741+
742 private void create_new_grid () {
743 // Grid properties
744 current_grid = new Gtk.Grid ();
745 current_grid.expand = true;
746 current_grid.row_homogeneous = true;
747 current_grid.column_homogeneous = true;
748+ current_grid.margin_start = 12;
749+ current_grid.margin_end = 12;
750
751 current_grid.row_spacing = Pixels.ROW_SPACING;
752 current_grid.column_spacing = 0;
753@@ -99,25 +102,16 @@
754 }
755 }
756
757- public override void get_preferred_width (out int minimum_width, out int natural_width) {
758- minimum_width = (int)page.columns * Pixels.ITEM_SIZE;
759- natural_width = minimum_width;
760- }
761-
762- public override void get_preferred_height (out int minimum_height, out int natural_height) {
763- minimum_height = (int)page.rows * Pixels.ITEM_SIZE + ((int)page.rows - 1) * Pixels.ROW_SPACING;
764- natural_height = minimum_height;
765- }
766-
767 public void clear () {
768 foreach (Gtk.Grid grid in grids.values) {
769 foreach (Gtk.Widget widget in grid.get_children ()) {
770 widget.destroy ();
771 }
772+
773 grid.destroy ();
774 }
775+
776 grids.clear ();
777-
778 current_row = 0;
779 current_col = 0;
780 page.number = 1;
781@@ -125,11 +119,15 @@
782 stack.set_visible_child (current_grid);
783 }
784
785- public Gtk.Widget get_child_at (int column, int row) {
786+ public Gtk.Widget? get_child_at (int column, int row) {
787 var col = ((int)(column/page.columns))+1;
788-
789+
790 var grid = grids.get (col);
791- return grid.get_child_at (column - (int)page.columns*(col-1), row);
792+ if (grid != null) {
793+ return grid.get_child_at (column - (int)page.columns*(col-1), row) as Widgets.AppEntry;
794+ } else {
795+ return null;
796+ }
797 }
798
799 public int get_page_columns () {
800@@ -152,7 +150,7 @@
801 int page_number = get_current_page ()+1;
802 if (page_number <= get_n_pages ())
803 stack.set_visible_child_name (page_number.to_string ());
804-
805+
806 page_switcher.update_selected ();
807 }
808
809@@ -160,7 +158,7 @@
810 int page_number = get_current_page ()-1;
811 if (page_number > 0)
812 stack.set_visible_child_name (page_number.to_string ());
813-
814+
815 page_switcher.update_selected ();
816 }
817
818@@ -181,4 +179,4 @@
819 page.number = 1;
820 }
821 }
822-}
823\ No newline at end of file
824+}
825
826=== removed file 'src/Widgets/PopoverMenu.vala'
827--- src/Widgets/PopoverMenu.vala 2014-10-18 01:57:49 +0000
828+++ src/Widgets/PopoverMenu.vala 1970-01-01 00:00:00 +0000
829@@ -1,188 +0,0 @@
830-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
831-//
832-// Copyright (C) 2011-2012 Giulio Collura
833-// Copyright (C) 2014 Maddie May <madelynn@madelynnmay.com>
834-//
835-// This program is free software: you can redistribute it and/or modify
836-// it under the terms of the GNU General Public License as published by
837-// the Free Software Foundation, either version 3 of the License, or
838-// (at your option) any later version.
839-//
840-// This program is distributed in the hope that it will be useful,
841-// but WITHOUT ANY WARRANTY; without even the implied warranty of
842-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
843-// GNU General Public License for more details.
844-//
845-// You should have received a copy of the GNU General Public License
846-// along with this program. If not, see <http://www.gnu.org/licenses/>.
847-//
848-
849-// A menu to be used inside of popovers for when a normal context
850-// menu can't be used
851-namespace Slingshot.Widgets {
852-
853-public class PopoverMenu : Gtk.Grid {
854- private int line_count = 0;
855- private Gee.ArrayList<PopoverMenuItem> items = new Gee.ArrayList<PopoverMenuItem> ();
856-
857- public PopoverMenu () {
858- row_homogeneous = true;
859- column_homogeneous = true;
860- }
861-
862- public void add_menu_item (PopoverMenuItem item) {
863- line_count++;
864- this.items.add (item);
865- this.attach (item.child, 0, line_count, 1 , 1);
866- }
867-
868- public int get_size () {
869- return items.size;
870- }
871-
872- public override void show () {
873- base.show ();
874- bool has_image = false;
875- foreach (PopoverMenuItem item in items) {
876- if (item.image != null)
877- has_image = true;
878- }
879-
880- if (!has_image) {
881- foreach (PopoverMenuItem item in items) {
882- item.label_widget.margin_left = item.label_widget.margin_right = 8;
883- item.space_box.hide ();
884- }
885- }
886- }
887-}
888-
889-public class PopoverMenuItem : Object {
890- public Gtk.Widget child = null;
891- public signal void activated ();
892- public Gtk.Image? image;
893- public Gtk.Box? space_box;
894- public Gtk.Label label_widget;
895-
896- public PopoverMenuItem (string label, Gdk.Pixbuf? icon) {
897- var button = new Gtk.Button ();
898- button.get_style_context ().add_class (Gtk.STYLE_CLASS_MENUITEM);
899-
900- var grid = new Gtk.Grid ();
901- if (icon != null) {
902- image = new Gtk.Image.from_pixbuf (icon);
903- image.margin_left = 2;
904- image.halign = Gtk.Align.START;
905- grid.attach (image, 0, 0, 1, 1);
906- } else {
907- space_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
908- space_box.set_size_request (24, 16);
909- grid.attach (space_box, 0, 0, 1, 1);
910- }
911-
912- label_widget = new Gtk.Label.with_mnemonic (label);
913- label_widget.margin_left = 2;
914- label_widget.margin_right = 16;
915- label_widget.justify = Gtk.Justification.LEFT;
916- label_widget.set_alignment (0, 0);
917- grid.attach (label_widget, 1, 0, 1, 1);
918-
919- button.add (grid);
920- button.relief = Gtk.ReliefStyle.NONE;
921- button.clicked.connect (on_activate);
922- child = button;
923- }
924-
925- private void on_activate () {
926- activated ();
927- }
928-}
929-
930-// A popover that doesn't grab focus
931-public class NofocusPopover : Gtk.Popover {
932- private Gtk.Container parent_container;
933- private unowned SlingshotView view;
934-
935- private const string POPOVER_STYLESHEET = """
936- .popover,
937- .popover.osd,
938- GtkPopover {
939- border-radius: 0px;
940- margin: 0px;
941- text-shadow: none;
942- }
943- """;
944-
945- public NofocusPopover (SlingshotView view, Gtk.Container parent) {
946- this.view = view;
947- this.parent_container = parent;
948- connect_popover_signals (parent);
949- modal = false;
950- parent.button_release_event.connect (hide_popover_menu);
951- parent.button_press_event.connect (hide_popover_menu);
952- get_style_context ().add_class (Gtk.STYLE_CLASS_MENU);
953- Granite.Widgets.Utils.set_theming_for_screen (get_screen (), POPOVER_STYLESHEET,
954- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
955- }
956-
957- public void connect_popover_signals (Gtk.Container parent) {
958- foreach (Gtk.Widget child in parent.get_children ()) {
959- if (child is Gtk.Container) {
960- Gtk.Container container = child as Gtk.Container;
961- connect_popover_signals (container);
962- }
963-
964- if (child is Widgets.Switcher) {
965- var switcher = child as Widgets.Switcher;
966- switcher.on_stack_changed.connect (switched);
967- }
968-
969- child.button_release_event.connect (hide_popover_menu);
970- child.button_press_event.connect (hide_popover_menu);
971- }
972- }
973-
974- private void disconnect_popover_signals (Gtk.Container parent) {
975- foreach (Gtk.Widget child in parent.get_children ()) {
976- if (child is Gtk.Container) {
977- Gtk.Container container = child as Gtk.Container;
978- disconnect_popover_signals (container);
979- }
980-
981- if (child is Widgets.Switcher) {
982- var switcher = child as Widgets.Switcher;
983- switcher.on_stack_changed.disconnect (switched);
984- }
985-
986- child.button_release_event.disconnect (hide_popover_menu);
987- child.button_press_event.disconnect (hide_popover_menu);
988- }
989- }
990-
991- public void switched () {
992- this.hide ();
993- }
994-
995- public bool hide_popover_menu (Gdk.EventButton event) {
996- if (this.visible) {
997- view.set_focus (null);
998- view.search_entry.grab_focus ();
999-
1000- this.hide ();
1001- // Block here to replicate context menu behavior
1002- return true;
1003- }
1004- // Visible can be false but the popover still thinks it's up
1005- // and will show when it's view is switched back to
1006- // in that case don't block forwarding but make sure it is
1007- // really hidden
1008- this.hide ();
1009- return false;
1010- }
1011-
1012- ~NofocusPopover () {
1013- disconnect_popover_signals (parent_container);
1014- }
1015-}
1016-
1017-} // End namespace
1018\ No newline at end of file
1019
1020=== modified file 'src/Widgets/SearchItem.vala'
1021--- src/Widgets/SearchItem.vala 2014-11-08 05:40:53 +0000
1022+++ src/Widgets/SearchItem.vala 2015-02-01 15:13:29 +0000
1023@@ -35,7 +35,7 @@
1024 public SearchItem (Backend.App app, string search_term = "") {
1025 Object (app: app);
1026
1027- get_style_context ().add_class ("app");
1028+ get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT);
1029
1030 var markup = Backend.SynapseSearch.markup_string_with_search (app.name, search_term);
1031
1032@@ -97,4 +97,4 @@
1033 }
1034 }
1035
1036-}
1037\ No newline at end of file
1038+}
1039
1040=== modified file 'src/Widgets/SearchView.vala'
1041--- src/Widgets/SearchView.vala 2014-11-08 05:40:53 +0000
1042+++ src/Widgets/SearchView.vala 2015-02-01 15:13:29 +0000
1043@@ -19,8 +19,6 @@
1044 namespace Slingshot.Widgets {
1045
1046 public class SearchView : Gtk.ScrolledWindow {
1047- const int CONTEXT_WIDTH = 200;
1048- const int CONTEXT_ARROW_SIZE = 12;
1049 const int MAX_RESULTS = 20;
1050 const int MAX_RESULTS_BEFORE_LIMIT = 10;
1051
1052@@ -32,8 +30,6 @@
1053 private SearchItem selected_app = null;
1054 private Gtk.Box main_box;
1055
1056- private Gtk.Revealer revealer;
1057- private Gtk.EventBox context;
1058 private Gtk.Box context_box;
1059 private Gtk.Fixed context_fixed;
1060 private int context_selected_y;
1061@@ -87,30 +83,20 @@
1062
1063 public SearchView (SlingshotView parent) {
1064 view = parent;
1065-
1066+ hscrollbar_policy = Gtk.PolicyType.NEVER;
1067 items = new Gee.HashMap<Backend.App, SearchItem> ();
1068
1069 main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
1070 main_box.margin_start = 12;
1071- main_box.margin_end = 12;
1072
1073 context_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
1074 context_fixed = new Gtk.Fixed ();
1075- context_fixed.margin_start = CONTEXT_ARROW_SIZE;
1076+ context_fixed.margin_start = 12;
1077 context_fixed.put (context_box, 0, 0);
1078- context = new Gtk.EventBox ();
1079- context.draw.connect (draw_context);
1080- context.add (context_fixed);
1081-
1082- revealer = new Gtk.Revealer ();
1083- revealer.transition_duration = 400;
1084- revealer.transition_type = Gtk.RevealerTransitionType.CROSSFADE;
1085- revealer.no_show_all = true;
1086- revealer.add (context);
1087
1088 var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
1089 box.pack_start (main_box, true);
1090- box.pack_start (revealer, false);
1091+ box.pack_start (context_fixed, false);
1092
1093 add_with_viewport (box);
1094 }
1095@@ -189,7 +175,7 @@
1096 header.margin_start = 8;
1097 header.margin_bottom = 4;
1098 header.use_markup = true;
1099- header.get_style_context ().add_class ("category-label");
1100+ header.get_style_context ().add_class ("h4");
1101 header.show ();
1102 main_box.pack_start (header, false);
1103
1104@@ -252,10 +238,7 @@
1105 app.start_search.connect ((search, target) => start_search (search, target));
1106 context_box.pack_start (new SearchItem (app));
1107 }
1108- context.show_all ();
1109-
1110- revealer.show ();
1111- revealer.set_reveal_child (true);
1112+ context_box.show_all ();
1113
1114 Gtk.Allocation alloc;
1115 selected_app.get_allocation (out alloc);
1116@@ -267,9 +250,6 @@
1117 } else {
1118 in_context_view = false;
1119
1120- revealer.set_reveal_child (false);
1121- revealer.hide ();
1122-
1123 // trigger update of selection
1124 selected = selected;
1125 }
1126@@ -332,19 +312,6 @@
1127 return null;
1128 }
1129
1130- private bool draw_context (Cairo.Context cr) {
1131- cr.rectangle (CONTEXT_ARROW_SIZE, 0, context.get_allocated_width (), context.get_allocated_height ());
1132-
1133- cr.move_to (CONTEXT_ARROW_SIZE, context_selected_y + 6);
1134- cr.rel_line_to (-CONTEXT_ARROW_SIZE, 12);
1135- cr.rel_line_to (CONTEXT_ARROW_SIZE, 12);
1136- cr.close_path ();
1137-
1138- cr.set_source_rgb (0.85, 0.85, 0.85);
1139- cr.fill ();
1140- return false;
1141- }
1142-
1143 /**
1144 * Launch selected app
1145 *
1146@@ -358,4 +325,4 @@
1147
1148 }
1149
1150-}
1151\ No newline at end of file
1152+}

Subscribers

People subscribed via source and target branches