Skip to content

Commit

Permalink
Move window id generator from sway
Browse files Browse the repository at this point in the history
Allow to handle complex logic outside the Sway IPC handler.

Signed-off-by: Artem Senichev <[email protected]>
  • Loading branch information
artemsen committed Oct 16, 2023
1 parent 9bd3680 commit 0ba8f53
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 49 deletions.
38 changes: 31 additions & 7 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// Default layout for new windows
Expand All @@ -32,10 +33,30 @@ static struct context ctx = {
.switch_timeout = DEFAULT_TIMEOUT,
};

/* Generate unique window id. */
static unsigned long window_id(int wnd_id, const char* app_id, const char* title)
{
unsigned long id = wnd_id;

// check if the current container belongs to the web browser, we will
// use window title (which is a tab name) to generate unique id
if (app_id && title &&
(strcmp(app_id, "firefox") == 0 || strcmp(app_id, "chromium") == 0)) {
// djb2 hash
id = 5381;
while (*title) {
id = ((id << 5) + id) + *title++;
}
}

return id;
}

/** Focus change handler. */
static int on_focus_change(unsigned long window)
static int on_focus_change(int wnd_id, const char* app_id, const char* title)
{
int layout;
const unsigned long window = window_id(wnd_id, app_id, title);

// save current layout for previously focused window
if (ctx.last_window != INVALID_WINDOW &&
Expand Down Expand Up @@ -74,17 +95,20 @@ static int on_focus_change(unsigned long window)
}

/** Window close handler. */
static void on_window_close(unsigned long window)
static void on_window_close(int wnd_id, const char* app_id, const char* title)
{
const unsigned long window = window_id(wnd_id, app_id, title);

rm_layout(window);

if (window == ctx.last_window) {
// reset last window id to prevent saving layout for the closed window
ctx.last_window = INVALID_WINDOW;
}
}

/** Keyboard layout change handler. */
static void on_layout_change(unsigned long layout)
static void on_layout_change(int layout)
{
ctx.current_layout = layout;
clock_gettime(CLOCK_MONOTONIC, &ctx.switch_timestamp);
Expand Down Expand Up @@ -132,10 +156,10 @@ int main(int argc, char* argv[])
case 'h':
printf("Keyboard layout switcher for Sway.\n");
printf("Usage: %s [OPTION]\n", argv[0]);
printf(" -d, --default ID Default layout for new windows [%i]\n",
DEFAULT_LAYOUT);
printf(" -t, --timeout MS Delay between switching and saving layout [%i ms]\n",
DEFAULT_TIMEOUT);
printf(" -d, --default ID Default layout for new windows "
"[%i]\n", DEFAULT_LAYOUT);
printf(" -t, --timeout MS Delay between switching and "
"saving layout [%i ms]\n", DEFAULT_TIMEOUT);
printf(" -v, --version Print version info and exit\n");
printf(" -h, --help Print this help and exit\n");
return EXIT_SUCCESS;
Expand Down
65 changes: 29 additions & 36 deletions src/sway.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Copyright (C) 2020 Artem Senichev <[email protected]>

#include "sway.h"
#include "layouts.h"

#include <stdio.h>
#include <stdint.h>
Expand Down Expand Up @@ -213,43 +212,30 @@ static int ipc_change_layout(int sock, int layout)
}

/**
* Generate window Id from event message.
* Get container info from event message.
* @param[in] msg event message
* @return window Id
* @param[out] wnd_id identifier of currently focused window (container)
* @param[out] app_id application id
* @param[out] title title of the window
*/
static unsigned long window_id(struct json_object* msg)
static void container_info(struct json_object* msg, int* wnd_id,
const char** app_id, const char** title)
{
unsigned long wnd_id = INVALID_WINDOW;
const char* app_id = NULL;
const char* name = NULL;
struct json_object* cnt_node;
struct json_object* sub_node;

// parse message
if (json_object_object_get_ex(msg, "container", &cnt_node)) {
struct json_object* sub_node;
if (json_object_object_get_ex(cnt_node, "id", &sub_node)) {
wnd_id = json_object_get_int(sub_node);
}
if (json_object_object_get_ex(cnt_node, "app_id", &sub_node)) {
app_id = json_object_get_string(sub_node);
}
if (json_object_object_get_ex(cnt_node, "name", &sub_node)) {
name = json_object_get_string(sub_node);
}
if (!json_object_object_get_ex(msg, "container", &cnt_node)) {
return;
}

// check if the current container belongs to the web browser, we will
// use window title (which is a tab name) to generate unique id
if (app_id && name &&
(strcmp(app_id, "firefox") == 0 || strcmp(app_id, "chromium") == 0)) {
// djb2 hash
wnd_id = 5381;
while (*name) {
wnd_id = ((wnd_id << 5) + wnd_id) + *name++;
}
if (json_object_object_get_ex(cnt_node, "id", &sub_node)) {
*wnd_id = json_object_get_int(sub_node);
}
if (json_object_object_get_ex(cnt_node, "app_id", &sub_node)) {
*app_id = json_object_get_string(sub_node);
}
if (json_object_object_get_ex(cnt_node, "name", &sub_node)) {
*title = json_object_get_string(sub_node);
}

return wnd_id;
}

/**
Expand All @@ -270,7 +256,7 @@ static int layout_index(struct json_object* msg)
}
}
}
return INVALID_LAYOUT;
return -1;
}

int sway_monitor(on_focus fn_focus, on_close fn_close, on_layout fn_layout)
Expand All @@ -295,18 +281,25 @@ int sway_monitor(on_focus fn_focus, on_close fn_close, on_layout fn_layout)
} else {
struct json_object* event_node;
if (json_object_object_get_ex(msg, "change", &event_node)) {
int wnd_id = -1;
const char* app_id = "";
const char* title = "";
const char* event_name = json_object_get_string(event_node);
if (strcmp(event_name, "focus") == 0 ||
strcmp(event_name, "title") == 0) {
const unsigned long wid = window_id(msg);
const int layout = fn_focus(wid);
container_info(msg, &wnd_id, &app_id, &title);
const int layout = fn_focus(wnd_id, app_id, title);
if (layout >= 0) {
ipc_change_layout(sock, layout);
}
} else if (strcmp(event_name, "close") == 0) {
fn_close(window_id(msg));
container_info(msg, &wnd_id, &app_id, &title);
fn_close(wnd_id, app_id, title);
} else if (strcmp(event_name, "xkb_layout") == 0) {
fn_layout(layout_index(msg));
const int layout = layout_index(msg);
if (layout >= 0) {
fn_layout(layout);
}
}
}
json_object_put(msg);
Expand Down
16 changes: 10 additions & 6 deletions src/sway.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,26 @@

/**
* Callback function: Window focus change handler.
* @param[in] window identifier of currently focused window (container)
* @return keyboard layout to set, -1 to leave current
* @param[in] wnd_id identifier of currently focused window (container)
* @param[in] app_id application id
* @param[in] title title of the window
* @return keyboard layout to set, -1 to leave the current one
*/
typedef int (*on_focus)(unsigned long window);
typedef int (*on_focus)(int wnd_id, const char* app_id, const char* title);

/**
* Callback function: Window close handler.
* @param[in] window identifier of closed window (container)
* @param[in] wnd_id identifier of currently focused window (container)
* @param[in] app_id application id
* @param[in] title title of the window
*/
typedef void (*on_close)(unsigned long window);
typedef void (*on_close)(int wnd_id, const char* app_id, const char* title);

/**
* Callback function: Keyboard layout change handler.
* @param[in] layout current keyboard layout index
*/
typedef void (*on_layout)(unsigned long layout);
typedef void (*on_layout)(int layout);

/**
* Connect to Sway IPC and start event monitoring.
Expand Down

0 comments on commit 0ba8f53

Please sign in to comment.