@@ -107,12 +107,53 @@ public class Gala.DesktopIntegration : GLib.Object {
107107 foreach (unowned var app in apps) {
108108 foreach (weak Meta . Window window in app. get_windows ()) {
109109 if (window. get_id () == uid) {
110- window. get_workspace (). activate_with_focus (window, wm. get_display (). get_current_time ());
110+ if (window. has_focus ()) {
111+ notify_already_focused (window);
112+ } else {
113+ window. get_workspace (). activate_with_focus (window, wm. get_display (). get_current_time ());
114+ }
111115 }
112116 }
113117 }
114118 }
115119
120+ private bool notifying = false ;
121+ private void notify_already_focused (Meta .Window window ) {
122+ if (notifying) {
123+ return ;
124+ }
125+
126+ notifying = true ;
127+
128+ wm. get_display (). get_sound_player (). play_from_theme (" bell" , _(" Window has already focus" ), null );
129+
130+ if (window. get_maximized () == BOTH ) {
131+ notifying = false ;
132+ return ;
133+ }
134+
135+ var transition = new Clutter .KeyframeTransition (" translation-x" ) {
136+ repeat_count = 5 ,
137+ duration = 100 ,
138+ remove_on_complete = true
139+ };
140+ transition. set_from_value (0 );
141+ transition. set_to_value (0 );
142+ transition. set_key_frames ( { 0.5 , - 0.5 } );
143+
144+ var offset = InternalUtils . scale_to_int (15 , wm. get_display (). get_monitor_scale (window. get_monitor ()));
145+ transition. set_values ( { - offset, offset });
146+
147+ transition. stopped. connect (() = > {
148+ notifying = false ;
149+ wm. get_display (). enable_unredirect ();
150+ });
151+
152+ wm. get_display (). disable_unredirect ();
153+
154+ ((Meta . WindowActor ) window. get_compositor_private ()). add_transition (" notify-already-focused" , transition);
155+ }
156+
116157 public void show_windows_for (string app_id ) throws IOError , DBusError {
117158 if (wm. window_overview == null ) {
118159 throw new IOError .FAILED (" Window overview not provided by window manager" );
0 commit comments