194 lines
4.1 KiB
C
194 lines
4.1 KiB
C
|
|
/*
|
||
|
|
* DWN - Desktop Window Manager
|
||
|
|
* retoor <retoor@molodetz.nl>
|
||
|
|
* Window marks implementation
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "marks.h"
|
||
|
|
#include "client.h"
|
||
|
|
#include "workspace.h"
|
||
|
|
#include "notifications.h"
|
||
|
|
#include "util.h"
|
||
|
|
|
||
|
|
#include <string.h>
|
||
|
|
#include <ctype.h>
|
||
|
|
|
||
|
|
typedef enum {
|
||
|
|
MARKS_MODE_NONE,
|
||
|
|
MARKS_MODE_SET,
|
||
|
|
MARKS_MODE_GOTO
|
||
|
|
} MarksMode;
|
||
|
|
|
||
|
|
static Client *marked_clients[MAX_MARKS];
|
||
|
|
static MarksMode current_mode = MARKS_MODE_NONE;
|
||
|
|
|
||
|
|
void marks_init(void)
|
||
|
|
{
|
||
|
|
memset(marked_clients, 0, sizeof(marked_clients));
|
||
|
|
current_mode = MARKS_MODE_NONE;
|
||
|
|
LOG_INFO("Window marks system initialized");
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_cleanup(void)
|
||
|
|
{
|
||
|
|
marks_clear_all();
|
||
|
|
}
|
||
|
|
|
||
|
|
static int mark_to_index(char mark)
|
||
|
|
{
|
||
|
|
char lower = (char)tolower((unsigned char)mark);
|
||
|
|
if (lower >= 'a' && lower <= 'z') {
|
||
|
|
return lower - 'a';
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_set(char mark, Client *client)
|
||
|
|
{
|
||
|
|
int idx = mark_to_index(mark);
|
||
|
|
if (idx < 0 || client == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < MAX_MARKS; i++) {
|
||
|
|
if (marked_clients[i] == client) {
|
||
|
|
marked_clients[i] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
marked_clients[idx] = client;
|
||
|
|
|
||
|
|
char msg[128];
|
||
|
|
snprintf(msg, sizeof(msg), "Window marked as '%c'", mark);
|
||
|
|
notification_show("DWN Marks", "Mark Set", msg, NULL, 1500);
|
||
|
|
|
||
|
|
LOG_DEBUG("Set mark '%c' for window '%s'", mark, client->title);
|
||
|
|
}
|
||
|
|
|
||
|
|
Client *marks_get(char mark)
|
||
|
|
{
|
||
|
|
int idx = mark_to_index(mark);
|
||
|
|
if (idx < 0) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
return marked_clients[idx];
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_clear(char mark)
|
||
|
|
{
|
||
|
|
int idx = mark_to_index(mark);
|
||
|
|
if (idx >= 0) {
|
||
|
|
marked_clients[idx] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_clear_all(void)
|
||
|
|
{
|
||
|
|
memset(marked_clients, 0, sizeof(marked_clients));
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_remove_client(Client *client)
|
||
|
|
{
|
||
|
|
if (client == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < MAX_MARKS; i++) {
|
||
|
|
if (marked_clients[i] == client) {
|
||
|
|
marked_clients[i] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool marks_is_waiting_for_mark(void)
|
||
|
|
{
|
||
|
|
return current_mode == MARKS_MODE_SET;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool marks_is_waiting_for_goto(void)
|
||
|
|
{
|
||
|
|
return current_mode == MARKS_MODE_GOTO;
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_start_set_mode(void)
|
||
|
|
{
|
||
|
|
Workspace *ws = workspace_get_current();
|
||
|
|
if (ws == NULL || ws->focused == NULL) {
|
||
|
|
notification_show("DWN Marks", "No Window",
|
||
|
|
"Focus a window first to set a mark", NULL, 2000);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
current_mode = MARKS_MODE_SET;
|
||
|
|
notification_show("DWN Marks", "Set Mark",
|
||
|
|
"Press a-z to set mark for this window", NULL, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_start_goto_mode(void)
|
||
|
|
{
|
||
|
|
current_mode = MARKS_MODE_GOTO;
|
||
|
|
notification_show("DWN Marks", "Go to Mark",
|
||
|
|
"Press a-z to jump to marked window", NULL, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void marks_cancel_mode(void)
|
||
|
|
{
|
||
|
|
if (current_mode != MARKS_MODE_NONE) {
|
||
|
|
current_mode = MARKS_MODE_NONE;
|
||
|
|
notification_close_all();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool marks_handle_key(char key)
|
||
|
|
{
|
||
|
|
if (current_mode == MARKS_MODE_NONE) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
char lower = (char)tolower((unsigned char)key);
|
||
|
|
if (lower < 'a' || lower > 'z') {
|
||
|
|
marks_cancel_mode();
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
notification_close_all();
|
||
|
|
|
||
|
|
if (current_mode == MARKS_MODE_SET) {
|
||
|
|
Workspace *ws = workspace_get_current();
|
||
|
|
if (ws != NULL && ws->focused != NULL) {
|
||
|
|
marks_set(lower, ws->focused);
|
||
|
|
}
|
||
|
|
} else if (current_mode == MARKS_MODE_GOTO) {
|
||
|
|
Client *c = marks_get(lower);
|
||
|
|
if (c != NULL) {
|
||
|
|
if (c->workspace != (unsigned int)dwn->current_workspace) {
|
||
|
|
workspace_switch((int)c->workspace);
|
||
|
|
}
|
||
|
|
client_focus(c, true);
|
||
|
|
client_raise(c);
|
||
|
|
} else {
|
||
|
|
char msg[64];
|
||
|
|
snprintf(msg, sizeof(msg), "No window marked as '%c'", lower);
|
||
|
|
notification_show("DWN Marks", "Mark Not Found", msg, NULL, 1500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
current_mode = MARKS_MODE_NONE;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
char marks_get_mark_for_client(Client *client)
|
||
|
|
{
|
||
|
|
if (client == NULL) {
|
||
|
|
return '\0';
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < MAX_MARKS; i++) {
|
||
|
|
if (marked_clients[i] == client) {
|
||
|
|
return (char)('a' + i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return '\0';
|
||
|
|
}
|