~gala-dev/gala/windowswitcher-fade-opacity

« back to all changes in this revision

Viewing changes to src/WindowManager.vala

  • Committer: Rico Tzschichholz
  • Date: 2014-04-08 12:51:06 UTC
  • Revision ID: ricotz@ubuntu.com-20140408125106-6ahv3pbbwilck1pi
codestyle: Drop trailing spaces/tabs

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//  
 
1
//
2
2
//  Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
3
 
// 
 
3
//
4
4
//  This program is free software: you can redistribute it and/or modify
5
5
//  it under the terms of the GNU General Public License as published by
6
6
//  the Free Software Foundation, either version 3 of the License, or
7
7
//  (at your option) any later version.
8
 
// 
 
8
//
9
9
//  This program is distributed in the hope that it will be useful,
10
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
//  GNU General Public License for more details.
13
 
// 
 
13
//
14
14
//  You should have received a copy of the GNU General Public License
15
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
// 
 
16
//
17
17
 
18
18
using Meta;
19
19
 
26
26
                public Clutter.Actor window_group { get; protected set; }
27
27
                public Clutter.Actor top_window_group { get; protected set; }
28
28
                public Meta.BackgroundGroup background_group { get; protected set; }
29
 
                
 
29
 
30
30
                Meta.PluginInfo info;
31
 
                
 
31
 
32
32
                WindowSwitcher? winswitcher = null;
33
33
                WorkspaceView? workspace_view = null;
34
34
                WindowOverview? window_overview = null;
36
36
                // used to detect which corner was used to trigger an action
37
37
                Clutter.Actor? last_hotcorner;
38
38
                ScreenSaver? screensaver;
39
 
                
 
39
 
40
40
                Window? moving; //place for the window that is being moved over
41
 
                
 
41
 
42
42
                int modal_count = 0; //count of modal modes overlaying each other
43
 
                
 
43
 
44
44
                Gee.HashSet<Meta.WindowActor> minimizing = new Gee.HashSet<Meta.WindowActor> ();
45
45
                Gee.HashSet<Meta.WindowActor> maximizing = new Gee.HashSet<Meta.WindowActor> ();
46
46
                Gee.HashSet<Meta.WindowActor> unmaximizing = new Gee.HashSet<Meta.WindowActor> ();
51
51
                {
52
52
                        info = Meta.PluginInfo () {name = "Gala", version = Config.VERSION, author = "Gala Developers",
53
53
                                license = "GPLv3", description = "A nice elementary window manager"};
54
 
                        
 
54
 
55
55
                        Prefs.set_ignore_request_hide_titlebar (true);
56
56
                        Prefs.override_preference_schema ("dynamic-workspaces", Config.SCHEMA + ".behavior");
57
57
                        Prefs.override_preference_schema ("attach-modal-dialogs", Config.SCHEMA + ".appearance");
59
59
                        Prefs.override_preference_schema ("edge-tiling", Config.SCHEMA + ".behavior");
60
60
                        Prefs.override_preference_schema ("enable-animations", Config.SCHEMA + ".animations");
61
61
                }
62
 
                
 
62
 
63
63
                public override void start ()
64
64
                {
65
65
                        Util.later_add (LaterType.BEFORE_REDRAW, show_stage);
66
66
                }
67
 
                
 
67
 
68
68
                bool show_stage ()
69
69
                {
70
70
                        var screen = get_screen ();
71
 
                        
 
71
 
72
72
                        DBus.init (this);
73
73
                        EndSessionDialog.register (this);
74
74
                        BackgroundCache.init (screen);
75
 
                        
 
75
 
76
76
                        // Due to a bug which enables access to the stage when using multiple monitors
77
77
                        // in the screensaver, we have to listen for changes and make sure the input area
78
78
                        // is set to NONE when we are in locked mode
84
84
                                screensaver = null;
85
85
                                warning (e.message);
86
86
                        }
87
 
                        
 
87
 
88
88
                        stage = Compositor.get_stage_for_screen (screen) as Clutter.Stage;
89
 
                        
 
89
 
90
90
                        var color = BackgroundSettings.get_default ().primary_color;
91
91
                        stage.background_color = Clutter.Color.from_string (color);
92
 
                        
 
92
 
93
93
                        if (Prefs.get_dynamic_workspaces ())
94
94
                                screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
95
 
                        
 
95
 
96
96
                        /* our layer structure, copied from gnome-shell (from bottom to top):
97
97
                         * stage
98
98
                         * + system background
123
123
                        top_window_group = Compositor.get_top_window_group_for_screen (screen);
124
124
                        stage.remove_child (top_window_group);
125
125
                        ui_group.add_child (top_window_group);
126
 
                        
 
126
 
127
127
                        /*keybindings*/
128
 
                        
 
128
 
129
129
                        screen.get_display ().add_keybinding ("switch-to-workspace-first", KeybindingSettings.get_default ().schema, 0, () => {
130
130
                                screen.get_workspace_by_index (0).activate (screen.get_display ().get_current_time ());
131
131
                        });
150
150
                        screen.get_display ().add_keybinding ("cycle-workspaces-previous", KeybindingSettings.get_default ().schema, 0, () => {
151
151
                                cycle_workspaces (-1);
152
152
                        });
153
 
                        
 
153
 
154
154
                        screen.get_display ().overlay_key.connect (() => {
155
155
                                try {
156
156
                                        Process.spawn_command_line_async (
157
157
                                                BehaviorSettings.get_default ().overlay_action);
158
158
                                } catch (Error e) { warning (e.message); }
159
159
                        });
