ipc-server: add get_cursor IPC command that returns cursor position and information about the node under it

This commit is contained in:
OXDBXKXO 2025-06-25 23:44:33 +02:00
parent c2f08075ec
commit 495ba1e96e
3 changed files with 167 additions and 0 deletions

View file

@ -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),

View file

@ -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"
@ -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"
@ -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);

View file

@ -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
@ -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