Skip to content

Commit

Permalink
Add support for custom tab-enabled applications
Browse files Browse the repository at this point in the history
Resolves #8.

Signed-off-by: Artem Senichev <[email protected]>
  • Loading branch information
artemsen committed Oct 16, 2023
1 parent 0ba8f53 commit 5b09819
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 13 deletions.
70 changes: 57 additions & 13 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#define DEFAULT_LAYOUT 0
// Default ignored time between layout change and focus lost events
#define DEFAULT_TIMEOUT 50
// Default list of tab-enabled app IDs
#define DEFAULT_TABAPPS "firefox,chrome"

// Convert timespec to milliseconds
#define TIMESPEC_MS(ts) (ts.tv_sec * 1000 + ts.tv_nsec / 1000000)
Expand All @@ -25,6 +27,8 @@ struct context {
int current_layout; ///< Current layout index
int switch_timeout; ///< Ignored time between layout change and focus lost
struct timespec switch_timestamp; ///< Timestamp of the last layout change
char** tabapps;
size_t tabapps_num;
};
static struct context ctx = {
.last_window = INVALID_WINDOW,
Expand All @@ -40,12 +44,14 @@ static unsigned long window_id(int wnd_id, const char* app_id, const char* title

// 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++;
for (size_t i = 0; i < ctx.tabapps_num; ++i) {
if (strcmp(app_id, ctx.tabapps[i]) == 0) {
// djb2 hash
id = 5381;
while (*title) {
id = ((id << 5) + id) + *title++;
}
break;
}
}

Expand Down Expand Up @@ -114,6 +120,36 @@ static void on_layout_change(int layout)
clock_gettime(CLOCK_MONOTONIC, &ctx.switch_timestamp);
}

/** Set list of tab-enabled app IDs from command line arument. */
static void set_tabapps(const char* ids)
{
size_t size;

// get number of app ids
size = 1;
for(const char* ptr = ids; *ptr; ++ptr) {
if (*ptr == ',') {
++size;
}
}

// split into array
ctx.tabapps = malloc(size * sizeof(char*));
for(const char* ptr = ids; ; ++ptr) {
if (!*ptr || *ptr == ',') {
const size_t len = ptr - ids;
char* id = malloc(len + 1 /* last null */);
memcpy(id, ids, len);
id[len] = 0;
ids = ptr + 1;
ctx.tabapps[ctx.tabapps_num++] = id;
if (!*ptr) {
break;
}
}
}
}

/**
* Application entry point.
*/
Expand All @@ -122,11 +158,12 @@ int main(int argc, char* argv[])
const struct option long_opts[] = {
{ "default", required_argument, NULL, 'd' },
{ "timeout", required_argument, NULL, 't' },
{ "tabapps", required_argument, NULL, 'a' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
const char* short_opts = "d:t:vh";
const char* short_opts = "d:t:a:vh";

opterr = 0; // prevent native error messages

Expand All @@ -137,29 +174,32 @@ int main(int argc, char* argv[])
case 'd':
ctx.default_layout = atoi(optarg);
if (ctx.default_layout < -1 || ctx.default_layout > 0xffff) {
fprintf(stderr, "Invalid default layout: %s\n",
argv[optind - 1]);
fprintf(stderr, "Invalid default layout: %s\n", optarg);
return EXIT_FAILURE;
}
break;
case 't':
ctx.switch_timeout = atoi(optarg);
if (ctx.switch_timeout < 0) {
fprintf(stderr, "Invalid timeout value: %s\n",
argv[optind - 1]);
fprintf(stderr, "Invalid timeout value: %s\n", optarg);
return EXIT_FAILURE;
}
break;
case 'a':
set_tabapps(optarg);
break;
case 'v':
printf("swaykbdd version " VERSION ".\n");
return EXIT_SUCCESS;
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 "
printf(" -d, --default=ID Default layout for new windows "
"[%i]\n", DEFAULT_LAYOUT);
printf(" -t, --timeout MS Delay between switching and "
printf(" -t, --timeout=MS Delay between switching and "
"saving layout [%i ms]\n", DEFAULT_TIMEOUT);
printf(" -a, --tabapps=IDS List of tab-enabled app IDs "
"[" DEFAULT_TABAPPS "]\n");
printf(" -v, --version Print version info and exit\n");
printf(" -h, --help Print this help and exit\n");
return EXIT_SUCCESS;
Expand All @@ -173,5 +213,9 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}

if (ctx.tabapps_num == 0) {
set_tabapps(DEFAULT_TABAPPS);
}

return sway_monitor(on_focus_change, on_window_close, on_layout_change);
}
3 changes: 3 additions & 0 deletions swaykbdd.1
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ windows (currently active layout will be used instead).
.IP "\fB\-t\fR, \fB\-\-timeout\fR\fB=\fR\fIMS\fR"
Ignored time between layout change and focus lost events, in milliseconds. The
default value is 50.
.IP "\fB\-a\fR, \fB\-\-tabapps\fR\fB=\fR\fIIDS\fR"
A comma-separated list of tab-enabled application IDs, for which each tab will
have its own keyboard layout. The default value is "firefox,chrome"
.SH ENVIRONMENT
.IP \fISWAYSOCK\fR
Path to the socket file used for Sway IPC.
Expand Down

0 comments on commit 5b09819

Please sign in to comment.