160
 
                        
 
160
 
161
161
                        KeyBinding.set_custom_handler ("panel-main-menu", () => {
162
162
                                try {
163
163
                                        Process.spawn_command_line_async (
164
164
                                                BehaviorSettings.get_default ().panel_main_menu_action);
165
165
                                } catch (Error e) { warning (e.message); }
166
166
                        });
167
 
                        
 
167
 
168
168
                        KeyBinding.set_custom_handler ("toggle-recording", () => {
169
169
                                try {
170
170
                                        Process.spawn_command_line_async (
171
171
                                                BehaviorSettings.get_default ().toggle_recording_action);
172
172
                                } catch (Error e) { warning (e.message); }
173
173
                        });
174
 
                        
 
174
 
175
175
                        KeyBinding.set_custom_handler ("switch-to-workspace-up", () => {});
176
176
                        KeyBinding.set_custom_handler ("switch-to-workspace-down", () => {});
177
177
                        KeyBinding.set_custom_handler ("switch-to-workspace-left", handle_switch_to_workspace);
178
178
                        KeyBinding.set_custom_handler ("switch-to-workspace-right", handle_switch_to_workspace);
179
 
                        
 
179
 
180
180
                        KeyBinding.set_custom_handler ("move-to-workspace-up", () => {});
181
181
                        KeyBinding.set_custom_handler ("move-to-workspace-down", () => {});
182
182
                        KeyBinding.set_custom_handler ("move-to-workspace-left",  (d, s, w) => move_window (w, MotionDirection.LEFT) );
183
183
                        KeyBinding.set_custom_handler ("move-to-workspace-right", (d, s, w) => move_window (w, MotionDirection.RIGHT) );
184
 
                        
 
184
 
185
185
                        KeyBinding.set_custom_handler ("switch-group", () => {});
186
186
                        KeyBinding.set_custom_handler ("switch-group-backward", () => {});
187
 
                        
 
187
 
188
188
                        /*shadows*/
189
189
                        InternalUtils.reload_shadow ();
190
190
                        ShadowSettings.get_default ().notify.connect (InternalUtils.reload_shadow);
191
 
                        
 
191
 
192
192
                        /*hot corner, getting enum values from GraniteServicesSettings did not work, so we use GSettings directly*/
193
193
                        configure_hotcorners ();
194
194
                        screen.monitors_changed.connect (configure_hotcorners);
195
 
                        
 
195
 
196
196
                        BehaviorSettings.get_default ().schema.changed.connect ((key) => update_input_area ());
197
197
 
198
198
                        // initialize plugins and add default components if no plugin overrides them
204
204
                                workspace_view = new WorkspaceView (this);
205
205
                                workspace_view.visible = false;
206
206
                                ui_group.add_child (workspace_view);
207
 
                                
 
207
 
208
208
                                KeyBinding.set_custom_handler ("show-desktop", () => {
209
209
                                        workspace_view.show (true);
210
210
                                });
219
219
                                KeyBinding.set_custom_handler ("switch-applications", winswitcher.handle_switch_windows);
220
220
                                KeyBinding.set_custom_handler ("switch-applications-backward", winswitcher.handle_switch_windows);
221
221
                        }
222
 
                        
 
222
 
223
223
                        if (plugin_manager.window_overview_provider == null) {
224
224
                                window_overview = new WindowOverview (this);
225
225
                                ui_group.add_child (window_overview);
231
231
                                        window_overview.open (true, true);
232
232
                                });
233
233
                        }
234
 
                        
 
234
 
235
235
                        update_input_area ();
236
236
 
237
237
                        stage.show ();
243
243
                                plugin_manager.load_waiting_plugins ();
244
244
                                return false;
245
245
                        });
246
 
                        
 
246
 
247
247
                        return false;
248
248
                }
249
 
                
 
249
 
250
250
                void configure_hotcorners ()
251
251
                {
252
252
                        var geometry = get_screen ().get_monitor_geometry (get_screen ().get_primary_monitor ());
253
 
                        
 
253
 
254
254
                        add_hotcorner (geometry.x, geometry.y, "hotcorner-topleft");
255
255
                        add_hotcorner (geometry.x + geometry.width - 1, geometry.y, "hotcorner-topright");
256
256
                        add_hotcorner (geometry.x, geometry.y + geometry.height - 1, "hotcorner-bottomleft");
257
257
                        add_hotcorner (geometry.x + geometry.width - 1, geometry.y + geometry.height - 1, "hotcorner-bottomright");
258
 
                        
 
258
 
259
259
                        update_input_area ();
260
260
                }
261
 
                
 
261
 
262
262
                void add_hotcorner (float x, float y, string key)
263
263
                {
264
264
                        Clutter.Actor hot_corner;
265
265
                        var stage = Compositor.get_stage_for_screen (get_screen ());
266
 
                        
 
266
 
267
267
                        // if the hot corner already exists, just reposition it, create it otherwise
268
268
                        if ((hot_corner = stage.find_child_by_name (key)) == null) {
269
269
                                hot_corner = new Clutter.Actor ();
272
272
                                hot_corner.opacity = 0;
273
273
                                hot_corner.reactive = true;
274
274
                                hot_corner.name = key;
275
 
                                
 
275
 
276
276
                                stage.add_child (hot_corner);
277
 
                                
 
277
 
278
278
                                hot_corner.enter_event.connect (() => {
279
279
                                        last_hotcorner = hot_corner;
280
280
                                        perform_action ((ActionType)BehaviorSettings.get_default ().schema.get_enum (key));
281
281
                                        return false;
282
282
                                });
283
283
                        }
284
 
                        
 
284
 
285
285
                        hot_corner.x = x;
286
286
                        hot_corner.y = y;
287
287
                }
