mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-22 03:02:17 +03:00
feature: create a miraclemsg subproject (#224)
This commit is contained in:
parent
7b5504ff69
commit
d24adc7f34
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13
|
||||
sudo apt install libmiral-dev libmircommon-internal-dev libmircommon-dev libmirserver-internal-dev \
|
||||
libgtest-dev libyaml-cpp-dev libglib2.0-dev libevdev-dev nlohmann-json3-dev libnotify-dev pcre2-utils \
|
||||
libmiroil-dev libmirrenderer-dev libgles2-mesa-dev libmirwayland-dev
|
||||
libmiroil-dev libmirrenderer-dev libgles2-mesa-dev libmirwayland-dev libjson-c-dev
|
||||
|
||||
sudo apt install mir-platform-graphics-virtual xwayland \
|
||||
mir-platform-graphics-gbm-kms mir-platform-rendering-egl-generic
|
||||
|
@ -139,3 +139,4 @@ if(SNAP_BUILD)
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests/)
|
||||
add_subdirectory(miraclemsg/)
|
||||
|
17
miraclemsg/CMakeLists.txt
Normal file
17
miraclemsg/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(JSONC json-c REQUIRED)
|
||||
|
||||
add_executable(miraclemsg
|
||||
ipc.h
|
||||
ipc_client.cpp ipc_client.h
|
||||
main.cpp)
|
||||
|
||||
target_include_directories(miraclemsg PUBLIC SYSTEM
|
||||
${JSONC_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(miraclemsg
|
||||
${JSONC_LDFLAGS})
|
||||
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/bin/miraclemsg
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
19
miraclemsg/LICENSE.sway
Normal file
19
miraclemsg/LICENSE.sway
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016-2017 Drew DeVault
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
4
miraclemsg/README.md
Normal file
4
miraclemsg/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# miraclemsg
|
||||
This is a fork of [swaymsg](https://github.com/swaywm/sway/tree/master/swaymsg).
|
||||
At the moment, it is a direct fork of that project without any changes, however
|
||||
we may augment the IPC with new calls in the future.
|
63
miraclemsg/ipc.h
Normal file
63
miraclemsg/ipc.h
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
Copyright (C) 2024 Matthew Kosarek
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Portions of this code originate from swaymsg, licensed under the MIT license.
|
||||
See the LICENSE.Sway file for details.
|
||||
**/
|
||||
|
||||
|
||||
#ifndef _SWAY_IPC_H
|
||||
#define _SWAY_IPC_H
|
||||
|
||||
#define event_mask(ev) (1 << (ev & 0x7F))
|
||||
|
||||
enum ipc_command_type
|
||||
{
|
||||
// i3 command types - see i3's I3_REPLY_TYPE constants
|
||||
IPC_COMMAND = 0,
|
||||
IPC_GET_WORKSPACES = 1,
|
||||
IPC_SUBSCRIBE = 2,
|
||||
IPC_GET_OUTPUTS = 3,
|
||||
IPC_GET_TREE = 4,
|
||||
IPC_GET_MARKS = 5,
|
||||
IPC_GET_BAR_CONFIG = 6,
|
||||
IPC_GET_VERSION = 7,
|
||||
IPC_GET_BINDING_MODES = 8,
|
||||
IPC_GET_CONFIG = 9,
|
||||
IPC_SEND_TICK = 10,
|
||||
IPC_SYNC = 11,
|
||||
IPC_GET_BINDING_STATE = 12,
|
||||
|
||||
// sway-specific command types
|
||||
IPC_GET_INPUTS = 100,
|
||||
IPC_GET_SEATS = 101,
|
||||
|
||||
// Events sent from sway to clients. Events have the highest bits set.
|
||||
IPC_EVENT_WORKSPACE = ((1 << 31) | 0),
|
||||
IPC_EVENT_OUTPUT = ((1 << 31) | 1),
|
||||
IPC_EVENT_MODE = ((1 << 31) | 2),
|
||||
IPC_EVENT_WINDOW = ((1 << 31) | 3),
|
||||
IPC_EVENT_BARCONFIG_UPDATE = ((1 << 31) | 4),
|
||||
IPC_EVENT_BINDING = ((1 << 31) | 5),
|
||||
IPC_EVENT_SHUTDOWN = ((1 << 31) | 6),
|
||||
IPC_EVENT_TICK = ((1 << 31) | 7),
|
||||
|
||||
// sway-specific event types
|
||||
IPC_EVENT_BAR_STATE_UPDATE = ((1 << 31) | 20),
|
||||
IPC_EVENT_INPUT = ((1 << 31) | 21),
|
||||
};
|
||||
|
||||
#endif
|
200
miraclemsg/ipc_client.cpp
Normal file
200
miraclemsg/ipc_client.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/**
|
||||
Copyright (C) 2024 Matthew Kosarek
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Portions of this code originate from swaymsg, licensed under the MIT license.
|
||||
See the LICENSE.Sway file for details.
|
||||
**/
|
||||
|
||||
#include "ipc_client.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char ipc_magic[] = { 'i', '3', '-', 'i', 'p', 'c' };
|
||||
|
||||
#define IPC_HEADER_SIZE (sizeof(ipc_magic) + 8)
|
||||
|
||||
char* get_socketpath(void)
|
||||
{
|
||||
const char* swaysock = getenv("SWAYSOCK");
|
||||
if (swaysock)
|
||||
{
|
||||
return strdup(swaysock);
|
||||
}
|
||||
char* line = NULL;
|
||||
size_t line_size = 0;
|
||||
FILE* fp = popen("sway --get-socketpath 2>/dev/null", "r");
|
||||
if (fp)
|
||||
{
|
||||
ssize_t nret = getline(&line, &line_size, fp);
|
||||
pclose(fp);
|
||||
if (nret > 0)
|
||||
{
|
||||
// remove trailing newline, if there is one
|
||||
if (line[nret - 1] == '\n')
|
||||
{
|
||||
line[nret - 1] = '\0';
|
||||
}
|
||||
return line;
|
||||
}
|
||||
}
|
||||
const char* i3sock = getenv("I3SOCK");
|
||||
if (i3sock)
|
||||
{
|
||||
free(line);
|
||||
return strdup(i3sock);
|
||||
}
|
||||
fp = popen("i3 --get-socketpath 2>/dev/null", "r");
|
||||
if (fp)
|
||||
{
|
||||
ssize_t nret = getline(&line, &line_size, fp);
|
||||
pclose(fp);
|
||||
if (nret > 0)
|
||||
{
|
||||
// remove trailing newline, if there is one
|
||||
if (line[nret - 1] == '\n')
|
||||
{
|
||||
line[nret - 1] = '\0';
|
||||
}
|
||||
return line;
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ipc_open_socket(const char* socket_path)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int socketfd;
|
||||
if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
std::cerr << "Unable to open Unix socket" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
|
||||
int l = sizeof(struct sockaddr_un);
|
||||
if (connect(socketfd, (struct sockaddr*)&addr, l) == -1)
|
||||
{
|
||||
std::cout << "Unable to connect to " << socket_path << std::endl;
|
||||
}
|
||||
return socketfd;
|
||||
}
|
||||
|
||||
bool ipc_set_recv_timeout(int socketfd, struct timeval tv)
|
||||
{
|
||||
if (setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
|
||||
{
|
||||
std::cerr << "Failed to set ipc recv timeout" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ipc_response* ipc_recv_response(int socketfd)
|
||||
{
|
||||
char data[IPC_HEADER_SIZE];
|
||||
|
||||
size_t total = 0;
|
||||
while (total < IPC_HEADER_SIZE)
|
||||
{
|
||||
ssize_t received = recv(socketfd, data + total, IPC_HEADER_SIZE - total, 0);
|
||||
if (received <= 0)
|
||||
{
|
||||
std::cerr << "Unable to receive IPC response" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
total += received;
|
||||
}
|
||||
|
||||
ipc_response* response = static_cast<ipc_response*>(malloc(sizeof(struct ipc_response)));
|
||||
if (!response)
|
||||
{
|
||||
std::cerr << "Unable to allocate memory for IPC response" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&response->size, data + sizeof(ipc_magic), sizeof(uint32_t));
|
||||
memcpy(&response->type, data + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t));
|
||||
|
||||
char* payload = (char*)malloc(response->size + 1);
|
||||
if (!payload)
|
||||
{
|
||||
goto error_2;
|
||||
}
|
||||
|
||||
total = 0;
|
||||
while (total < response->size)
|
||||
{
|
||||
ssize_t received = recv(socketfd, payload + total, response->size - total, 0);
|
||||
if (received < 0)
|
||||
{
|
||||
std::cerr << "Unable to receive IPC response" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
total += received;
|
||||
}
|
||||
payload[response->size] = '\0';
|
||||
response->payload = payload;
|
||||
|
||||
return response;
|
||||
error_2:
|
||||
free(response);
|
||||
error_1:
|
||||
std::cerr << "Unable to allocate memory for IPC response" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ipc_response(struct ipc_response* response)
|
||||
{
|
||||
free(response->payload);
|
||||
free(response);
|
||||
}
|
||||
|
||||
char* ipc_single_command(int socketfd, uint32_t type, const char* payload, uint32_t* len)
|
||||
{
|
||||
char data[IPC_HEADER_SIZE];
|
||||
memcpy(data, ipc_magic, sizeof(ipc_magic));
|
||||
memcpy(data + sizeof(ipc_magic), len, sizeof(*len));
|
||||
memcpy(data + sizeof(ipc_magic) + sizeof(*len), &type, sizeof(type));
|
||||
|
||||
if (write(socketfd, data, IPC_HEADER_SIZE) == -1)
|
||||
{
|
||||
std::cerr << "Unable to send IPC header" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (write(socketfd, payload, *len) == -1)
|
||||
{
|
||||
std::cerr << "Unable to send IPC payload" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
struct ipc_response* resp = ipc_recv_response(socketfd);
|
||||
char* response = resp->payload;
|
||||
*len = resp->size;
|
||||
free(resp);
|
||||
|
||||
return response;
|
||||
}
|
71
miraclemsg/ipc_client.h
Normal file
71
miraclemsg/ipc_client.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
Copyright (C) 2024 Matthew Kosarek
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Portions of this code originate from swaymsg, licensed under the MIT license.
|
||||
See the LICENSE.Sway file for details.
|
||||
**/
|
||||
|
||||
|
||||
#ifndef _SWAY_IPC_CLIENT_H
|
||||
#define _SWAY_IPC_CLIENT_H
|
||||
|
||||
// arbitrary number, it's probably sufficient, higher number = more memory usage
|
||||
#define JSON_MAX_DEPTH 512
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "ipc.h"
|
||||
|
||||
/**
|
||||
* IPC response including type of IPC response, size of payload and the json
|
||||
* encoded payload string.
|
||||
*/
|
||||
struct ipc_response
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t type;
|
||||
char* payload;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the path to the IPC socket from sway.
|
||||
*/
|
||||
char* get_socketpath(void);
|
||||
/**
|
||||
* Opens the sway socket.
|
||||
*/
|
||||
int ipc_open_socket(const char* socket_path);
|
||||
/**
|
||||
* Issues a single IPC command and returns the buffer. len will be updated with
|
||||
* the length of the buffer returned from sway.
|
||||
*/
|
||||
char* ipc_single_command(int socketfd, uint32_t type, const char* payload, uint32_t* len);
|
||||
/**
|
||||
* Receives a single IPC response and returns an ipc_response.
|
||||
*/
|
||||
struct ipc_response* ipc_recv_response(int socketfd);
|
||||
/**
|
||||
* Free ipc_response struct
|
||||
*/
|
||||
void free_ipc_response(struct ipc_response* response);
|
||||
/**
|
||||
* Sets the receive timeout for the IPC socket
|
||||
*/
|
||||
bool ipc_set_recv_timeout(int socketfd, struct timeval tv);
|
||||
|
||||
#endif
|
790
miraclemsg/main.cpp
Normal file
790
miraclemsg/main.cpp
Normal file
@ -0,0 +1,790 @@
|
||||
/**
|
||||
Copyright (C) 2024 Matthew Kosarek
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Portions of this code originate from swaymsg, licensed under the MIT license.
|
||||
See the LICENSE.Sway file for details.
|
||||
**/
|
||||
|
||||
#include "ipc_client.h"
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <json.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void sway_terminate(int exit_code)
|
||||
{
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
static bool success_object(json_object* result)
|
||||
{
|
||||
json_object* success;
|
||||
|
||||
if (!json_object_object_get_ex(result, "success", &success))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return json_object_get_boolean(success);
|
||||
}
|
||||
|
||||
// Iterate results array and return false if any of them failed
|
||||
static bool success(json_object* r, bool fallback)
|
||||
{
|
||||
if (!json_object_is_type(r, json_type_array))
|
||||
{
|
||||
if (json_object_is_type(r, json_type_object))
|
||||
{
|
||||
return success_object(r);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
size_t results_len = json_object_array_length(r);
|
||||
if (!results_len)
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < results_len; ++i)
|
||||
{
|
||||
json_object* result = json_object_array_get_idx(r, i);
|
||||
|
||||
if (!success_object(result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pretty_print_cmd(json_object* r)
|
||||
{
|
||||
if (!success_object(r))
|
||||
{
|
||||
json_object* error;
|
||||
if (!json_object_object_get_ex(r, "error", &error))
|
||||
{
|
||||
printf("An unknown error occurred");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: %s\n", json_object_get_string(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pretty_print_workspace(json_object* w)
|
||||
{
|
||||
json_object *name, *rect, *visible, *output, *urgent, *layout,
|
||||
*representation, *focused;
|
||||
json_object_object_get_ex(w, "name", &name);
|
||||
json_object_object_get_ex(w, "rect", &rect);
|
||||
json_object_object_get_ex(w, "visible", &visible);
|
||||
json_object_object_get_ex(w, "output", &output);
|
||||
json_object_object_get_ex(w, "urgent", &urgent);
|
||||
json_object_object_get_ex(w, "layout", &layout);
|
||||
json_object_object_get_ex(w, "representation", &representation);
|
||||
json_object_object_get_ex(w, "focused", &focused);
|
||||
printf(
|
||||
"Workspace %s%s%s%s\n"
|
||||
" Output: %s\n"
|
||||
" Layout: %s\n"
|
||||
" Representation: %s\n\n",
|
||||
json_object_get_string(name),
|
||||
json_object_get_boolean(focused) ? " (focused)" : "",
|
||||
!json_object_get_boolean(visible) ? " (off-screen)" : "",
|
||||
json_object_get_boolean(urgent) ? " (urgent)" : "",
|
||||
json_object_get_string(output),
|
||||
json_object_get_string(layout),
|
||||
json_object_get_string(representation));
|
||||
}
|
||||
|
||||
static const char* pretty_type_name(const char* name)
|
||||
{
|
||||
// TODO these constants probably belong in the common lib
|
||||
struct
|
||||
{
|
||||
const char* a;
|
||||
const char* b;
|
||||
} type_names[] = {
|
||||
{ "keyboard", "Keyboard" },
|
||||
{ "pointer", "Mouse" },
|
||||
{ "touchpad", "Touchpad" },
|
||||
{ "tablet_pad", "Tablet pad" },
|
||||
{ "tablet_tool", "Tablet tool" },
|
||||
{ "touch", "Touch" },
|
||||
{ "switch", "Switch" },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(type_names) / sizeof(type_names[0]); ++i)
|
||||
{
|
||||
if (strcmp(type_names[i].a, name) == 0)
|
||||
{
|
||||
return type_names[i].b;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static void pretty_print_input(json_object* i)
|
||||
{
|
||||
json_object *id, *name, *type, *product, *vendor, *kbdlayout, *libinput;
|
||||
json_object_object_get_ex(i, "identifier", &id);
|
||||
json_object_object_get_ex(i, "name", &name);
|
||||
json_object_object_get_ex(i, "type", &type);
|
||||
json_object_object_get_ex(i, "product", &product);
|
||||
json_object_object_get_ex(i, "vendor", &vendor);
|
||||
|
||||
const char* fmt = "Input device: %s\n"
|
||||
" Type: %s\n"
|
||||
" Identifier: %s\n"
|
||||
" Product ID: %d\n"
|
||||
" Vendor ID: %d\n";
|
||||
|
||||
printf(fmt, json_object_get_string(name),
|
||||
pretty_type_name(json_object_get_string(type)),
|
||||
json_object_get_string(id),
|
||||
json_object_get_int(product),
|
||||
json_object_get_int(vendor));
|
||||
|
||||
if (json_object_object_get_ex(i, "xkb_active_layout_name", &kbdlayout))
|
||||
{
|
||||
const char* layout = json_object_get_string(kbdlayout);
|
||||
printf(" Active Keyboard Layout: %s\n", layout ? layout : "(unnamed)");
|
||||
}
|
||||
|
||||
if (json_object_object_get_ex(i, "libinput", &libinput))
|
||||
{
|
||||
json_object* events;
|
||||
if (json_object_object_get_ex(libinput, "send_events", &events))
|
||||
{
|
||||
printf(" Libinput Send Events: %s\n",
|
||||
json_object_get_string(events));
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
char* join_args(char** argv, int argc)
|
||||
{
|
||||
int len = 0, i;
|
||||
for (i = 0; i < argc; ++i)
|
||||
{
|
||||
len += strlen(argv[i]) + 1;
|
||||
}
|
||||
char* res = (char*)malloc(len);
|
||||
len = 0;
|
||||
for (i = 0; i < argc; ++i)
|
||||
{
|
||||
strcpy(res + len, argv[i]);
|
||||
len += strlen(argv[i]);
|
||||
res[len++] = ' ';
|
||||
}
|
||||
res[len - 1] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
static void pretty_print_seat(json_object* i)
|
||||
{
|
||||
json_object *name, *capabilities, *devices;
|
||||
json_object_object_get_ex(i, "name", &name);
|
||||
json_object_object_get_ex(i, "capabilities", &capabilities);
|
||||
json_object_object_get_ex(i, "devices", &devices);
|
||||
|
||||
const char* fmt = "Seat: %s\n"
|
||||
" Capabilities: %d\n";
|
||||
|
||||
printf(fmt, json_object_get_string(name),
|
||||
json_object_get_int(capabilities));
|
||||
|
||||
size_t devices_len = json_object_array_length(devices);
|
||||
if (devices_len > 0)
|
||||
{
|
||||
printf(" Devices:\n");
|
||||
for (size_t i = 0; i < devices_len; ++i)
|
||||
{
|
||||
json_object* device = json_object_array_get_idx(devices, i);
|
||||
|
||||
json_object* device_name;
|
||||
json_object_object_get_ex(device, "name", &device_name);
|
||||
|
||||
printf(" %s\n", json_object_get_string(device_name));
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void pretty_print_output(json_object* o)
|
||||
{
|
||||
json_object *name, *rect, *focused, *active, *power, *ws, *current_mode, *non_desktop;
|
||||
json_object_object_get_ex(o, "name", &name);
|
||||
json_object_object_get_ex(o, "rect", &rect);
|
||||
json_object_object_get_ex(o, "focused", &focused);
|
||||
json_object_object_get_ex(o, "active", &active);
|
||||
json_object_object_get_ex(o, "power", &power);
|
||||
json_object_object_get_ex(o, "current_workspace", &ws);
|
||||
json_object_object_get_ex(o, "non_desktop", &non_desktop);
|
||||
json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
|
||||
*transform, *max_render_time, *adaptive_sync_status, *allow_tearing;
|
||||
json_object_object_get_ex(o, "make", &make);
|
||||
json_object_object_get_ex(o, "model", &model);
|
||||
json_object_object_get_ex(o, "serial", &serial);
|
||||
json_object_object_get_ex(o, "scale", &scale);
|
||||
json_object_object_get_ex(o, "scale_filter", &scale_filter);
|
||||
json_object_object_get_ex(o, "subpixel_hinting", &subpixel);
|
||||
json_object_object_get_ex(o, "transform", &transform);
|
||||
json_object_object_get_ex(o, "max_render_time", &max_render_time);
|
||||
json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status);
|
||||
json_object_object_get_ex(o, "allow_tearing", &allow_tearing);
|
||||
json_object *x, *y;
|
||||
json_object_object_get_ex(rect, "x", &x);
|
||||
json_object_object_get_ex(rect, "y", &y);
|
||||
json_object* modes;
|
||||
json_object_object_get_ex(o, "modes", &modes);
|
||||
json_object *width, *height, *refresh;
|
||||
json_object_object_get_ex(o, "current_mode", ¤t_mode);
|
||||
json_object_object_get_ex(current_mode, "width", &width);
|
||||
json_object_object_get_ex(current_mode, "height", &height);
|
||||
json_object_object_get_ex(current_mode, "refresh", &refresh);
|
||||
|
||||
if (json_object_get_boolean(non_desktop))
|
||||
{
|
||||
printf(
|
||||
"Output %s '%s %s %s' (non-desktop)\n",
|
||||
json_object_get_string(name),
|
||||
json_object_get_string(make),
|
||||
json_object_get_string(model),
|
||||
json_object_get_string(serial));
|
||||
}
|
||||
else if (json_object_get_boolean(active))
|
||||
{
|
||||
printf(
|
||||
"Output %s '%s %s %s'%s\n"
|
||||
" Current mode: %dx%d @ %.3f Hz\n"
|
||||
" Power: %s\n"
|
||||
" Position: %d,%d\n"
|
||||
" Scale factor: %f\n"
|
||||
" Scale filter: %s\n"
|
||||
" Subpixel hinting: %s\n"
|
||||
" Transform: %s\n"
|
||||
" Workspace: %s\n",
|
||||
json_object_get_string(name),
|
||||
json_object_get_string(make),
|
||||
json_object_get_string(model),
|
||||
json_object_get_string(serial),
|
||||
json_object_get_boolean(focused) ? " (focused)" : "",
|
||||
json_object_get_int(width),
|
||||
json_object_get_int(height),
|
||||
(double)json_object_get_int(refresh) / 1000,
|
||||
json_object_get_boolean(power) ? "on" : "off",
|
||||
json_object_get_int(x), json_object_get_int(y),
|
||||
json_object_get_double(scale),
|
||||
json_object_get_string(scale_filter),
|
||||
json_object_get_string(subpixel),
|
||||
json_object_get_string(transform),
|
||||
json_object_get_string(ws));
|
||||
|
||||
int max_render_time_int = json_object_get_int(max_render_time);
|
||||
printf(" Max render time: ");
|
||||
printf(max_render_time_int == 0 ? "off\n" : "%d ms\n", max_render_time_int);
|
||||
|
||||
printf(" Adaptive sync: %s\n",
|
||||
json_object_get_string(adaptive_sync_status));
|
||||
|
||||
printf(" Allow tearing: %s\n",
|
||||
json_object_get_boolean(allow_tearing) ? "yes" : "no");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(
|
||||
"Output %s '%s %s %s' (disabled)\n",
|
||||
json_object_get_string(name),
|
||||
json_object_get_string(make),
|
||||
json_object_get_string(model),
|
||||
json_object_get_string(serial));
|
||||
}
|
||||
|
||||
size_t modes_len = json_object_is_type(modes, json_type_array)
|
||||
? json_object_array_length(modes)
|
||||
: 0;
|
||||
if (modes_len > 0)
|
||||
{
|
||||
printf(" Available modes:\n");
|
||||
for (size_t i = 0; i < modes_len; ++i)
|
||||
{
|
||||
json_object* mode = json_object_array_get_idx(modes, i);
|
||||
|
||||
json_object *mode_width, *mode_height, *mode_refresh,
|
||||
*mode_picture_aspect_ratio;
|
||||
json_object_object_get_ex(mode, "width", &mode_width);
|
||||
json_object_object_get_ex(mode, "height", &mode_height);
|
||||
json_object_object_get_ex(mode, "refresh", &mode_refresh);
|
||||
json_object_object_get_ex(mode, "picture_aspect_ratio",
|
||||
&mode_picture_aspect_ratio);
|
||||
|
||||
printf(" %dx%d @ %.3f Hz", json_object_get_int(mode_width),
|
||||
json_object_get_int(mode_height),
|
||||
(double)json_object_get_int(mode_refresh) / 1000);
|
||||
if (mode_picture_aspect_ratio && strcmp("none", json_object_get_string(mode_picture_aspect_ratio)) != 0)
|
||||
{
|
||||
printf(" (%s)", json_object_get_string(mode_picture_aspect_ratio));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void pretty_print_version(json_object* v)
|
||||
{
|
||||
json_object* ver;
|
||||
json_object_object_get_ex(v, "human_readable", &ver);
|
||||
printf("sway version %s\n", json_object_get_string(ver));
|
||||
}
|
||||
|
||||
static void pretty_print_config(json_object* c)
|
||||
{
|
||||
json_object* config;
|
||||
json_object_object_get_ex(c, "config", &config);
|
||||
printf("%s\n", json_object_get_string(config));
|
||||
}
|
||||
|
||||
static void pretty_print_tree(json_object* obj, int indent)
|
||||
{
|
||||
for (int i = 0; i < indent; i++)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
int id = json_object_get_int(json_object_object_get(obj, "id"));
|
||||
const char* name = json_object_get_string(json_object_object_get(obj, "name"));
|
||||
const char* type = json_object_get_string(json_object_object_get(obj, "type"));
|
||||
const char* shell = json_object_get_string(json_object_object_get(obj, "shell"));
|
||||
|
||||
printf("#%d: %s \"%s\"", id, type, name);
|
||||
|
||||
if (shell != NULL)
|
||||
{
|
||||
int pid = json_object_get_int(json_object_object_get(obj, "pid"));
|
||||
const char* app_id = json_object_get_string(json_object_object_get(obj, "app_id"));
|
||||
json_object* window_props_obj = json_object_object_get(obj, "window_properties");
|
||||
const char* instance = json_object_get_string(json_object_object_get(window_props_obj, "instance"));
|
||||
const char* class_ = json_object_get_string(json_object_object_get(window_props_obj, "class"));
|
||||
int x11_id = json_object_get_int(json_object_object_get(obj, "window"));
|
||||
|
||||
printf(" (%s, pid: %d", shell, pid);
|
||||
if (app_id != NULL)
|
||||
{
|
||||
printf(", app_id: \"%s\"", app_id);
|
||||
}
|
||||
if (instance != NULL)
|
||||
{
|
||||
printf(", instance: \"%s\"", instance);
|
||||
}
|
||||
if (class_ != NULL)
|
||||
{
|
||||
printf(", class: \"%s\"", class_);
|
||||
}
|
||||
if (x11_id != 0)
|
||||
{
|
||||
printf(", X11 window: 0x%X", x11_id);
|
||||
}
|
||||
printf(")");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
json_object* nodes_obj = json_object_object_get(obj, "nodes");
|
||||
size_t len = json_object_array_length(nodes_obj);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
pretty_print_tree(json_object_array_get_idx(nodes_obj, i), indent + 1);
|
||||
}
|
||||
|
||||
json_object* floating_nodes_obj;
|
||||
json_bool floating_nodes = json_object_object_get_ex(obj, "floating_nodes", &floating_nodes_obj);
|
||||
if (floating_nodes)
|
||||
{
|
||||
size_t len = json_object_array_length(floating_nodes_obj);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
pretty_print_tree(json_object_array_get_idx(floating_nodes_obj, i), indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pretty_print(int type, json_object* resp)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case IPC_SEND_TICK:
|
||||
return;
|
||||
case IPC_GET_VERSION:
|
||||
pretty_print_version(resp);
|
||||
return;
|
||||
case IPC_GET_CONFIG:
|
||||
pretty_print_config(resp);
|
||||
return;
|
||||
case IPC_GET_TREE:
|
||||
pretty_print_tree(resp, 0);
|
||||
return;
|
||||
case IPC_COMMAND:
|
||||
case IPC_GET_WORKSPACES:
|
||||
case IPC_GET_INPUTS:
|
||||
case IPC_GET_OUTPUTS:
|
||||
case IPC_GET_SEATS:
|
||||
break;
|
||||
default:
|
||||
printf("%s\n", json_object_to_json_string_ext(resp, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
|
||||
return;
|
||||
}
|
||||
|
||||
json_object* obj;
|
||||
size_t len = json_object_array_length(resp);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
obj = json_object_array_get_idx(resp, i);
|
||||
switch (type)
|
||||
{
|
||||
case IPC_COMMAND:
|
||||
pretty_print_cmd(obj);
|
||||
break;
|
||||
case IPC_GET_WORKSPACES:
|
||||
pretty_print_workspace(obj);
|
||||
break;
|
||||
case IPC_GET_INPUTS:
|
||||
pretty_print_input(obj);
|
||||
break;
|
||||
case IPC_GET_OUTPUTS:
|
||||
pretty_print_output(obj);
|
||||
break;
|
||||
case IPC_GET_SEATS:
|
||||
pretty_print_seat(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
static bool quiet = false;
|
||||
static bool raw = false;
|
||||
static bool monitor = false;
|
||||
char* socket_path = NULL;
|
||||
char* cmdtype = NULL;
|
||||
|
||||
static const struct option long_options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "monitor", no_argument, NULL, 'm' },
|
||||
{ "pretty", no_argument, NULL, 'p' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "raw", no_argument, NULL, 'r' },
|
||||
{ "socket", required_argument, NULL, 's' },
|
||||
{ "type", required_argument, NULL, 't' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
const char* usage = "Usage: swaymsg [options] [message]\n"
|
||||
"\n"
|
||||
" -h, --help Show help message and quit.\n"
|
||||
" -m, --monitor Monitor until killed (-t SUBSCRIBE only)\n"
|
||||
" -p, --pretty Use pretty output even when not using a tty\n"
|
||||
" -q, --quiet Be quiet.\n"
|
||||
" -r, --raw Use raw output even if using a tty\n"
|
||||
" -s, --socket <socket> Use the specified socket.\n"
|
||||
" -t, --type <type> Specify the message type.\n"
|
||||
" -v, --version Show the version number and quit.\n";
|
||||
|
||||
raw = !isatty(STDOUT_FILENO);
|
||||
|
||||
int c;
|
||||
while (1)
|
||||
{
|
||||
int option_index = 0;
|
||||
c = getopt_long(argc, argv, "hmpqrs:t:v", long_options, &option_index);
|
||||
if (c == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
case 'm': // Monitor
|
||||
monitor = true;
|
||||
break;
|
||||
case 'p': // Pretty
|
||||
raw = false;
|
||||
break;
|
||||
case 'q': // Quiet
|
||||
quiet = true;
|
||||
break;
|
||||
case 'r': // Raw
|
||||
raw = true;
|
||||
break;
|
||||
case 's': // Socket
|
||||
socket_path = strdup(optarg);
|
||||
break;
|
||||
case 't': // Type
|
||||
cmdtype = strdup(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
printf("miraclemsg version 0.0.1\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s", usage);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmdtype)
|
||||
{
|
||||
cmdtype = strdup("command");
|
||||
}
|
||||
if (!socket_path)
|
||||
{
|
||||
socket_path = get_socketpath();
|
||||
if (!socket_path)
|
||||
{
|
||||
if (quiet)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
std::cerr << "Unable to retrieve socket path" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t type = IPC_COMMAND;
|
||||
|
||||
if (strcasecmp(cmdtype, "command") == 0)
|
||||
{
|
||||
type = IPC_COMMAND;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_workspaces") == 0)
|
||||
{
|
||||
type = IPC_GET_WORKSPACES;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_seats") == 0)
|
||||
{
|
||||
type = IPC_GET_SEATS;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_inputs") == 0)
|
||||
{
|
||||
type = IPC_GET_INPUTS;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_outputs") == 0)
|
||||
{
|
||||
type = IPC_GET_OUTPUTS;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_tree") == 0)
|
||||
{
|
||||
type = IPC_GET_TREE;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_marks") == 0)
|
||||
{
|
||||
type = IPC_GET_MARKS;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_bar_config") == 0)
|
||||
{
|
||||
type = IPC_GET_BAR_CONFIG;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_version") == 0)
|
||||
{
|
||||
type = IPC_GET_VERSION;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_binding_modes") == 0)
|
||||
{
|
||||
type = IPC_GET_BINDING_MODES;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_binding_state") == 0)
|
||||
{
|
||||
type = IPC_GET_BINDING_STATE;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "get_config") == 0)
|
||||
{
|
||||
type = IPC_GET_CONFIG;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "send_tick") == 0)
|
||||
{
|
||||
type = IPC_SEND_TICK;
|
||||
}
|
||||
else if (strcasecmp(cmdtype, "subscribe") == 0)
|
||||
{
|
||||
type = IPC_SUBSCRIBE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quiet)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
std::cerr << "Unknown message type: " << cmdtype << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
free(cmdtype);
|
||||
|
||||
if (monitor && type != IPC_SUBSCRIBE)
|
||||
{
|
||||
if (!quiet)
|
||||
{
|
||||
std::cerr << "Monitor can only be used with -t SUBSCRIBE" << std::endl;
|
||||
}
|
||||
free(socket_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* command = NULL;
|
||||
if (optind < argc)
|
||||
{
|
||||
command = join_args(argv + optind, argc - optind);
|
||||
}
|
||||
else
|
||||
{
|
||||
command = strdup("");
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
int socketfd = ipc_open_socket(socket_path);
|
||||
struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
|
||||
ipc_set_recv_timeout(socketfd, timeout);
|
||||
uint32_t len = strlen(command);
|
||||
char* resp = ipc_single_command(socketfd, type, command, &len);
|
||||
|
||||
// pretty print the json
|
||||
json_tokener* tok = json_tokener_new_ex(JSON_MAX_DEPTH);
|
||||
if (tok == NULL)
|
||||
{
|
||||
if (quiet)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
std::cerr << "failed allocating json_tokener" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
json_object* obj = json_tokener_parse_ex(tok, resp, -1);
|
||||
enum json_tokener_error err = json_tokener_get_error(tok);
|
||||
json_tokener_free(tok);
|
||||
if (obj == NULL || err != json_tokener_success)
|
||||
{
|
||||
if (!quiet)
|
||||
{
|
||||
std::cerr << "failed to parse payload as json: " << json_tokener_error_desc(err) << std::endl;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!success(obj, true))
|
||||
{
|
||||
ret = 2;
|
||||
}
|
||||
if (!quiet && (type != IPC_SUBSCRIBE || ret != 0))
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
printf("%s\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
|
||||
}
|
||||
else
|
||||
{
|
||||
pretty_print(type, obj);
|
||||
}
|
||||
}
|
||||
json_object_put(obj);
|
||||
}
|
||||
free(command);
|
||||
free(resp);
|
||||
|
||||
if (type == IPC_SUBSCRIBE && ret == 0)
|
||||
{
|
||||
// Remove the timeout for subscribed events
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
ipc_set_recv_timeout(socketfd, timeout);
|
||||
|
||||
do
|
||||
{
|
||||
struct ipc_response* reply = ipc_recv_response(socketfd);
|
||||
if (!reply)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
json_tokener* tok = json_tokener_new_ex(JSON_MAX_DEPTH);
|
||||
if (tok == NULL)
|
||||
{
|
||||
if (quiet)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
std::cerr << "failed allocating json_tokener" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
json_object* obj = json_tokener_parse_ex(tok, reply->payload, -1);
|
||||
enum json_tokener_error err = json_tokener_get_error(tok);
|
||||
json_tokener_free(tok);
|
||||
if (obj == NULL || err != json_tokener_success)
|
||||
{
|
||||
if (!quiet)
|
||||
{
|
||||
std::cerr << "failed to parse payload as json: " << json_tokener_error_desc(err) << std::endl;
|
||||
}
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
else if (quiet)
|
||||
{
|
||||
json_object_put(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
printf("%s\n", json_object_to_json_string(obj));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
|
||||
}
|
||||
fflush(stdout);
|
||||
json_object_put(obj);
|
||||
}
|
||||
|
||||
free_ipc_response(reply);
|
||||
} while (monitor);
|
||||
}
|
||||
|
||||
close(socketfd);
|
||||
free(socket_path);
|
||||
return ret;
|
||||
}
|
@ -33,6 +33,9 @@ apps:
|
||||
miracle-wm-sensible-terminal:
|
||||
command: usr/local/bin/miracle-wm-sensible-terminal
|
||||
|
||||
miraclemsg:
|
||||
command: usr/local/bin/miraclemsg
|
||||
|
||||
parts:
|
||||
miracle-wm:
|
||||
build-attributes:
|
||||
@ -76,6 +79,7 @@ parts:
|
||||
- libgles2-mesa-dev
|
||||
- libmirrenderer-dev
|
||||
- libmirwayland-dev
|
||||
- libjson-c-dev
|
||||
stage-packages:
|
||||
- libmiral7
|
||||
- libmiroil5
|
||||
|
@ -23,6 +23,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
|
||||
MIRACLEMSG_LICENSE = """/**
|
||||
Copyright (C) 2024 Matthew Kosarek
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Portions of this code originate from swaymsg, licensed under the MIT license.
|
||||
See the LICENSE.Sway file for details.
|
||||
**/
|
||||
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser(description="This tool checks the licenses on CPP files and fixes them if told to do so")
|
||||
parser.add_argument('--fix', type=bool,
|
||||
help="Fix the licenses if required")
|
||||
@ -30,26 +52,37 @@ parser.add_argument('--fix', type=bool,
|
||||
args = parser.parse_args()
|
||||
fix = args.fix
|
||||
|
||||
root_dir = Path(__file__).parent.parent / "src"
|
||||
error_files = []
|
||||
error_data = []
|
||||
for x in os.listdir(root_dir.as_posix()):
|
||||
file = root_dir / x
|
||||
if file.as_posix().endswith(".h") or file.as_posix().endswith(".cpp"):
|
||||
with open(file, 'r') as original:
|
||||
content = original.read()
|
||||
if not content.startswith(LICENSE):
|
||||
error_files.append(file.as_posix())
|
||||
error_data.append(content)
|
||||
to_check = ["src", "miraclemsg"]
|
||||
|
||||
if fix is True:
|
||||
for i in range(0, len(error_files)):
|
||||
file = error_files[i]
|
||||
data = error_data[i]
|
||||
with open(file, 'w') as f:
|
||||
f.write(LICENSE)
|
||||
f.write(data)
|
||||
elif len(error_files) > 0:
|
||||
print("The following files are missing the GPL License at the top: ")
|
||||
print(" " + "\n ".join(error_files))
|
||||
exit(1)
|
||||
for d in to_check:
|
||||
root_dir = Path(__file__).parent.parent / d
|
||||
error_files = []
|
||||
error_data = []
|
||||
for x in os.listdir(root_dir.as_posix()):
|
||||
file = root_dir / x
|
||||
if file.as_posix().endswith(".h") or file.as_posix().endswith(".cpp"):
|
||||
with open(file, 'r') as original:
|
||||
content = original.read()
|
||||
is_error = False
|
||||
if d == "miraclemsg":
|
||||
if not content.startswith(MIRACLEMSG_LICENSE):
|
||||
is_error = True
|
||||
elif not content.startswith(LICENSE):
|
||||
is_error = True
|
||||
|
||||
if is_error:
|
||||
error_files.append(file.as_posix())
|
||||
error_data.append(content)
|
||||
|
||||
if fix is True:
|
||||
for i in range(0, len(error_files)):
|
||||
file = error_files[i]
|
||||
data = error_data[i]
|
||||
with open(file, 'w') as f:
|
||||
to_write = MIRACLEMSG_LICENSE if "miraclemsg" in file else LICENSE
|
||||
f.write(to_write)
|
||||
f.write(data)
|
||||
elif len(error_files) > 0:
|
||||
print("The following files are missing the GPL License at the top: ")
|
||||
print(" " + "\n ".join(error_files))
|
||||
exit(1)
|
||||
|
@ -1,3 +1,4 @@
|
||||
#!/bin/bash
|
||||
find ./src/ -regex '.*\.\(cpp\|h\)' -exec clang-format -style=file -i {} \;
|
||||
find ./tests/ -regex '.*\.\(cpp\|h\)' -exec clang-format -style=file -i {} \;
|
||||
find ./tests/ -regex '.*\.\(cpp\|h\)' -exec clang-format -style=file -i {} \;
|
||||
find ./miraclemsg/ -regex '.*\.\(cpp\|h\)' -exec clang-format -style=file -i {} \;
|
||||
|
Loading…
Reference in New Issue
Block a user