2023-09-11 15:19:06 +00:00
|
|
|
/**
|
|
|
|
* Looking Glass
|
2024-02-01 06:16:31 +00:00
|
|
|
* Copyright © 2017-2024 The Looking Glass Authors
|
2023-09-11 15:19:06 +00:00
|
|
|
* https://looking-glass.io
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _H_X11DS_WM_DEFAULT_
|
|
|
|
#define _H_X11DS_WM_DEFAULT_
|
|
|
|
|
|
|
|
#include "wm.h"
|
|
|
|
#include "x11.h"
|
|
|
|
#include "atoms.h"
|
|
|
|
#include "common/debug.h"
|
|
|
|
#include "common/option.h"
|
2023-09-11 16:03:24 +00:00
|
|
|
#include "common/util.h"
|
2023-09-11 15:19:06 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
static struct Option options[] =
|
|
|
|
{
|
|
|
|
// app options
|
|
|
|
{
|
|
|
|
.module = "i3",
|
|
|
|
.name = "globalFullScreen",
|
|
|
|
.description = "Use i3's global full screen feature (spans all monitors)",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct i3state
|
|
|
|
{
|
|
|
|
int sock;
|
|
|
|
bool globalFullScreen;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct i3state i3;
|
|
|
|
|
|
|
|
static void wm_i3_setup(void)
|
|
|
|
{
|
|
|
|
option_register(options);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool wm_i3_init(void)
|
|
|
|
{
|
|
|
|
memset(&i3, 0, sizeof(i3));
|
|
|
|
|
|
|
|
i3.globalFullScreen = option_get_bool("i3", "globalFullScreen");
|
|
|
|
|
|
|
|
FILE * fd = popen("i3 --get-socketpath", "r");
|
|
|
|
if (!fd)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
2023-11-11 02:47:43 +00:00
|
|
|
char * path = (char *)&addr.sun_path;
|
2023-09-11 15:19:06 +00:00
|
|
|
int pathLen;
|
2023-11-11 02:47:43 +00:00
|
|
|
if ((pathLen = fread(path, 1, sizeof(addr.sun_path), fd)) <= 0)
|
2023-09-11 15:19:06 +00:00
|
|
|
{
|
|
|
|
pclose(fd);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pclose(fd);
|
|
|
|
|
|
|
|
if(path[pathLen-1] == '\n')
|
|
|
|
--pathLen;
|
|
|
|
path[pathLen] = '\0';
|
|
|
|
|
|
|
|
i3.sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
if (i3.sock < 0)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to create socket for i3 IPC");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (connect(i3.sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to connect to the i3 IPC socket");
|
|
|
|
perror("connect");
|
|
|
|
goto err_socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_INFO("i3 IPC Connected");
|
|
|
|
return true;
|
|
|
|
|
|
|
|
err_socket:
|
|
|
|
close(i3.sock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wm_i3_deinit(void)
|
|
|
|
{
|
|
|
|
close(i3.sock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wm_i3_setFullscreen(bool enable)
|
|
|
|
{
|
|
|
|
if (!i3.globalFullScreen)
|
|
|
|
{
|
|
|
|
X11WM_Default.setFullscreen(enable);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct i3Msg
|
|
|
|
{
|
|
|
|
char magic[6];
|
|
|
|
uint32_t length;
|
|
|
|
uint32_t type;
|
|
|
|
char payload[0];
|
|
|
|
}
|
|
|
|
__attribute__((packed));
|
|
|
|
|
|
|
|
#define I3_IPC_TYPE_RUN_COMMAND 0
|
|
|
|
|
|
|
|
char cmd[128];
|
|
|
|
int cmdLen = snprintf(cmd, sizeof(cmd),
|
|
|
|
"[id=%lu] fullscreen toggle global",
|
|
|
|
x11.window);
|
|
|
|
|
|
|
|
struct i3Msg *msg = alloca(sizeof(struct i3Msg) + cmdLen);
|
|
|
|
memcpy(msg->magic, "i3-ipc", 6);
|
|
|
|
msg->length = cmdLen;
|
|
|
|
msg->type = I3_IPC_TYPE_RUN_COMMAND;
|
|
|
|
memcpy(msg->payload, cmd, cmdLen);
|
|
|
|
|
|
|
|
int msgSize = sizeof(*msg) + msg->length;
|
|
|
|
char * buf = (char *)msg;
|
|
|
|
while(msgSize)
|
|
|
|
{
|
|
|
|
int wrote = write(i3.sock, buf, msgSize);
|
2023-09-11 16:03:24 +00:00
|
|
|
if (wrote <= 0)
|
2023-09-11 15:19:06 +00:00
|
|
|
{
|
|
|
|
DEBUG_WARN("i3 IPC communication failure");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf += wrote;
|
|
|
|
msgSize -= wrote;
|
|
|
|
}
|
2023-09-11 16:03:24 +00:00
|
|
|
|
|
|
|
if ((msgSize = read(i3.sock, msg, sizeof(*msg))) < 0)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("i3 IPC read failure");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(msg->magic, "i3-ipc", 6) != 0 ||
|
|
|
|
msg->type != I3_IPC_TYPE_RUN_COMMAND)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("i3 IPC unexpected reply");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read and discard the payload
|
|
|
|
while(msg->length)
|
|
|
|
{
|
|
|
|
int len = read(i3.sock, cmd, min(msg->length, sizeof(cmd)));
|
|
|
|
if (len <= 0)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("i3 IPC failed to read payload");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
msg->length -= len;
|
|
|
|
}
|
2023-09-11 15:19:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
X11WM X11WM_i3 =
|
|
|
|
{
|
|
|
|
.setup = wm_i3_setup,
|
|
|
|
.init = wm_i3_init,
|
|
|
|
.deinit = wm_i3_deinit,
|
|
|
|
.setFullscreen = wm_i3_setFullscreen
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|