288
 
                
 
288
 
289
289
                void handle_switch_to_workspace (Meta.Display display, Meta.Screen screen, Meta.Window? window,
290
290
                        X.Event event, Meta.KeyBinding binding)
291
291
                {
292
292
                        var direction = (binding.get_name () == "switch-to-workspace-left" ? MotionDirection.LEFT : MotionDirection.RIGHT);
293
293
                        switch_to_next_workspace (direction);
294
294
                }
295
 
                
 
295
 
296
296
                public void switch_to_next_workspace (MotionDirection direction)
297
297
                {
298
298
                        var screen = get_screen ();
299
299
                        var display = screen.get_display ();
300
300
                        var old_index = screen.get_active_workspace_index ();
301
301
                        var neighbor = screen.get_active_workspace ().get_neighbor (direction);
302
 
                        
 
302
 
303
303
                        neighbor.activate (display.get_current_time ());
304
 
                        
305
 
                        // if we didnt switch, show a nudge-over animation. need to take the indices 
 
304
 
 
305
                        // if we didnt switch, show a nudge-over animation. need to take the indices
306
306
                        // here since the changing only applies after the animation ends
307
307
                        if ((old_index == 0
308
308
                                && direction == MotionDirection.LEFT)
309
309
                                || (old_index == screen.n_workspaces - 1
310
310
                                && direction == MotionDirection.RIGHT)) {
311
 
                                
 
311
 
312
312
                                var dest = (direction == MotionDirection.LEFT ? 32.0f : -32.0f);
313
313
                                ui_group.animate (Clutter.AnimationMode.LINEAR, 100, x:dest);
314
314
                                Timeout.add (210, () => {
317
317
                                });
318
318
                        }
319
319
                }
320
 
                
 
320
 
321
321
                public void update_input_area ()
