Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions lib/DragDropAction.vala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ namespace Gala {
*/
public signal void destination_crossed (Clutter.Actor destination, bool hovered);

/**
* Emitted on the source when we are hovering over a destination.
*
* @param destination The destination actor that we are hovering over
* @param x The x coordinate relative to the destination actor
* @param y The y coordinate relative to the destination actor
*/
public signal void destination_motion (Clutter.Actor destination, float x, float y);

/**
* The source has been clicked, but the movement was not larger than
* the drag threshold. Useful if the source is also activatable.
Expand Down Expand Up @@ -341,7 +350,7 @@ namespace Gala {
last_y = y;

var stage = actor.get_stage ();
var actor = stage.get_actor_at_pos (Clutter.PickMode.REACTIVE, (int) x, (int) y);
var actor = stage.get_actor_at_pos (NONE, (int) x, (int) y);
DragDropAction action = null;
// if we're allowed to bubble and this actor is not a destination, check its parents
if (actor != null && (action = get_drag_drop_action (actor)) == null && allow_bubbling) {
Expand All @@ -352,8 +361,12 @@ namespace Gala {
}

// didn't change, no need to do anything
if (actor == hovered)
if (actor == hovered) {
if (hovered != null) {
destination_motion (hovered, x - hovered.x, y - hovered.y);
}
return Clutter.EVENT_STOP;
}

if (action == null) {
// apparently we left ours if we had one before
Expand Down Expand Up @@ -436,12 +449,12 @@ namespace Gala {
}

private void finish () {
drag_end (hovered);

// make sure they reset the style or whatever they changed when hovered
emit_crossed (hovered, false);

cleanup ();

drag_end (hovered);
}

private void cleanup () {
Expand Down
13 changes: 10 additions & 3 deletions lib/WindowManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,20 @@ namespace Gala {
public abstract Meta.BackgroundGroup background_group { get; protected set; }

/**
* Enters the modal mode, which means that all events are directed to the stage instead
* of the windows. This is the only way to receive keyboard events besides shortcut listeners.
* Enters the modal mode, which will block keybindings and gestures. See {@link ModalProxy} for
* how to allow certain gestures and keybindings.
* If {@link grab} is true all events will be redirected to the given {@link Clutter.Actor}.
* If {@link grab} is false other actors and shell windows may still receive events.
* Normal windows will never receive keyboard focus though they will still receive pointer events
* if {@link grab} is false and their {@link Meta.WindowActor} is visible.
*
* @param actor The actor to grab events for
* @param grab Whether to grab all events onto the actor
*
* @return a {@link ModalProxy} which is needed to end the modal mode again and provides some
* some basic control on the behavior of the window manager while it is in modal mode.
*/
public abstract ModalProxy push_modal (Clutter.Actor actor);
public abstract ModalProxy push_modal (Clutter.Actor actor, bool grab);

/**
* May exit the modal mode again, unless another component has called {@link push_modal}
Expand Down
2 changes: 1 addition & 1 deletion plugins/pip/SelectionArea.vala
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public class Gala.Plugins.PIP.SelectionArea : CanvasActor {
wm.get_display ().set_cursor (Meta.Cursor.CROSSHAIR);
grab_key_focus ();

modal_proxy = wm.push_modal (this);
modal_proxy = wm.push_modal (this, true);
}

private void get_selection_rectangle (out int x, out int y, out int width, out int height) {
Expand Down
4 changes: 0 additions & 4 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,14 @@ src/ShellClients/NotificationsClient.vala
src/ShellClients/PanelWindow.vala
src/ShellClients/ShellClientsManager.vala
src/Widgets/DwellClickTimer.vala
src/Widgets/MultitaskingView/IconGroup.vala
src/Widgets/MultitaskingView/IconGroupContainer.vala
src/Widgets/MultitaskingView/MonitorClone.vala
src/Widgets/MultitaskingView/MultitaskingView.vala
src/Widgets/MultitaskingView/StaticWindowClone.vala
src/Widgets/MultitaskingView/StaticWindowContainer.vala
src/Widgets/MultitaskingView/Tooltip.vala
src/Widgets/MultitaskingView/WindowClone.vala
src/Widgets/MultitaskingView/WindowCloneContainer.vala
src/Widgets/MultitaskingView/WindowIconActor.vala
src/Widgets/MultitaskingView/WorkspaceClone.vala
src/Widgets/MultitaskingView/WorkspaceInsertThumb.vala
src/Widgets/MultitaskingView/WorkspaceRow.vala
src/Widgets/PixelPicker.vala
src/Widgets/PointerLocator.vala
Expand Down
6 changes: 6 additions & 0 deletions protocol/pantheon-desktop-shell-v1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@

<arg name="hide_mode" type="uint" enum="hide_mode" summary="hide mode"/>
</request>

<request name="request_visible_in_multitasking_view">
<description summary="request visible in multitasking view">
Tell the shell that the panel would like to be visible in the multitasking view.
</description>
</request>
</interface>

<interface name="io_elementary_pantheon_widget_v1" version="1">
Expand Down
3 changes: 3 additions & 0 deletions protocol/pantheon-desktop-shell.vapi
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ namespace Pantheon.Desktop {
public Focus focus;
public SetSize set_size;
public SetHideMode set_hide_mode;
public RequestVisibleInMultitaskingView request_visible_in_multitasking_view;
}

[CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "struct io_elementary_pantheon_widget_v1_interface")]
Expand Down Expand Up @@ -75,6 +76,8 @@ namespace Pantheon.Desktop {
[CCode (has_target = false, has_typedef = false)]
public delegate void SetHideMode (Wl.Client client, Wl.Resource resource, [CCode (type = "uint32_t")] HideMode hide_mode);
[CCode (has_target = false, has_typedef = false)]
public delegate void RequestVisibleInMultitaskingView (Wl.Client client, Wl.Resource resource);
[CCode (has_target = false, has_typedef = false)]
public delegate void SetKeepAbove (Wl.Client client, Wl.Resource resource);
[CCode (has_target = false, has_typedef = false)]
public delegate void MakeCentered (Wl.Client client, Wl.Resource resource);
Expand Down
13 changes: 13 additions & 0 deletions src/DBus.vala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ public class Gala.DBus {
public static void init (WindowManagerGala _wm, NotificationsManager notifications_manager, ScreenshotManager screenshot_manager) {
wm = _wm;

Bus.own_name (
SESSION, "io.elementary.gala", NONE,
(connection) => {
try {
connection.register_object ("/io/elementary/gala", WindowDragProvider.get_instance ());
} catch (Error e) {
warning (e.message);
}
},
() => {},
() => critical ("Could not acquire name")
);

Bus.own_name (BusType.SESSION, "org.pantheon.gala", BusNameOwnerFlags.NONE,
(connection) => {
if (instance == null)
Expand Down
24 changes: 18 additions & 6 deletions src/DesktopIntegration.vala
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,31 @@ public class Gala.DesktopIntegration : GLib.Object {
return (owned) returned_windows;
}

public void focus_window (uint64 uid) throws GLib.DBusError, GLib.IOError {
private Meta.Window find_window_by_uid (uint64 uid) throws IOError {
var apps = Gala.AppSystem.get_default ().get_running_apps ();
foreach (unowned var app in apps) {
foreach (weak Meta.Window window in app.get_windows ()) {
if (window.get_id () == uid) {
if (window.has_focus ()) {
notify_already_focused (window);
} else {
window.get_workspace ().activate_with_focus (window, wm.get_display ().get_current_time ());
}
return window;
}
}
}

throw new IOError.NOT_FOUND ("Window with UID " + uid.to_string () + " not found");
}

public void focus_window (uint64 uid) throws GLib.DBusError, GLib.IOError {
var window = find_window_by_uid (uid);
if (window.has_focus ()) {
notify_already_focused (window);
} else {
window.get_workspace ().activate_with_focus (window, wm.get_display ().get_current_time ());
}
}

public void move_window_to_workspace (uint64 uid, int index) throws DBusError, IOError {
var window = find_window_by_uid (uid);
window.change_workspace_by_index (index, false);
}

public void activate_workspace (int index) throws GLib.DBusError, GLib.IOError {
Expand Down
66 changes: 66 additions & 0 deletions src/InternalUtils.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Gala {
public enum InputArea {
NONE,
FULLSCREEN,
MULTITASKING_VIEW,
DEFAULT
}

Expand All @@ -32,6 +33,36 @@ namespace Gala {
rects = {rect};
break;

case InputArea.MULTITASKING_VIEW:
var shell_client_rect = ShellClientsManager.get_instance ().get_shell_client_rect ();

int width, height;
display.get_size (out width, out height);

if (shell_client_rect != null) {
X.Xrectangle left_rect = {0, 0, (ushort) shell_client_rect.x, (ushort) height};
X.Xrectangle right_rect = {
(short) (shell_client_rect.x + shell_client_rect.width), 0,
(ushort) (width - shell_client_rect.x - shell_client_rect.width), (ushort) height
};
X.Xrectangle top_rect = {
(short) shell_client_rect.x, 0,
(ushort) shell_client_rect.width, (ushort) shell_client_rect.y
};
X.Xrectangle bottom_rect = {
(short) shell_client_rect.x,
(short) (shell_client_rect.y + shell_client_rect.height),
(ushort) shell_client_rect.width,
(ushort) (height - shell_client_rect.y - shell_client_rect.height)
};
rects = {left_rect, right_rect, top_rect, bottom_rect};
} else {
X.Xrectangle rect = {0, 0, (ushort)width, (ushort)height};
rects = {rect};
}

break;

case InputArea.DEFAULT:
// add plugin's requested areas
foreach (var rect in PluginManager.get_default ().get_regions ()) {
Expand Down Expand Up @@ -159,5 +190,40 @@ namespace Gala {
var is_in_fullscreen = display.get_monitor_in_fullscreen (primary_monitor);
return !Meta.Util.is_wayland_compositor () && is_in_fullscreen;
}

/**
* Returns the most recently used "normal" window (as gotten via {@link get_window_is_normal}) in the given workspace.
* If there is a not normal but more recent window (e.g. a menu/tooltip) any_window will be set to that window otherwise
* it will be set to the same window that is returned.
*/
public static Meta.Window? get_mru_window (Meta.Workspace workspace, out Meta.Window? any_window = null) {
any_window = null;

var list = workspace.list_windows ();

if (list.is_empty ()) {
return null;
}

list.sort ((a, b) => {
return (int) b.get_user_time () - (int) a.get_user_time ();
});

foreach (var window in list) {
if (!ShellClientsManager.get_instance ().is_positioned_window (window)) {
if (any_window == null) {
any_window = window;
}

if (!Utils.get_window_is_normal (window)) {
continue;
}

return window;
}
}

return null;
}
}
}
18 changes: 18 additions & 0 deletions src/PantheonShell.vala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace Gala {
focus_panel,
set_size,
set_hide_mode,
request_visible_in_multitasking_view,
};

