Skip to content
Open
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
1 change: 1 addition & 0 deletions completions/fish/swaymsg.fish
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ complete -c swaymsg -s t -l type -fra 'get_binding_modes' --description "Gets a
complete -c swaymsg -s t -l type -fra 'get_binding_state' --description "Get JSON-encoded info about the current binding state."
complete -c swaymsg -s t -l type -fra 'get_config' --description "Gets a JSON-encoded copy of the current configuration."
complete -c swaymsg -s t -l type -fra 'get_seats' --description "Gets a JSON-encoded list of all seats, its properties and all assigned devices."
complete -c swaymsg -s t -l type -fra 'get_cursor' --description "Get JSON-encoded information about the current cursor position and the node under it."
complete -c swaymsg -s t -l type -fra 'send_tick' --description "Sends a tick event to all subscribed clients."
complete -c swaymsg -s t -l type -fra 'subscribe' --description "Subscribe to a list of event types."
1 change: 1 addition & 0 deletions completions/zsh/_swaymsg
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ types=(
'get_binding_modes'
'get_binding_state'
'get_config'
'get_cursor'
'send_tick'
'subscribe'
)
Expand Down
1 change: 1 addition & 0 deletions include/ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum ipc_command_type {
// sway-specific command types
IPC_GET_INPUTS = 100,
IPC_GET_SEATS = 101,
IPC_GET_CURSOR = 102,

// Events sent from sway to clients. Events have the highest bits set.
IPC_EVENT_WORKSPACE = ((1<<31) | 0),
Expand Down
98 changes: 98 additions & 0 deletions sway/ipc-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <sys/un.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_cursor.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/desktop/transaction.h"
Expand All @@ -24,9 +25,12 @@
#include "sway/input/input-manager.h"
#include "sway/input/keyboard.h"
#include "sway/input/seat.h"
#include "sway/input/cursor.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "sway/tree/node.h"
#include "sway/tree/container.h"
#include "list.h"
#include "log.h"
#include "util.h"
Expand Down Expand Up @@ -811,6 +815,100 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
goto exit_cleanup;
}

case IPC_GET_CURSOR:
{
json_object *cursor_info = json_object_new_object();
struct sway_seat *seat = input_manager_get_default_seat();

if (seat && seat->cursor) {
json_object_object_add(cursor_info, "x",
json_object_new_int((int)seat->cursor->cursor->x));
json_object_object_add(cursor_info, "y",
json_object_new_int((int)seat->cursor->cursor->y));

struct wlr_surface *surface = NULL;
double sx, sy;
struct sway_node *node = node_at_coords(seat,
seat->cursor->cursor->x, seat->cursor->cursor->y, &surface, &sx, &sy);

if (node) {
const char *node_type_str;
switch (node->type) {
case N_ROOT:
node_type_str = "root";
break;
case N_OUTPUT:
node_type_str = "output";
break;
case N_WORKSPACE:
node_type_str = "workspace";
break;
case N_CONTAINER:
node_type_str = "con";
break;
default:
node_type_str = "none";
break;
}

json_object_object_add(cursor_info, "node_type",
json_object_new_string(node_type_str));

// Node-specific information
if (node->type == N_CONTAINER) {
json_object_object_add(cursor_info, "surface_x",
json_object_new_int((int)sx));
json_object_object_add(cursor_info, "surface_y",
json_object_new_int((int)sy));

struct sway_container *container = node->sway_container;
if (container->title) {
json_object_object_add(cursor_info, "window_title",
json_object_new_string(container->title));
}
if (container->view) {
// Handle both XDG and XWayland views
const char *app_id = NULL;
if (container->view->type == SWAY_VIEW_XDG_SHELL) {
app_id = view_get_app_id(container->view);
}
#if WLR_HAS_XWAYLAND
else if (container->view->type == SWAY_VIEW_XWAYLAND) {
app_id = view_get_class(container->view);
}
#endif

if (app_id) {
json_object_object_add(cursor_info, "app_id",
json_object_new_string(app_id));
}

if (container->view->pid > 0) {
json_object_object_add(cursor_info, "pid",
json_object_new_int(container->view->pid));
}
}

if (container->pending.workspace && container->pending.workspace->name) {
json_object_object_add(cursor_info, "workspace_name",
json_object_new_string(container->pending.workspace->name));
}
} else if (node->type == N_WORKSPACE) {
struct sway_workspace *workspace = node->sway_workspace;
if (workspace->name) {
json_object_object_add(cursor_info, "workspace_name",
json_object_new_string(workspace->name));
}
}
}
}

const char *json_string = json_object_to_json_string(cursor_info);
ipc_send_reply(client, payload_type, json_string, (uint32_t)strlen(json_string));
json_object_put(cursor_info);
break;
}