322
322
                {
323
323
                        var schema = BehaviorSettings.get_default ().schema;
324
324
                        var screen = get_screen ();
325
 
                        
 
325
 
326
326
                        if (screensaver != null) {
327
327
                                try {
328
328
                                        if (screensaver.get_active ()) {
331
331
                                        }
332
332
                                } catch (IOError e) { warning (e.message); }
333
333
                        }
334
 
                        
 
334
 
335
335
                        if (modal_count > 0)
336
336
                                InternalUtils.set_input_area (screen, InputArea.FULLSCREEN);
337
337
                        else if (schema.get_enum ("hotcorner-topleft") != ActionType.NONE ||
346
346
                public uint32[] get_all_xids ()
347
347
                {
348
348
                        var list = new Gee.ArrayList<uint32> ();
349
 
                        
 
349
 
350
350
                        foreach (var workspace in get_screen ().get_workspaces ()) {
351
351
                                foreach (var window in workspace.list_windows ())
352
352
                                        list.add ((uint32)window.get_xwindow ());
353
353
                        }
354
 
                        
 
354
 
355
355
                        return list.to_array ();
356
356
                }
357
 
                
 
357
 
358
358
                void cycle_workspaces (int direction)
359
359
                {
360
360
                        var screen = get_screen ();
366
366
 
367
367
                        screen.get_workspace_by_index (index).activate (screen.get_display ().get_current_time ());
368
368
                }
369
 
                
 
369
 
370
370
                public void move_window (Window? window, MotionDirection direction)
371
371
                {
372
372
                        if (window == null)
373
373
                                return;
374
 
                        
 
374
 
375
375
                        var screen = get_screen ();
376
376
                        var display = screen.get_display ();
377
 
                        
 
377
 
378
378
                        var active = screen.get_active_workspace ();
379
379
                        var next = active.get_neighbor (direction);
380
 
                        
 
380
 
381
381
                        //dont allow empty workspaces to be created by moving, if we have dynamic workspaces
382
382
                        if (Prefs.get_dynamic_workspaces () && active.n_windows == 1 && next.index () ==  screen.n_workspaces - 1) {
383
383
                                Utils.bell (screen);
384
384
                                return;
385
385
                        }
386
 
                        
 
386
 
387
387
                        moving = window;
388
 
                        
 
388
 
389
389
                        if (!window.is_on_all_workspaces ())
390
390
                                window.change_workspace (next);
391
 
                        
 
391
 
392
392
                        next.activate_with_focus (window, display.get_current_time ());
393
393
                }
394
 
                
 
394
 
395
395
                public new void begin_modal ()
396
396
                {
397
397
                        modal_count ++;
398
398
                        if (modal_count > 1)
399
399
                                return;
400
 
                        
 
400
 
401
401
                        var screen = get_screen ();
402
402
                        var display = screen.get_display ();
403
 
                        
 
403
 
404
404
                        update_input_area ();
405
405
#if HAS_MUTTER310
406
406
                        base.begin_modal (0, display.get_current_time ());
410
410
 
411
411
                        Meta.Util.disable_unredirect_for_screen (screen);
412
412
                }
413
 
                
 
413
 
414
414
                public new void end_modal ()
415
415
                {
416
416
                        modal_count --;
417
417
                        if (modal_count > 0)
418
418
                                return;
419
 
                        
 
419
 
420
420
                        update_input_area ();
421
 
                        
 
421
 
422
422
                        var screen = get_screen ();
423
423
                        base.end_modal (screen.get_display ().get_current_time ());
424
424
                        Meta.Util.enable_unredirect_for_screen (screen);
425
425
                }
426
 
                
 
426
 
427
427
                public void get_current_cursor_position (out int x, out int y)
428
428
                {
429
 
                        Gdk.Display.get_default ().get_device_manager ().get_client_pointer ().get_position (null, 
 
429
                        Gdk.Display.get_default ().get_device_manager ().get_client_pointer ().get_position (null,
430
430
                                out x, out y);
431
431
                }
432
 
                
 
432
 
433
433
                public void dim_window (Window window, bool dim)
434
434
                {
435
435
                        /*FIXME we need a super awesome blureffect here, the one from clutter is just... bah!
441
441
                        } else
442
442
                                win.clear_effects ();*/
443
443
                }
444
 
                
 
444
 
445
445
                public void perform_action (ActionType type)
446
446
                {
447
447
                        var screen = get_screen ();
448
448
                        var display = screen.get_display ();
449
449
                        var current = display.get_focus_window ();
450
 
                        
 
450
 
451
451
                        switch (type) {
452
452
                                case ActionType.SHOW_WORKSPACE_VIEW:
453
453
                                        workspace_view.show ();
455
455
                                case ActionType.MAXIMIZE_CURRENT:
456
456
                                        if (current == null || current.window_type != WindowType.NORMAL)
457
457
                                                break;
458
 
                                        
 
458
 
459
459
                                        if (current.get_maximized () == (MaximizeFlags.HORIZONTAL | MaximizeFlags.VERTICAL))
460
460
                                                current.unmaximize (MaximizeFlags.HORIZONTAL | MaximizeFlags.VERTICAL);
461
461
                                        else
511
511
                                        break;
512
512
                        }
513
513
                }
514
 
                
 
514
 
515
515
                /*
516
516
                 * effects
517
517
                 */
518
 
                
 
518
 
519
519
                public override void minimize (WindowActor actor)
520
520
                {
521
 
                        if (!AnimationSettings.get_default ().enable_animations || 
522
 
                                AnimationSettings.get_default ().minimize_duration == 0 || 
 
521
                        if (!AnimationSettings.get_default ().enable_animations ||
 
522
                                AnimationSettings.get_default ().minimize_duration == 0 ||
523
523
                                actor.get_meta_window ().window_type != WindowType.NORMAL) {
524
524
                                minimize_completed (actor);
525
525
                                return;
526
526
                        }
527
 
                        
 
527
 
528
528
                        kill_window_effects (actor);
529
529
                        minimizing.add (actor);
530
 
                        
 
530
 
531
531
                        int width, height;
532
532
                        get_screen ().get_size (out width, out height);
533
 
                        
 
533
 
534
534
                        Rectangle icon = {};
535
535
                        //FIXME don't use the icon geometry, since it seems broken right now
536
536
                        if (false && actor.get_meta_window ().get_icon_geometry (out icon)) {
537
 
                                
 
537
 
538
538
                                float scale_x  = (float)icon.width  / actor.width;
539
539
                                float scale_y  = (float)icon.height / actor.height;
540
540
                                float anchor_x = (float)(actor.x - icon.x) * actor.width  / (icon.width  - actor.width);
541
541
                                float anchor_y = (float)(actor.y - icon.y) * actor.height / (icon.height - actor.height);
542
 
                                
 
542
 
543
543
                                actor.move_anchor_point (anchor_x, anchor_y);
544
 
                                actor.animate (Clutter.AnimationMode.EASE_IN_EXPO, AnimationSettings.get_default ().minimize_duration, 
 
544
                                actor.animate (Clutter.AnimationMode.EASE_IN_EXPO, AnimationSettings.get_default ().minimize_duration,
545
545
                                        scale_x:scale_x, scale_y:scale_y,opacity:0)
546
546
                                        .completed.connect (() => {
547
547
                                        //FIXME once we enable this part and we still haven't found a fix for below issue, add the idle here too
552
552
                                        minimize_completed (actor);
553
553
                                        minimizing.remove (actor);
554
554
                                });
555
 
                                
 
555
 
556
556
                        } else {
557
557
                                actor.scale_center_x = width / 2.0f - actor.x;
558
558
                                actor.scale_center_y = height - actor.y;
559
 
                                actor.animate (Clutter.AnimationMode.EASE_IN_EXPO, AnimationSettings.get_default ().minimize_duration, 
 
559
                                actor.animate (Clutter.AnimationMode.EASE_IN_EXPO, AnimationSettings.get_default ().minimize_duration,
560
560
                                        scale_x : 0.0f, scale_y : 0.0f, opacity : 0)
561
561
                                        .completed.connect (() => {
562
562
                                        //FIXME for unknown reasons clutter won't apply properties that are changed here,
573
573
                                });
574
574
                        }
575
575
                }
576
 
                
 
576
 
577
577
                //stolen from original mutter plugin
578
578
                public override void maximize (WindowActor actor, int ex, int ey, int ew, int eh)
579
579
                {
580
580
                        float x, y, width, height;
581
581
                        actor.get_size (out width, out height);
582
582
                        actor.get_position (out x, out y);
583
 
                        
584
 
                        if (!AnimationSettings.get_default ().enable_animations || 
585
 
                                AnimationSettings.get_default ().snap_duration == 0 || 
 
583
 
 
584
                        if (!AnimationSettings.get_default ().enable_animations ||
 
585
                                AnimationSettings.get_default ().snap_duration == 0 ||
586
586
                                (x == ex && y == ey && ew == width && eh == height)) {
587
587
                                maximize_completed (actor);
588
588
                                return;
589
589
                        }
590
 
                        
 
590
 
591
591
                        if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
592
592
                                maximizing.add (actor);
593
 
                                
 
593
 
594
594
                                float scale_x  = (float)ew  / width;
595
595
                                float scale_y  = (float)eh / height;
596
596
                                float anchor_x = (float)(x - ex) * width  / (ew - width);
597
597
                                float anchor_y = (float)(y - ey) * height / (eh - height);
598
 
                                
 
598
 
599
599
                                //reset the actor's anchors
600
600
                                actor.scale_gravity = actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
601
 
                                
 
601
 
602
602
                                actor.move_anchor_point (anchor_x, anchor_y);
603
 
                                actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration, 
 
603
                                actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration,
604
604
                                        scale_x:scale_x, scale_y:scale_y).get_timeline ().completed.connect ( () => {
605
 
                                        
 
605
 
606
606
                                        actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
607
607
                                        actor.set_scale (1.0, 1.0);
608
 
                                        
 
608
 
609
609
                                        maximizing.remove (actor);
610
610
                                        maximize_completed (actor);
611
611
                                });
612
 
                                
 
612
 
613
613
                                return;
614
614
                        }
615
 
                        
 
615
 
616
616
                        maximize_completed (actor);
617
617
                }
618
 
                
 
618
 
619
619
                public override void map (WindowActor actor)
620
620
                {
621
621
                        if (!AnimationSettings.get_default ().enable_animations) {
623
623
                                map_completed (actor);
624
624
                                return;
625
625
                        }
626
 
                        
 
626
 
627
627
                        var window = actor.get_meta_window ();
628
 
                        
 
628
 
629
629
                        actor.detach_animation ();
630
630
                        actor.show ();
631
 
                        
 
631
 
632
632
                        switch (window.window_type) {
633
633
                                case WindowType.NORMAL:
634
634
                                        if (AnimationSettings.get_default ().open_duration == 0) {
635
635
                                                map_completed (actor);
636
636
                                                return;
637
637
                                        }
638
 
                                        
 
638
 
639
639
                                        mapping.add (actor);
640
 
                                        
 
640
 
641
641
                                        actor.scale_gravity = Clutter.Gravity.SOUTH;
642
642
                                        actor.scale_x = 0.01f;
643
643
                                        actor.scale_y = 0.1f;
644
644
                                        actor.opacity = 0;
645
 
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_EXPO, AnimationSettings.get_default ().open_duration, 
 
645
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_EXPO, AnimationSettings.get_default ().open_duration,
646
646
                                                scale_x:1.0f, scale_y:1.0f, opacity:255)
647
647
                                                .completed.connect ( () => {
648
 
                                                
 
648
 
649
649
                                                mapping.remove (actor);
650
650
                                                map_completed (actor);
651
651
                                        });
657
657
                                                map_completed (actor);
658
658
                                                return;
659
659
                                        }
660
 
                                        
 
660
 
661
661
                                        mapping.add (actor);
662
 
                                        
 
662
 
663
663
                                        actor.scale_gravity = Clutter.Gravity.CENTER;
664
664
                                        actor.rotation_center_x = {0, 0, 10};
665
665
                                        actor.scale_x = 0.9f;
666
666
                                        actor.scale_y = 0.9f;
667
667
                                        actor.opacity = 0;
668
 
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, AnimationSettings.get_default ().menu_duration, 
 
668
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, AnimationSettings.get_default ().menu_duration,
669
669
                                                scale_x:1.0f, scale_y:1.0f, opacity:255)
670
670
                                                .completed.connect ( () => {
671
 
                                                
 
671
 
672
672
                                                mapping.remove (actor);
673
673
                                                map_completed (actor);
674
674
                                        });
675
675
                                        break;
676
676
                                case WindowType.MODAL_DIALOG:
677
677
                                case WindowType.DIALOG:
678
 
                                        
 
678
 
679
679
                                        mapping.add (actor);
680
 
                                        
 
680
 
681
681
                                        actor.scale_gravity = Clutter.Gravity.NORTH;
682
682
                                        actor.scale_y = 0.0f;
683
683
                                        actor.opacity = 0;
684
 
                                        
685
 
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250, 
 
684
 
 
685
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250,
686
686
                                                scale_y:1.0f, opacity:255).completed.connect ( () => {
687
 
                                                
 
687
 
688
688
                                                mapping.remove (actor);
689
689
                                                map_completed (actor);
690
690
                                        });
691
 
                                        
 
691
 
692
692
                                        if (AppearanceSettings.get_default ().dim_parents &&
693
 
                                                window.window_type == WindowType.MODAL_DIALOG && 
 
693
                                                window.window_type == WindowType.MODAL_DIALOG &&
694
694
                                                window.is_attached_dialog ())
695
695
                                                dim_window (window.find_root_ancestor (), true);
696
 
                                        
 
696
 
697
697
                                        break;
698
698
                                default:
699
699
                                        map_completed (actor);
700
700
                                        break;
701
701
                        }
702
702
                }
703
 
                
 
703
 
704
704
                public override void destroy (WindowActor actor)
705
705
                {
706
706
                        var window = actor.get_meta_window ();
707
 
                        
 
707
 
708
708
                        if (!AnimationSettings.get_default ().enable_animations) {
709
709
                                destroy_completed (actor);
710
710
 
714
714
 
715
715
                                return;
716
716
                        }
717
 
                        
 
717
 
718
718
                        actor.detach_animation ();
719
 
                        
 
719
 
720
720
                        switch (window.window_type) {
721
721
                                case WindowType.NORMAL:
722
722
                                        if (AnimationSettings.get_default ().close_duration == 0) {
723
723
                                                destroy_completed (actor);
724
724
                                                return;
725
725
                                        }
726
 
                                        
 
726
 
727
727
                                        destroying.add (actor);
728
 
                                        
 
728
 
729
729
                                        actor.scale_gravity = Clutter.Gravity.CENTER;
730
730
                                        actor.show ();
731
 
                                        actor.animate (Clutter.AnimationMode.LINEAR, AnimationSettings.get_default ().close_duration, 
 
731
                                        actor.animate (Clutter.AnimationMode.LINEAR, AnimationSettings.get_default ().close_duration,
732
732
                                                scale_x:0.8f, scale_y:0.8f, opacity:0)
733
733
                                                .completed.connect ( () => {
734
 
                                                
 
734
 
735
735
                                                destroying.remove (actor);
736
736
                                                destroy_completed (actor);
737
737
                                                Utils.request_clean_icon_cache (get_all_xids ());
740
740
                                case WindowType.MODAL_DIALOG:
741
741
                                case WindowType.DIALOG:
742
742
                                        destroying.add (actor);
743
 
                                        
 
743
 
744
744
                                        actor.scale_gravity = Clutter.Gravity.NORTH;
745
 
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, 
 
745
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200,
746
746
                                                scale_y:0.0f, opacity:0).completed.connect ( () => {
747
 
                                                
 
747
 
748
748
                                                destroying.remove (actor);
749
749
                                                destroy_completed (actor);
750
750
                                        });
751
 
                                        
 
751
 
752
752
                                        dim_window (window.find_root_ancestor (), false);
753
 
                                        
 
753
 
754
754
                                        break;
755
755
                                case WindowType.MENU:
756
756
                                case WindowType.DROPDOWN_MENU:
759
759
                                                destroy_completed (actor);
760
760
                                                return;
761
761
                                        }
762
 
                                        
 
762
 
763
763
                                        destroying.add (actor);
764
 
                                        
765
 
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, AnimationSettings.get_default ().menu_duration, 
 
764
 
 
765
                                        actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, AnimationSettings.get_default ().menu_duration,
766
766
                                                scale_x:0.8f, scale_y:0.8f, opacity:0)
767
767
                                                .completed.connect ( () => {
768
 
                                                
 
768
 
769
769
                                                destroying.remove (actor);
770
770
                                                destroy_completed (actor);
771
771
                                        });
775
775
                                        break;
776
776
                        }
777
777
                }
778
 
                
 
778
 
779
779
                public override void unmaximize (Meta.WindowActor actor, int ex, int ey, int ew, int eh)
780
780
                {
781
781
                        if (!AnimationSettings.get_default ().enable_animations || AnimationSettings.get_default ().snap_duration == 0) {
782
782
                                unmaximize_completed (actor);
783
783
                                return;
784
784
                        }
785
 
                        
 
785
 
786
786
                        if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
787
787
                                unmaximizing.add (actor);
788
 
                                
 
788
 
789
789
                                float x, y, width, height;
790
790
                                actor.get_size (out width, out height);
791
791
                                actor.get_position (out x, out y);
792
 
                                
 
792
 
793
793
                                float scale_x  = (float)ew  / width;
794
794
                                float scale_y  = (float)eh / height;
795
795
                                float anchor_x = (float)(x - ex) * width  / (ew - width);
796
796
                                float anchor_y = (float)(y - ey) * height / (eh - height);
797
 
                                
 
797
 
798
798
                                actor.move_anchor_point (anchor_x, anchor_y);
799
 
                                actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration, 
 
799
                                actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration,
800
800
                                        scale_x:scale_x, scale_y:scale_y).completed.connect ( () => {
801
801
                                        actor.move_anchor_point_from_gravity (Clutter.Gravity.NORTH_WEST);
802
 
                                        actor.animate (Clutter.AnimationMode.LINEAR, 1, scale_x:1.0f, 
 
802
                                        actor.animate (Clutter.AnimationMode.LINEAR, 1, scale_x:1.0f,
803
803
                                                scale_y:1.0f);//just scaling didnt want to work..
804
 
                                        
 
804
 
805
805
                                        unmaximizing.remove (actor);
806
806
                                        unmaximize_completed (actor);
807
807
                                });
808
 
                                
 
808
 
809
809
                                return;
810
810
                        }
811
 
                        
 
811
 
812
812
                        unmaximize_completed (actor);
813
813
                }
