2
2
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
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.
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.
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/>.
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; }
30
30
Meta.PluginInfo info;
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;
40
40
Window? moving; //place for the window that is being moved over
42
42
int modal_count = 0; //count of modal modes overlaying each other
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> ();
52
52
info = Meta.PluginInfo () {name = "Gala", version = Config.VERSION, author = "Gala Developers",
53
53
license = "GPLv3", description = "A nice elementary window manager"};
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");
63
63
public override void start ()
65
65
Util.later_add (LaterType.BEFORE_REDRAW, show_stage);
70
70
var screen = get_screen ();
73
73
EndSessionDialog.register (this);
74
74
BackgroundCache.init (screen);
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);
88
88
stage = Compositor.get_stage_for_screen (screen) as Clutter.Stage;
90
90
var color = BackgroundSettings.get_default ().primary_color;
91
91
stage.background_color = Clutter.Color.from_string (color);
93
93
if (Prefs.get_dynamic_workspaces ())
94
94
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
96
96
/* our layer structure, copied from gnome-shell (from bottom to top):
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);
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 ());
150
150
screen.get_display ().add_keybinding ("cycle-workspaces-previous", KeybindingSettings.get_default ().schema, 0, () => {
151
151
cycle_workspaces (-1);
154
154
screen.get_display ().overlay_key.connect (() => {
156
156
Process.spawn_command_line_async (
157
157
BehaviorSettings.get_default ().overlay_action);
158
158
} catch (Error e) { warning (e.message); }
161
161
KeyBinding.set_custom_handler ("panel-main-menu", () => {
163
163
Process.spawn_command_line_async (
164
164
BehaviorSettings.get_default ().panel_main_menu_action);
165
165
} catch (Error e) { warning (e.message); }
168
168
KeyBinding.set_custom_handler ("toggle-recording", () => {
170
170
Process.spawn_command_line_async (
171
171
BehaviorSettings.get_default ().toggle_recording_action);
172
172
} catch (Error e) { warning (e.message); }
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);
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) );
185
185
KeyBinding.set_custom_handler ("switch-group", () => {});
186
186
KeyBinding.set_custom_handler ("switch-group-backward", () => {});
189
189
InternalUtils.reload_shadow ();
190
190
ShadowSettings.get_default ().notify.connect (InternalUtils.reload_shadow);
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);
196
196
BehaviorSettings.get_default ().schema.changed.connect ((key) => update_input_area ());
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);
208
208
KeyBinding.set_custom_handler ("show-desktop", () => {
209
209
workspace_view.show (true);
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);
223
223
if (plugin_manager.window_overview_provider == null) {
224
224
window_overview = new WindowOverview (this);
225
225
ui_group.add_child (window_overview);
243
243
plugin_manager.load_waiting_plugins ();
250
250
void configure_hotcorners ()
252
252
var geometry = get_screen ().get_monitor_geometry (get_screen ().get_primary_monitor ());
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");
259
259
update_input_area ();
262
262
void add_hotcorner (float x, float y, string key)
264
264
Clutter.Actor hot_corner;
265
265
var stage = Compositor.get_stage_for_screen (get_screen ());
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;
276
276
stage.add_child (hot_corner);
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));
285
285
hot_corner.x = x;
286
286
hot_corner.y = y;
289
289
void handle_switch_to_workspace (Meta.Display display, Meta.Screen screen, Meta.Window? window,
290
290
X.Event event, Meta.KeyBinding binding)
292
292
var direction = (binding.get_name () == "switch-to-workspace-left" ? MotionDirection.LEFT : MotionDirection.RIGHT);
293
293
switch_to_next_workspace (direction);
296
296
public void switch_to_next_workspace (MotionDirection direction)
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);
303
303
neighbor.activate (display.get_current_time ());
305
// if we didnt switch, show a nudge-over animation. need to take the indices
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)) {
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, () => {
346
346
public uint32[] get_all_xids ()
348
348
var list = new Gee.ArrayList<uint32> ();
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 ());
355
355
return list.to_array ();
358
358
void cycle_workspaces (int direction)
360
360
var screen = get_screen ();
367
367
screen.get_workspace_by_index (index).activate (screen.get_display ().get_current_time ());
370
370
public void move_window (Window? window, MotionDirection direction)
372
372
if (window == null)
375
375
var screen = get_screen ();
376
376
var display = screen.get_display ();
378
378
var active = screen.get_active_workspace ();
379
379
var next = active.get_neighbor (direction);
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);
389
389
if (!window.is_on_all_workspaces ())
390
390
window.change_workspace (next);
392
392
next.activate_with_focus (window, display.get_current_time ());
395
395
public new void begin_modal ()
398
398
if (modal_count > 1)
401
401
var screen = get_screen ();
402
402
var display = screen.get_display ();
404
404
update_input_area ();
405
405
#if HAS_MUTTER310
406
406
base.begin_modal (0, display.get_current_time ());
411
411
Meta.Util.disable_unredirect_for_screen (screen);
414
414
public new void end_modal ()
417
417
if (modal_count > 0)
420
420
update_input_area ();
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);
427
427
public void get_current_cursor_position (out int x, out int y)
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,
433
433
public void dim_window (Window window, bool dim)
435
435
/*FIXME we need a super awesome blureffect here, the one from clutter is just... bah!
519
519
public override void minimize (WindowActor actor)
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);
528
528
kill_window_effects (actor);
529
529
minimizing.add (actor);
531
531
int width, height;
532
532
get_screen ().get_size (out width, out height);
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)) {
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);
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);
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,
577
577
//stolen from original mutter plugin
578
578
public override void maximize (WindowActor actor, int ex, int ey, int ew, int eh)
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);
584
if (!AnimationSettings.get_default ().enable_animations ||
585
AnimationSettings.get_default ().snap_duration == 0 ||
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);
591
591
if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
592
592
maximizing.add (actor);
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);
599
599
//reset the actor's anchors
600
600
actor.scale_gravity = actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
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 ( () => {
606
606
actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
607
607
actor.set_scale (1.0, 1.0);
609
609
maximizing.remove (actor);
610
610
maximize_completed (actor);
616
616
maximize_completed (actor);
619
619
public override void map (WindowActor actor)
621
621
if (!AnimationSettings.get_default ().enable_animations) {
623
623
map_completed (actor);
627
627
var window = actor.get_meta_window ();
629
629
actor.detach_animation ();
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);
639
639
mapping.add (actor);
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 ( () => {
649
649
mapping.remove (actor);
650
650
map_completed (actor);
657
657
map_completed (actor);
661
661
mapping.add (actor);
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 ( () => {
672
672
mapping.remove (actor);
673
673
map_completed (actor);
676
676
case WindowType.MODAL_DIALOG:
677
677
case WindowType.DIALOG:
679
679
mapping.add (actor);
681
681
actor.scale_gravity = Clutter.Gravity.NORTH;
682
682
actor.scale_y = 0.0f;
683
683
actor.opacity = 0;
685
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250,
685
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250,
686
686
scale_y:1.0f, opacity:255).completed.connect ( () => {
688
688
mapping.remove (actor);
689
689
map_completed (actor);
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);
699
699
map_completed (actor);
704
704
public override void destroy (WindowActor actor)
706
706
var window = actor.get_meta_window ();
708
708
if (!AnimationSettings.get_default ().enable_animations) {
709
709
destroy_completed (actor);
718
718
actor.detach_animation ();
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);
727
727
destroying.add (actor);
729
729
actor.scale_gravity = Clutter.Gravity.CENTER;
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 ( () => {
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);
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 ( () => {
748
748
destroying.remove (actor);
749
749
destroy_completed (actor);
752
752
dim_window (window.find_root_ancestor (), false);
755
755
case WindowType.MENU:
756
756
case WindowType.DROPDOWN_MENU:
759
759
destroy_completed (actor);
763
763
destroying.add (actor);
765
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, AnimationSettings.get_default ().menu_duration,
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 ( () => {
769
769
destroying.remove (actor);
770
770
destroy_completed (actor);
779
779
public override void unmaximize (Meta.WindowActor actor, int ex, int ey, int ew, int eh)
781
781
if (!AnimationSettings.get_default ().enable_animations || AnimationSettings.get_default ().snap_duration == 0) {
782
782
unmaximize_completed (actor);
786
786
if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
787
787
unmaximizing.add (actor);
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);
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);
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..
805
805
unmaximizing.remove (actor);
806
806
unmaximize_completed (actor);
812
812
unmaximize_completed (actor);
815
815
// Cancel attached animation of an actor and reset it
816
816
bool end_animation (ref Gee.HashSet<Meta.WindowActor> list, WindowActor actor)
818
818
if (!list.contains (actor))
821
821
if (actor.is_destroyed ()) {
822
822
list.remove (actor);
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;
834
834
list.remove (actor);
838
838
public override void kill_window_effects (WindowActor actor)
840
840
if (end_animation (ref mapping, actor))
879
879
public override void switch_workspace (int from, int to, MotionDirection direction)
881
881
if (!AnimationSettings.get_default ().enable_animations || AnimationSettings.get_default ().workspace_switch_duration == 0) {
882
882
switch_workspace_completed ();
886
886
var screen = get_screen ();
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);
891
891
unowned List<WindowActor> windows = Compositor.get_window_actors (screen);
893
893
screen.get_size (out w, out h);
895
895
var x2 = 0.0f; var y2 = 0.0f;
896
896
if (direction == MotionDirection.LEFT)
903
903
var group = Compositor.get_window_group_for_screen (screen);
904
904
var wallpaper = background_group;
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> ();
912
912
var wallpaper_clone = new Clutter.Clone (wallpaper);
913
913
wallpaper_clone.x = (x2 < 0 ? w : -w);
915
915
clones.append (wallpaper_clone);
917
917
group.add_child (wallpaper_clone);
918
918
group.add_child (in_group);
919
919
group.add_child (out_group);
921
921
WindowActor moving_actor = null;
922
922
if (moving != null) {
923
923
moving_actor = moving.get_compositor_private () as WindowActor;
925
925
win.append (moving_actor);
926
926
par.append (moving_actor.get_parent ());
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);
934
934
var to_has_fullscreened = false;
935
935
var from_has_fullscreened = false;
936
936
var docks = new List<WindowActor> ();
938
938
foreach (var window in windows) {
939
939
var meta_window = window.get_meta_window ();
941
if (!meta_window.showing_on_its_workspace () ||
941
if (!meta_window.showing_on_its_workspace () ||
942
942
moving != null && window == moving_actor)
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);
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 ());
970
970
var clone = new Clutter.Clone (window);
971
971
clone.x = window.x;
972
972
clone.y = window.y;
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);
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);
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);
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;
998
998
var animation_duration = AnimationSettings.get_default ().workspace_switch_duration;
999
999
var animation_mode = Clutter.AnimationMode.EASE_OUT_CUBIC;
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);
1009
1009
void end_switch_workspace ()
1011
1011
if (win == null || par == null)
1014
1014
var screen = get_screen ();
1015
1015
var display = screen.get_display ();
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 ())
1022
1022
if (window.get_parent () == out_group) {
1023
1023
clutter_actor_reparent (window, par.nth_data (i));
1024
1024
window.hide ();
1026
1026
clutter_actor_reparent (window, par.nth_data (i));
1029
1029
foreach (var workspace in screen.get_workspaces ()) {
1030
1030
workspace.window_removed.disconnect (watch_window);
1033
1033
if (clones != null) {
1034
1034
foreach (var clone in clones) {
1035
1035
clone.destroy ();
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;
1053
1053
var wallpaper = background_group;
1054
1054
wallpaper.detach_animation ();
1055
1055
wallpaper.x = 0.0f;
1057
1057
switch_workspace_completed ();
1062
1062
public override void kill_switch_workspace ()
1064
1064
end_switch_workspace ();
1067
1067
public override bool xevent_filter (X.Event event)
1069
1069
return x_handle_event (event) != 0;
1072
1072
public override bool keybinding_filter (Meta.KeyBinding binding)
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;
1079
1079
public override unowned Meta.PluginInfo? plugin_info ()
1084
1084
static void clutter_actor_reparent (Clutter.Actor actor, Clutter.Actor new_parent)
1086
1086
if (actor == new_parent)
1090
1090
actor.get_parent ().remove_child (actor);
1091
1091
new_parent.add_child (actor);
1092
1092
actor.unref ();
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")]