2
* Copyright (C) 2009 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by Neil Jagdish Patel <neil.patel@canonical.com>
24
static string? boot_logging_filename = null;
28
public class DragDest: Gtk.Window
32
Object (type:Gtk.WindowType.TOPLEVEL,
33
type_hint:Gdk.WindowTypeHint.DOCK,
39
this.set_accept_focus (false);
43
public enum InputState
52
public class ActorBlur : Ctk.Bin
54
private Clutter.Clone clone;
55
//private Ctk.EffectBlur blur;
57
public ActorBlur (Clutter.Actor actor)
59
clone = new Clutter.Clone (actor);
64
clone.set_position (0, 0);
65
//blur = new Ctk.EffectBlur ();
66
//blur.set_factor (9f);
77
public class Plugin : Object, Shell
80
public signal void window_minimized (Plugin plugin, Mutter.Window window);
81
public signal void window_maximized (Plugin plugin,
87
public signal void window_unmaximized (Plugin plugin,
93
public signal void window_mapped (Plugin plugin, Mutter.Window window);
94
public signal void window_destroyed (Plugin plugin, Mutter.Window window);
95
public signal void kill_window_effects (Plugin plugin, Mutter.Window window);
96
public signal void kill_switch_workspace (Plugin plugin);
98
public signal void workspace_switch_event (Plugin plugin,
103
public signal void restore_input_region (bool fullscreen);
106
private Mutter.Plugin? _plugin;
107
public Mutter.Plugin? plugin {
108
get { return _plugin; }
109
set { _plugin = value; Idle.add (real_construct); }
111
private bool _super_key_enable=true;
112
public bool super_key_enable {
113
get { return _super_key_enable; }
114
set { _super_key_enable = value; }
117
public ExposeManager expose_manager { get; private set; }
119
public bool menus_swallow_events { get { return false; } }
121
private bool _super_key_active = false;
122
public bool super_key_active {
123
get { return _super_key_active; }
124
set { _super_key_active = value; }
126
public bool is_starting {get; set;}
128
public bool expose_showing { get { return expose_manager.expose_showing; } }
130
private static const int PANEL_HEIGHT = 24;
131
private static const int QUICKLAUNCHER_WIDTH = 58;
132
private static const string UNDECORATED_HINT = "UNDECORATED_HINT";
134
public Gee.ArrayList<Background> backgrounds;
135
public Gdk.Rectangle primary_monitor;
137
private Clutter.Stage stage;
138
private Application app;
139
private WindowManagement wm;
140
private Maximus maximus;
142
/* Unity Components */
143
private SpacesManager spaces_manager;
144
private Launcher.Launcher launcher;
145
private Places.Controller places_controller;
146
private Places.View places;
147
private Panel.View panel;
148
private Clutter.Rectangle dark_box;
149
private unowned Mutter.MetaWindow? focus_window = null;
150
private unowned Mutter.MetaDisplay? display = null;
152
private DragDest drag_dest;
153
private bool places_showing;
154
private bool _fullscreen_obstruction;
155
private InputState last_input_state = InputState.NONE;
157
private Gee.ArrayList<Object> fullscreen_requests;
159
private bool fullscreen_obstruction
162
return _fullscreen_obstruction;
165
_fullscreen_obstruction = value;
166
ensure_input_region ();
170
private bool grab_enabled = false;
171
private DBus.Connection screensaver_conn;
172
private dynamic DBus.Object screensaver;
174
public Gesture.Dispatcher gesture_dispatcher;
175
private Gesture.Type active_gesture_type = Gesture.Type.NONE;
178
/* private float start_pinch_radius = 0.0f; */
179
private unowned Mutter.Window? resize_window = null;
180
/*private float resize_last_x1 = 0.0f;
181
private float resize_last_y1 = 0.0f;
182
private float resize_last_x2 = 0.0f;
183
private float resize_last_y2 = 0.0f;*/
186
private unowned Mutter.Window? start_pan_window = null;
187
private unowned Clutter.Rectangle? start_frame_rect = null;
188
private float last_pan_x_root = 0.0f;
189
private float last_pan_maximised_x_root = 0.0f;
190
private enum MaximizeType {
196
private MaximizeType maximize_type = MaximizeType.NONE;
198
private enum ExposeType {
204
private ExposeType expose_type = ExposeType.NONE;
205
private unowned Mutter.Window? start_pinch_window = null;
208
private const string GCONF_DIR = "/desktop/unity/launcher";
209
private const string GCONF_SUPER_KEY_ENABLE_KEY = "super_key_enable";
214
fullscreen_requests = new Gee.ArrayList<Object> ();
215
Unity.global_shell = this;
216
Unity.TimelineLogger.get_default(); // just inits the timer for logging
217
// attempt to get a boot logging filename
218
boot_logging_filename = Environment.get_variable ("UNITY_BOOTLOG_FILENAME");
219
if (boot_logging_filename != null)
221
Unity.is_logging = true;
225
Unity.is_logging = false;
228
string[] args = { "mutter" };
230
LOGGER_START_PROCESS ("ctk_init");
231
Ctk.init_after (ref args);
232
LOGGER_END_PROCESS ("ctk_init");
234
Gtk.Settings.get_default ().gtk_icon_theme_name = "ubuntu-mono-dark";
236
/* Unique instancing */
237
LOGGER_START_PROCESS ("unity_application_constructor");
238
this.app = new Unity.Application ();
239
this.app.shell = this;
240
LOGGER_END_PROCESS ("unity_application_constructor");
244
this.screensaver_conn = DBus.Bus.get (DBus.BusType.SESSION);
245
this.screensaver = this.screensaver_conn.get_object ("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver");
246
this.screensaver.ActiveChanged.connect (got_screensaver_changed);
253
this.wm = new WindowManagement (this);
254
this.maximus = new Maximus ();
256
(Clutter.Stage.get_default () as Clutter.Stage).color = { 0, 0, 0, 255 };
261
private bool real_construct ()
265
Clutter.set_gl_picking_enabled (false);
267
this.stage = (Clutter.Stage)this.plugin.get_stage ();
268
this.stage.actor_added.connect ((a) => { ensure_input_region (); });
269
this.stage.actor_removed.connect ((a) => { ensure_input_region (); });
271
this.drag_dest = new DragDest ();
272
this.drag_dest.show ();
273
Gtk.TargetEntry[] target_list =
275
Gtk.TargetEntry () {target="STRING", flags=0,
276
info=Unity.dnd_targets.TARGET_STRING },
277
Gtk.TargetEntry () {target="text/plain", flags=0,
278
info=Unity.dnd_targets.TARGET_STRING },
279
Gtk.TargetEntry () {target="text/uri-list", flags=0,
280
info=Unity.dnd_targets.TARGET_URL },
281
Gtk.TargetEntry () {target="x-url/http",
282
flags=0, info=Unity.dnd_targets.TARGET_URL },
283
Gtk.TargetEntry () {target="x-url/ftp",
284
flags=0, info=Unity.dnd_targets.TARGET_URL },
285
Gtk.TargetEntry () {target="_NETSCAPE_URL", flags=0,
286
info=Unity.dnd_targets.TARGET_URL }
289
Ctk.dnd_init ((Gtk.Widget)this.drag_dest, target_list);
291
Clutter.Group window_group = (Clutter.Group) this.plugin.get_window_group ();
293
/* we need to hook into the super key bound by mutter for g-shell.
294
don't ask me why mutter binds things for g-shell explictly...
296
var gc = GConf.Client.get_default();
297
Mutter.MetaDisplay display = Mutter.MetaScreen.get_display (plugin.get_screen ());
300
super_key_enable = gc.get_bool(GCONF_DIR + "/" + GCONF_SUPER_KEY_ENABLE_KEY);
301
} catch (GLib.Error e) {
302
super_key_enable = true;
303
warning("Cannot find super_key_enable gconf key");
306
gc.add_dir(GCONF_DIR, GConf.ClientPreloadType.ONELEVEL);
307
gc.notify_add(GCONF_DIR + "/" + GCONF_SUPER_KEY_ENABLE_KEY, this.gconf_super_key_enable_cb);
308
} catch (GLib.Error e) {
309
warning("Cannot set gconf callback function of super_key_enable");
312
display.overlay_key_down.connect (() => {
313
if (super_key_enable) {
314
super_key_active = true;
318
display.overlay_key.connect (() => {
319
super_key_active = false;
322
display.overlay_key_with_modifier.connect ((keysym) => {
323
super_key_modifier_release (keysym);
326
display.overlay_key_with_modifier_down.connect ((keysym) => {
327
if (super_key_enable) {
328
super_key_modifier_press (keysym);
332
/* Setup the backgrounds */
333
unowned Gdk.Screen screen = Gdk.Screen.get_default ();
334
backgrounds = new Gee.ArrayList<Background> ();
336
/* Connect to interestng signals */
337
screen.monitors_changed.connect (relayout);
338
screen.size_changed.connect (relayout);
340
this.launcher = new Launcher.Launcher (this);
341
this.launcher.get_view ().opacity = 0;
343
this.spaces_manager = new SpacesManager (this);
344
this.spaces_manager.set_padding (50, 50, get_launcher_width_foobar () + 50, 50);
345
this.launcher.model.add (spaces_manager.button);
347
this.expose_manager = new ExposeManager (this, launcher);
348
this.expose_manager.hovered_opacity = 255;
349
this.expose_manager.unhovered_opacity = 255;
350
this.expose_manager.darken = 25;
351
this.expose_manager.right_buffer = 10;
352
this.expose_manager.top_buffer = this.expose_manager.bottom_buffer = 20;
354
this.expose_manager.coverflow = false;
356
window_group.add_actor (this.launcher.get_container ());
357
(this.launcher.get_container () as Ctk.Bin).add_actor (this.launcher.get_view ());
358
window_group.raise_child (this.launcher.get_container (),
359
this.plugin.get_normal_window_group ());
360
this.launcher.get_view ().animate (Clutter.AnimationMode.EASE_IN_SINE, 400,
363
this.places_controller = new Places.Controller (this);
364
this.places = this.places_controller.get_view ();
366
window_group.add_actor (this.places);
367
window_group.raise_child (this.places,
368
this.launcher.get_container ());
369
this.places.opacity = 0;
370
this.places.reactive = false;
372
this.places_showing = false;
374
this.panel = new Panel.View (this);
375
window_group.add_actor (this.panel);
376
window_group.raise_child (this.panel,
377
this.launcher.get_container ());
380
this.stage.notify["width"].connect (this.relayout);
381
this.stage.notify["height"].connect (this.relayout);
386
if (boot_logging_filename != null)
388
Timeout.add_seconds (5, () => {
389
Unity.TimelineLogger.get_default().write_log (boot_logging_filename);
394
gesture_dispatcher = new Gesture.XCBDispatcher ();
395
gesture_dispatcher.gesture.connect (on_gesture_received);
397
this.ensure_input_region ();
398
GLib.Idle.add (() => { is_starting = false; return false; });
403
private void gconf_super_key_enable_cb(GConf.Client gc, uint cxnid, GConf.Entry entry) {
404
bool new_value = true;
406
new_value = gc.get_bool(GCONF_DIR + "/" + GCONF_SUPER_KEY_ENABLE_KEY);
407
} catch (GLib.Error e) {
410
super_key_enable = new_value;
413
private void on_focus_window_changed ()
415
check_fullscreen_obstruction ();
417
if (focus_window != null)
419
focus_window.notify["fullscreen"].disconnect (on_focus_window_fullscreen_changed);
422
display.get ("focus-window", ref focus_window);
423
focus_window.notify["fullscreen"].connect (on_focus_window_fullscreen_changed);
426
private void on_focus_window_fullscreen_changed ()
428
check_fullscreen_obstruction ();
431
private void got_screensaver_changed (dynamic DBus.Object screensaver, bool changed)
435
this.launcher.get_container ().hide ();
437
var menu = Unity.Launcher.QuicklistController.get_current_menu ();
438
if (menu.is_menu_open ())
439
menu.state = Unity.Launcher.QuicklistControllerState.CLOSED;
441
fullscreen_obstruction = true;
445
this.launcher.get_container ().show ();
447
fullscreen_obstruction = false;
451
public uint32 get_current_time ()
453
return Mutter.MetaDisplay.get_current_time (Mutter.MetaScreen.get_display (plugin.get_screen ()));
456
void check_fullscreen_obstruction ()
458
Mutter.Window focus = null;
459
bool fullscreen = false;
461
// prevent segfault when mutter beats us to the initialization punch
462
if (!(launcher is Launcher.Launcher) || !(panel is Clutter.Actor))
465
unowned GLib.List<Mutter.Window> mutter_windows = plugin.get_windows ();
466
foreach (Mutter.Window w in mutter_windows)
468
unowned Mutter.MetaWindow meta = w.get_meta_window ();
470
if (meta != null && Mutter.MetaWindow.has_focus (w.get_meta_window ()))
480
(focus.get_meta_window () as GLib.Object).get ("fullscreen", ref fullscreen);
481
(this.launcher.get_container () as Launcher.LauncherContainer).cache.invalidate_texture_cache ();
482
this.panel.cache.invalidate_texture_cache ();
484
Clutter.Animation? anim;
485
Clutter.Animation? panim;
488
anim = this.launcher.get_container ().animate (Clutter.AnimationMode.EASE_IN_SINE, 200, "x", -100f);
489
panim = this.panel.animate (Clutter.AnimationMode.EASE_IN_SINE, 200, "opacity", 0);
490
fullscreen_obstruction = true;
494
anim = this.launcher.get_container ().animate (Clutter.AnimationMode.EASE_IN_SINE, 200, "x", 0f);
495
panim = this.panel.animate (Clutter.AnimationMode.EASE_IN_SINE, 200, "opacity", 255);
496
fullscreen_obstruction = false;
499
if (anim is Clutter.Animation)
501
anim.completed.connect (()=> {
502
(this.launcher.get_container () as Launcher.LauncherContainer).cache.update_texture_cache ();
506
if (panim is Clutter.Animation)
508
panim.completed.connect (() => { this.panel.cache.update_texture_cache (); });
512
private void refresh_n_backgrounds (int n_monitors)
514
int size = backgrounds.size;
516
if (size == n_monitors)
518
else if (size < n_monitors)
520
for (int i = 0; i < n_monitors - size; i++)
522
var bg = new Background ();
523
backgrounds.add (bg);
524
stage.add_actor (bg);
528
bg.animate (Clutter.AnimationMode.EASE_IN_QUAD, 2000,
534
for (int i = 0; i < size - n_monitors; i++)
536
var bg = backgrounds.get (0);
537
if (bg is Clutter.Actor)
539
backgrounds.remove (bg);
540
stage.remove_actor (bg);
545
private void relayout ()
549
unowned Gdk.Screen screen = Gdk.Screen.get_default ();
550
int x, y, width, height;
552
/* Figure out what should be the right size and location of Unity */
553
/* FIXME: This needs to always be monitor 0 right now as it doesn't
554
* seem possible to have panels on a vertical edge of a monitor unless
555
* it's the first or last monitor :(
557
screen.get_monitor_geometry (0, // Should be screen.get_primary_monitor()
558
out primary_monitor);
559
x = primary_monitor.x;
560
y = primary_monitor.y;
561
width = primary_monitor.width;
562
height = primary_monitor.height;
564
/* The drag-n-drop region */
565
drag_dest.resize (QUICKLAUNCHER_WIDTH,
566
height - PANEL_HEIGHT);
567
drag_dest.move (x, y + PANEL_HEIGHT);
569
/* We're responsible for painting the backgrounds on all the monitors */
570
refresh_n_backgrounds (screen.get_n_monitors ());
571
for (int i = 0; i < screen.get_n_monitors (); i++)
573
var bg = backgrounds.get (i);
574
if (bg is Background)
577
screen.get_monitor_geometry (i, out rect);
579
bg.set_position (rect.x, rect.y);
580
bg.set_size (rect.width, rect.height);
584
this.launcher.get_container ().set_size (this.QUICKLAUNCHER_WIDTH,
585
(height-this.PANEL_HEIGHT));
586
this.launcher.get_container ().set_position (x, y + this.PANEL_HEIGHT);
587
this.launcher.get_container ().set_clip (0, 0,
588
this.QUICKLAUNCHER_WIDTH,
589
height-this.PANEL_HEIGHT);
591
Utils.set_strut ((Gtk.Window)this.drag_dest,
592
this.QUICKLAUNCHER_WIDTH, y, (uint32)height,
593
PANEL_HEIGHT, x, (uint32)width);
595
this.places.set_size (width - this.QUICKLAUNCHER_WIDTH, height);
596
this.places.set_position (x + this.QUICKLAUNCHER_WIDTH, y);
598
this.panel.set_size (width, PANEL_HEIGHT);
599
this.panel.set_position (x, y);
601
ensure_input_region ();
606
public void add_fullscreen_request (Object o)
608
fullscreen_requests.add (o);
609
ensure_input_region ();
612
public bool remove_fullscreen_request (Object o)
614
bool result = fullscreen_requests.remove (o);
615
ensure_input_region ();
619
public void ensure_input_region ()
621
if (fullscreen_obstruction)
623
if (last_input_state == InputState.ZERO)
625
last_input_state = InputState.ZERO;
626
this.plugin.set_stage_input_area(0, 0, 0, 0);
628
this.grab_keyboard (false, Clutter.get_current_event_time ());
630
else if (fullscreen_requests.size > 0 || places_showing)
632
// Fullscreen required
633
if (last_input_state == InputState.FULLSCREEN)
636
last_input_state = InputState.FULLSCREEN;
637
this.restore_input_region (true);
639
this.stage.set_key_focus (null as Clutter.Actor);
640
this.grab_keyboard (true, Clutter.get_current_event_time ());
644
// Unity mode requred
645
if (last_input_state == InputState.UNITY)
648
last_input_state = InputState.UNITY;
649
this.restore_input_region (false);
651
this.grab_keyboard (false, Clutter.get_current_event_time ());
656
* SHELL IMPLEMENTATION
658
public Clutter.Stage get_stage ()
663
public void close_xids (Array<uint32> xids)
665
for (int i = 0; i < xids.length; i++)
667
uint32 xid = xids.index (i);
669
unowned GLib.List<Mutter.Window> mutter_windows = this.plugin.get_windows ();
670
foreach (Mutter.Window window in mutter_windows)
672
uint32 wxid = (uint32) Mutter.MetaWindow.get_xwindow (window.get_meta_window ());
675
Mutter.MetaWindow.delete (window.get_meta_window (), Clutter.get_current_event_time ());
681
public void expose_xids (Array<uint32> xids)
683
spaces_manager.hide_spaces_picker ();
684
SList<Clutter.Actor> windows = new SList<Clutter.Actor> ();
685
for (int i = 0; i < xids.length; i++)
687
uint32 xid = xids.index (i);
689
unowned GLib.List<Mutter.Window> mutter_windows = plugin.get_windows ();
690
foreach (Mutter.Window w in mutter_windows)
692
uint32 wxid = (uint32) Mutter.MetaWindow.get_xwindow (w.get_meta_window ());
701
expose_windows (windows, get_launcher_width_foobar () + 10);
704
public void stop_expose ()
706
expose_manager.end_expose ();
709
public void show_window (uint32 xid)
711
unowned GLib.List<Mutter.Window> mutter_windows = this.plugin.get_windows ();
713
foreach (Mutter.Window mutter_window in mutter_windows)
715
ulong window_xid = (ulong) Mutter.MetaWindow.get_xwindow (mutter_window.get_meta_window ());
716
if (window_xid != xid)
719
int type = mutter_window.get_window_type ();
721
if (type != Mutter.MetaWindowType.NORMAL &&
722
type != Mutter.MetaWindowType.DIALOG &&
723
type != Mutter.MetaWindowType.MODAL_DIALOG)
727
unowned Mutter.MetaWindow meta = mutter_window.get_meta_window ();
729
time_ = Mutter.MetaDisplay.get_current_time (Mutter.MetaWindow.get_display (meta));
730
Mutter.MetaWorkspace.activate (Mutter.MetaWindow.get_workspace (meta), time_);
731
Mutter.MetaWindow.activate (meta, time_);
735
public ShellMode get_mode ()
737
return places_showing ? ShellMode.DASH : ShellMode.MINIMIZED;
740
public int get_indicators_width ()
742
return this.panel.get_indicators_width ();
745
public void expose_windows (GLib.SList<Clutter.Actor> windows,
746
int left_buffer = 75)
748
expose_manager.left_buffer = left_buffer;
749
expose_manager.start_expose (windows);
753
public void hide_unity ()
755
if (places_showing == false)
758
places_showing = false;
760
var anim = dark_box.animate (Clutter.AnimationMode.EASE_IN_QUAD, 100, "opacity", 0);
761
anim.completed.connect ((an) => {
762
(an.get_object () as Clutter.Actor).destroy ();
765
plugin.get_normal_window_group ().animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100, "opacity", 255);
767
anim = places.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100,
769
anim.completed.connect ((an) => {
770
(an.get_object () as Clutter.Actor).hide ();
773
panel.set_indicator_mode (false);
774
ensure_input_region ();
776
while (Gtk.events_pending ())
777
Gtk.main_iteration ();
781
mode_changed (ShellMode.MINIMIZED);
784
public void show_unity ()
786
if (this.places_showing)
792
this.places_showing = true;
795
this.places.opacity = 0;
796
this.dark_box = new Clutter.Rectangle.with_color ({0, 0, 0, 255});
798
(this.plugin.get_window_group () as Clutter.Container).add_actor (this.dark_box);
799
this.dark_box.raise (plugin.get_normal_window_group ());
801
this.dark_box.set_position (primary_monitor.x, primary_monitor.y);
802
this.dark_box.set_size (primary_monitor.width, primary_monitor.height);
804
this.dark_box.show ();
806
this.panel.set_indicator_mode (true);
808
this.ensure_input_region ();
810
new X.Display (null).flush ();
812
this.dark_box.opacity = 0;
814
this.dark_box.animate (Clutter.AnimationMode.EASE_IN_QUAD, 100, "opacity", 180);
815
plugin.get_normal_window_group ().animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100, "opacity", 0);
816
places.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100,
821
mode_changed (ShellMode.DASH);
825
public void about_to_show_places ()
827
places.about_to_show ();
830
public void grab_keyboard (bool grab, uint32 timestamp)
832
if (this.grab_enabled == grab)
837
this.plugin.begin_modal (Utils.get_stage_window (this.stage),
845
this.plugin.end_modal (timestamp);
848
this.grab_enabled = grab;
851
private unowned Mutter.MetaWindow? get_window_for_xid (uint32 xid)
853
unowned GLib.List<Mutter.Window> mutter_windows = this.plugin.get_windows ();
854
foreach (Mutter.Window window in mutter_windows)
856
uint32 wxid = (uint32) Mutter.MetaWindow.get_xwindow (window.get_meta_window ());
859
unowned Mutter.MetaWindow win = window.get_meta_window ();
867
public void get_window_details (uint32 xid,
868
out bool allows_resize,
869
out bool is_maximised)
871
unowned Mutter.MetaWindow? win = get_window_for_xid (xid);
875
allows_resize = Mutter.MetaWindow.allows_resize (win);
876
is_maximised = (Mutter.MetaWindow.is_maximized (win) ||
877
Mutter.MetaWindow.is_maximized_horizontally (win) ||
878
Mutter.MetaWindow.is_maximized_vertically (win));
883
public void do_window_action (uint32 xid, WindowAction action)
885
unowned Mutter.MetaWindow? win = get_window_for_xid (xid);
891
case WindowAction.CLOSE:
892
Mutter.MetaWindow.delete (win, get_current_time ());
895
case WindowAction.MINIMIZE:
896
Mutter.MetaWindow.minimize (win);
899
case WindowAction.MAXIMIZE:
900
Mutter.MetaWindow.maximize (win,
901
Mutter.MetaMaximizeFlags.HORIZONTAL |
902
Mutter.MetaMaximizeFlags.VERTICAL);
905
case WindowAction.UNMAXIMIZE:
906
Mutter.MetaWindow.unmaximize (win,
907
Mutter.MetaMaximizeFlags.HORIZONTAL |
908
Mutter.MetaMaximizeFlags.VERTICAL);
912
warning (@"Window action type $action not supported");
918
private void on_gesture_received (Gesture.Event event)
920
if (active_gesture_type != Gesture.Type.NONE
921
&& active_gesture_type != event.type
922
&& event.state != Gesture.State.ENDED)
924
/* A new gesture is beginning */
925
if (event.state == Gesture.State.BEGAN)
927
active_gesture_type = event.type;
931
/* We don't want to handle it */
936
if (event.type == Gesture.Type.TAP)
938
if (event.fingers == 4
939
&& !expose_manager.expose_showing)
941
if (places_showing == true)
947
if (expose_manager.expose_showing == false)
951
expose_manager.end_expose ();
954
else if (event.type == Gesture.Type.PINCH)
956
if (event.fingers == 3
957
&& places_showing == false)
959
if (event.state == Gesture.State.ENDED)
961
if (event.pinch_event.radius_delta < 0)
964
if (expose_type == ExposeType.NONE || !expose_manager.expose_showing)
966
Mutter.Window? window = null;
968
var actor = stage.get_actor_at_pos (Clutter.PickMode.ALL,
971
if (actor is Mutter.Window == false)
972
actor = actor.get_parent ();
974
if (actor is Mutter.Window)
976
window = actor as Mutter.Window;
978
if (window.get_window_type () != Mutter.MetaCompWindowType.NORMAL &&
979
window.get_window_type () != Mutter.MetaCompWindowType.DIALOG &&
980
window.get_window_type () != Mutter.MetaCompWindowType.MODAL_DIALOG &&
981
window.get_window_type () != Mutter.MetaCompWindowType.UTILITY)
985
start_pinch_window = null;
987
if (window is Mutter.Window)
989
var matcher = Bamf.Matcher.get_default ();
990
var xwin = (uint32)Mutter.MetaWindow.get_xwindow (window.get_meta_window ());
992
foreach (Bamf.Application app in matcher.get_running_applications ())
994
Array<uint32> last_pinch_xids = app.get_xids ();
995
for (int i = 0; i < last_pinch_xids.length; i++)
997
uint32 xid = last_pinch_xids.index (i);
1000
// Found the right application, so pick it
1001
expose_xids (last_pinch_xids);
1002
expose_type = ExposeType.APPLICATION;
1003
start_pinch_window = window;
1010
/* If we're here we didnt find window, so lets do window expose */
1011
SList<Clutter.Actor> windows = new SList<Clutter.Actor> ();
1012
unowned GLib.List<Mutter.Window> mutter_windows = plugin.get_windows ();
1013
foreach (Mutter.Window w in mutter_windows)
1017
expose_windows (windows, get_launcher_width_foobar () + 10);
1019
expose_type = ExposeType.WINDOWS;
1022
else if (expose_type == ExposeType.APPLICATION)
1024
SList<Clutter.Actor> windows = new SList<Clutter.Actor> ();
1025
unowned GLib.List<Mutter.Window> mutter_windows = plugin.get_windows ();
1026
foreach (Mutter.Window w in mutter_windows)
1030
expose_windows (windows, get_launcher_width_foobar () + 10);
1032
expose_type = ExposeType.WINDOWS;
1034
else if (expose_type == ExposeType.WINDOWS)
1036
expose_type = ExposeType.WORKSPACE;
1042
if (expose_type == ExposeType.NONE || !expose_manager.expose_showing)
1044
expose_manager.end_expose ();
1045
expose_type = ExposeType.NONE;
1047
else if (expose_type == ExposeType.APPLICATION)
1049
expose_manager.end_expose ();
1050
expose_type = ExposeType.NONE;
1052
else if (expose_type == ExposeType.WINDOWS)
1054
var matcher = Bamf.Matcher.get_default ();
1055
var xwin = (uint32)Mutter.MetaWindow.get_xwindow (start_pinch_window.get_meta_window ());
1057
foreach (Bamf.Application app in matcher.get_running_applications ())
1059
Array<uint32> last_pinch_xids = app.get_xids ();
1060
for (int i = 0; i < last_pinch_xids.length; i++)
1062
uint32 xid = last_pinch_xids.index (i);
1065
// Found the right application, so pick it
1066
expose_xids (last_pinch_xids);
1067
expose_type = ExposeType.APPLICATION;
1072
expose_manager.end_expose ();
1073
expose_type = ExposeType.NONE;
1075
else if (expose_type == ExposeType.WORKSPACE)
1077
expose_type = ExposeType.WINDOWS;
1083
else if (event.type == Gesture.Type.PAN)
1085
if (resize_window is Mutter.Window)
1088
if (event.fingers == 3)
1090
if (event.state == Gesture.State.BEGAN
1091
&& event.pan_event.current_n_fingers == 2)
1093
start_pan_window = null;
1095
var actor = stage.get_actor_at_pos (Clutter.PickMode.ALL,
1098
if (actor is Mutter.Window == false)
1099
actor = actor.get_parent ();
1101
if (actor is Mutter.Window)
1103
start_pan_window = actor as Mutter.Window;
1105
if (start_pan_window.get_window_type () != Mutter.MetaCompWindowType.NORMAL &&
1106
start_pan_window.get_window_type () != Mutter.MetaCompWindowType.DIALOG &&
1107
start_pan_window.get_window_type () != Mutter.MetaCompWindowType.MODAL_DIALOG &&
1108
start_pan_window.get_window_type () != Mutter.MetaCompWindowType.UTILITY)
1109
start_pan_window = null;
1112
else if (event.state == Gesture.State.CONTINUED
1113
&& event.pan_event.current_n_fingers == 2)
1115
if (start_pan_window is Mutter.Window == false)
1118
last_pan_x_root = event.root_x;
1120
unowned Mutter.MetaWindow win = start_pan_window.get_meta_window ();
1121
bool fullscreen = false;
1122
win.get ("fullscreen", out fullscreen);
1124
if (!Mutter.MetaWindow.is_maximized (win) && fullscreen == false)
1126
if (start_pan_window.y == PANEL_HEIGHT
1127
&& event.pan_event.delta_y <= 0.0f)
1129
if (start_frame_rect is Clutter.Rectangle == false)
1131
Clutter.Rectangle frame = new Clutter.Rectangle.with_color ({ 0, 0, 0, 10 });
1132
frame.border_color = { 255, 255, 255, 255 };
1133
frame.border_width = 3;
1135
stage.add_actor (frame);
1136
frame.set_size (start_pan_window.width,
1137
start_pan_window.height);
1138
frame.set_position (start_pan_window.x,
1139
start_pan_window.y);
1142
start_frame_rect = frame;
1144
last_pan_maximised_x_root = start_pan_window.x;
1147
maximize_type = MaximizeType.FULL;
1148
var MAX_DELTA = 50.0f;
1149
if (start_pan_window.x < last_pan_maximised_x_root - MAX_DELTA)
1151
maximize_type = MaximizeType.LEFT;
1152
start_frame_rect.animate (Clutter.AnimationMode.EASE_OUT_QUAD,
1154
"x", (float)QUICKLAUNCHER_WIDTH,
1155
"y", (float)PANEL_HEIGHT,
1156
"width", (stage.width - QUICKLAUNCHER_WIDTH)/2.0f,
1157
"height", stage.height - PANEL_HEIGHT);
1160
else if (start_pan_window.x > last_pan_maximised_x_root + MAX_DELTA)
1162
maximize_type = MaximizeType.RIGHT;
1163
start_frame_rect.animate (Clutter.AnimationMode.EASE_OUT_QUAD,
1165
"x", (float)((stage.width - QUICKLAUNCHER_WIDTH)/2.0f) + QUICKLAUNCHER_WIDTH,
1166
"y", (float)PANEL_HEIGHT,
1167
"width", (stage.width - QUICKLAUNCHER_WIDTH)/2.0f,
1168
"height", stage.height - PANEL_HEIGHT);
1172
start_frame_rect.animate (Clutter.AnimationMode.EASE_OUT_QUAD,
1174
"x", (float)QUICKLAUNCHER_WIDTH,
1175
"y", (float)PANEL_HEIGHT,
1176
"width", stage.width - QUICKLAUNCHER_WIDTH,
1177
"height", stage.height - PANEL_HEIGHT);
1183
if (start_frame_rect is Clutter.Rectangle)
1185
if (start_frame_rect.opacity == 0)
1187
stage.remove_actor (start_frame_rect);
1188
start_frame_rect = null;
1190
else if (start_pan_window.y > PANEL_HEIGHT + 5 &&
1191
(start_frame_rect.get_animation () is Clutter.Animation == false))
1193
start_frame_rect.animate (Clutter.AnimationMode.EASE_IN_QUAD,
1195
"x", start_pan_window.x,
1196
"y", start_pan_window.y,
1197
"width", start_pan_window.width,
1198
"height", start_pan_window.height,
1203
start_pan_window.x += Math.floorf (event.pan_event.delta_x + 0.5f);
1204
start_pan_window.y += Math.floorf (event.pan_event.delta_y + 0.5f);
1205
start_pan_window.x = float.max (start_pan_window.x, QUICKLAUNCHER_WIDTH);
1206
start_pan_window.y = float.max (start_pan_window.y, PANEL_HEIGHT);
1210
if (event.pan_event.delta_y >= 0.0f && fullscreen == false)
1212
Mutter.MetaWindow.unmaximize (win,
1213
Mutter.MetaMaximizeFlags.HORIZONTAL | Mutter.MetaMaximizeFlags.VERTICAL);
1217
else if (event.state == Gesture.State.ENDED)
1219
if (start_pan_window is Mutter.Window)
1221
unowned Mutter.MetaWindow win = start_pan_window.get_meta_window ();
1226
bool move_resize = false;
1227
bool fullscreen = false;
1228
win.get ("fullscreen", out fullscreen);
1231
Mutter.MetaWindow.get_geometry (win, out wx, out wy, out ww, out wh);
1232
Mutter.MetaRectangle rect = Mutter.MetaRectangle ();
1233
Mutter.MetaWindow.get_outer_rect (win, rect);
1235
if (Mutter.MetaWindow.is_maximized (win) || fullscreen)
1238
else if (start_pan_window.y == PANEL_HEIGHT && event.pan_event.delta_y < 0.0f)
1240
if (maximize_type == MaximizeType.FULL)
1243
Mutter.MetaWindow.maximize (win,
1244
Mutter.MetaMaximizeFlags.HORIZONTAL | Mutter.MetaMaximizeFlags.VERTICAL);
1245
move_resize = false;
1247
else if (maximize_type == MaximizeType.RIGHT)
1249
nx = (float)QUICKLAUNCHER_WIDTH + (stage.width-QUICKLAUNCHER_WIDTH)/2.0f;
1250
ny = (float)PANEL_HEIGHT;
1251
nwidth = (stage.width - QUICKLAUNCHER_WIDTH)/2.0f;
1252
nheight = stage.height - PANEL_HEIGHT;
1256
else if (maximize_type == MaximizeType.LEFT)
1258
nx = (float)QUICKLAUNCHER_WIDTH;
1259
ny = (float)PANEL_HEIGHT;
1260
nwidth = (stage.width - QUICKLAUNCHER_WIDTH)/2.0f;
1261
nheight = stage.height - PANEL_HEIGHT;
1268
nx = start_pan_window.x;
1269
ny = start_pan_window.y;
1277
X.Window xwin = start_pan_window.get_x_window ();
1278
if (nwidth > 0.0f && nheight > 0.0f)
1280
Mutter.MetaWindow.move_resize (win, false, ((int)nx),
1282
(int)nwidth, (int)nheight);
1286
/* We use gdk_window_move because we don't want
1287
* to send in the width and height if we dont
1288
* need to, as otherwise we'll cause a resize
1289
* for no reason, and most likely get it
1290
* wrong (you need to take into account frame
1291
* size inside Mutter
1293
unowned Gdk.Window w = Gdk.Window.foreign_new ((Gdk.NativeWindow)xwin);
1294
w.move ((int)nx, (int)ny);
1299
if (start_frame_rect is Clutter.Rectangle)
1300
stage.remove_actor (start_frame_rect);
1307
* MUTTER PLUGIN HOOKS
1309
public void minimize (Mutter.Window window)
1311
this.window_minimized (this, window);
1314
public void maximize (Mutter.Window window,
1320
if (window.get_data<string> (UNDECORATED_HINT) == null)
1322
Utils.window_set_decorations (Mutter.MetaWindow.get_xwindow (window.get_meta_window ()), 0);
1325
this.window_maximized (this, window, x, y, width, height);
1327
active_window_state_changed ();
1330
public void unmaximize (Mutter.Window window,
1336
if (window.get_data<string> (UNDECORATED_HINT) == null)
1338
Utils.window_set_decorations (Mutter.MetaWindow.get_xwindow (window.get_meta_window ()), 1);
1341
this.window_unmaximized (this, window, x, y, width, height);
1343
active_window_state_changed ();
1346
public void map (Mutter.Window window)
1348
unowned Mutter.MetaWindow win = window.get_meta_window ();
1350
if (window.get_window_type () == Mutter.MetaCompWindowType.NORMAL)
1355
bool decorated = Utils.window_is_decorated (Mutter.MetaWindow.get_xwindow (win));
1356
bool maximized = Mutter.MetaWindow.is_maximized (win);
1359
win.get ("fullscreen", out fullscreen);
1361
if (!decorated && !maximized)
1363
window.set_data (UNDECORATED_HINT, "%s".printf ("true"));
1365
else if (decorated && maximized && !fullscreen)
1367
Utils.window_set_decorations (Mutter.MetaWindow.get_xwindow (win), 0);
1374
else if (window.get_window_type () == Mutter.MetaCompWindowType.DOCK)
1376
if (win.get_xwindow (win) == Gdk.x11_drawable_get_xid (drag_dest.window))
1382
this.maximus.process_window (window);
1383
this.window_mapped (this, window);
1385
if (display == null)
1387
display = Mutter.MetaWindow.get_display (window.get_meta_window ());
1388
display.notify["focus-window"].connect (on_focus_window_changed);
1392
public void destroy (Mutter.Window window)
1394
this.window_destroyed (this, window);
1397
public void switch_workspace (int from,
1401
this.workspace_switch_event (this, from, to, direction);
1404
public void on_kill_window_effects (Mutter.Window window)
1406
this.kill_window_effects (this, window);
1409
public void on_kill_switch_workspace ()
1411
this.kill_switch_workspace (this);
1414
public int get_panel_height ()
1416
return this.PANEL_HEIGHT;
1419
public int get_launcher_width ()
1421
return this.QUICKLAUNCHER_WIDTH;
1424
/* this is needed to avoid a symbol clash in unity/targets/mutter/main.c */
1425
public int get_panel_height_foobar ()
1427
return this.get_panel_height ();
1430
/* this is needed to avoid a symbol clash in unity/targets/mutter/main.c */
1431
public int get_launcher_width_foobar ()
1433
return this.get_launcher_width ();