814
 
                
 
814
 
815
815
                // Cancel attached animation of an actor and reset it
816
816
                bool end_animation (ref Gee.HashSet<Meta.WindowActor> list, WindowActor actor)
817
817
                {
818
818
                        if (!list.contains (actor))
819
819
                                return false;
820
 
                        
 
820
 
821
821
                        if (actor.is_destroyed ()) {
822
822
                                list.remove (actor);
823
823
                                return false;
824
824
                        }
825
 
                        
 
825
 
826
826
                        actor.detach_animation ();
827
827
                        actor.opacity = 255;
828
828
                        actor.scale_x = 1.0f;
830
830
                        actor.rotation_angle_x = 0.0f;
831
831
                        actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
832
832
                        actor.scale_gravity = Clutter.Gravity.NORTH_WEST;
833
 
                        
 
833
 
834
834
                        list.remove (actor);
835
835
                        return true;
836
836
                }
837
 
                
 
837
 
838
838
                public override void kill_window_effects (WindowActor actor)
839
839
                {
840
840
                        if (end_animation (ref mapping, actor))
848
848
                        if (end_animation (ref destroying, actor))
849
849
                                destroy_completed (actor);
850
850
                }
851
 
                
 
851
 
852
852
                /*workspace switcher*/
853
853
                List<WindowActor>? win;