wayland_pantheon_widget_interface = {
Expand Down Expand Up @@ -292,6 +293,23 @@ namespace Gala {
ShellClientsManager.get_instance ().set_hide_mode (window, hide_mode);
}

internal static void request_visible_in_multitasking_view (Wl.Client client, Wl.Resource resource) {
unowned PanelSurface? panel_surface = resource.get_user_data<PanelSurface> ();
if (panel_surface.wayland_surface == null) {
warning ("Window tried to set visible in multitasking view but wayland surface is null.");
return;
}

Meta.Window? window;
panel_surface.wayland_surface.get ("window", out window, null);
if (window == null) {
warning ("Window tried to set visible in multitasking view but wayland surface had no associated window.");
return;
}

ShellClientsManager.get_instance ().request_visible_in_multitasking_view (window);
}

internal static void set_keep_above (Wl.Client client, Wl.Resource resource) {
unowned ExtendedBehaviorSurface? eb_surface = resource.get_user_data<ExtendedBehaviorSurface> ();
if (eb_surface.wayland_surface == null) {
Expand Down
9 changes: 7 additions & 2 deletions src/ShellClients/HideTracker.vala
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ public class Gala.HideTracker : Object {
focus_maximized_overlap = false;
fullscreen_overlap = display.get_monitor_in_fullscreen (panel.window.get_monitor ());

foreach (var window in display.get_workspace_manager ().get_active_workspace ().list_windows ()) {
unowned var active_workspace = display.get_workspace_manager ().get_active_workspace ();

Meta.Window? normal_mru_window, any_mru_window;
normal_mru_window = InternalUtils.get_mru_window (active_workspace, out any_mru_window);

foreach (var window in active_workspace.list_windows ()) {
if (window == panel.window) {
continue;
}
Expand All @@ -173,7 +178,7 @@ public class Gala.HideTracker : Object {

overlap = true;

if (window != display.focus_window) {
if (window != normal_mru_window && window != any_mru_window) {
continue;
}

Expand Down
5 changes: 5 additions & 0 deletions src/ShellClients/PanelWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public class Gala.PanelWindow : ShellWindow, RootTarget {
hide_tracker.show.connect (show);
}

public void request_visible_in_multitasking_view () {
visible_in_multitasking_view = true;
actor.add_action (new DragDropAction (DESTINATION, "multitaskingview-window"));
}

private void hide () {
gesture_controller.goto (1);
}
Expand Down
22 changes: 22 additions & 0 deletions src/ShellClients/ShellClientsManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,15 @@ public class Gala.ShellClientsManager : Object, GestureTarget {
panel_windows[window].hide_mode = hide_mode;
}

public void request_visible_in_multitasking_view (Meta.Window window) {
if (!(window in panel_windows)) {
warning ("Set anchor for window before visible in mutltiasking view.");
return;
}

panel_windows[window].request_visible_in_multitasking_view ();
}

public void make_centered (Meta.Window window) requires (!is_itself_positioned (window)) {
positioned_windows[window] = new ShellWindow (window, CENTER);

Expand Down Expand Up @@ -290,6 +299,10 @@ public class Gala.ShellClientsManager : Object, GestureTarget {
}
break;

case "visible-in-multitasking-view":
request_visible_in_multitasking_view (window);
break;

case "centered":
make_centered (window);
break;
Expand All @@ -309,4 +322,13 @@ public class Gala.ShellClientsManager : Object, GestureTarget {
requires (window in panel_windows) {
panel_windows[window].restore_previous_x11_region = true;
}

public Mtk.Rectangle? get_shell_client_rect () {
foreach (var client in panel_windows.get_values ()) {
if (client.visible_in_multitasking_view) {
return client.get_custom_window_rect ();
}
}
return null;
}
}
Loading