/** * Looking Glass * Copyright © 2017-2023 The Looking Glass Authors * 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" #include "common/util.h" #include #include #include #include #include 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 }; char path[sizeof(addr.sun_path)]; int pathLen; if ((pathLen = fread(path, 1, sizeof(path), fd)) <= 0) { 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; } strncpy(addr.sun_path, path, sizeof(addr.sun_path)); 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); if (wrote <= 0) { DEBUG_WARN("i3 IPC communication failure"); return; } buf += wrote; msgSize -= wrote; } 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; } }; X11WM X11WM_i3 = { .setup = wm_i3_setup, .init = wm_i3_init, .deinit = wm_i3_deinit, .setFullscreen = wm_i3_setFullscreen }; #endif