case IPC_GET_TREE:
{
json_object *tree = ipc_json_describe_node_recursive(&root->node);
Expand Down
68 changes: 68 additions & 0 deletions sway/sway-ipc.7.scd
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ supported. *For all replies, any properties not listed are subject to removal.*
|- 101
: GET_SEATS
: Get the list of seats
|- 102
: GET_CURSOR
: Get the current cursor position and information about the element under it

## 0. RUN_COMMAND

Expand Down Expand Up @@ -1458,6 +1461,71 @@ one seat. Each object has the following properties:
]
```

## 102. GET_CURSOR

*MESSAGE*++
Retrieve the current cursor position and information about the element under it

*REPLY*++
An object containing the following properties:

[- *PROPERTY*
:- *DATA TYPE*
:- *DESCRIPTION*
|- x
: integer
:[ The x coordinate of the cursor (absolute screen coordinates)
|- y
: integer
: The y coordinate of the cursor (absolute screen coordinates)
|- surface_x
: integer
: The x coordinate of the cursor relative to the surface under it (only available when over a container)
|- surface_y
: integer
: The y coordinate of the cursor relative to the surface under it (only available when over a container)
|- node_type
: string
: The type of the node under the cursor (e.g., "con", "workspace", "output")
|- window_title
: string
: The title of the window under the cursor (if applicable)
|- app_id
: string
: The application ID of the window under the cursor (if applicable)
|- workspace_name
: string
: The name of the workspace under the cursor (if applicable)
|- pid
: integer
: The process ID of the application under the cursor (if applicable)


*Example Reply (cursor over container):*
```
{
"x": 1024,
"y": 768,
"surface_x": 24,
"surface_y": 48,
"node_type": "con",
"window_title": "Terminal",
"app_id": "termite",
"workspace_name": "1",
"pid": 25370
}
```

*Example Reply (cursor over workspace):*
```
{
"x": 1024,
"y": 768,
"node_type": "workspace",
"workspace_name": "1"
}
```

# EVENTS

Events are a way for client to get notified of changes to sway. A client can
Expand Down
46 changes: 45 additions & 1 deletion swaymsg/main.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -377,6 +376,46 @@ static void pretty_print_tree(json_object *obj, int indent) {
}
}

static void pretty_print_cursor(json_object *c) {
json_object *x, *y, *surface_x, *surface_y, *node_type, *window_title, *app_id, *workspace_name, *pid;
json_object_object_get_ex(c, "x", &x);
json_object_object_get_ex(c, "y", &y);
json_object_object_get_ex(c, "surface_x", &surface_x);
json_object_object_get_ex(c, "surface_y", &surface_y);
json_object_object_get_ex(c, "node_type", &node_type);
json_object_object_get_ex(c, "window_title", &window_title);
json_object_object_get_ex(c, "app_id", &app_id);
json_object_object_get_ex(c, "workspace_name", &workspace_name);
json_object_object_get_ex(c, "pid", &pid);

printf("Cursor position: %d, %d",
json_object_get_int(x), json_object_get_int(y));

if (surface_x && surface_y) {
printf(" (relative: %d, %d)",
json_object_get_int(surface_x), json_object_get_int(surface_y));
}
printf("\n");

if (node_type) {
printf("Under cursor: %s", json_object_get_string(node_type));

if (workspace_name) {
printf(" \"%s\"", json_object_get_string(workspace_name));
}
if (window_title) {
printf(" - %s", json_object_get_string(window_title));
}
if (app_id) {
printf(" (%s)", json_object_get_string(app_id));
}
if (pid) {
printf(" [PID: %d]", json_object_get_int(pid));
}
printf("\n");
}
}

static void pretty_print(int type, json_object *resp) {
switch (type) {
case IPC_SEND_TICK:
Expand All @@ -390,6 +429,9 @@ static void pretty_print(int type, json_object *resp) {
case IPC_GET_TREE:
pretty_print_tree(resp, 0);
return;
case IPC_GET_CURSOR:
pretty_print_cursor(resp);
return;
case IPC_COMMAND:
case IPC_GET_WORKSPACES:
case IPC_GET_INPUTS:
Expand Down Expand Up @@ -518,6 +560,8 @@ int main(int argc, char **argv) {
type = IPC_GET_WORKSPACES;
} else if (strcasecmp(cmdtype, "get_seats") == 0) {
type = IPC_GET_SEATS;
} else if (strcasecmp(cmdtype, "get_cursor") == 0) {
type = IPC_GET_CURSOR;
} else if (strcasecmp(cmdtype, "get_inputs") == 0) {
type = IPC_GET_INPUTS;
} else if (strcasecmp(cmdtype, "get_outputs") == 0) {
Expand Down
3 changes: 3 additions & 0 deletions swaymsg/swaymsg.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ _swaymsg_ [options...] [message]
Gets a list of all seats,
its properties and all assigned devices.

*get\_cursor*
Gets the current cursor position and information about the element under it.

*get\_marks*
Get a JSON-encoded list of marks.

Expand Down