854
854
                List<Clutter.Actor>? par; //class space for kill func
856
856
                Clutter.Actor? in_group;
857
857
                Clutter.Actor? out_group;
858
858
                Clutter.Actor? moving_window_container;
859
 
                
 
859
 
860
860
                void watch_window (Meta.Workspace workspace, Meta.Window window)
861
861
                {
862
862
                        if (clones == null) {
865
865
                        }
866
866
 
867
867
                        warning ("Dock window '%s' closed while switching workspaces", window.get_title ());
868
 
                        
 
868
 
869
869
                        // finding the correct window here is not so easy
870
870
                        // and for those default 400ms we can live with
871
871
                        // some windows disappearing which in fact should never
875
875
                        }
876
876
                        clones = null;
877
877
                }
878
 
                
 
878
 
879
879
                public override void switch_workspace (int from, int to, MotionDirection direction)
880
880
                {
881
881
                        if (!AnimationSettings.get_default ().enable_animations || AnimationSettings.get_default ().workspace_switch_duration == 0) {
882
882
                                switch_workspace_completed ();
883
883
                                return;
884
884
                        }
885
 
                        
 
885
 
886
886
                        var screen = get_screen ();
887
 
                        
 
887
 
888
888
                        unowned Meta.Workspace wp_from = screen.get_workspace_by_index (from);
889
889
                        unowned Meta.Workspace wp_to = screen.get_workspace_by_index (to);
890
 
                        
 
890
 
891
891
                        unowned List<WindowActor> windows = Compositor.get_window_actors (screen);
892
892
                        float w, h;
893
893
                        screen.get_size (out w, out h);
894
 
                        
 
894
 
895
895
                        var x2 = 0.0f; var y2 = 0.0f;
896
896
                        if (direction == MotionDirection.LEFT)
897
897
                                x2 = w;
899
899
                                x2 = -w;
900
900
                        else
901
901
                                return;
902
 
                        
 
902
 
903
903
                        var group = Compositor.get_window_group_for_screen (screen);
904
904
                        var wallpaper = background_group;
905
 
                        
 
905
 
906
906
                        in_group  = new Clutter.Actor ();
907
907
                        out_group = new Clutter.Actor ();
908
908
                        win = new List<WindowActor> ();
909
909
                        par = new List<Clutter.Actor> ();
910
910
                        clones = new List<Clutter.Clone> ();
911
 
                        
 
911
 
912
912
                        var wallpaper_clone = new Clutter.Clone (wallpaper);
913
913
                        wallpaper_clone.x = (x2 < 0 ? w : -w);
914
 
                        
 
914
 
915
915
                        clones.append (wallpaper_clone);
916
 
                        
 
916
 
917
917
                        group.add_child (wallpaper_clone);
918
918
                        group.add_child (in_group);
919
919
                        group.add_child (out_group);
920
 
                        
 
920
 
921
921
                        WindowActor moving_actor = null;
922
922
                        if (moving != null) {
923
923
                                moving_actor = moving.get_compositor_private () as WindowActor;
924
 
                                
 
924
 
925
925
                                win.append (moving_actor);
926
926
                                par.append (moving_actor.get_parent ());
927
 
                                
 
927
 
928
928
                                // for some reason the actor alone won't stay where it should, only in a container
929
929
                                moving_window_container = new Clutter.Actor ();
930
930
                                clutter_actor_reparent (moving_actor, moving_window_container);
931
931
                                group.add_child (moving_window_container);
932
932
                        }
933
 
                        
 
933
 
934
934
                        var to_has_fullscreened = false;
935
935
                        var from_has_fullscreened = false;
936
936
                        var docks = new List<WindowActor> ();
937
 
                        
 
937
 
938
938
                        foreach (var window in windows) {
939
939
                                var meta_window = window.get_meta_window ();
940
 
                                
941
 
                                if (!meta_window.showing_on_its_workspace () || 
 
940
 
 
941
                                if (!meta_window.showing_on_its_workspace () ||
942
942
                                        moving != null && window == moving_actor)
943
943
                                        continue;
944
 
                                
 
944
 
945
945
                                if (meta_window.get_workspace () == wp_from) {
946
946
                                        win.append (window);
947
947
                                        par.append (window.get_parent ());
958
958
                                        docks.append (window);
959
959
                                }
960
960
                        }
961
 
                        
 
961
 
962
962
                        // make sure we don't add docks when there are fullscreened
963
 
                        // windows on one of the groups. Simply raising seems not to 
 
963
                        // windows on one of the groups. Simply raising seems not to
964
964
                        // work, mutter probably reverts the order internally to match
965
965
                        // the display stack
966
966
                        foreach (var window in docks) {
967
967
                                win.append (window);
968
968
                                par.append (window.get_parent ());
969
 
                                
 
969
 
970
970
                                var clone = new Clutter.Clone (window);
971
971
                                clone.x = window.x;
972
972
                                clone.y = window.y;
973
 
                                
 
973
 
974
974
                                clones.append (clone);
975
975
                                if (!to_has_fullscreened)
976
976
                                        in_group.add_child (clone);
977
977
                                if (!from_has_fullscreened)
978
978
                                        clutter_actor_reparent (window, out_group);
979
979
                        }
980
 
                        
 
980
 
981
981
                        // monitor the workspaces to see whether a window was removed
982
982
                        // in which case we need to stop the clones from drawing
983
983
                        // we monitor every workspace here because finding the ones a
985
985
                        foreach (var workspace in screen.get_workspaces ()) {
986
986
                                workspace.window_removed.connect (watch_window);
987
987
                        }
988
 
                        
 
988
 
989
989
                        in_group.set_position (-x2, -y2);
990
990
                        group.set_child_above_sibling (in_group, null);
991
991
                        if (moving_window_container != null)
992
992
                                group.set_child_above_sibling (moving_window_container, null);
993
 
                        
 
993
 
994
994
                        in_group.clip_to_allocation = out_group.clip_to_allocation = true;
995
995
                        in_group.width = out_group.width = w;
996
996
                        in_group.height = out_group.height = h;
997
 
                        
 
997
 
998
998
                        var animation_duration = AnimationSettings.get_default ().workspace_switch_duration;
999
999
                        var animation_mode = Clutter.AnimationMode.EASE_OUT_CUBIC;
1000
 
                        
 
1000
 
1001
1001
                        out_group.animate (animation_mode, animation_duration, x : x2, y : y2);
1002
1002
                        in_group.animate (animation_mode, animation_duration, x : 0.0f, y : 0.0f).completed.connect (() => {
1003
1003
                                end_switch_workspace ();
1005
1005
                        wallpaper.animate (animation_mode, animation_duration, x : (x2 < 0 ? -w : w));
1006
1006
                        wallpaper_clone.animate (animation_mode, animation_duration, x : 0.0f);
1007
1007
                }
1008
 
                
 
1008
 
1009
1009
                void end_switch_workspace ()
1010
1010
                {
1011
1011
                        if (win == null || par == null)
1012
1012
                                return;
1013
 
                        
 
1013
 
1014
1014
                        var screen = get_screen ();
1015
1015
                        var display = screen.get_display ();
1016
 
                        
 
1016
 
1017
1017
                        for (var i=0;i<win.length ();i++) {
1018
1018
                                var window = win.nth_data (i);
1019
1019
                                if (window == null || window.is_destroyed ())
1020
1020
                                        continue;
1021
 
                                
 
1021
 
1022
1022
                                if (window.get_parent () == out_group) {
1023
1023
                                        clutter_actor_reparent (window, par.nth_data (i));
1024
1024
                                        window.hide ();
1025
1025
                                } else
1026
1026
                                        clutter_actor_reparent (window, par.nth_data (i));
1027
1027
                        }
1028
 
                        
 
1028
 
1029
1029
                        foreach (var workspace in screen.get_workspaces ()) {
1030
1030
                                workspace.window_removed.disconnect (watch_window);
1031
1031
                        }
1032
 
                        
 
1032
 
1033
1033
                        if (clones != null) {
1034
1034
                                foreach (var clone in clones) {
1035
1035
                                        clone.destroy ();
1036
1036
                                }
1037
1037
                                clones = null;
1038
1038
                        }
1039
 
                        
 
1039
 
1040
1040
                        win = null;
1041
1041
                        par = null;
1042
 
                        
 
1042
 
1043
1043
                        if (in_group != null)
1044
1044
                                in_group.destroy ();
1045
1045
                        in_group = null;
1049
1049
                        if (moving_window_container != null)
1050
1050
                                moving_window_container.destroy ();
1051
1051
                        moving_window_container = null;
1052
 
                        
 
1052
 
1053
1053
                        var wallpaper = background_group;
1054
1054
                        wallpaper.detach_animation ();
1055
1055
                        wallpaper.x = 0.0f;
1056
 
                        
 
1056
 
1057
1057
                        switch_workspace_completed ();
1058
 
                        
 
1058
 
1059
1059
                        moving = null;
1060
1060
                }
1061
 
                
 
1061
 
1062
1062
                public override void kill_switch_workspace ()
1063
1063
                {
1064
1064
                        end_switch_workspace ();
1065
1065
                }
1066
 
                
 
1066
 
1067
1067
                public override bool xevent_filter (X.Event event)
1068
1068
                {
1069
1069
                        return x_handle_event (event) != 0;
1071
1071
 
1072
1072
                public override bool keybinding_filter (Meta.KeyBinding binding)
1073
1073
                {
1074
 
                        // for now we'll just block all keybindings if we're in modal mode, 
 
1074
                        // for now we'll just block all keybindings if we're in modal mode,
1075
1075
                        // do something useful with this later
1076
1076
                        return modal_count > 0;
1077
1077
                }
1078
 
                
 
1078
 
1079
1079
                public override unowned Meta.PluginInfo? plugin_info ()
1080
1080
                {
1081
1081
                        return info;
1082
1082
                }
1083
 
                
 
1083
 
1084
1084
                static void clutter_actor_reparent (Clutter.Actor actor, Clutter.Actor new_parent)
1085
1085
                {
1086
1086
                        if (actor == new_parent)
1087
1087
                                return;
1088
 
                        
 
1088
 
1089
1089
                        actor.ref ();
1090
1090
                        actor.get_parent ().remove_child (actor);
1091
1091
                        new_parent.add_child (actor);
1092
1092
                        actor.unref ();
1093
1093
                }
1094
1094
        }
1095
 
        
 
1095
 
1096
1096
        [CCode (cname="clutter_x11_handle_event")]
1097
1097
        public extern int x_handle_event (X.Event xevent);
1098
1098
        [CCode (cname="clutter_x11_get_stage_window")]